@duckmind/dm-darwin-x64 0.52.3 → 0.53.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.
Files changed (56) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +15 -8
  3. package/extensions/dm-cua/bin/browser-cua.mjs +6 -6
  4. package/extensions/dm-cua/index.js +5 -5
  5. package/extensions/dm-cua/src/browser-cua-lib.mjs +2 -2
  6. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +8 -1
  7. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +1 -1
  8. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +1 -1
  9. package/extensions/greedysearch-dm/bin/cdp.mjs +29 -20
  10. package/extensions/greedysearch-dm/bin/gschrome.mjs +1 -10
  11. package/extensions/greedysearch-dm/bin/kill-visible.mjs +1 -1
  12. package/extensions/greedysearch-dm/bin/launch-visible.mjs +1 -4
  13. package/extensions/greedysearch-dm/bin/launch.mjs +9 -5
  14. package/extensions/greedysearch-dm/bin/mcp.mjs +375 -0
  15. package/extensions/greedysearch-dm/bin/search.mjs +310 -156
  16. package/extensions/greedysearch-dm/bin/visible.mjs +1 -1
  17. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +205 -68
  18. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +229 -140
  19. package/extensions/greedysearch-dm/extractors/common.mjs +160 -50
  20. package/extensions/greedysearch-dm/extractors/consensus.mjs +225 -92
  21. package/extensions/greedysearch-dm/extractors/consent.mjs +44 -17
  22. package/extensions/greedysearch-dm/extractors/gemini.mjs +275 -136
  23. package/extensions/greedysearch-dm/extractors/google-ai.mjs +172 -64
  24. package/extensions/greedysearch-dm/extractors/logically.mjs +183 -69
  25. package/extensions/greedysearch-dm/extractors/perplexity.mjs +331 -65
  26. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +118 -41
  27. package/extensions/greedysearch-dm/index.js +20 -17
  28. package/extensions/greedysearch-dm/package.json +8 -3
  29. package/extensions/greedysearch-dm/skills/greedy-search/skill.md +8 -8
  30. package/extensions/greedysearch-dm/src/fetcher.mjs +2 -2
  31. package/extensions/greedysearch-dm/src/formatters/results.js +8 -6
  32. package/extensions/greedysearch-dm/src/github.mjs +7 -7
  33. package/extensions/greedysearch-dm/src/reddit.mjs +1 -1
  34. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +10 -9
  35. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +48 -0
  36. package/extensions/greedysearch-dm/src/search/chrome.mjs +129 -53
  37. package/extensions/greedysearch-dm/src/search/constants.mjs +8 -8
  38. package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
  39. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +154 -77
  40. package/extensions/greedysearch-dm/src/search/minimize.mjs +1 -0
  41. package/extensions/greedysearch-dm/src/search/paths.mjs +1 -1
  42. package/extensions/greedysearch-dm/src/search/pdf.mjs +1 -1
  43. package/extensions/greedysearch-dm/src/search/port-pid.mjs +1 -0
  44. package/extensions/greedysearch-dm/src/search/progress.mjs +2 -0
  45. package/extensions/greedysearch-dm/src/search/recovery.mjs +1 -1
  46. package/extensions/greedysearch-dm/src/search/research.mjs +262 -167
  47. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +11 -0
  48. package/extensions/greedysearch-dm/src/search/simple-research.mjs +827 -0
  49. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +11 -11
  50. package/extensions/greedysearch-dm/src/search/synthesis.mjs +11 -11
  51. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +23 -20
  52. package/extensions/greedysearch-dm/src/tools/shared.js +10 -9
  53. package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +1 -1
  54. package/package.json +1 -1
  55. package/extensions/greedysearch-dm/src/search/cdp-endpoint.mjs +0 -3
  56. package/extensions/greedysearch-dm/src/utils/browser-executable.mjs +0 -1
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_process";import{dirname as oe,join as ue}from"node:path";import{fileURLToPath as le}from"node:url";import{basename as ae}from"node:path";function fe(t=process.env,e=process.execPath){let n=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(n?.trim())return n.trim();let r=ae(e||"").toLowerCase();if(r==="node"||r==="node.exe")return e;return"node"}var ce=oe(le(import.meta.url)),ge=ue(ce,"..","bin","cdp.mjs");function g(t,e=30000){return G(t,null,e)}function G(t,e=null,n=30000){return new Promise((r,i)=>{let o=ie(fe(),[ge,...t],{stdio:[e==null?"ignore":"pipe","pipe","pipe"]});if(e!=null)o.stdin.write(e),o.stdin.end();let u="",a="";o.stdout.on("data",(f)=>u+=f),o.stderr.on("data",(f)=>a+=f);let l=setTimeout(()=>{o.kill(),i(Error(`cdp timeout: ${t[0]}`))},n);o.on("close",(f)=>{if(clearTimeout(l),f===0)r(u.trim());else i(Error(a.trim()||`cdp exit ${f}`))})})}async function st(t){if(t)return t;let e=(await g(["list"])).split(`
3
- `)[0]?.slice(0,8);if(!e)throw Error("No Chrome tabs found. Is Chrome running with --remote-debugging-port=9222?");let n=await g(["evalraw",e,"Target.createTarget",'{"url":"about:blank"}']),{targetId:r}=JSON.parse(n);await g(["list"]);let i=r.slice(0,8);try{await ht(i)}catch(o){process.stderr.write(`[getOrOpenTab] stealth injection failed: ${o.message}
4
- `)}return i}async function bt(t,e){let n=`
2
+ import{randomInt as at}from"node:crypto";import{spawn as lt}from"node:child_process";import{basename as ut}from"node:path";import{dirname as ct,join as ft}from"node:path";import{fileURLToPath as gt}from"node:url";function st(e=process.env,t=process.execPath){let n=e.GREEDY_SEARCH_NODE||e.NODE_BINARY||e.NODE;if(n?.trim())return n.trim();let i=ut(t||"").toLowerCase();if(i==="node"||i==="node.exe")return t;return"node"}var ht=ct(gt(import.meta.url)),pt=ft(ht,"..","bin","cdp.mjs"),mt=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"]);function yt(e){if(!Array.isArray(e)||e.length===0)throw Error("cdp: args must be a non-empty array");if(e[0]==="test")return e.map((t,n)=>pe(t,n));if(!mt.has(e[0]))throw Error(`cdp: unknown subcommand '${e[0]}'`);return e.map((t,n)=>pe(t,n))}function pe(e,t){if(typeof e!=="string")throw Error(`cdp: argv[${t}] must be a string (got ${typeof e})`);if(e.includes("\x00"))throw Error(`cdp: argv[${t}] contains a null byte`);return e}function h(e,t=30000){return ee(e,null,t)}function ee(e,t=null,n=30000){let i=yt(e);return new Promise((r,o)=>{let a=lt(st(),[pt,...i],{stdio:[t==null?"ignore":"pipe","pipe","pipe"]});if(t!=null)a.stdin.write(t),a.stdin.end();let l="",u="";a.stdout.on("data",(s)=>l+=s),a.stderr.on("data",(s)=>u+=s);let f=setTimeout(()=>{a.kill(),o(Error(`cdp timeout: ${e[0]}`))},n);a.on("close",(s)=>{if(clearTimeout(f),s===0)r(l.trim());else o(Error(u.trim()||`cdp exit ${s}`))})})}function me(e,t){let n=(a)=>String(a??"").replace(/\s+/g," ").trim(),i=n(e),r=n(t);if(!r)return!1;if(i.length<Math.ceil(r.length*0.8))return!1;let o=Math.min(40,r.length);return i.includes(r.slice(0,o))&&i.includes(r.slice(-o))}async function ye(e){if(e)return e;let t=(await h(["list"])).split(`
3
+ `)[0]?.slice(0,8);if(!t)throw Error("No Chrome tabs found. Is Chrome running with --remote-debugging-port=9222?");let n=await h(["evalraw",t,"Target.createTarget",'{"url":"about:blank"}']),i;try{i=JSON.parse(n)}catch(a){throw Error(`Target.createTarget returned invalid JSON: ${a.message}`)}let{targetId:r}=i;if(!r)throw Error("Target.createTarget did not return a targetId");await h(["list"]);let o=r.slice(0,8);try{await be(o)}catch(a){process.stderr.write(`[getOrOpenTab] stealth injection failed: ${a.message}
4
+ `)}return o}async function de(e,t){let n=`
5
5
  (() => {
6
- window.${e} = null;
6
+ window.${t} = null;
7
7
  const _clipboard = navigator.clipboard;
8
8
  if (!_clipboard) return;
9
9
  const _origWriteText = typeof _clipboard.writeText === 'function'
@@ -14,7 +14,7 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
14
14
  : null;
15
15
 
16
16
  _clipboard.writeText = function(text) {
17
- window.${e} = String(text ?? '');
17
+ window.${t} = String(text ?? '');
18
18
  if (!_origWriteText) return Promise.resolve();
19
19
  // The OS/browser clipboard write may be denied in automated Chrome or
20
20
  // when the tab is not focused. We only need the captured text; returning
@@ -28,7 +28,7 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
28
28
  for (const item of items || []) {
29
29
  if (item.types && item.types.includes('text/plain')) {
30
30
  const blob = await item.getType('text/plain');
31
- window.${e} = await blob.text();
31
+ window.${t} = await blob.text();
32
32
  break;
33
33
  }
34
34
  }
@@ -38,7 +38,26 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
38
38
  catch (_) { return undefined; }
39
39
  };
40
40
  })();
41
- `;await g(["eval",t,n])}async function ht(t){await g(["evalraw",t,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
41
+ `;await h(["eval",e,n])}async function te(e,t,n,i={}){let{timeoutMs:r=2600}=i,o=i.retryClick!=null?i.retryClick:Math.floor(r*0.4),a=String.raw`
42
+ new Promise((resolve) => {
43
+ const _deadline = Date.now() + ${r};
44
+ const _retryAt = Date.now() + ${o};
45
+ let _retried = false;
46
+ function _click() { try { ${t}; } catch(_) {} }
47
+ function _poll() {
48
+ const val = window.${n};
49
+ if (val) { resolve(val); return; }
50
+ if (!_retried && Date.now() >= _retryAt) {
51
+ _retried = true;
52
+ _click();
53
+ }
54
+ if (Date.now() < _deadline) { setTimeout(_poll, 100); }
55
+ else { resolve(window.${n} || ''); }
56
+ }
57
+ _click();
58
+ _poll();
59
+ })
60
+ `;return await h(["eval",e,a],r+5000).catch(()=>"")}async function be(e){await h(["evalraw",e,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
42
61
  (function() {
43
62
  // ── Runtime.enable / CDP detection masking ──────────────
44
63
  try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
@@ -49,40 +68,62 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
49
68
  try { delete window._phantom; } catch(_) {}
50
69
  try { delete window.Buffer; } catch(_) {}
51
70
 
52
- // Real Chrome without automation does not expose a useful webdriver value.
53
- // A literal false value is itself a common stealth tell; prefer undefined and
54
- // make the descriptor configurable like native browser properties.
55
- Object.defineProperty(navigator, 'webdriver', { get: () => undefined, configurable: true });
71
+ // Real Chrome without automation should not expose navigator.webdriver at all.
72
+ // A literal false or an own-property getter returning undefined is itself a
73
+ // common stealth tell; remove both instance and prototype properties when the
74
+ // descriptor is configurable (as it is with --disable-blink-features).
75
+ try { delete navigator.webdriver; } catch(_) {}
76
+ try { delete Navigator.prototype.webdriver; } catch(_) {}
56
77
  Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
57
78
  Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
58
79
  Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
59
80
  Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
81
+ Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
82
+ Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
83
+ var __greedyMimeTypes = null;
84
+ function __makeMimeTypes() {
85
+ var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
86
+ var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
87
+ try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
88
+ try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
89
+ var m = [pdf, textPdf];
90
+ try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
91
+ m.item = function item(i) { return this[i] || null; };
92
+ m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
93
+ return m;
94
+ }
60
95
  Object.defineProperty(navigator, 'plugins', {
61
96
  get: () => {
62
- var p = [
63
- { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
64
- { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
65
- { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' },
66
- ];
67
- p.length = 3;
97
+ __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
98
+ var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
99
+ var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
100
+ var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
101
+ try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
102
+ try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
103
+ try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
104
+ var p = [plugin0, plugin1, plugin2];
105
+ p.item = function item(i) { return this[i] || null; };
106
+ p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
107
+ p.refresh = function refresh() {};
108
+ try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
109
+ try {
110
+ __greedyMimeTypes[0].enabledPlugin = p[0];
111
+ __greedyMimeTypes[1].enabledPlugin = p[0];
112
+ } catch(_) {}
68
113
  return p;
69
114
  },
115
+ configurable: true,
70
116
  });
71
117
  Object.defineProperty(navigator, 'mimeTypes', {
72
118
  get: () => {
73
- var m = [
74
- { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null },
75
- { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null },
76
- ];
77
- m.item = function(i) { return m[i] || null; };
78
- m.namedItem = function(name) { return m.find(function(x) { return x.type === name; }) || null; };
79
- return m;
119
+ __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
120
+ return __greedyMimeTypes;
80
121
  },
81
122
  configurable: true,
82
123
  });
83
124
  Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
84
125
  try {
85
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, saveData: false }), configurable: true });
126
+ Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
86
127
  } catch(_) {}
87
128
  if (!navigator.mediaDevices) {
88
129
  Object.defineProperty(navigator, 'mediaDevices', {
@@ -98,6 +139,18 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
98
139
  configurable: true,
99
140
  });
100
141
  }
142
+ // ── Missing platform APIs (headless often lacks these) ─
143
+ try {
144
+ if (!navigator.share) {
145
+ navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
146
+ }
147
+ } catch(_) {}
148
+ try {
149
+ if (!navigator.contentIndex) {
150
+ Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
151
+ }
152
+ } catch(_) {}
153
+
101
154
  if (!window.chrome) {
102
155
  window.chrome = {
103
156
  app: { isInstalled: false, InstallState: {}, RunningState: {} },
@@ -105,8 +158,8 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
105
158
  OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
106
159
  connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
107
160
  },
108
- loadTimes: () => ({}),
109
- csi: () => ({}),
161
+ loadTimes: function() { return { requestTime: 0, startLoadTime: Date.now() - 5000, commitLoadTime: Date.now() - 3000, finishDocumentLoadTime: Date.now() - 2000, finishLoadTime: Date.now() - 1000, firstPaintTime: Date.now() - 800, navigationType: 'Other', wasFetchedViaSpdy: true, wasNpnNegotiated: true, npnNegotiatedProtocol: 'h2', wasAlternateProtocolAvailable: false, connectionInfo: 'http/2' }; },
162
+ csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
110
163
  };
111
164
  }
112
165
  var __greedyNativeFns = [];
@@ -127,6 +180,19 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
127
180
  return getParam.call(this, p);
128
181
  });
129
182
  } catch(_) {}
