@duckmind/dm-darwin-arm64 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.
- package/dm +0 -0
- package/extensions/.dm-extensions.json +15 -8
- package/extensions/dm-cua/bin/browser-cua.mjs +6 -6
- package/extensions/dm-cua/index.js +5 -5
- package/extensions/dm-cua/src/browser-cua-lib.mjs +2 -2
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +8 -1
- package/extensions/greedysearch-dm/bin/cdp-headless.mjs +1 -1
- package/extensions/greedysearch-dm/bin/cdp-visible.mjs +1 -1
- package/extensions/greedysearch-dm/bin/cdp.mjs +29 -20
- package/extensions/greedysearch-dm/bin/gschrome.mjs +1 -10
- package/extensions/greedysearch-dm/bin/kill-visible.mjs +1 -1
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +1 -4
- package/extensions/greedysearch-dm/bin/launch.mjs +9 -5
- package/extensions/greedysearch-dm/bin/mcp.mjs +375 -0
- package/extensions/greedysearch-dm/bin/search.mjs +310 -156
- package/extensions/greedysearch-dm/bin/visible.mjs +1 -1
- package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +205 -68
- package/extensions/greedysearch-dm/extractors/chatgpt.mjs +229 -140
- package/extensions/greedysearch-dm/extractors/common.mjs +160 -50
- package/extensions/greedysearch-dm/extractors/consensus.mjs +225 -92
- package/extensions/greedysearch-dm/extractors/consent.mjs +44 -17
- package/extensions/greedysearch-dm/extractors/gemini.mjs +275 -136
- package/extensions/greedysearch-dm/extractors/google-ai.mjs +172 -64
- package/extensions/greedysearch-dm/extractors/logically.mjs +183 -69
- package/extensions/greedysearch-dm/extractors/perplexity.mjs +331 -65
- package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +118 -41
- package/extensions/greedysearch-dm/index.js +20 -17
- package/extensions/greedysearch-dm/package.json +8 -3
- package/extensions/greedysearch-dm/skills/greedy-search/skill.md +8 -8
- package/extensions/greedysearch-dm/src/fetcher.mjs +2 -2
- package/extensions/greedysearch-dm/src/formatters/results.js +8 -6
- package/extensions/greedysearch-dm/src/github.mjs +7 -7
- package/extensions/greedysearch-dm/src/reddit.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +10 -9
- package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +48 -0
- package/extensions/greedysearch-dm/src/search/chrome.mjs +129 -53
- package/extensions/greedysearch-dm/src/search/constants.mjs +8 -8
- package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +154 -77
- package/extensions/greedysearch-dm/src/search/minimize.mjs +1 -0
- package/extensions/greedysearch-dm/src/search/paths.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/pdf.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/port-pid.mjs +1 -0
- package/extensions/greedysearch-dm/src/search/progress.mjs +2 -0
- package/extensions/greedysearch-dm/src/search/recovery.mjs +1 -1
- package/extensions/greedysearch-dm/src/search/research.mjs +262 -167
- package/extensions/greedysearch-dm/src/search/scale-aware.mjs +11 -0
- package/extensions/greedysearch-dm/src/search/simple-research.mjs +827 -0
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +11 -11
- package/extensions/greedysearch-dm/src/search/synthesis.mjs +11 -11
- package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +23 -20
- package/extensions/greedysearch-dm/src/tools/shared.js +10 -9
- package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +1 -1
- package/package.json +1 -1
- package/extensions/greedysearch-dm/src/search/cdp-endpoint.mjs +0 -3
- 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
|
|
3
|
-
`)[0]?.slice(0,8);if(!
|
|
4
|
-
`)}return
|
|
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.${
|
|
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.${
|
|
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.${
|
|
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
|
|
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
|
|
53
|
-
// A literal false
|
|
54
|
-
//
|
|
55
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
74
|
-
|
|
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()
|
|
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
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
176
|
-
|
|
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
|
|
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 = ${
|
|
253
|
-
const _stableRounds = ${
|
|
254
|
-
const _minLength = ${
|
|
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?.
|
|
267
|
-
|
|
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
|
-
`,
|
|
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 = ${
|
|
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('${
|
|
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
|
|
307
|
-
`)}function
|
|
308
|
-
`)}process.stderr.write(`Error: ${
|
|
309
|
-
`),process.exit(1)}import{spawn as
|
|
310
|
-
[greedysearch] Available engines: ${Object.keys(
|
|
311
|
-
`);if(n.length>0)return n;process.stderr.write(`[greedysearch] Warning: no valid engines in ${v}, falling back to defaults: ${
|
|
312
|
-
`)}}}catch{}return
|
|
313
|
-
`,"utf8")}catch{}}
|
|
314
|
-
[greedysearch] Available synthesizers: ${
|
|
315
|
-
[greedysearch] Falling back to default: ${
|
|
316
|
-
`)}}}catch{}return
|
|
317
|
-
|
|
318
|
-
`}function
|
|
319
|
-
`)
|
|
320
|
-
`)
|
|
321
|
-
`);return
|
|
322
|
-
${l}`,"utf8");try{
|
|
323
|
-
`)
|
|
324
|
-
`),await
|
|
325
|
-
`)
|
|
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
|
-
`,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
448
|
-
`)[0],o=await new Promise((
|
|
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(!
|
|
454
|
-
`),
|
|
455
|
-
`),
|
|
456
|
-
`)
|
|
457
|
-
`),"
|
|
458
|
-
`),"
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
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(
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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();
|