@duckmind/dm-darwin-x64 0.52.6 → 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 (58) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +14 -10
  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 -8
  11. package/extensions/greedysearch-dm/bin/kill-visible.mjs +1 -1
  12. package/extensions/greedysearch-dm/bin/launch-visible.mjs +1 -2
  13. package/extensions/greedysearch-dm/bin/launch.mjs +9 -11
  14. package/extensions/greedysearch-dm/bin/mcp.mjs +375 -0
  15. package/extensions/greedysearch-dm/bin/search.mjs +309 -157
  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 +226 -93
  21. package/extensions/greedysearch-dm/extractors/consent.mjs +44 -17
  22. package/extensions/greedysearch-dm/extractors/gemini.mjs +277 -138
  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 +23 -20
  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 -8
  35. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +48 -0
  36. package/extensions/greedysearch-dm/src/search/chrome.mjs +130 -54
  37. package/extensions/greedysearch-dm/src/search/constants.mjs +6 -6
  38. package/extensions/greedysearch-dm/src/search/engines.mjs +9 -9
  39. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +160 -83
  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 -1
  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 +9 -9
  50. package/extensions/greedysearch-dm/src/search/synthesis.mjs +10 -10
  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/search/launcher-paths.mjs +0 -3
  57. package/extensions/greedysearch-dm/src/search/partial-output.mjs +0 -1
  58. package/extensions/greedysearch-dm/src/utils/browser-executable.mjs +0 -1