183
+ // ── WebGL readPixels noise ──────────────────────────
184
+ // CreepJS and other fingerprinters draw content with WebGL and read back the
185
+ // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
186
+ try {
187
+ var origReadPixels = WebGLRenderingContext.prototype.readPixels;
188
+ WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
189
+ var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
190
+ if (pixels && pixels.length > 0) {
191
+ pixels[0] ^= 1;
192
+ }
193
+ return result;
194
+ });
195
+ } catch(_) {}
130
196
  Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
131
197
  Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
132
198
 
@@ -134,7 +200,7 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
134
200
  // Headless rendering engines produce slightly different canvas output
135
201
  // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
136
202
  try {
137
- var __canvasNoise = ((Date.now() % 997) + Math.floor(Math.random() * 997)) & 1;
203
+ var __canvasNoise = ((Date.now() & 0xFF) | 1);
138
204
  var origFill = CanvasRenderingContext2D.prototype.fillText;
139
205
  CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
140
206
  this.globalAlpha = 0.9995;
@@ -153,15 +219,39 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
153
219
  HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
154
220
  var ctx = this.getContext('2d');
155
221
  if (ctx) {
156
- // Add 1px noise pixel in corner (invisible but changes hash)
157
- var imgData = ctx.getImageData(0, 0, 1, 1);
158
- if (imgData) imgData.data[0] ^= __canvasNoise;
159
- ctx.putImageData(imgData, 0, 0);
222
+ // Spread noise across canvas to break hash-based fingerprinting.
223
+ // Uses a deterministic pattern so it's consistent per page load
224
+ // but varies between sessions.
225
+ var w = this.width, h = this.height;
226
+ if (w > 0 && h > 0) {
227
+ var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
228
+ if (imgData && imgData.data) {
229
+ for (var __i = 0; __i < imgData.data.length; __i += 4) {
230
+ imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
231
+ }
232
+ ctx.putImageData(imgData, 0, 0);
233
+ }
234
+ }
160
235
  }
161
236
  return origToDataURL.apply(this, arguments);
162
237
  });
163
238
  } catch(_) {}
164
239
 
240
+ // ── AudioContext fingerprint noise ────────────────────
241
+ // Headless Chrome's AudioContext produces slightly different output.
242
+ // Subtle noise breaks audio-based fingerprinting.
243
+ try {
244
+ var __audioSeed = ((Date.now() & 0x1F) | 1);
245
+ var origGetChannelData = AudioBuffer.prototype.getChannelData;
246
+ AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
247
+ var data = origGetChannelData.call(this, channel);
248
+ for (var __i = 0; __i < data.length; __i += 64) {
249
+ data[__i] *= 0.99999;
250
+ }
251
+ return data;
252
+ });
253
+ } catch(_) {}
254
+
165
255
  // ── window outer dimensions ──────────────────────────
166
256
  // outerWidth/Height = 0 in headless — a well-known bot signal.
167
257
  // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
@@ -171,9 +261,15 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
171
261
  } catch(_) {}
172
262
 
173
263
  // ── screen properties ─────────────────────────────────
264
+ // Headless Chrome often reports an 800x600 screen even when the viewport is
265
+ // 1920x1080. Keep screen metrics internally consistent with our launch flags.
174
266
  try {
175
- if (!screen.colorDepth) Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
176
- if (!screen.pixelDepth) Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
267
+ Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
268
+ Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
269
+ Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
270
+ Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
271
+ Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
272
+ Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
177
273
  } catch(_) {}
178
274
 
179
275
  // ── navigator.userAgentData (UA Client Hints) ─────────
@@ -246,12 +342,12 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
246
342
  };
247
343
  } catch(_) {}
248
344
  })();
249
- `})])}function yt(t){if(!t)return[];let e=[],n=0;while(n<t.length&&e.length<10){let r=t.indexOf("[",n);if(r===-1)break;let i=t.indexOf("](",r);if(i===-1)break;let o=i+2,u=-1;for(let a=o;a<t.length;a++){let l=t[a];if(l===")"){u=a;break}if(/\s/.test(l))break}if(u!==-1){let a=t.slice(r+1,i),l=t.slice(o,u);if(/^https?:\/\//i.test(l)&&a){if(!e.some((f)=>f.url===l))e.push({title:a,url:l})}n=u+1}else n=r+1}return e}var T={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};function B(t){let e=t*0.4,n=re(-Math.floor(e),Math.floor(e)+1);return Math.max(50,Math.round(t+n))}async function wt(t,e={}){let{timeout:n=20000,interval:r=600,stableRounds:i=3,selector:o="document.body",minLength:u=0}=e,a=String.raw`
345
+ `})])}function ve(e){if(!e)return[];let t=[],n=0;while(n<e.length&&t.length<10){let i=e.indexOf("[",n);if(i===-1)break;let r=e.indexOf("](",i);if(r===-1)break;let o=r+2,a=-1;for(let l=o;l<e.length;l++){let u=e[l];if(u===")"){a=l;break}if(/\s/.test(u))break}if(a!==-1){let l=e.slice(i+1,r),u=e.slice(o,a);if(/^https?:\/\//i.test(u)&&l){if(!t.some((f)=>f.url===u))t.push({title:l,url:u})}n=a+1}else n=i+1}return t}var Q={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};function B(e){let t=e*0.2,n=at(-Math.floor(t),Math.floor(t)+1);return Math.max(50,Math.round(e+n))}async function we(e,t={}){let{timeout:n=20000,interval:i=600,stableRounds:r=3,selector:o="document.body",minLength:a=0,isStreamingExpr:l="false"}=t,u=String.raw`
250
346
  new Promise((resolve, reject) => {
251
347
  const _deadline = Date.now() + ${n};
252
- const _baseInterval = ${r};
253
- const _stableRounds = ${i};
254
- const _minLength = ${u};
348
+ const _baseInterval = ${i};
349
+ const _stableRounds = ${r};
350
+ const _minLength = ${a};
255
351
  let _lastLen = -1;
256
352
  let _stableCount = 0;
257
353
 
@@ -263,8 +359,12 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
263
359
  try {
264
360
  // Re-query DOM each tick — element may not exist at eval start
265
361
  const el = ${o};
266
- const cur = el?.innerText?.length ?? 0;
267
- if (cur >= _minLength) {
362
+ const cur = el?.textContent?.length ?? 0;
363
+ const streaming = ${l};
364
+ if (streaming) {
365
+ if (cur !== _lastLen) _lastLen = cur;
366
+ _stableCount = 0;
367
+ } else if (cur >= _minLength) {
268
368
  if (cur === _lastLen) {
269
369
  _stableCount++;
270
370
  if (_stableCount >= _stableRounds) { resolve(cur); return; }
@@ -276,7 +376,7 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
276
376
  if (Date.now() < _deadline) {
277
377
  setTimeout(_poll, _jitter(_baseInterval));
278
378
  } else {
279
- if (_lastLen >= _minLength) { resolve(_lastLen); }
379
+ if (_lastLen >= _minLength && !streaming) { resolve(_lastLen); }
280
380
  else { reject(new Error('Generation did not stabilise within ${n}ms')); }
281
381
  }
282
382
  } catch(e) { reject(e); }
@@ -284,10 +384,10 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
284
384
 
285
385
  _poll();
286
386
  })
287
- `,l=await g(["eval",t,a],n+1e4),f=parseInt(l,10)||0;if(f>=u)return f;throw Error(`Generation did not stabilise within ${n}ms`)}async function mt(t,e,n=15000,r=500){let i=String.raw`
387
+ `,f=await h(["eval",e,u],n+1e4),s=parseInt(f,10)||0;if(s>=a)return s;throw Error(`Generation did not stabilise within ${n}ms`)}async function xe(e,t,n=15000,i=500){let r=String.raw`
288
388
  new Promise((resolve) => {
289
389
  const _deadline = Date.now() + ${n};
290
- const _baseInterval = ${r};
390
+ const _baseInterval = ${i};
291
391
 
292
392
  function _jitter(ms) {
293
393
  return Math.max(50, ms + (Math.random() * ms * 0.4 - ms * 0.2));
@@ -295,7 +395,7 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
295
395
 
296
396
  function _poll() {
297
397
  try {
298
- if (document.querySelector('${e}')) { resolve(true); return; }
398
+ if (document.querySelector('${t}')) { resolve(true); return; }
299
399
  if (Date.now() < _deadline) { setTimeout(_poll, _jitter(_baseInterval)); }
300
400
  else { resolve(false); }
301
401
  } catch(_) { resolve(false); }
@@ -303,27 +403,26 @@ import{randomInt as re}from"node:crypto";import{spawn as ie}from"node:child_proc
303
403
 
304
404
  _poll();
305
405
  })
306
- `;return await g(["eval",t,i],n+5000)==="true"}async function vt(t){let e=t.indexOf("--stdin");if(e===-1)return t;let n=await new Promise((i)=>{let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(u)=>o+=u),process.stdin.on("end",()=>i(o.trim()))}),r=[...t];return r[e]=n,r}function pt(t){let e=t.includes("--short"),n=t.filter((a)=>a!=="--short"),r=n.indexOf("--tab"),i=r===-1?null:n[r+1];if(r!==-1)n=n.filter((a,l)=>l!==r&&l!==r+1);let o=n.indexOf("--locale"),u=o===-1?null:n[o+1];if(o!==-1)n=n.filter((a,l)=>l!==o&&l!==o+1);return{query:n.join(" "),tabPrefix:i,short:e,locale:u}}function xt(t,e){if(!t.length||t[0]==="--help")process.stderr.write(e),process.exit(1)}function $t(t,e,n=300){if(!e||t.length<=n)return t;let r=t.slice(0,n),i=r.lastIndexOf(" ");return i>0?`${r.slice(0,i)}…`:`${r}…`}function Jt(t){process.stdout.write(`${JSON.stringify(t,null,2)}
307
- `)}function kt(t,e=null){if(e){let n=JSON.stringify({_envelope:e,error:t.message});process.stdout.write(`${n}
308
- `)}process.stderr.write(`Error: ${t.message}
309
- `),process.exit(1)}import{spawn as Ce,execFileSync as zt,execSync as ot}from"node:child_process";import{existsSync as R,readFileSync as S,renameSync as de,unlinkSync as p,writeFileSync as z}from"node:fs";import ut from"node:http";import{platform as lt,tmpdir as Ye}from"node:os";import{join as ze}from"node:path";import{basename as se}from"node:path";function Wt(t=process.env,e=process.execPath){let n=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(n?.trim())return n.trim();let r=se(e||"").toLowerCase();if(r==="node"||r==="node.exe")return e;return"node"}import{existsSync as Nt}from"node:fs";import{platform as be}from"node:os";import{join as x}from"node:path";function y(t){let e=be()==="win32",n=process.env.SystemRoot||"C:\\Windows",r={win32:{powershell:x(n,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:x(n,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:x(n,"System32","netstat.exe"),taskkill:x(n,"System32","taskkill.exe"),tasklist:x(n,"System32","tasklist.exe"),cmd:x(n,"System32","cmd.exe")},unix:{ps:"/usr/bin/ps",lsof:"/usr/bin/lsof",ss:"/usr/sbin/ss",grep:"/usr/bin/grep",kill:"/usr/bin/kill"}},i=e?r.win32:r.unix,o=t.toLowerCase();if(i[o]&&Nt(i[o]))return i[o];if(e&&o==="netstat"){let u=x(n,"Sysnative","netstat.exe");if(Nt(u))return u}return t}import{existsSync as M,mkdirSync as he,readFileSync as qt,writeFileSync as ye}from"node:fs";import{homedir as we}from"node:os";import{join as Qt}from"node:path";import{tmpdir as U}from"node:os";var h=9222,$=`${U().replaceAll("\\","/")}/greedysearch-chrome-profile`,X=`${$}/DevToolsActivePort`,me=`${U().replaceAll("\\","/")}/cdp-pages.json`,J=`${U().replaceAll("\\","/")}/greedysearch-chrome-mode`,On=`${U().replaceAll("\\","/")}/greedysearch-visible-recovery.jsonl`,I=Qt(we(),".dm"),v=Qt(I,"greedyconfig"),F=["perplexity","google","chatgpt"],E="gemini";function ve(){try{if(M(v)){let t=qt(v,"utf8"),e=JSON.parse(t);if(Array.isArray(e.engines)&&e.engines.length>0&&e.engines.every((n)=>typeof n==="string")){let n=e.engines.filter((i)=>L[i]),r=e.engines.filter((i)=>!L[i]);if(r.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${v}: ${r.join(", ")}
310
- [greedysearch] Available engines: ${Object.keys(L).join(", ")}
311
- `);if(n.length>0)return n;process.stderr.write(`[greedysearch] Warning: no valid engines in ${v}, falling back to defaults: ${F.join(", ")}
312
- `)}}}catch{}return F}function pe(){try{if(!M(I))he(I,{recursive:!0});if(!M(v))ye(v,JSON.stringify({engines:F,synthesizer:E},null,2)+`
313
- `,"utf8")}catch{}}pe();var Xt=["gemini","chatgpt"];function xe(){try{if(M(v)){let t=qt(v,"utf8"),e=JSON.parse(t);if(typeof e.synthesizer==="string"){let n=e.synthesizer.toLowerCase();if(Xt.includes(n))return n;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${e.synthesizer}" in ${v}
314
- [greedysearch] Available synthesizers: ${Xt.join(", ")}
315
- [greedysearch] Falling back to default: ${E}
316
- `)}}}catch{}return E}var L={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},_n=ve();var An=xe(),Tn=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=$;import{existsSync as Kn,mkdirSync as $e,readFileSync as Bt,renameSync as Je,unlinkSync as ke,writeFileSync as Zt}from"node:fs";import We from"node:http";import{platform as Ht}from"node:os";import{dirname as Ne}from"node:path";var Vt=[9222,9223],Xe=/^(0|false|no|off)$/i;function qe(t){return[...new Set(t.filter(Boolean))]}function jt(t,e="explicit"){let n=new URL(t),r=n.protocol==="wss:"?"wss:":"ws:",i=n.port?Number.parseInt(n.port,10):r==="wss:"?443:80;return{source:e,wsUrl:`${r}//${n.host}${n.pathname}${n.search}`,host:n.hostname,port:i,path:`${n.pathname}${n.search}`,httpUrl:`http://${n.hostname}:${i}`}}function Ot(t=process.env){return![t.GREEDY_SEARCH_REUSE_EXISTING_BROWSER,t.DM_CUA_REUSE_EXISTING_BROWSER].some((e)=>e!==void 0&&Xe.test(String(e)))}function tt(t){let e=Number.parseInt(String(t??""),10);return Number.isInteger(e)&&e>0&&e<65536?e:null}function Qe(t){if(!t)return null;let e=String(t).trim();if(!e)return null;let n=new URL(e.includes("://")?e:`http://${e}`),r=tt(n.port)||(n.protocol==="https:"?443:80);return{host:n.hostname,port:r,source:`env:${e}`}}function je(t){if(!t)return[];return String(t).split(/[,\s]+/).map(tt).filter(Boolean)}function Be({env:t=process.env,platformName:e=Ht(),procVersionText:n=null}={}){if(e!=="linux")return!1;if(t.WSL_DISTRO_NAME||t.WSL_INTEROP)return!0;let r=n??(()=>{try{return Bt("/proc/version","utf8")}catch{return""}})();return/microsoft|wsl/i.test(r)}function Ze({env:t=process.env,platformName:e=Ht(),procVersionText:n=null,resolvConfText:r=null}={}){let i=["localhost","127.0.0.1"];if(Be({env:t,platformName:e,procVersionText:n})){let u=(r??(()=>{try{return Bt("/etc/resolv.conf","utf8")}catch{return""}})()).match(/^\s*nameserver\s+([^\s#]+)/m);if(u)i.push(u[1]);i.push("host.docker.internal")}return qe(i)}function He({env:t=process.env,hosts:e=Ze({env:t}),autoPorts:n=Vt,excludePorts:r=[]}={}){let i=[];for(let l of["GREEDY_SEARCH_CDP_WS_URL","DM_CUA_CDP_WS_URL","CDP_WS_URL"])if(t[l])i.push({wsUrl:t[l],source:`env:${l}`});for(let l of["GREEDY_SEARCH_CDP_URL","DM_CUA_CDP_URL","CDP_URL"])try{let f=Qe(t[l]);if(f)i.push(f)}catch{}for(let l of["GREEDY_SEARCH_EXISTING_CDP_PORT","DM_CUA_EXISTING_CDP_PORT","GREEDY_SEARCH_CDP_PORT","DM_CUA_CDP_PORT"]){let f=tt(t[l]);if(!f)continue;for(let c of e)i.push({host:c,port:f,source:`env:${l}`})}let o=je(t.GREEDY_SEARCH_EXISTING_CDP_PORTS);for(let l of o)for(let f of e)i.push({host:f,port:l,source:"env:GREEDY_SEARCH_EXISTING_CDP_PORTS"});let u=new Set(r.filter(Boolean));if(Ot(t))for(let l of n){if(u.has(l))continue;for(let f of e)i.push({host:f,port:l,source:"auto"})}let a=new Set;return i.filter((l)=>{let f=l.wsUrl||`${l.host}:${l.port}`;if(a.has(f))return!1;return a.add(f),!0})}async function Ve(t,{timeoutMs:e=700}={}){if(t.wsUrl)return jt(t.wsUrl,t.source);let n=t.host||"localhost",r=t.port;if(!r)return null;let i=await new Promise((o)=>{let u=We.get({host:n,port:r,path:"/json/version",timeout:e},(a)=>{let l="";a.setEncoding("utf8"),a.on("data",(f)=>l+=f),a.on("end",()=>o(a.statusCode===200?l:null))});u.on("error",()=>o(null)),u.setTimeout(e,()=>{u.destroy(),o(null)})});if(!i)return null;try{let o=JSON.parse(i);if(!o.webSocketDebuggerUrl)return null;let u=jt(o.webSocketDebuggerUrl,t.source),a=u.path||new URL(o.webSocketDebuggerUrl).pathname;return{...u,host:n,port:r,httpUrl:`http://${n}:${r}`,wsUrl:`ws://${n}:${r}${a}`,path:a}}catch{return null}}async function Oe(t={}){for(let e of He(t)){let n=await Ve(e,t);if(n)return n}return null}function _e(t){if(!t)throw Error("missing CDP endpoint");let e=new URL(t.wsUrl);return`${e.host}
317
- ${e.pathname}${e.search}
318
- `}function Ae(t,e){$e(Ne(t),{recursive:!0});let n=`${t}.tmp-${process.pid}`;Zt(n,_e(e),"utf8");try{ke(t)}catch{}Je(n,t)}async function _t({activePortFile:t,modeFile:e,env:n=process.env,excludePorts:r=[],autoPorts:i=Vt}={}){if(!Ot(n))return null;let o=await Oe({env:n,excludePorts:r,autoPorts:i});if(!o)return null;if(Ae(t,o),e)Zt(e,"existing","utf8");return o}import{execFileSync as At,execSync as et}from"node:child_process";import{existsSync as K,mkdirSync as Te,readFileSync as q,unlinkSync as W,writeFileSync as N}from"node:fs";import{platform as nt,tmpdir as Dt}from"node:os";var V=Dt().replaceAll("\\","/"),D=`${V}/greedysearch-chrome-metadata.json`,k=`${V}/greedysearch-chrome-launch.lock`,Me=15000,C=`${V}/greedysearch-chrome.pid`,d=`${V}/greedysearch-chrome-mode`,Z=`${V}/greedysearch-chrome-last-activity`;function H(t){if(!Number.isInteger(t)||t<=0)return!1;try{return process.kill(t,0),!0}catch{return!1}}function Ue(t){if(!H(t))return null;try{if(nt()==="win32")return At(y("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${t}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return At(y("ps"),["-p",String(t),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Ke(t,e,n=h){if(!t)return!1;let r=(u)=>String(u||"").replaceAll("\\","/").toLowerCase(),i=r(t),o=r(e);return i.includes(o)&&i.includes(`--remote-debugging-port=${n}`)&&!i.includes("--type=")}function Tt(t,e,n=h){return Ke(Ue(t),e,n)}function De(t=h){try{if(nt()==="win32"){let n=et(`${y("netstat")} -ano -p TCP 2>nul`,{encoding:"utf8"}),r=new RegExp(String.raw`TCP\s+\S+:${t}\s+\S+:0\s+LISTENING\s+(\d+)`,"i"),i=n.match(r);return i?Number.parseInt(i[1],10):null}let e=et(`${y("lsof")} -i :${t} -t 2>/dev/null || ${y("ss")} -tlnp 2>/dev/null | ${y("grep")} :${t} | ${y("grep")} -oP 'pid=\\K\\d+'`,{encoding:"utf8"}).trim();return e?Number.parseInt(e.split(`
319
- `)[0],10):null}catch{return null}}function Mt(t){try{if(nt()==="win32")et(`${y("taskkill")} /F /T /PID ${t}`,{stdio:"ignore"});else{try{process.kill(-t,"SIGKILL")}catch{}try{process.kill(t,"SIGKILL")}catch{}}return!0}catch{return!1}}function O(){try{if(K(D)){let t=q(D,"utf8"),e=JSON.parse(t);if(e&&typeof e.tempDir==="string"&&typeof e.debugPort==="number")return{browserPid:Number.isInteger(e.browserPid)?e.browserPid:void 0,debugPort:e.debugPort,tempDir:e.tempDir,clientPids:Array.isArray(e.clientPids)?e.clientPids.filter((n)=>Number.isInteger(n)&&n>0):[],sessionMode:e.sessionMode==="visible"?"visible":"headless",lastActivity:Number.isFinite(e.lastActivity)?e.lastActivity:0,launchedAt:Number.isFinite(e.launchedAt)?e.launchedAt:0}}}catch{}try{let t=K(C)?Number.parseInt(q(C,"utf8").trim(),10)||void 0:void 0,e=K(d)?q(d,"utf8").trim()==="visible"?"visible":"headless":"headless",n=K(Z)?Number.parseInt(q(Z,"utf8").trim(),10)||0:0;return{browserPid:t,debugPort:h,tempDir:$,clientPids:t?[t]:[],sessionMode:e,lastActivity:n,launchedAt:0}}catch{return null}}function Y(t){try{N(D,JSON.stringify({browserPid:t.browserPid,debugPort:t.debugPort,tempDir:t.tempDir,clientPids:[...new Set(t.clientPids.filter((e)=>e>0))],sessionMode:t.sessionMode,lastActivity:t.lastActivity,launchedAt:t.launchedAt},null,2),"utf8")}catch{}try{if(t.browserPid)N(C,String(t.browserPid),"utf8")}catch{}try{N(d,t.sessionMode,"utf8")}catch{}try{N(Z,String(t.lastActivity),"utf8")}catch{}}function Ut(){try{W(D)}catch{}try{W(C)}catch{}try{W(d)}catch{}try{W(Z)}catch{}}function Ct(t){if(!t)return t;let e={...t,clientPids:[...new Set([...t.clientPids,process.pid].filter((n)=>H(n)||n===process.pid))]};return Y(e),e}function rt(t){let e=Date.now();try{if(t)Y({...t,lastActivity:e});else N(Z,String(e),"utf8")}catch{}}var Ln=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Kt=!1;function dt(){if(Kt)return;Kt=!0;let t=O();if(!t)return;if(t.browserPid){if(!H(t.browserPid)){Mt(t.browserPid),Ut();return}if(!Tt(t.browserPid,t.tempDir,t.debugPort))Ut();else Y({...t,clientPids:t.clientPids.filter((i)=>H(i))})}let e=De();if(e&&e!==t.browserPid)if(Tt(e,$,h))Y({browserPid:e,debugPort:h,tempDir:$,clientPids:[e],sessionMode:t.sessionMode,lastActivity:Date.now(),launchedAt:Date.now()});else Mt(e)}function Yt(){Te(Dt(),{recursive:!0});try{let t=JSON.stringify({pid:process.pid,ts:Date.now()});return N(k,t,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{let e=q(k,"utf8");if(JSON.parse(e).pid===process.pid)W(k)}catch{}}}}catch(t){if(t?.code!=="EEXIST")return{acquired:!1,release:()=>{}}}try{let t=q(k,"utf8"),e=JSON.parse(t),n=Date.now()-(e.ts||0);if(!H(e.pid)||n>Me){try{W(k)}catch{}try{let i=JSON.stringify({pid:process.pid,ts:Date.now()});return N(k,i,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{W(k)}catch{}}}}catch{return{acquired:!1,release:()=>{}}}}}catch{}return{acquired:!1,release:()=>{}}}var Re=import.meta.dirname||new URL(".",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1"),St=Ye().replaceAll("\\","/"),_=`${St}/greedysearch-chrome.pid`,A=`${St}/greedysearch-chrome-last-activity`,Se=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,Pe=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;function Ge(t,e=h){let n=String(t||"").toLowerCase();if(!n.includes(`--remote-debugging-port=${e}`)||n.includes("--type="))return null;return n.includes("--headless")}function Pt(){try{let t=at(),e=t?Ie(t):null,n=Ge(e);if(n!==null){try{z(J,n?"headless":"visible","utf8")}catch{}return n}}catch{}try{if(!R(J))return!0;return S(J,"utf8").trim()==="headless"}catch{return!0}}function Le(){try{z(A,String(Date.now()),"utf8")}catch{}try{let t=O();if(t)rt(t)}catch{}}function Ie(t){try{if(lt()==="win32")return zt(y("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${t}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return zt(y("ps"),["-p",String(t),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function at(){try{if(lt()==="win32"){let e=ot(`${y("netstat")} -ano -p TCP 2>nul`,{encoding:"utf8"}),n=new RegExp(String.raw`TCP\s+\S+:${h}\s+\S+:0\s+LISTENING\s+(\d+)`,"i"),r=e.match(n);return r?Number.parseInt(r[1],10):null}let t=ot(`${y("lsof")} -i :${h} -t 2>/dev/null || ${y("ss")} -tlnp 2>/dev/null | ${y("grep")} :${h} | ${y("grep")} -oP 'pid=\\K\\d+'`,{encoding:"utf8"}).trim();return t?Number.parseInt(t.split(`
320
- `)[0],10):null}catch{return null}}async function Fe(t=1500){try{let n=await new Promise((i,o)=>{let u=ut.get(`http://localhost:${h}/json/version`,(a)=>{let l="";a.on("data",(f)=>l+=f),a.on("end",()=>{try{i(JSON.parse(l))}catch{o(Error("bad JSON"))}})});u.on("error",o),u.setTimeout(1000,()=>{u.destroy(),o(Error("timeout"))})}),r=new globalThis.WebSocket(n.webSocketDebuggerUrl);await new Promise((i)=>{r.onopen=()=>{r.send(JSON.stringify({id:1,method:"Browser.close"})),setTimeout(()=>{r.close(),i()},200)},r.onerror=()=>i(),setTimeout(i,1000)})}catch{}let e=Date.now()+t;while(Date.now()<e){if(!at())return!0;await new Promise((r)=>setTimeout(r,150))}return Ee()}function Ee(){try{let t=at();if(!t&&R(_))t=Number.parseInt(S(_,"utf8").trim(),10)||null;if(!t)return!1;if(lt()==="win32")ot(`${y("taskkill")} /F /PID ${t}`,{stdio:"ignore"});else process.kill(t,"SIGKILL");return!0}catch{return!1}}async function Gt(){if(!await Q(500)){try{p(_)}catch{}try{p(A)}catch{}try{p(J)}catch{}return!1}let e=await Fe(1500);try{p(_)}catch{}try{p(A)}catch{}try{p(J)}catch{}if(e)process.stderr.write(`[greedysearch] Killed Chrome on port ${h}.
321
- `);return e}var Rt=Gt;async function tn(){let e=Pt()?Se:Pe;if(e<=0)return!1;if(!R(A))return Le(),!1;try{let n=Number.parseInt(S(A,"utf8").trim(),10);if(!n)return!1;if((Date.now()-n)/60000>=e)return Gt()}catch{}return!1}function Q(t=3000){return new Promise((e)=>{let n=ut.get(`http://localhost:${h}/json/version`,(r)=>{r.resume(),e(r.statusCode===200)});n.on("error",()=>e(!1)),n.setTimeout(t,()=>{n.destroy(),e(!1)})})}async function it(){let t=`${X}.lock`,e=`${X}.tmp`,n=5000,r=1000,i=await new Promise((o)=>{let u=Date.now(),a=()=>{try{let l=JSON.stringify({pid:process.pid,ts:Date.now()});z(t,l,{encoding:"utf8",flag:"wx"}),o(!0)}catch(l){if(l?.code!=="EEXIST"){if(Date.now()-u<1000)setTimeout(a,50);else o(!1);return}try{let f=S(t,"utf8").trim(),c=f.startsWith("{")?JSON.parse(f):{ts:Number(f)},b=Number(c?.ts)||0;if(b>0&&Date.now()-b>5000)try{p(t)}catch{}if(Date.now()-u<1000)setTimeout(a,50);else o(!1)}catch{if(Date.now()-u<1000)setTimeout(a,50);else o(!1)}}};a()});try{let o=await new Promise((f,c)=>{let b=ut.get(`http://localhost:${h}/json/version`,(s)=>{let m="";s.on("data",(P)=>m+=P),s.on("end",()=>f(m))});b.on("error",c),b.setTimeout(3000,()=>{b.destroy(),c(Error("timeout"))})}),{webSocketDebuggerUrl:u}=JSON.parse(o),a=new URL(u),l=`${a.pathname}${a.search}`;if(i){z(e,`localhost:${h}
322
- ${l}`,"utf8");try{p(X)}catch{}de(e,X)}}catch{}finally{if(i)try{p(t)}catch{}}}async function Lt(){let t=R(_)||!!O(),e=await _t({activePortFile:X,modeFile:J,excludePorts:t?[h]:[]});if(e){process.stderr.write(`[greedysearch] Reusing existing browser CDP endpoint ${e.httpUrl} (${e.source}).
323
- `);return}dt();let n=await tn(),r=n?!1:await Q();if(!r&&!n)await new Promise((a)=>setTimeout(a,500)),r=await Q();let i=!1;if(r){let a=Pt(),l=process.env.GREEDY_SEARCH_VISIBLE==="1";if(!l&&!a)process.stderr.write(`[greedysearch] Visible Chrome detected — switching to headless mode...
324
- `),await Rt(),await new Promise((f)=>setTimeout(f,1000)),i=!0;else if(l&&a)process.stderr.write(`[greedysearch] Headless Chrome detected switching to visible mode...
325
- `),await Rt(),await new Promise((f)=>setTimeout(f,1000)),i=!0}if(i?!1:await Q()){await it();try{let a=O();if(a)rt(a),Ct(a)}catch{}return}let u=Yt();if(!u.acquired){if(await new Promise((l)=>setTimeout(l,3000)),await Q(5000)){await it();return}}try{if(await Q(1000)){await it();return}process.stderr.write(`GreedySearch Chrome not running on port ${h} auto-launching...
326
- `);let l=[ze(Re,"..","..","bin","launch.mjs")];if(process.env.GREEDY_SEARCH_VISIBLE!=="1")l.push("--headless");await new Promise((f,c)=>{Ce(Wt(),l,{stdio:["ignore",process.stderr,process.stderr]}).on("close",(s)=>s===0?f():c(Error("launch.mjs failed")))})}finally{u.release()}}import{randomInt as en}from"node:crypto";import{existsSync as nn,readFileSync as rn}from"node:fs";import on from"node:http";var un=`
406
+ `;return await h(["eval",e,r],n+5000)==="true"}async function $e(e){let t=e.indexOf("--stdin");if(t===-1)return e;let n=await new Promise((r)=>{let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(a)=>o+=a),process.stdin.on("end",()=>r(o.trim()))}),i=[...e];return i[t]=n,i}function ke(e){let t=e.includes("--short"),n=e.filter((l)=>l!=="--short"),i=n.indexOf("--tab"),r=i===-1?null:n[i+1];if(i!==-1)n=n.filter((l,u)=>u!==i&&u!==i+1);let o=n.indexOf("--locale"),a=o===-1?null:n[o+1];if(o!==-1)n=n.filter((l,u)=>u!==o&&u!==o+1);return{query:n.join(" "),tabPrefix:r,short:t,locale:a}}function _e(e,t){if(!e.length||e[0]==="--help")process.stderr.write(t),process.exit(1)}function Je(e,t,n=300){if(!t||e.length<=n)return e;let i=e.slice(0,n),r=i.lastIndexOf(" ");return r>0?`${i.slice(0,r)}…`:`${i}…`}function Ne(e){process.stdout.write(`${JSON.stringify(e,null,2)}
407
+ `)}function We(e,t=null){if(t){let n=JSON.stringify({_envelope:t,error:e.message});process.stdout.write(`${n}
408
+ `)}process.stderr.write(`Error: ${e.message}
409
+ `),process.exit(1)}import{spawn as Ut,execFileSync as ue,execSync as Ln}from"node:child_process";import{basename as dt}from"node:path";function Te(e=process.env,t=process.execPath){let n=e.GREEDY_SEARCH_NODE||e.NODE_BINARY||e.NODE;if(n?.trim())return n.trim();let i=dt(t||"").toLowerCase();if(i==="node"||i==="node.exe")return t;return"node"}import{existsSync as Ye,readFileSync as se,renameSync as Pt,unlinkSync as w,writeFileSync as F}from"node:fs";import ce from"node:http";import{platform as Re}from"node:os";import{join as zt}from"node:path";import{existsSync as je}from"node:fs";import{platform as bt}from"node:os";import{join as k}from"node:path";function b(e){let t=bt()==="win32",n=process.env.SystemRoot||"C:\\Windows",i={win32:{powershell:k(n,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:k(n,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:k(n,"System32","netstat.exe"),taskkill:k(n,"System32","taskkill.exe"),tasklist:k(n,"System32","tasklist.exe"),cmd:k(n,"System32","cmd.exe")},unix:{ps:"/usr/bin/ps",lsof:"/usr/bin/lsof",ss:"/usr/sbin/ss",grep:"/usr/bin/grep",kill:"/usr/bin/kill"}},r=t?i.win32:i.unix,o=e.toLowerCase();if(r[o]&&je(r[o]))return r[o];if(t&&o==="netstat"){let a=k(n,"Sysnative","netstat.exe");if(je(a))return a}return e}import{execFileSync as vt}from"node:child_process";import{platform as wt}from"node:os";function xt(e,t){return vt(b(e),t,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5000})}function $t(e){let t=String(e||"").match(/\b(\d+)\b/);return t?Number.parseInt(t[1],10):null}function kt(e){return $t(e)}function _t(e,t){for(let n of String(e||"").split(/\r?\n/)){if(!/\bLISTEN\b/i.test(n))continue;if(!n.trim().split(/\s+/).slice(0,6).some((o)=>o.endsWith(`:${t}`)))continue;let r=n.match(/\bpid=(\d+)\b/);if(r)return Number.parseInt(r[1],10)}return null}function Jt(e,t){for(let n of String(e||"").split(/\r?\n/)){let i=n.trim().split(/\s+/);if(i.length<5||i[0].toUpperCase()!=="TCP")continue;if(!i.at(-2)?.toUpperCase().startsWith("LISTEN"))continue;if(!i[1].endsWith(`:${t}`))continue;let r=Number.parseInt(i.at(-1),10);if(Number.isInteger(r)&&r>0)return r}return null}function ne(e,t,n){try{return e(t,n)}catch{return null}}function qe(e,{platformName:t=wt(),run:n=xt}={}){if(t==="win32")return Jt(ne(n,"netstat",["-ano","-p","TCP"]),e);let i=ne(n,"lsof",["-nP",`-iTCP:${e}`,"-sTCP:LISTEN","-t"]),r=kt(i);if(r)return r;if(t!=="linux")return null;return _t(ne(n,"ss",["-ltnp"]),e)}import{existsSync as C,mkdirSync as Nt,readFileSync as Be,writeFileSync as Wt}from"node:fs";import{homedir as Tt}from"node:os";import{join as He}from"node:path";import{tmpdir as jt}from"node:os";function qt(e,t=9222){let n=Number.parseInt(String(e??""),10);return Number.isInteger(n)&&n>1024&&n<65535?n:t}var Ot=jt().replaceAll("\\","/"),m=qt(process.env.GREEDY_SEARCH_PORT),y=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${Ot}/greedysearch-chrome-profile`).replaceAll("\\","/"),H=`${y}/DevToolsActivePort`,U=process.env.GREEDY_SEARCH_PID_FILE||`${y}/browser.pid`,Bt=process.env.CDP_PAGES_CACHE||`${y}/cdp-pages.json`,$=process.env.GREEDY_SEARCH_MODE_FILE||`${y}/browser-mode`,Ve=process.env.GREEDY_SEARCH_METADATA_FILE||`${y}/browser-metadata.json`,Me=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${y}/browser-launch.lock`,P=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${y}/browser-last-activity`,Sn=(process.env.CDP_SOCKET_DIR||`${y}/cdp-sockets`).replaceAll("\\","/"),Zn=`${y}/visible-recovery.jsonl`,ie=He(Tt(),".dm"),v=He(ie,"greedyconfig"),oe=["perplexity","google","chatgpt","gemini"],ae="gemini";function Ht(){try{if(C(v)){let e=Be(v,"utf8"),t=JSON.parse(e);if(Array.isArray(t.engines)&&t.engines.length>0&&t.engines.every((n)=>typeof n==="string")){let n=t.engines.filter((r)=>re[r]),i=t.engines.filter((r)=>!re[r]);if(i.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${v}: ${i.join(", ")}
410
+ [greedysearch] Available engines: ${Object.keys(re).join(", ")}
411
+ `);if(n.length>0)return n;process.stderr.write(`[greedysearch] Warning: no valid engines in ${v}, falling back to defaults: ${oe.join(", ")}
412
+ `)}}}catch{}return oe}function Vt(){try{if(!C(ie))Nt(ie,{recursive:!0});if(!C(v))Wt(v,JSON.stringify({engines:oe,synthesizer:ae},null,2)+`
413
+ `,"utf8")}catch{}}Vt();var Oe=["gemini","chatgpt"];function Mt(){try{if(C(v)){let e=Be(v,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let n=t.synthesizer.toLowerCase();if(Oe.includes(n))return n;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${v}
414
+ [greedysearch] Available synthesizers: ${Oe.join(", ")}
415
+ [greedysearch] Falling back to default: ${ae}
416
+ `)}}}catch{}return ae}var re={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},Qn=Ht();var Cn=Mt(),Un=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=y;import{execFileSync as Xe,execSync as Se}from"node:child_process";import{existsSync as z,mkdirSync as Xt,readFileSync as j,unlinkSync as J,writeFileSync as N}from"node:fs";import{platform as Ue}from"node:os";var A=Ve,_=Me,St=15000,D=U,K=$,V=P;function M(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}function Zt(e){if(!M(e))return null;try{if(Ue()==="win32")return Xe(b("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return Xe(b("ps"),["-p",String(e),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Qt(e,t,n=m){if(!e)return!1;let i=(a)=>String(a||"").replaceAll("\\","/").toLowerCase(),r=i(e),o=i(t);return r.includes(o)&&r.includes(`--remote-debugging-port=${n}`)&&!r.includes("--type=")}function Ze(e,t,n=m){return Qt(Zt(e),t,n)}function Ct(e=m){try{if(Ue()==="win32"){let n=Se(`${b("netstat")} -ano -p TCP 2>nul`,{encoding:"utf8"}),i=new RegExp(String.raw`TCP\s+\S+:${e}\s+\S+:0\s+LISTENING\s+(\d+)`,"i"),r=n.match(i);return r?Number.parseInt(r[1],10):null}let t=Se(`${b("lsof")} -i :${e} -t 2>/dev/null || ${b("ss")} -tlnp 2>/dev/null | ${b("grep")} :${e} | ${b("grep")} -oP 'pid=\\K\\d+'`,{encoding:"utf8"}).trim();return t?Number.parseInt(t.split(`
417
+ `)[0],10):null}catch{return null}}function X(){try{if(z(A)){let e=j(A,"utf8"),t=JSON.parse(e);if(t&&typeof t.tempDir==="string"&&typeof t.debugPort==="number")return{browserPid:Number.isInteger(t.browserPid)?t.browserPid:void 0,debugPort:t.debugPort,tempDir:t.tempDir,clientPids:Array.isArray(t.clientPids)?t.clientPids.filter((n)=>Number.isInteger(n)&&n>0):[],sessionMode:t.sessionMode==="visible"?"visible":"headless",lastActivity:Number.isFinite(t.lastActivity)?t.lastActivity:0,launchedAt:Number.isFinite(t.launchedAt)?t.launchedAt:0}}}catch{}try{let e=z(D)?Number.parseInt(j(D,"utf8").trim(),10)||void 0:void 0,t=z(K)?j(K,"utf8").trim()==="visible"?"visible":"headless":"headless",n=z(V)?Number.parseInt(j(V,"utf8").trim(),10)||0:0;return{browserPid:e,debugPort:m,tempDir:y,clientPids:e?[e]:[],sessionMode:t,lastActivity:n,launchedAt:0}}catch{return null}}function Y(e){try{N(A,JSON.stringify({browserPid:e.browserPid,debugPort:e.debugPort,tempDir:e.tempDir,clientPids:[...new Set(e.clientPids.filter((t)=>t>0))],sessionMode:e.sessionMode,lastActivity:e.lastActivity,launchedAt:e.launchedAt},null,2),"utf8")}catch{}try{if(e.browserPid)N(D,String(e.browserPid),"utf8")}catch{}try{N(K,e.sessionMode,"utf8")}catch{}try{N(V,String(e.lastActivity),"utf8")}catch{}}function Qe(){try{J(A)}catch{}try{J(D)}catch{}try{J(K)}catch{}try{J(V)}catch{}}function le(e){if(!e)return e;let t={...e,clientPids:[...new Set([...e.clientPids,process.pid].filter((n)=>M(n)||n===process.pid))]};return Y(t),t}function R(e){let t=Date.now();try{if(e)Y({...e,lastActivity:t});else N(V,String(t),"utf8")}catch{}}var Rn=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Ce=!1;function Pe(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD)return;if(Ce)return;Ce=!0;let e=X();if(!e)return;if(e.browserPid){if(!M(e.browserPid)){Qe();return}if(!Ze(e.browserPid,e.tempDir,e.debugPort))Qe();else Y({...e,clientPids:e.clientPids.filter((r)=>M(r))})}let t=Ct();if(t&&t!==e.browserPid)if(Ze(t,y,m))Y({browserPid:t,debugPort:m,tempDir:y,clientPids:[t],sessionMode:e.sessionMode,lastActivity:Date.now(),launchedAt:Date.now()});else process.stderr.write(`[greedysearch] Refusing to kill unverified listener ${t} on port ${m}.
418
+ `)}function ze(){Xt(y,{recursive:!0});try{let e=JSON.stringify({pid:process.pid,ts:Date.now()});return N(_,e,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{let t=j(_,"utf8");if(JSON.parse(t).pid===process.pid)J(_)}catch{}}}}catch(e){if(e?.code!=="EEXIST")return{acquired:!1,release:()=>{}}}try{let e=j(_,"utf8"),t=JSON.parse(e),n=Date.now()-(t.ts||0);if(!M(t.pid)||n>St){try{J(_)}catch{}try{let r=JSON.stringify({pid:process.pid,ts:Date.now()});return N(_,r,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{J(_)}catch{}}}}catch{return{acquired:!1,release:()=>{}}}}}catch{}return{acquired:!1,release:()=>{}}}var At=import.meta.dirname||new URL(".",import.meta.url).pathname.replace(/^\/([A-Z]:)/,"$1"),Ae=U,S=P,Dt=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,Kt=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;function Yt(e,t=m){let n=String(e||"").toLowerCase();if(!n.includes(`--remote-debugging-port=${t}`)||n.includes("--type="))return null;return n.includes("--headless")}function Ge(){try{let e=I(),t=e?Fe(e):null,n=Yt(t);if(n!==null){try{F($,n?"headless":"visible","utf8")}catch{}return n}}catch{}try{if(!Ye($))return!0;return se($,"utf8").trim()==="headless"}catch{return!0}}function Rt(){try{F(S,String(Date.now()),"utf8")}catch{}try{let e=X();if(e)R(e)}catch{}}function Fe(e){try{if(Re()==="win32")return ue(b("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return ue(b("ps"),["-p",String(e),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Gt(e){let t=String(e||"").replaceAll("\\","/"),n=y.replaceAll("\\","/");return t.includes(`--remote-debugging-port=${m}`)&&t.includes(`--user-data-dir=${n}`)&&!t.includes("--type=")}function I(){return qe(m)}function L(){let e=I();return e&&Gt(Fe(e))?e:null}async function Ft(e=1500){let t=L();if(!t)return process.stderr.write(`[greedysearch] Refusing to close an unverified listener.
419
+ `),!1;try{let i=await new Promise((o,a)=>{let l=ce.get(`http://localhost:${m}/json/version`,(u)=>{let f="";u.on("data",(s)=>f+=s),u.on("end",()=>{try{o(JSON.parse(f))}catch{a(Error("bad JSON"))}})});l.on("error",a),l.setTimeout(1000,()=>{l.destroy(),a(Error("timeout"))})}),r=new globalThis.WebSocket(i.webSocketDebuggerUrl);await new Promise((o)=>{r.onopen=()=>{if(L()!==t){r.close(),o();return}r.send(JSON.stringify({id:1,method:"Browser.close"})),setTimeout(()=>{r.close(),o()},200)},r.onerror=()=>o(),setTimeout(o,1000)})}catch{}let n=Date.now()+e;while(Date.now()<n){let i=I();if(!i)return!0;if(i!==t)return!1;await new Promise((r)=>setTimeout(r,150))}return Lt(t)}function Lt(e=null){try{let t=L();if(!t||e&&t!==e)return!1;if(Re()==="win32")ue(b("taskkill"),["/F","/PID",String(t)],{stdio:"ignore",windowsHide:!0});else process.kill(t,"SIGKILL");return!0}catch{return!1}}async function Le(){if(!L()){if(I())process.stderr.write(`[greedysearch] Refusing to kill an unverified listener.
420
+ `);return!1}if(!await x(500)){try{w(Ae)}catch{}try{w(S)}catch{}try{w($)}catch{}return!1}let t=await Ft(1500);try{w(Ae)}catch{}try{w(S)}catch{}try{w($)}catch{}if(t)process.stderr.write(`[greedysearch] Killed Chrome on port ${m}.
421
+ `);return t}var De=Le;async function It(){let t=Ge()?Dt:Kt;if(t<=0)return!1;if(!Ye(S))return Rt(),!1;try{let n=Number.parseInt(se(S,"utf8").trim(),10);if(!n)return!1;if((Date.now()-n)/60000>=t)return Le()}catch{}return!1}function x(e=3000){return new Promise((t)=>{let n=ce.get(`http://localhost:${m}/json/version`,(i)=>{i.resume(),t(i.statusCode===200)});n.on("error",()=>t(!1)),n.setTimeout(e,()=>{n.destroy(),t(!1)})})}async function Ke(e=3000,t=200){let n=Date.now()+e;while(Date.now()<n){if(!await x(300))return!0;await new Promise((i)=>setTimeout(i,t))}return!await x(300)}async function G(){let e=`${H}.lock`,t=`${H}.tmp`,n=5000,i=1000,r=await new Promise((o)=>{let a=Date.now(),l=()=>{try{let u=JSON.stringify({pid:process.pid,ts:Date.now()});F(e,u,{encoding:"utf8",flag:"wx"}),o(!0)}catch(u){if(u?.code!=="EEXIST"){if(Date.now()-a<1000)setTimeout(l,50);else o(!1);return}try{let f=se(e,"utf8").trim(),s=f.startsWith("{")?JSON.parse(f):{ts:Number(f)},g=Number(s?.ts)||0;if(g>0&&Date.now()-g>5000)try{w(e)}catch{}if(Date.now()-a<1000)setTimeout(l,50);else o(!1)}catch{if(Date.now()-a<1000)setTimeout(l,50);else o(!1)}}};l()});try{let o=await new Promise((u,f)=>{let s=ce.get(`http://localhost:${m}/json/version`,(g)=>{let p="";g.on("data",(c)=>p+=c),g.on("end",()=>u(p))});s.on("error",f),s.setTimeout(3000,()=>{s.destroy(),f(Error("timeout"))})}),{webSocketDebuggerUrl:a}=JSON.parse(o),l=new URL(a).pathname;if(r){F(t,`${m}
422
+ ${l}`,"utf8");try{w(H)}catch{}Pt(t,H)}}catch{}finally{if(r)try{w(e)}catch{}}}async function Ie(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD&&await x()){await G();try{let o=X();if(o)R(o),le(o)}catch{}return}Pe();let e=await It(),t=e?!1:await x();if(!t&&!e)await new Promise((o)=>setTimeout(o,500)),t=await x();let n=!1;if(t){let o=Ge(),a=process.env.GREEDY_SEARCH_VISIBLE==="1";if(!a&&!o)process.stderr.write(`[greedysearch] Visible Chrome detected switching to headless mode...
423
+ `),await De(),await Ke(),n=!0;else if(a&&o)process.stderr.write(`[greedysearch] Headless Chrome detected — switching to visible mode...
424
+ `),await De(),await Ke(),n=!0}if(n?!1:await x()){await G();try{let o=X();if(o)R(o),le(o)}catch{}return}let r=ze();if(!r.acquired){let o=Date.now()+12000,a=!1;while(Date.now()<o){if(a=await x(500),a)break;await new Promise((l)=>setTimeout(l,250))}if(a){await G();return}}try{if(await x(1000)){await G();return}process.stderr.write(`GreedySearch Chrome not running on port ${m} — auto-launching...
425
+ `);let a=[zt(At,"..","..","bin","launch.mjs")];if(process.env.GREEDY_SEARCH_VISIBLE!=="1")a.push("--headless");await new Promise((l,u)=>{Ut(Te(),a,{stdio:["ignore",process.stderr,process.stderr]}).on("close",(s)=>s===0?l():u(Error("launch.mjs failed")))})}finally{r.release()}}import{randomInt as Et}from"node:crypto";import{existsSync as en,readFileSync as tn}from"node:fs";import nn from"node:http";var rn=`
327
426
  (function() {
328
427
  // Google consent page (consent.google.com)
329
428
  var g = document.querySelector('#L2AGLb, button[jsname="b3VHJd"], .tHlp8d');
@@ -340,7 +439,7 @@ ${l}`,"utf8");try{p(X)}catch{}de(e,X)}}catch{}finally{if(i)try{p(t)}catch{}}}asy
340
439
 
341
440
  return null;
342
441
  })()
343
- `,ln=`
442
+ `,on=`
344
443
  (function() {
345
444
  var url = document.location.href;
346
445
 
@@ -371,12 +470,24 @@ ${l}`,"utf8");try{p(X)}catch{}de(e,X)}}catch{}finally{if(i)try{p(t)}catch{}}}asy
371
470
 
372
471
  // --- Cloudflare Turnstile widget inside closed shadow DOM (Copilot, etc.) ---
373
472
  // The iframe is not queryable from main document, but the host container
374
- // (#cf-turnstile) and the hidden response input are.
375
- var cfTurnstileHost = document.querySelector('#cf-turnstile, [id^="cf-chl-widget-"]');
473
+ // (#cf-turnstile) and the hidden response input are. When only the
474
+ // hidden response input matches (no #cf-turnstile host and no visible
475
+ // iframe), the actual challenge widget is rendered inside a closed
476
+ // shadow DOM and cannot be auto-clicked. Return a sentinel so callers
477
+ // know to surface this as needs-human verification instead of wasting
478
+ // time on a doomed waitForSelector.
479
+ var cfTurnstileHost = document.querySelector('#cf-turnstile');
376
480
  if (cfTurnstileHost) {
377
481
  var r2 = cfTurnstileHost.getBoundingClientRect();
378
482
  return JSON.stringify({t:'xy',x:r2.left+r2.width/2,y:r2.top+r2.height/2});
379
483
  }
484
+ // Hidden cf-chl-widget-*_response input present but no visible host:
485
+ // the widget is in closed shadow DOM. Signal this so handleVerification
486
+ // can return 'needs-human' rather than 'clear'.
487
+ var cfResponseInput = document.querySelector('input[name="cf-turnstile-response"], [id^="cf-chl-widget-"][id$="_response"]');
488
+ if (cfResponseInput && cfResponseInput.value === '') {
489
+ return 'cf-closed-shadow-dom';
490
+ }
380
491
 
381
492
  // --- Cloudflare challenge page ---
382
493
  var cfCheckbox = document.querySelector('#cf-stage input[type="checkbox"], .ctp-checkbox-container input');
@@ -391,15 +502,28 @@ ${l}`,"utf8");try{p(X)}catch{}de(e,X)}}catch{}finally{if(i)try{p(t)}catch{}}}asy
391
502
  }
392
503
 
393
504
  // --- Generic verify/continue/proceed buttons (catch-all) ---
394
- // IMPORTANT: exclude sign-in / OAuth buttons (e.g. "Continue with Google")
505
+ // IMPORTANT: exclude sign-in / OAuth buttons (e.g. "Continue with Google",
506
+ // "Continue with email", "Login or sign up for free"). These appear on
507
+ // many sites (Perplexity, ChatGPT, etc.) when the user isn't logged in,
508
+ // and clicking them triggers a sign-in flow that takes us to a login
509
+ // wall — a much worse outcome than the original search failure we were
510
+ // trying to recover from. The exclusion list must cover both OAuth
511
+ // providers AND generic "sign in / log in / with email" patterns.
395
512
  var btns = Array.from(document.querySelectorAll('button, input[type=submit], a[role=button]'));
396
513
  var verify = btns.find(b => {
397
514
  var t = (b.innerText?.trim() || b.value || '').toLowerCase();
398
- var isVerifyLike = (t.includes('verify') || t.includes('human') || t.includes('robot') || t.includes('continue') || t.includes('proceed')) &&
515
+ var isVerifyLike = (t === 'continue' || t === 'proceed' || t === 'next' ||
516
+ t.startsWith('verify ') || t.startsWith('human ') || t === 'i am human' || t.includes('robot check')) &&
399
517
  !t.includes('verified') && !document.querySelector('iframe[src*="recaptcha"]');
400
518
  if (!isVerifyLike) return false;
401
519
  // Exclude OAuth / sign-in buttons to prevent accidental login flows
402
- var isSignIn = /sign.in|log.in|google|microsoft|apple|facebook|github|auth/i.test(t);
520
+ // covers "Continue with Google", "Continue with Apple", "Continue
521
+ // with email", "Login or sign up", "Log in", "Sign in", "Sign up",
522
+ // "Single sign-on", and the visible panel "Login or sign up for free"
523
+ // text. The previous list missed "email" and "sso" which let the
524
+ // auto-click land on the email/SSO sign-in buttons on Perplexity's
525
+ // anonymous-mode homepage, navigating us into a login flow.
526
+ var isSignIn = new RegExp("sign.?in|log.?in|sign.?up|with\\s+(google|apple|email|github|facebook|microsoft|sso)|sso|auth", "i").test(t);
403
527
  return !isSignIn;
404
528
  });
405
529
  if (verify) { verify.setAttribute('data-gs-verify','1'); return JSON.stringify({t:'sel',s:'[data-gs-verify="1"]',txt:verify.innerText?.trim()||verify.value}); }
@@ -444,74 +568,89 @@ ${l}`,"utf8");try{p(X)}catch{}de(e,X)}}catch{}finally{if(i)try{p(t)}catch{}}}asy
444
568
 
445
569
  return 'still-verifying';
446
570
  })()