@@ -1,8 +1,8 @@
1
- import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_process";import{dirname as E,join as U}from"node:path";import{fileURLToPath as F}from"node:url";import{basename as N}from"node:path";function O(z=process.env,K=process.execPath){let Q=z.GREEDY_SEARCH_NODE||z.NODE_BINARY||z.NODE;if(Q?.trim())return Q.trim();let X=N(K||"").toLowerCase();if(X==="node"||X==="node.exe")return K;return"node"}var T=E(F(import.meta.url)),V=U(T,"..","bin","cdp.mjs");function G(z,K=30000){return B(z,null,K)}function B(z,K=null,Q=30000){return new Promise((X,Z)=>{let Y=D(O(),[V,...z],{stdio:[K==null?"ignore":"pipe","pipe","pipe"]});if(K!=null)Y.stdin.write(K),Y.stdin.end();let $="",q="";Y.stdout.on("data",(W)=>$+=W),Y.stderr.on("data",(W)=>q+=W);let A=setTimeout(()=>{Y.kill(),Z(Error(`cdp timeout: ${z[0]}`))},Q);Y.on("close",(W)=>{if(clearTimeout(A),W===0)X($.trim());else Z(Error(q.trim()||`cdp exit ${W}`))})})}async function h(z){if(z)return z;let Q=(await G(["list"])).split(`
2
- `)[0]?.slice(0,8);if(!Q)throw Error("No Chrome tabs found. Is Chrome running with --remote-debugging-port=9222?");let X=await G(["evalraw",Q,"Target.createTarget",'{"url":"about:blank"}']),{targetId:Z}=JSON.parse(X);await G(["list"]);let Y=Z.slice(0,8);try{await R(Y)}catch($){process.stderr.write(`[getOrOpenTab] stealth injection failed: ${$.message}
3
- `)}return Y}async function b(z,K){let Q=`
1
+ import{randomInt as E}from"node:crypto";import{spawn as A}from"node:child_process";import{basename as D}from"node:path";function C(K=process.env,Q=process.execPath){let X=K.GREEDY_SEARCH_NODE||K.NODE_BINARY||K.NODE;if(X?.trim())return X.trim();let Y=D(Q||"").toLowerCase();if(Y==="node"||Y==="node.exe")return Q;return"node"}import{dirname as T,join as w}from"node:path";import{fileURLToPath as B}from"node:url";var R=T(B(import.meta.url)),z=w(R,"..","bin","cdp.mjs"),y=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"]);function V(K){if(!Array.isArray(K)||K.length===0)throw Error("cdp: args must be a non-empty array");if(K[0]==="test")return K.map((Q,X)=>F(Q,X));if(!y.has(K[0]))throw Error(`cdp: unknown subcommand '${K[0]}'`);return K.map((Q,X)=>F(Q,X))}function F(K,Q){if(typeof K!=="string")throw Error(`cdp: argv[${Q}] must be a string (got ${typeof K})`);if(K.includes("\x00"))throw Error(`cdp: argv[${Q}] contains a null byte`);return K}function O(K,Q=30000){return L(K,null,Q)}function L(K,Q=null,X=30000){let Y=V(K);return new Promise((Z,q)=>{let $=A(C(),[z,...Y],{stdio:[Q==null?"ignore":"pipe","pipe","pipe"]});if(Q!=null)$.stdin.write(Q),$.stdin.end();let J="",W="";$.stdout.on("data",(H)=>J+=H),$.stderr.on("data",(H)=>W+=H);let G=setTimeout(()=>{$.kill(),q(Error(`cdp timeout: ${K[0]}`))},X);$.on("close",(H)=>{if(clearTimeout(G),H===0)Z(J.trim());else q(Error(W.trim()||`cdp exit ${H}`))})})}function m(K,Q){let X=($)=>String($??"").replace(/\s+/g," ").trim(),Y=X(K),Z=X(Q);if(!Z)return!1;if(Y.length<Math.ceil(Z.length*0.8))return!1;let q=Math.min(40,Z.length);return Y.includes(Z.slice(0,q))&&Y.includes(Z.slice(-q))}async function x(K){if(K)return K;let X=(await O(["list"])).split(`
2
+ `)[0]?.slice(0,8);if(!X)throw Error("No Chrome tabs found. Is Chrome running with --remote-debugging-port=9222?");let Y=await O(["evalraw",X,"Target.createTarget",'{"url":"about:blank"}']),Z;try{Z=JSON.parse(Y)}catch(J){throw Error(`Target.createTarget returned invalid JSON: ${J.message}`)}let{targetId:q}=Z;if(!q)throw Error("Target.createTarget did not return a targetId");await O(["list"]);let $=q.slice(0,8);try{await j($)}catch(J){process.stderr.write(`[getOrOpenTab] stealth injection failed: ${J.message}
3
+ `)}return $}async function g(K,Q){let X=`
4
4
  (() => {
5
- window.${K} = null;
5
+ window.${Q} = null;
6
6
  const _clipboard = navigator.clipboard;
7
7
  if (!_clipboard) return;
8
8
  const _origWriteText = typeof _clipboard.writeText === 'function'
@@ -13,7 +13,7 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
13
13
  : null;
14
14
 
15
15
  _clipboard.writeText = function(text) {
16
- window.${K} = String(text ?? '');
16
+ window.${Q} = String(text ?? '');
17
17
  if (!_origWriteText) return Promise.resolve();
18
18
  // The OS/browser clipboard write may be denied in automated Chrome or
19
19
  // when the tab is not focused. We only need the captured text; returning
@@ -27,7 +27,7 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
27
27
  for (const item of items || []) {
28
28
  if (item.types && item.types.includes('text/plain')) {
29
29
  const blob = await item.getType('text/plain');
30
- window.${K} = await blob.text();
30
+ window.${Q} = await blob.text();
31
31
  break;
32
32
  }
33
33
  }
@@ -37,7 +37,26 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
37
37
  catch (_) { return undefined; }
38
38
  };
39
39
  })();