447
- `;async function Ft(t,e){let n=await e(["eval",t,un]).catch(()=>null);if(n&&n!=="null")await new Promise((r)=>setTimeout(r,1500))}function w(t,e){return en(t*1000,e*1000)/1000}async function fn(t,e){if(!globalThis.WebSocket)return;let n=process.env.CDP_PROFILE_DIR;if(!n)return;let r=`${n.replaceAll("\\","/")}/DevToolsActivePort`;if(!nn(r))return;let i=rn(r,"utf8").trim().split(`
448
- `)[0],o=await new Promise((l,f)=>{let c=on.get(`http://localhost:${i}/json/version`,(b)=>{let s="";b.on("data",(m)=>s+=m),b.on("end",()=>{try{l(JSON.parse(s))}catch{f(Error("bad JSON"))}})});c.on("error",f),c.setTimeout(1000,()=>{c.destroy(),f(Error("timeout"))})}),u=new globalThis.WebSocket(o.webSocketDebuggerUrl),a=0;await new Promise((l)=>{u.onopen=async()=>{let f=(s,m)=>new Promise((P)=>{let ct=++a,gt=(ne)=>{if(JSON.parse(ne.data).id===ct)u.removeEventListener("message",gt),P()};u.addEventListener("message",gt),u.send(JSON.stringify({id:ct,method:s,params:m}))}),c=t+w(-2,2),b=e+w(-2,2);await f("Input.dispatchMouseEvent",{type:"mouseMoved",x:c,y:b,button:"none"}),await new Promise((s)=>setTimeout(s,w(80,160))),await f("Input.dispatchMouseEvent",{type:"mousePressed",x:c,y:b,button:"left",clickCount:1}),await new Promise((s)=>setTimeout(s,w(30,80))),await f("Input.dispatchMouseEvent",{type:"mouseReleased",x:c+w(-1,1),y:b+w(-1,1),button:"left",clickCount:1}),setTimeout(()=>{u.close(),l()},200)},u.onerror=()=>l(),setTimeout(l,3000)})}async function Et(t,e,n,r){let i=Number.parseFloat(n),o=Number.parseFloat(r);if(Number.isNaN(i)||Number.isNaN(o))throw Error(`humanClickXY: invalid coordinates (${n}, ${r})`);let u={button:"left",clickCount:1,modifiers:0},a=i+w(-3,3),l=o+w(-3,3);await e(["evalraw",t,"Input.dispatchMouseEvent",JSON.stringify({...u,type:"mouseMoved",x:a,y:l})]),await new Promise((m)=>setTimeout(m,w(80,180)));let f=i+w(-2,2),c=o+w(-2,2);await e(["evalraw",t,"Input.dispatchMouseEvent",JSON.stringify({...u,type:"mousePressed",x:f,y:c})]),await new Promise((m)=>setTimeout(m,w(30,90)));let b=f+w(-1,1),s=c+w(-1,1);return await e(["evalraw",t,"Input.dispatchMouseEvent",JSON.stringify({...u,type:"mouseReleased",x:b,y:s})]),await fn(i,o).catch(()=>{}),await new Promise((m)=>setTimeout(m,w(100,300))),`human-clicked at (${i.toFixed(0)}, ${o.toFixed(0)})`}async function cn(t,e,n){let r=await e(["eval",t,`(function() {
571
+ `;async function et(e,t){let n=await t(["eval",e,rn]).catch(()=>null);if(n&&n!=="null")await new Promise((i)=>setTimeout(i,1500))}function d(e,t){return Et(e*1000,t*1000)/1000}async function ln(e,t){if(!globalThis.WebSocket)return;let n=process.env.CDP_PROFILE_DIR;if(!n)return;let i=`${n.replaceAll("\\","/")}/DevToolsActivePort`;if(!en(i))return;let r=tn(i,"utf8").trim().split(`
572
+ `)[0],o=await new Promise((u,f)=>{let s=nn.get(`http://localhost:${r}/json/version`,(g)=>{let p="";g.on("data",(c)=>p+=c),g.on("end",()=>{try{u(JSON.parse(p))}catch{f(Error("bad JSON"))}})});s.on("error",f),s.setTimeout(1000,()=>{s.destroy(),f(Error("timeout"))})}),a=new globalThis.WebSocket(o.webSocketDebuggerUrl),l=0;await new Promise((u)=>{a.onopen=async()=>{let f=(p,c)=>new Promise((Z)=>{let W=++l,T=(O)=>{if(JSON.parse(O.data).id===W)a.removeEventListener("message",T),Z()};a.addEventListener("message",T),a.send(JSON.stringify({id:W,method:p,params:c}))}),s=e+d(-2,2),g=t+d(-2,2);await f("Input.dispatchMouseEvent",{type:"mouseMoved",x:s,y:g,button:"none"}),await new Promise((p)=>setTimeout(p,d(80,160))),await f("Input.dispatchMouseEvent",{type:"mousePressed",x:s,y:g,button:"left",clickCount:1}),await new Promise((p)=>setTimeout(p,d(30,80))),await f("Input.dispatchMouseEvent",{type:"mouseReleased",x:s+d(-1,1),y:g+d(-1,1),button:"left",clickCount:1}),setTimeout(()=>{a.close(),u()},200)},a.onerror=()=>u(),setTimeout(u,3000)})}async function tt(e,t,n,i){let r=Number.parseFloat(n),o=Number.parseFloat(i);if(Number.isNaN(r)||Number.isNaN(o))throw Error(`humanClickXY: invalid coordinates (${n}, ${i})`);let a={button:"left",clickCount:1,modifiers:0},l=r+d(-3,3),u=o+d(-3,3);await t(["evalraw",e,"Input.dispatchMouseEvent",JSON.stringify({...a,type:"mouseMoved",x:l,y:u})]),await new Promise((c)=>setTimeout(c,d(80,180)));let f=r+d(-2,2),s=o+d(-2,2);await t(["evalraw",e,"Input.dispatchMouseEvent",JSON.stringify({...a,type:"mousePressed",x:f,y:s})]),await new Promise((c)=>setTimeout(c,d(30,90)));let g=f+d(-1,1),p=s+d(-1,1);return await t(["evalraw",e,"Input.dispatchMouseEvent",JSON.stringify({...a,type:"mouseReleased",x:g,y:p})]),await ln(r,o).catch(()=>{}),await new Promise((c)=>setTimeout(c,d(100,300))),`human-clicked at (${r.toFixed(0)}, ${o.toFixed(0)})`}async function un(e,t,n){let i=await t(["eval",e,`(function() {
449
573
  var el = document.querySelector('${n.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}');
450
574
  if (!el) return 'null';
451
575
  var r = el.getBoundingClientRect();
452
576
  return JSON.stringify({x: r.left + r.width / 2, y: r.top + r.height / 2, w: r.width, h: r.height});
453
- })()`]).catch(()=>"null");if(!r||r==="null")return null;let i=JSON.parse(r);if(i.w===0||i.h===0||i.x===0&&i.y===0)return null;let{x:o,y:u}=i;return Et(t,e,o,u)}async function It(t,e,n){if(!n||n==="null"||n==="cleared"||n==="still-verifying")return!1;try{let r=JSON.parse(n);if(r.t==="sel"&&r.s)return process.stderr.write(`[greedysearch] Human-clicking "${r.txt}" via CDP...
454
- `),await cn(t,e,r.s)!==null;if(r.t==="xy"){if(!r.x&&!r.y)return!1;return process.stderr.write(`[greedysearch] Human-clicking at (${r.x.toFixed(0)}, ${r.y.toFixed(0)})...
455
- `),await Et(t,e,r.x,r.y),!0}}catch{}return!1}async function gn(t,e){let n=await e(["eval",t,ln]).catch(()=>null);return n&&n!=="null"?n:null}async function te(t,e,n=30000){let r=await gn(t,e);if(!r)return"clear";if(r==="sorry-page"){process.stderr.write(`[greedysearch] Google CAPTCHA detected please solve it in the browser window (waiting up to ${Math.floor(n/1000)}s)...
456
- `);let i=Date.now()+n;while(Date.now()<i)if(await new Promise((o)=>setTimeout(o,2000)),!(await e(["eval",t,"document.location.href"]).catch(()=>"")).includes("/sorry/"))return"cleared-by-user";return"needs-human"}if(await It(t,e,r)){await new Promise((o)=>setTimeout(o,2000));let i=Date.now()+n;while(Date.now()<i){let o=await e(["eval",t,an]).catch(()=>null);if(o==="cleared"||!o||o==="null")return process.stderr.write(`[greedysearch] Verification cleared.
457
- `),"clicked";if(o!=="still-verifying")await It(t,e,o),await new Promise((u)=>setTimeout(u,2000));else await new Promise((u)=>setTimeout(u,1500))}return process.stderr.write(`[greedysearch] Verification may require manual intervention.
458
- `),"needs-human"}return"clear"}var ee={perplexity:{input:"#ask-input",copyButton:null,sourceItem:"[data-pplx-citation-url]",sourceLink:"a",consent:"#onetrust-accept-btn-handler"},bing:{input:"#userInput",copyButton:'button[data-testid="copy-ai-message-button"]',sourceLink:'a[href^="http"][target="_blank"]',sourceExclude:"copilot.microsoft.com",consent:"#onetrust-accept-btn-handler"},google:{answerContainer:".pWvJNd",sourceLink:'a[href^="http"]',sourceExclude:["google.","gstatic","googleapis"],sourceHeadingParent:"[data-snhf]",consent:'#L2AGLb, button[jsname="b3VHJd"], .tHlp8d'},gemini:{input:"rich-textarea .ql-editor",copyButton:'button:has(mat-icon[data-mat-icon-name="copy"])',sendButton:'button:has(mat-icon[data-mat-icon-name="arrow_upward"]), [data-test-id="send-button"], .send-button',sourcesSidebarButton:"button.legacy-sources-sidebar-button",sourcesExclude:["gemini.google","gstatic","google.com/search"],citationButtonPattern:'button[aria-label*="citation from"]',citationNameRegex:/from\s{1,20}([^.]{1,200})\.\s/}};var j=ee.gemini,ft="__geminiClipboard";async function sn(t,e){if(await g(["click",t,j.input]),await new Promise((r)=>setTimeout(r,B(200))),await G(["type",t,"--stdin"],e),await new Promise((r)=>setTimeout(r,B(300))),await g(["eval",t,`(function() {
459
- var el = document.querySelector('${j.input}');
460
- if (!el) return false;
461
- var content = el.innerText || el.textContent || '';
462
- return content.trim().length >= ${Math.floor(e.length*0.8)};
463
- })()`])!=="true")throw Error("Gemini input field did not accept text — input verification failed")}async function bn(t){await g(["eval",t,`(function() {
577
+ })()`]).catch(()=>"null");if(!i||i==="null")return null;let r=JSON.parse(i);if(r.w===0||r.h===0||r.x===0&&r.y===0)return null;let{x:o,y:a}=r;return tt(e,t,o,a)}function Ee(e,t,n){if(!n||n==="null"||n==="cleared"||n==="still-verifying"||n==="cf-closed-shadow-dom")return Promise.resolve("no-challenge");try{let i=JSON.parse(n);if(i.t==="sel"&&i.s)return process.stderr.write(`[greedysearch] Human-clicking "${i.txt}" via CDP...
578
+ `),un(e,t,i.s).then((r)=>r!==null?"clicked":"cant-click");if(i.t==="xy"){if(!i.x&&!i.y)return Promise.resolve("cant-click");return process.stderr.write(`[greedysearch] Human-clicking at (${i.x.toFixed(0)}, ${i.y.toFixed(0)})...
579
+ `),tt(e,t,i.x,i.y).then(()=>"clicked")}}catch{}return Promise.resolve("no-challenge")}async function sn(e,t){let n=await t(["eval",e,on]).catch(()=>null);if(n==="cf-closed-shadow-dom"){let i=await cn(e,t).catch(()=>null);if(i)return i;return n}if(n&&n!=="null")return n;return null}async function cn(e,t){if(typeof t!=="function")return null;await t(["evalraw",e,"DOM.enable","{}"]).catch(()=>{});let n=await t(["evalraw",e,"DOM.getDocument",JSON.stringify({depth:-1,pierce:!0})]).catch(()=>null);if(!n)return null;let i;try{i=JSON.parse(n)}catch{return null}if(i.error||!i.root)return null;let r=i.root;return await nt(r,e,t)}async function nt(e,t,n){if(!e)return null;let i=[];if(e.shadowRoots&&e.shadowRoots.length>0)for(let r of e.shadowRoots)i.push(r);if(e.children)for(let r of e.children)i.push(r);for(let r of i){if(r.nodeName==="IFRAME"){let a=r.attributes||[],l=a.indexOf("src"),u=l>=0?a[l+1]:"";if(u&&/challenges\.cloudflare\.com|turnstile/i.test(u)&&r.backendNodeId){let f=await n(["evalraw",t,"DOM.getBoxModel",JSON.stringify({backendNodeId:r.backendNodeId})]).catch(()=>null);if(!f)continue;let s;try{s=JSON.parse(f)}catch{continue}let g=s?.model?.content||s?.result?.model?.content;if(!g||g.length<8)continue;let p=g[0],c=g[1],Z=g[4],W=g[5],T=Z-p,O=W-c;if(T<50||O<20)continue;let ge=p+T*0.25,he=c+O*0.5;return process.stderr.write(`[greedysearch] Found CF iframe via CDP pierce at (${p.toFixed(0)}, ${c.toFixed(0)}) ${T.toFixed(0)}x${O.toFixed(0)}, clicking checkbox at (${ge.toFixed(0)}, ${he.toFixed(0)})
580
+ `),JSON.stringify({t:"xy",x:ge,y:he})}}let o=await nt(r,t,n);if(o)return o}return null}async function rt(e,t,n=30000){let i=await sn(e,t);if(!i)return"clear";if(i==="sorry-page"){process.stderr.write(`[greedysearch] Google CAPTCHA detected — please solve it in the browser window (waiting up to ${Math.floor(n/1000)}s)...
581
+ `);let o=Date.now()+n;while(Date.now()<o)if(await new Promise((a)=>setTimeout(a,2000)),!(await t(["eval",e,"document.location.href"]).catch(()=>"")).includes("/sorry/"))return"cleared-by-user";return"needs-human"}let r=await Ee(e,t,i);if(r==="clicked"){await new Promise((a)=>setTimeout(a,2000));let o=Date.now()+n;while(Date.now()<o){let a=await t(["eval",e,an]).catch(()=>null);if(a==="cleared"||!a||a==="null")return process.stderr.write(`[greedysearch] Verification cleared.
582
+ `),"clicked";if(a!=="still-verifying")await Ee(e,t,a),await new Promise((l)=>setTimeout(l,2000));else await new Promise((l)=>setTimeout(l,1500))}return process.stderr.write(`[greedysearch] Verification may require manual intervention.
583
+ `),"needs-human"}if(r==="cant-click")return process.stderr.write(`[greedysearch] Verification challenge detected but cannot be auto-clicked — please solve it manually in the visible browser window.
584
+ `),"needs-human";return"clear"}var it={perplexity:{input:"#ask-input",copyButton:null,sourceItem:"[data-pplx-citation-url]",sourceLink:"a",consent:"#onetrust-accept-btn-handler"},bing:{input:"#userInput",copyButton:'button[data-testid="copy-ai-message-button"]',sourceLink:'a[href^="http"][target="_blank"]',sourceExclude:"copilot.microsoft.com",consent:"#onetrust-accept-btn-handler"},google:{answerContainer:".pWvJNd",sourceLink:'a[href^="http"]',sourceExclude:["google.","gstatic","googleapis"],sourceHeadingParent:"[data-snhf]",consent:'#L2AGLb, button[jsname="b3VHJd"], .tHlp8d'},gemini:{input:"rich-textarea .ql-editor",copyButton:'button:has(mat-icon[data-mat-icon-name="copy"])',sendButton:'button:has(mat-icon[data-mat-icon-name="arrow_upward"]), [data-test-id="send-button"], .send-button',sourcesSidebarButton:"button.legacy-sources-sidebar-button",sourcesExclude:["gemini.google","gstatic","google.com/search"],citationButtonPattern:'button[aria-label*="citation from"]',citationNameRegex:/from\s{1,20}([^.]{1,200})\.\s/}};var q=it.gemini,E="__geminiClipboard";async function fn(e,t){await h(["click",e,q.input]),await new Promise((a)=>setTimeout(a,B(200)));let n=async()=>{await ee(["type",e,"--stdin"],t),await new Promise((a)=>setTimeout(a,B(300)))},i=async()=>{let a=await h(["eval",e,`(() => {
585
+ const el = document.querySelector('${q.input}');
586
+ return JSON.stringify(el ? el.innerText || el.textContent || '' : '');
587
+ })()`]);try{return JSON.parse(a)}catch{return a}},r=async()=>me(await i(),t),o=async()=>{await h(["eval",e,`(() => {
588
+ const el = document.querySelector('${q.input}');
589
+ if (!el) return false;
590
+ el.focus();
591
+ const range = document.createRange();
592
+ range.selectNodeContents(el);
593
+ const selection = window.getSelection();
594
+ selection.removeAllRanges();
595
+ selection.addRange(range);
596
+ document.execCommand('delete');
597
+ return true;
598
+ })()`])};if(await n(),await r())return;if(await o(),await n(),!await r())throw Error("Gemini input field did not accept text — input verification failed")}async function fe(e,{required:t=!1}={}){try{return await h(["evalraw",e,"Page.bringToFront","{}"],5000),!0}catch(n){if(console.error(`[gemini] bringToFront failed: ${n.message}`),t)throw n;return!1}}async function gn(e){await h(["eval",e,`(function() {
464
599
  const chat = document.querySelector('chat-window, [role="main"], main') || document.body;
465
600
  chat.scrollTo ? chat.scrollTo({ top: chat.scrollHeight, behavior: 'smooth' }) : window.scrollTo(0, document.body.scrollHeight);
466
- })()`])}async function hn(t){let e=await g(["eval",t,String.raw`
467
- (() => {
468
- // The model-response element is a custom element <model-response>.
469
- // Its innerText starts with the "Gemini said" label in the
470
- // current locale; strip that prefix and return the rest.
471
- const resp = document.querySelector('model-response');
472
- if (!resp) return JSON.stringify({ answer: '', sources: [] });
473
- const text = (resp.innerText || resp.textContent || '').trim();
474
- // Strip the locale-specific "Gemini said" label prefix.
475
- // It varies ("Το Gemini είπε" in Greek, "Gemini said" in
476
- // English, etc.) so we just look for the first newline and
477
- // take what follows.
478
- const idx = text.indexOf('\n');
479
- const answer = idx >= 0 ? text.slice(idx + 1).trim() : text;
480
- if (!answer) return JSON.stringify({ answer: '', sources: [] });
481
- // Extract source links from the response.
482
- const seen = new Set();
483
- const sources = [];
484
- for (const link of resp.querySelectorAll('a[href]')) {
485
- const url = link.href;
486
- if (!url || seen.has(url)) continue;
487
- seen.add(url);
488
- const title = (link.innerText || link.textContent || '').replace(/\s+/g, ' ').trim();
489
- sources.push({ title, url });
490
- if (sources.length >= 10) break;
491
- }
492
- return JSON.stringify({ answer, sources });
493
- })()
494
- `]);try{return JSON.parse(e)}catch{return{answer:"",sources:[]}}}async function yn(t,e=""){let n=e.toLowerCase().trim(),r=!1,i=Date.now()+12000;while(Date.now()<i){if(await g(["eval",t,String.raw`(() => {
495
- const r = document.querySelector('model-response');
496
- if (!r) return false;
497
- const t = (r.innerText || '').trim();
498
- // Must have content beyond the locale-specific label
499
- // ("Gemini said" / "Το Gemini είπε" / etc.) and ideally
500
- // a copy button rendered on the response.
501
- return t.length > 20;
502
- })()`])===!0){r=!0;break}await new Promise((b)=>setTimeout(b,800))}if(!r)console.error("[gemini] Warning: model-response did not render content");await g(["eval",t,`(() => {
503
- const resp = document.querySelector('model-response');
504
- if (!resp) return 'no-model-response';
505
- const btn = resp.querySelector('${j.copyButton}');
506
- if (!btn) return 'no-copy-button';
507
- btn.click();
508
- return 'clicked';
509
- })()`]),await new Promise((c)=>setTimeout(c,600));let o=await g(["eval",t,`window.${ft} || ''`]);if(o&&n&&(o.toLowerCase().trim()===n||o.trim().length<n.length))console.error("[gemini] Clipboard echoed query, retrying in 2s..."),await new Promise((c)=>setTimeout(c,2000)),await g(["eval",t,`(() => {
510
- const resp = document.querySelector('model-response');
511
- if (!resp) return 'no-model-response';
512
- const btn = resp.querySelector('${j.copyButton}');
513
- if (!btn) return 'no-copy-button';
514
- btn.click();
515
- return 'clicked';
516
- })()`]),await new Promise((c)=>setTimeout(c,600)),o=await g(["eval",t,`window.${ft} || ''`]);let u=null;if(!o||n&&(o.toLowerCase().trim()===n||o.trim().length<n.length)){if(u=await hn(t),u.answer)o=u.answer}if(!o)throw Error("Gemini returned no answer — model-response never rendered content");let a=yt(o),l=new Map;for(let c of[...u?.sources||[],...a])if(c?.url&&!l.has(c.url))l.set(c.url,c);let f=Array.from(l.values()).slice(0,10);return{answer:o.trim(),sources:f}}var wn=`Usage: node extractors/gemini.mjs "<query>" [--tab <prefix>]
517
- `;async function mn(){let t=await vt(process.argv.slice(2));xt(t,wn);let{query:e,tabPrefix:n,short:r}=pt(t);if(process.env.GREEDY_SEARCH_VISIBLE!=="1"&&process.env.GREEDY_SEARCH_ALWAYS_VISIBLE!=="1")process.env.GREEDY_SEARCH_HEADLESS="1";await Lt();try{await g(["list"]);let i=await st(n),o=await g(["eval",i,"document.location.href"]).catch(()=>""),u=!1;try{let s=new URL(o).hostname.toLowerCase();u=s==="gemini.google.com"||s.endsWith(".gemini.google.com")}catch{}if(!u)await g(["nav",i,"https://gemini.google.com/app"],20000),await new Promise((s)=>setTimeout(s,600));await Ft(i,g),await te(i,g,1e4),await mt(i,j.input,8000,T.inputPoll),await new Promise((s)=>setTimeout(s,B(T.postClick))),await bt(i,ft),await sn(i,e),await new Promise((s)=>setTimeout(s,B(T.postType))),await g(["eval",i,`document.querySelector('${j.sendButton}')?.click()`]);let a=0,l=setInterval(()=>{if(++a%10===0)bn(i).catch(()=>null)},6000);try{await wt(i,{timeout:45000,minLength:50})}finally{clearInterval(l)}let{answer:f,sources:c}=await yn(i,e);if(!f)throw Error("No answer captured from Gemini clipboard");let b=await g(["eval",i,"document.location.href"]).catch(()=>"https://gemini.google.com/app");Jt({query:e,url:b,answer:$t(f,r),sources:c})}catch(i){kt(i)}}mn();
601
+ })()`])}async function hn(e){let t=await h(["eval",e,String.raw`
602
+ new Promise((resolve) => {
603
+ const _deadline = Date.now() + 6000;
604
+ function _tryExtract() {
605
+ const responses = Array.from(document.querySelectorAll('model-response'));
606
+ const resp = responses[responses.length - 1];
607
+ if (resp) {
608
+ const text = (resp.innerText || resp.textContent || '').trim();
609
+ const idx = text.indexOf('\n');
610
+ const answer = idx >= 0 ? text.slice(idx + 1).trim() : text;
611
+ if (answer) {
612
+ const seen = new Set();
613
+ const sources = [];
614
+ for (const link of resp.querySelectorAll('a[href]')) {
615
+ const url = link.href;
616
+ if (!url || seen.has(url)) continue;
617
+ seen.add(url);
618
+ const title = (link.innerText || link.textContent || '').replace(/\s+/g, ' ').trim();
619
+ sources.push({ title, url });
620
+ if (sources.length >= 10) break;
621
+ }
622
+ return resolve(JSON.stringify({ answer, sources }));
623
+ }
624
+ }
625
+ if (Date.now() < _deadline) {
626
+ setTimeout(_tryExtract, 500);
627
+ } else {
628
+ resolve(JSON.stringify({ answer: '', sources: [] }));
629
+ }
630
+ }
631
+ _tryExtract();
632
+ })
633
+ `],8000);try{return JSON.parse(t)}catch(n){return console.error(`[gemini] DOM fallback JSON parse failed (${t.length} chars): ${n.message}`),{answer:"",sources:[]}}}var ot=`(() => {
634
+ window.${E} = '';
635
+ const responses = Array.from(document.querySelectorAll('model-response'));
636
+ const resp = responses[responses.length - 1];
637
+ if (!resp) return;
638
+ const buttons = Array.from(resp.querySelectorAll('${q.copyButton}'));
639
+ const nonCodeButtons = buttons.filter((btn) => !btn.closest('pre, code, code-block, .code-block, .code-container'));
640
+ const btn = nonCodeButtons[nonCodeButtons.length - 1] || buttons[buttons.length - 1];
641
+ if (btn) btn.click();
642
+ })()`;async function pn(e,t="",n=!1){let i=t.toLowerCase().trim(),r=!1;if(n)r=await h(["eval",e,String.raw`(() => {
643
+ const responses = Array.from(document.querySelectorAll('model-response'));
644
+ const r = responses[responses.length - 1];
645
+ return !!r && (r.innerText || '').trim().length > 60;
646
+ })()`]).catch(()=>"false")==="true";else{let c=Date.now()+12000;while(Date.now()<c){if(await h(["eval",e,String.raw`(() => {
647
+ const responses = Array.from(document.querySelectorAll('model-response'));
648
+ const r = responses[responses.length - 1];
649
+ if (!r) return false;
650
+ const t = (r.innerText || '').trim();
651
+ // Must have content beyond the locale-specific label
652
+ // ("Gemini said" / "Το Gemini είπε" / etc.) and ideally
653
+ // a copy button rendered on the response.
654
+ return t.length > 60;
655
+ })()`])==="true"){r=!0;break}await new Promise((W)=>setTimeout(W,800))}}if(!r)console.error("[gemini] Warning: model-response did not render content");let o=await te(e,ot,E,{timeoutMs:600,retryClick:600});if(o&&i&&(o.toLowerCase().trim()===i||o.trim().length<i.length))console.error("[gemini] Clipboard echoed query, retrying in 2s..."),await new Promise((c)=>setTimeout(c,2000)),o=await te(e,ot,E,{timeoutMs:600,retryClick:600});let a=null,l=o?.trim()||"",u=i&&(l.toLowerCase()===i||l.length<i.length);if(!(l.length>500&&!u)){a=await hn(e);let c=l&&a.answer.includes(l)&&a.answer.length>l.length*2;if(a.answer&&(!l||u||c))o=a.answer}if(!o)throw Error("Gemini returned no answer — model-response never rendered content");let s=ve(o),g=new Map;for(let c of[...a?.sources||[],...s])if(c?.url&&!g.has(c.url))g.set(c.url,c);let p=Array.from(g.values()).slice(0,10);return{answer:o.trim(),sources:p}}var mn=`Usage: node extractors/gemini.mjs "<query>" [--tab <prefix>]
656
+ `;async function yn(){let e=await $e(process.argv.slice(2));_e(e,mn);let{query:t,tabPrefix:n,short:i}=ke(e);if(process.env.GREEDY_SEARCH_VISIBLE!=="1"&&process.env.GREEDY_SEARCH_ALWAYS_VISIBLE!=="1")process.env.GREEDY_SEARCH_HEADLESS="1";await Ie();try{await h(["list"]);let r=await ye(n),o=await h(["eval",r,"document.location.href"]).catch(()=>""),a=!1;try{let c=new URL(o).hostname.toLowerCase();a=c==="gemini.google.com"||c.endsWith(".gemini.google.com")}catch{}if(!a)await h(["nav",r,"https://gemini.google.com/app"],20000),await new Promise((c)=>setTimeout(c,600));await et(r,h),await rt(r,h,1e4),await xe(r,q.input,8000,Q.inputPoll),await new Promise((c)=>setTimeout(c,B(Q.postClick))),await fe(r,{required:!0}),await de(r,E),await fn(r,t),await new Promise((c)=>setTimeout(c,B(Q.postType))),await h(["eval",r,`document.querySelector('${q.sendButton}')?.click()`]),await fe(r);let l=0,u=setInterval(()=>{if(fe(r).catch(()=>null),++l%10===0)gn(r).catch(()=>null)},6000),f=!0;try{await we(r,{timeout:45000,stableRounds:5,minLength:60,selector:"(() => { const responses = Array.from(document.querySelectorAll('model-response')); return responses[responses.length - 1]; })()"})}catch{f=!1}finally{clearInterval(u)}let{answer:s,sources:g}=await pn(r,t,f);if(!s)throw Error("No answer captured from Gemini clipboard");let p=await h(["eval",r,"document.location.href"]).catch(()=>"https://gemini.google.com/app");Ne({query:t,url:p,answer:Je(s,i),sources:g})}catch(r){We(r)}}yn();