40
- `;await G(["eval",z,Q])}async function R(z){await G(["evalraw",z,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
40
+ `;await O(["eval",K,X])}async function p(K,Q,X,Y={}){let{timeoutMs:Z=2600}=Y,q=Y.retryClick!=null?Y.retryClick:Math.floor(Z*0.4),$=String.raw`
41
+ new Promise((resolve) => {
42
+ const _deadline = Date.now() + ${Z};
43
+ const _retryAt = Date.now() + ${q};
44
+ let _retried = false;
45
+ function _click() { try { ${Q}; } catch(_) {} }
46
+ function _poll() {
47
+ const val = window.${X};
48
+ if (val) { resolve(val); return; }
49
+ if (!_retried && Date.now() >= _retryAt) {
50
+ _retried = true;
51
+ _click();
52
+ }
53
+ if (Date.now() < _deadline) { setTimeout(_poll, 100); }
54
+ else { resolve(window.${X} || ''); }
55
+ }
56
+ _click();
57
+ _poll();
58
+ })
59
+ `;return await O(["eval",K,$],Z+5000).catch(()=>"")}async function j(K){await O(["evalraw",K,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
41
60
  (function() {
42
61
  // ── Runtime.enable / CDP detection masking ──────────────
43
62
  try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
@@ -48,40 +67,62 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
48
67
  try { delete window._phantom; } catch(_) {}
49
68
  try { delete window.Buffer; } catch(_) {}
50
69
 
51
- // Real Chrome without automation does not expose a useful webdriver value.
52
- // A literal false value is itself a common stealth tell; prefer undefined and
53
- // make the descriptor configurable like native browser properties.
54
- Object.defineProperty(navigator, 'webdriver', { get: () => undefined, configurable: true });
70
+ // Real Chrome without automation should not expose navigator.webdriver at all.
71
+ // A literal false or an own-property getter returning undefined is itself a
72
+ // common stealth tell; remove both instance and prototype properties when the
73
+ // descriptor is configurable (as it is with --disable-blink-features).
74
+ try { delete navigator.webdriver; } catch(_) {}
75
+ try { delete Navigator.prototype.webdriver; } catch(_) {}
55
76
  Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
56
77
  Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
57
78
  Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
58
79
  Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
80
+ Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
81
+ Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
82
+ var __greedyMimeTypes = null;
83
+ function __makeMimeTypes() {
84
+ var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
85
+ var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
86
+ try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
87
+ try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
88
+ var m = [pdf, textPdf];
89
+ try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
90
+ m.item = function item(i) { return this[i] || null; };
91
+ m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
92
+ return m;
93
+ }
59
94
  Object.defineProperty(navigator, 'plugins', {
60
95
  get: () => {
61
- var p = [
62
- { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' },
63
- { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' },
64
- { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' },
65
- ];
66
- p.length = 3;
96
+ __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
97
+ var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
98
+ var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
99
+ var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
100
+ try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
101
+ try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
102
+ try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
103
+ var p = [plugin0, plugin1, plugin2];
104
+ p.item = function item(i) { return this[i] || null; };
105
+ p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
106
+ p.refresh = function refresh() {};
107
+ try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
108
+ try {
109
+ __greedyMimeTypes[0].enabledPlugin = p[0];
110
+ __greedyMimeTypes[1].enabledPlugin = p[0];
111
+ } catch(_) {}
67
112
  return p;
68
113
  },
114
+ configurable: true,
69
115
  });
70
116
  Object.defineProperty(navigator, 'mimeTypes', {
71
117
  get: () => {
72
- var m = [
73
- { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null },
74
- { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null },
75
- ];
76
- m.item = function(i) { return m[i] || null; };
77
- m.namedItem = function(name) { return m.find(function(x) { return x.type === name; }) || null; };
78
- return m;
118
+ __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
119
+ return __greedyMimeTypes;
79
120
  },
80
121
  configurable: true,
81
122
  });
82
123
  Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
83
124
  try {
84
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, saveData: false }), configurable: true });
125
+ Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
85
126
  } catch(_) {}
86
127
  if (!navigator.mediaDevices) {
87
128
  Object.defineProperty(navigator, 'mediaDevices', {
@@ -97,6 +138,18 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
97
138
  configurable: true,
98
139
  });
99
140
  }
141
+ // ── Missing platform APIs (headless often lacks these) ─
142
+ try {
143
+ if (!navigator.share) {
144
+ navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
145
+ }
146
+ } catch(_) {}
147
+ try {
148
+ if (!navigator.contentIndex) {
149
+ Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
150
+ }
151
+ } catch(_) {}
152
+
100
153
  if (!window.chrome) {
101
154
  window.chrome = {
102
155
  app: { isInstalled: false, InstallState: {}, RunningState: {} },
@@ -104,8 +157,8 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
104
157
  OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
105
158
  connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
106
159
  },
107
- loadTimes: () => ({}),
108
- csi: () => ({}),
160
+ 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' }; },
161
+ csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
109
162
  };
110
163
  }
111
164
  var __greedyNativeFns = [];
@@ -126,6 +179,19 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
126
179
  return getParam.call(this, p);
127
180
  });
128
181
  } catch(_) {}
182
+ // ── WebGL readPixels noise ──────────────────────────
183
+ // CreepJS and other fingerprinters draw content with WebGL and read back the
184
+ // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
185
+ try {
186
+ var origReadPixels = WebGLRenderingContext.prototype.readPixels;
187
+ WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
188
+ var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
189
+ if (pixels && pixels.length > 0) {
190
+ pixels[0] ^= 1;
191
+ }
192
+ return result;
193
+ });
194
+ } catch(_) {}
129
195
  Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
130
196
  Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
131
197
 
@@ -133,7 +199,7 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
133
199
  // Headless rendering engines produce slightly different canvas output
134
200
  // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
135
201
  try {
136
- var __canvasNoise = ((Date.now() % 997) + Math.floor(Math.random() * 997)) & 1;
202
+ var __canvasNoise = ((Date.now() & 0xFF) | 1);
137
203
  var origFill = CanvasRenderingContext2D.prototype.fillText;
138
204
  CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
139
205
  this.globalAlpha = 0.9995;
@@ -152,15 +218,39 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
152
218
  HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
153
219
  var ctx = this.getContext('2d');
154
220
  if (ctx) {
155
- // Add 1px noise pixel in corner (invisible but changes hash)
156
- var imgData = ctx.getImageData(0, 0, 1, 1);
157
- if (imgData) imgData.data[0] ^= __canvasNoise;
158
- ctx.putImageData(imgData, 0, 0);
221
+ // Spread noise across canvas to break hash-based fingerprinting.
222
+ // Uses a deterministic pattern so it's consistent per page load
223
+ // but varies between sessions.
224
+ var w = this.width, h = this.height;
225
+ if (w > 0 && h > 0) {
226
+ var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
227
+ if (imgData && imgData.data) {
228
+ for (var __i = 0; __i < imgData.data.length; __i += 4) {
229
+ imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
230
+ }
231
+ ctx.putImageData(imgData, 0, 0);
232
+ }
233
+ }
159
234
  }
160
235
  return origToDataURL.apply(this, arguments);
161
236
  });
162
237
  } catch(_) {}
163
238
 
239
+ // ── AudioContext fingerprint noise ────────────────────
240
+ // Headless Chrome's AudioContext produces slightly different output.
241
+ // Subtle noise breaks audio-based fingerprinting.
242
+ try {
243
+ var __audioSeed = ((Date.now() & 0x1F) | 1);
244
+ var origGetChannelData = AudioBuffer.prototype.getChannelData;
245
+ AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
246
+ var data = origGetChannelData.call(this, channel);
247
+ for (var __i = 0; __i < data.length; __i += 64) {
248
+ data[__i] *= 0.99999;
249
+ }
250
+ return data;
251
+ });
252
+ } catch(_) {}
253
+
164
254
  // ── window outer dimensions ──────────────────────────
165
255
  // outerWidth/Height = 0 in headless — a well-known bot signal.
166
256
  // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
@@ -170,9 +260,15 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
170
260
  } catch(_) {}
171
261
 
172
262
  // ── screen properties ─────────────────────────────────
263
+ // Headless Chrome often reports an 800x600 screen even when the viewport is
264
+ // 1920x1080. Keep screen metrics internally consistent with our launch flags.
173
265
  try {
174
- if (!screen.colorDepth) Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
175
- if (!screen.pixelDepth) Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
266
+ Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
267
+ Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
268
+ Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
269
+ Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
270
+ Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
271
+ Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
176
272
  } catch(_) {}
177
273
 
178
274
  // ── navigator.userAgentData (UA Client Hints) ─────────
@@ -245,10 +341,20 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
245
341
  };
246
342
  } catch(_) {}
247
343
  })();
248
- `})])}function v(z){if(!z)return[];let K=[],Q=0;while(Q<z.length&&K.length<10){let X=z.indexOf("[",Q);if(X===-1)break;let Z=z.indexOf("](",X);if(Z===-1)break;let Y=Z+2,$=-1;for(let q=Y;q<z.length;q++){let A=z[q];if(A===")"){$=q;break}if(/\s/.test(A))break}if($!==-1){let q=z.slice(X+1,Z),A=z.slice(Y,$);if(/^https?:\/\//i.test(A)&&q){if(!K.some((W)=>W.url===A))K.push({title:q,url:A})}Q=$+1}else Q=X+1}return K}function y(z){if(!z)return!1;for(let K=0;K<z.length;K++){let Q=z.charCodeAt(K);if(Q<48||Q>57)return!1}return!0}function g(z){if(!z)return[];let K=[],Q=new Map,X=/^\[(\d+)\]:\s*(https?:\/\/[^\s"]+)(?:\s+"([^"]*)")?/gm,Z;while((Z=X.exec(z))!==null){let $=Z[1],q=Z[2],A=Z[3]||"";Q.set($,{url:q,title:A})}let Y=0;while(Y<z.length){let $=z.indexOf("[",Y);if($===-1)break;let q=z.indexOf("]",$+1);if(q===-1)break;if(z[q+1]!=="["){Y=$+1;continue}let A=z.indexOf("]",q+2);if(A===-1)break;let W=z.slice($+1,q),J=z.slice(q+2,A);if(y(J)){let H=Q.get(J);if(H&&!K.some((C)=>C.url===H.url))K.push({title:W.trim()||H.title||"",url:H.url})}Y=A+1}return K}var L={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};async function m(z,K,Q={}){let{timeout:X=60000,onPoll:Z}=Q,Y=Date.now()+X,$=0;while(Date.now()<Y){if(await new Promise((A)=>setTimeout(A,j(L.copyPoll))),Z)await Z(++$).catch(()=>null);if(await G(["eval",z,`!!document.querySelector('${K}')`]).catch(()=>"false")==="true")return}throw Error(`Copy button ('${K}') did not appear within ${X}ms`)}function j(z){let K=z*0.4,Q=_(-Math.floor(K),Math.floor(K)+1);return Math.max(50,Math.round(z+Q))}async function x(z,K={}){let{timeout:Q=20000,interval:X=600,stableRounds:Z=3,selector:Y="document.body",minLength:$=0}=K,q=String.raw`
344
+ `})])}function u(K){if(!K)return[];let Q=[],X=0;while(X<K.length&&Q.length<10){let Y=K.indexOf("[",X);if(Y===-1)break;let Z=K.indexOf("](",Y);if(Z===-1)break;let q=Z+2,$=-1;for(let J=q;J<K.length;J++){let W=K[J];if(W===")"){$=J;break}if(/\s/.test(W))break}if($!==-1){let J=K.slice(Y+1,Z),W=K.slice(q,$);if(/^https?:\/\//i.test(W)&&J){if(!Q.some((G)=>G.url===W))Q.push({title:J,url:W})}X=$+1}else X=Y+1}return Q}function N(K){if(!K)return!1;for(let Q=0;Q<K.length;Q++){let X=K.charCodeAt(Q);if(X<48||X>57)return!1}return!0}function d(K){if(!K)return[];let Q=[],X=new Map,Y=/^\[(\d+)\]:\s*(https?:\/\/[^\s"]+)(?:\s+"([^"]*)")?/gm,Z;while((Z=Y.exec(K))!==null){let $=Z[1],J=Z[2],W=Z[3]||"";X.set($,{url:J,title:W})}let q=0;while(q<K.length){let $=K.indexOf("[",q);if($===-1)break;let J=K.indexOf("]",$+1);if(J===-1)break;if(K[J+1]!=="["){q=$+1;continue}let W=K.indexOf("]",J+2);if(W===-1)break;let G=K.slice($+1,J),H=K.slice(J+2,W);if(N(H)){let U=X.get(H);if(U&&!Q.some((_)=>_.url===U.url))Q.push({title:G.trim()||U.title||"",url:U.url})}q=W+1}return Q}var S={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};async function c(K,Q,X={}){let{timeout:Y=60000,onPoll:Z}=X;if(!Z){let J=String.raw`
345
+ new Promise((resolve) => {
346
+ const _deadline = Date.now() + ${Y};
347
+ function _poll() {
348
+ if (document.querySelector('${Q}')) { resolve(true); return; }
349
+ if (Date.now() < _deadline) { setTimeout(_poll, 150); }
350
+ else { resolve(false); }
351
+ }
352
+ _poll();
353
+ })
354
+ `;if(await O(["eval",K,J],Y+5000).catch(()=>"false")==="true")return;throw Error(`Copy button ('${Q}') did not appear within ${Y}ms`)}let q=Date.now()+Y,$=0;while(Date.now()<q){if(await O(["eval",K,`!!document.querySelector('${Q}')`]).catch(()=>"false")==="true")return;await Z(++$).catch(()=>null),await new Promise((W)=>setTimeout(W,M(S.copyPoll)))}throw Error(`Copy button ('${Q}') did not appear within ${Y}ms`)}function M(K){let Q=K*0.2,X=E(-Math.floor(Q),Math.floor(Q)+1);return Math.max(50,Math.round(K+X))}async function i(K,Q={}){let{timeout:X=20000,interval:Y=600,stableRounds:Z=3,selector:q="document.body",minLength:$=0,isStreamingExpr:J="false"}=Q,W=String.raw`
249
355
  new Promise((resolve, reject) => {
250
- const _deadline = Date.now() + ${Q};
251
- const _baseInterval = ${X};
356
+ const _deadline = Date.now() + ${X};
357
+ const _baseInterval = ${Y};
252
358
  const _stableRounds = ${Z};
253
359
  const _minLength = ${$};
254
360
  let _lastLen = -1;
@@ -261,9 +367,13 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
261
367
  function _poll() {
262
368
  try {
263
369
  // Re-query DOM each tick — element may not exist at eval start
264
- const el = ${Y};
265
- const cur = el?.innerText?.length ?? 0;
266
- if (cur >= _minLength) {
370
+ const el = ${q};
371
+ const cur = el?.textContent?.length ?? 0;
372
+ const streaming = ${J};
373
+ if (streaming) {
374
+ if (cur !== _lastLen) _lastLen = cur;
375
+ _stableCount = 0;
376
+ } else if (cur >= _minLength) {
267
377
  if (cur === _lastLen) {
268
378
  _stableCount++;
269
379
  if (_stableCount >= _stableRounds) { resolve(cur); return; }
@@ -275,18 +385,18 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
275
385
  if (Date.now() < _deadline) {
276
386
  setTimeout(_poll, _jitter(_baseInterval));
277
387
  } else {
278
- if (_lastLen >= _minLength) { resolve(_lastLen); }
279
- else { reject(new Error('Generation did not stabilise within ${Q}ms')); }
388
+ if (_lastLen >= _minLength && !streaming) { resolve(_lastLen); }
389
+ else { reject(new Error('Generation did not stabilise within ${X}ms')); }
280
390
  }
281
391
  } catch(e) { reject(e); }
282
392
  }
283
393
 
284
394
  _poll();
285
395
  })
286
- `,A=await G(["eval",z,q],Q+1e4),W=parseInt(A,10)||0;if(W>=$)return W;throw Error(`Generation did not stabilise within ${Q}ms`)}async function p(z,K,Q=15000,X=500){let Z=String.raw`
396
+ `,G=await O(["eval",K,W],X+1e4),H=parseInt(G,10)||0;if(H>=$)return H;throw Error(`Generation did not stabilise within ${X}ms`)}async function l(K,Q,X=15000,Y=500){let Z=String.raw`
287
397
  new Promise((resolve) => {
288
- const _deadline = Date.now() + ${Q};
289
- const _baseInterval = ${X};
398
+ const _deadline = Date.now() + ${X};
399
+ const _baseInterval = ${Y};
290
400
 
291
401
  function _jitter(ms) {
292
402
  return Math.max(50, ms + (Math.random() * ms * 0.4 - ms * 0.2));
@@ -294,7 +404,7 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
294
404
 
295
405
  function _poll() {
296
406
  try {
297
- if (document.querySelector('${K}')) { resolve(true); return; }
407
+ if (document.querySelector('${Q}')) { resolve(true); return; }
298
408
  if (Date.now() < _deadline) { setTimeout(_poll, _jitter(_baseInterval)); }
299
409
  else { resolve(false); }
300
410
  } catch(_) { resolve(false); }
@@ -302,7 +412,7 @@ import{randomInt as _}from"node:crypto";import{spawn as D}from"node:child_proces
302
412
 
303
413
  _poll();
304
414
  })
305
- `;return await G(["eval",z,Z],Q+5000)==="true"}async function u(z){let K=z.indexOf("--stdin");if(K===-1)return z;let Q=await new Promise((Z)=>{let Y="";process.stdin.setEncoding("utf8"),process.stdin.on("data",($)=>Y+=$),process.stdin.on("end",()=>Z(Y.trim()))}),X=[...z];return X[K]=Q,X}function d(z){let K=z.includes("--short"),Q=z.filter((A)=>A!=="--short"),X=Q.indexOf("--tab"),Z=X===-1?null:Q[X+1];if(X!==-1)Q=Q.filter((A,W)=>W!==X&&W!==X+1);let Y=Q.indexOf("--locale"),$=Y===-1?null:Q[Y+1];if(Y!==-1)Q=Q.filter((A,W)=>W!==Y&&W!==Y+1);return{query:Q.join(" "),tabPrefix:Z,short:K,locale:$}}function c(z,K){if(!z.length||z[0]==="--help")process.stderr.write(K),process.exit(1)}function i(z,K,Q=300){if(!K||z.length<=Q)return z;let X=z.slice(0,Q),Z=X.lastIndexOf(" ");return Z>0?`${X.slice(0,Z)}…`:`${X}…`}function l(z){process.stdout.write(`${JSON.stringify(z,null,2)}
306
- `)}function n(z,K,Q=null){if(!z||typeof z!=="object")return;let X=Q?` (+${Date.now()-Q}ms)`:"";if(z.lastStage=K,!Array.isArray(z.stages))z.stages=[];z.stages.push({stage:K,at:Date.now()});let Z=z.engine||"extractor";console.error(`[${Z}] stage: ${K}${X}`)}function o({engine:z,mode:K="headless",clipboardEmpty:Q=null,fallbackUsed:X=null,blockedBy:Z=null,verificationResult:Y=null,inputReady:$=null,durationMs:q=null,lastStage:A=null,stages:W=null}={}){return{engine:z,mode:K,clipboardEmpty:Q,fallbackUsed:X,blockedBy:Z,verificationResult:Y,inputReady:$,durationMs:q,lastStage:A,stages:W}}function s(z,K=null){if(K){let Q=JSON.stringify({_envelope:K,error:z.message});process.stdout.write(`${Q}
307
- `)}process.stderr.write(`Error: ${z.message}
308
- `),process.exit(1)}export{x as waitForStreamComplete,p as waitForSelector,m as waitForCopyButton,c as validateQuery,u as prepareArgs,g as parseSourcesFromMarkdownRefStyle,v as parseSourcesFromMarkdown,d as parseArgs,l as outputJson,n as logStage,j as jitter,R as injectHeadlessStealth,b as injectClipboardInterceptor,s as handleError,h as getOrOpenTab,i as formatAnswer,B as cdpWithInput,G as cdp,o as buildEnvelope,L as TIMING};
415
+ `;return await O(["eval",K,Z],X+5000)==="true"}async function n(K){let Q=K.indexOf("--stdin");if(Q===-1)return K;let X=await new Promise((Z)=>{let q="";process.stdin.setEncoding("utf8"),process.stdin.on("data",($)=>q+=$),process.stdin.on("end",()=>Z(q.trim()))}),Y=[...K];return Y[Q]=X,Y}function s(K){let Q=K.includes("--short"),X=K.filter((W)=>W!=="--short"),Y=X.indexOf("--tab"),Z=Y===-1?null:X[Y+1];if(Y!==-1)X=X.filter((W,G)=>G!==Y&&G!==Y+1);let q=X.indexOf("--locale"),$=q===-1?null:X[q+1];if(q!==-1)X=X.filter((W,G)=>G!==q&&G!==q+1);return{query:X.join(" "),tabPrefix:Z,short:Q,locale:$}}function o(K,Q){if(!K.length||K[0]==="--help")process.stderr.write(Q),process.exit(1)}function r(K,Q,X=300){if(!Q||K.length<=X)return K;let Y=K.slice(0,X),Z=Y.lastIndexOf(" ");return Z>0?`${Y.slice(0,Z)}…`:`${Y}…`}function a(K){process.stdout.write(`${JSON.stringify(K,null,2)}
416
+ `)}function t(K,Q,X=null){if(!K||typeof K!=="object")return;let Y=X?` (+${Date.now()-X}ms)`:"";if(K.lastStage=Q,!Array.isArray(K.stages))K.stages=[];K.stages.push({stage:Q,at:Date.now()});let Z=K.engine||"extractor";console.error(`[${Z}] stage: ${Q}${Y}`)}function e({engine:K,mode:Q="headless",clipboardEmpty:X=null,fallbackUsed:Y=null,blockedBy:Z=null,verificationResult:q=null,inputReady:$=null,durationMs:J=null,lastStage:W=null,stages:G=null}={}){return{engine:K,mode:Q,clipboardEmpty:X,fallbackUsed:Y,blockedBy:Z,verificationResult:q,inputReady:$,durationMs:J,lastStage:W,stages:G}}function KK(K,Q=null){if(Q){let X=JSON.stringify({_envelope:Q,error:K.message});process.stdout.write(`${X}
417
+ `)}process.stderr.write(`Error: ${K.message}
418
+ `),process.exit(1)}export{i as waitForStreamComplete,l as waitForSelector,c as waitForCopyButton,m as verifyInputText,o as validateQuery,n as prepareArgs,d as parseSourcesFromMarkdownRefStyle,u as parseSourcesFromMarkdown,s as parseArgs,a as outputJson,t as logStage,M as jitter,j as injectHeadlessStealth,g as injectClipboardInterceptor,KK as handleError,x as getOrOpenTab,r as formatAnswer,p as clickCopyAndAwaitClipboard,L as cdpWithInput,O as cdp,e as buildEnvelope,S as TIMING};