@duckmind/dm-windows-x64 0.60.6 → 0.60.8

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 (197) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +70 -123
  3. package/extensions/dm-9router-ext/src/index.js +410 -5
  4. package/extensions/dm-caveman/extensions/caveman.js +283 -12
  5. package/extensions/dm-cliproxy/index.js +182 -2
  6. package/extensions/dm-cliproxy/scripts/check-config-migration.js +66 -8
  7. package/extensions/dm-cliproxy/src/apply.js +228 -1
  8. package/extensions/dm-cliproxy/src/cache.js +42 -1
  9. package/extensions/dm-cliproxy/src/commands.js +50 -2
  10. package/extensions/dm-cliproxy/src/compat.js +81 -1
  11. package/extensions/dm-cliproxy/src/config.js +192 -2
  12. package/extensions/dm-cliproxy/src/conflicts.js +46 -1
  13. package/extensions/dm-cliproxy/src/fetch-models.js +190 -1
  14. package/extensions/dm-cliproxy/src/fetch-usage.js +41 -1
  15. package/extensions/dm-cliproxy/src/log.js +23 -1
  16. package/extensions/dm-cliproxy/src/status-quota.js +77 -1
  17. package/extensions/dm-cliproxy/src/ui-frame.js +50 -1
  18. package/extensions/dm-cliproxy/src/ui-hub/hub.js +199 -2
  19. package/extensions/dm-cliproxy/src/ui-hub/index.js +26 -2
  20. package/extensions/dm-cliproxy/src/ui-hub/shell.js +46 -1
  21. package/extensions/dm-cliproxy/src/ui-hub/view-diagnostics.js +69 -1
  22. package/extensions/dm-cliproxy/src/ui-hub/view-models.js +379 -1
  23. package/extensions/dm-cliproxy/src/ui-hub/view-usage.js +106 -1
  24. package/extensions/dm-cliproxy/src/ui-picker/catalog.js +41 -1
  25. package/extensions/dm-cliproxy/src/ui-picker/mutate.js +115 -1
  26. package/extensions/dm-cliproxy/src/ui-picker/prompt-confirm.js +35 -1
  27. package/extensions/dm-cliproxy/src/ui-picker/prompt-name.js +62 -1
  28. package/extensions/dm-cliproxy/src/ui-picker/providers.js +45 -1
  29. package/extensions/dm-cliproxy/src/ui-picker/render-text.js +34 -1
  30. package/extensions/dm-cliproxy/src/ui-picker/rows.js +57 -1
  31. package/extensions/dm-cliproxy/src/ui-setup.js +260 -2
  32. package/extensions/dm-cliproxy/src/ui-usage.js +151 -1
  33. package/extensions/dm-cliproxy/src/usage-shared-cache.js +97 -1
  34. package/extensions/dm-context/src/context.js +144 -1
  35. package/extensions/dm-context/src/index.js +339 -7
  36. package/extensions/dm-context/src/utils.js +9 -1
  37. package/extensions/dm-cua/bin/browser-cua.mjs +73 -8
  38. package/extensions/dm-cua/index.js +75 -6
  39. package/extensions/dm-cua/src/browser-cua-lib.mjs +490 -6
  40. package/extensions/dm-cua/src/browser-install.mjs +331 -2
  41. package/extensions/dm-fff/src/index.js +688 -12
  42. package/extensions/dm-fff/src/query.js +60 -1
  43. package/extensions/dm-goal/src/goal.js +894 -23
  44. package/extensions/dm-image2/index.js +103 -9
  45. package/extensions/dm-image2/src/image-lib.mjs +1275 -8
  46. package/extensions/dm-subagents/install.mjs +62 -8
  47. package/extensions/dm-subagents/src/agents/agent-management.js +1190 -36
  48. package/extensions/dm-subagents/src/agents/agent-memory.js +216 -6
  49. package/extensions/dm-subagents/src/agents/agent-scope.js +5 -1
  50. package/extensions/dm-subagents/src/agents/agent-selection.js +20 -1
  51. package/extensions/dm-subagents/src/agents/agent-serializer.js +120 -5
  52. package/extensions/dm-subagents/src/agents/agents.js +1139 -11
  53. package/extensions/dm-subagents/src/agents/chain-serializer.js +299 -11
  54. package/extensions/dm-subagents/src/agents/frontmatter.js +65 -6
  55. package/extensions/dm-subagents/src/agents/identity.js +29 -1
  56. package/extensions/dm-subagents/src/agents/proactive-skills.js +141 -1
  57. package/extensions/dm-subagents/src/agents/skills.js +614 -6
  58. package/extensions/dm-subagents/src/extension/config.js +35 -2
  59. package/extensions/dm-subagents/src/extension/control-notices.js +69 -4
  60. package/extensions/dm-subagents/src/extension/doctor.js +172 -15
  61. package/extensions/dm-subagents/src/extension/fanout-child.js +158 -231
  62. package/extensions/dm-subagents/src/extension/index.js +521 -359
  63. package/extensions/dm-subagents/src/extension/rpc.js +266 -7
  64. package/extensions/dm-subagents/src/extension/schemas.js +275 -1
  65. package/extensions/dm-subagents/src/extension/tool-description.js +111 -6
  66. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +126 -4
  67. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +452 -5
  68. package/extensions/dm-subagents/src/intercom/result-intercom.js +319 -3
  69. package/extensions/dm-subagents/src/profiles/profiles.js +458 -3
  70. package/extensions/dm-subagents/src/runs/background/async-execution.js +834 -40
  71. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +435 -14
  72. package/extensions/dm-subagents/src/runs/background/async-resume.js +334 -8
  73. package/extensions/dm-subagents/src/runs/background/async-status.js +313 -12
  74. package/extensions/dm-subagents/src/runs/background/chain-append.js +245 -2
  75. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +136 -1
  76. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +94 -1
  77. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +54 -1
  78. package/extensions/dm-subagents/src/runs/background/control-channel.js +190 -1
  79. package/extensions/dm-subagents/src/runs/background/fleet-view.js +483 -17
  80. package/extensions/dm-subagents/src/runs/background/notify.js +129 -3
  81. package/extensions/dm-subagents/src/runs/background/parallel-groups.js +34 -1
  82. package/extensions/dm-subagents/src/runs/background/result-watcher.js +236 -6
  83. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +76 -4
  84. package/extensions/dm-subagents/src/runs/background/run-status.js +427 -23
  85. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +487 -4
  86. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +306 -9
  87. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +2849 -73
  88. package/extensions/dm-subagents/src/runs/background/top-level-async.js +5 -1
  89. package/extensions/dm-subagents/src/runs/background/wait.js +206 -11
  90. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +1013 -12
  91. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +980 -101
  92. package/extensions/dm-subagents/src/runs/foreground/execution.js +1165 -45
  93. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +3157 -222
  94. package/extensions/dm-subagents/src/runs/shared/acceptance.js +835 -3
  95. package/extensions/dm-subagents/src/runs/shared/chain-outputs.js +104 -1
  96. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +116 -3
  97. package/extensions/dm-subagents/src/runs/shared/dm-args.js +208 -1
  98. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +90 -1
  99. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +282 -1
  100. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +148 -1
  101. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +305 -1
  102. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +194 -1
  103. package/extensions/dm-subagents/src/runs/shared/model-scope.js +65 -1
  104. package/extensions/dm-subagents/src/runs/shared/nested-events.js +851 -8
  105. package/extensions/dm-subagents/src/runs/shared/nested-path.js +41 -1
  106. package/extensions/dm-subagents/src/runs/shared/nested-render.js +105 -1
  107. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +81 -4
  108. package/extensions/dm-subagents/src/runs/shared/run-history.js +51 -4
  109. package/extensions/dm-subagents/src/runs/shared/single-output.js +149 -8
  110. package/extensions/dm-subagents/src/runs/shared/structured-output.js +58 -1
  111. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +166 -5
  112. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +329 -13
  113. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +73 -1
  114. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +47 -4
  115. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +196 -1
  116. package/extensions/dm-subagents/src/runs/shared/worktree.js +435 -3
  117. package/extensions/dm-subagents/src/shared/artifacts.js +92 -2
  118. package/extensions/dm-subagents/src/shared/atomic-json.js +55 -1
  119. package/extensions/dm-subagents/src/shared/child-transcript.js +167 -5
  120. package/extensions/dm-subagents/src/shared/file-coalescer.js +25 -1
  121. package/extensions/dm-subagents/src/shared/fork-context.js +147 -4
  122. package/extensions/dm-subagents/src/shared/formatters.js +98 -7
  123. package/extensions/dm-subagents/src/shared/jsonl-writer.js +56 -2
  124. package/extensions/dm-subagents/src/shared/model-info.js +62 -1
  125. package/extensions/dm-subagents/src/shared/post-exit-stdio-guard.js +68 -1
  126. package/extensions/dm-subagents/src/shared/session-identity.js +6 -1
  127. package/extensions/dm-subagents/src/shared/session-tokens.js +39 -2
  128. package/extensions/dm-subagents/src/shared/settings.js +198 -11
  129. package/extensions/dm-subagents/src/shared/status-format.js +53 -1
  130. package/extensions/dm-subagents/src/shared/types.js +184 -6
  131. package/extensions/dm-subagents/src/shared/utils.js +462 -2
  132. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +288 -1
  133. package/extensions/dm-subagents/src/slash/prompt-workflows.js +297 -7
  134. package/extensions/dm-subagents/src/slash/slash-bridge.js +118 -1
  135. package/extensions/dm-subagents/src/slash/slash-commands.js +1287 -31
  136. package/extensions/dm-subagents/src/slash/slash-live-state.js +240 -4
  137. package/extensions/dm-subagents/src/tui/render-helpers.js +64 -1
  138. package/extensions/dm-subagents/src/tui/render.js +1542 -4
  139. package/extensions/dm-usage/index.js +1294 -9
  140. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +40 -9
  141. package/extensions/greedysearch-dm/bin/cdp-headless.mjs +5 -2
  142. package/extensions/greedysearch-dm/bin/cdp-visible.mjs +5 -2
  143. package/extensions/greedysearch-dm/bin/cdp.mjs +896 -30
  144. package/extensions/greedysearch-dm/bin/gschrome.mjs +30 -2
  145. package/extensions/greedysearch-dm/bin/kill-visible.mjs +7 -2
  146. package/extensions/greedysearch-dm/bin/launch-visible.mjs +13 -2
  147. package/extensions/greedysearch-dm/bin/launch.mjs +282 -10
  148. package/extensions/greedysearch-dm/bin/mcp.mjs +386 -361
  149. package/extensions/greedysearch-dm/bin/search.mjs +620 -540
  150. package/extensions/greedysearch-dm/bin/visible.mjs +22 -2
  151. package/extensions/greedysearch-dm/extractors/bing-copilot.mjs +329 -579
  152. package/extensions/greedysearch-dm/extractors/chatgpt.mjs +301 -583
  153. package/extensions/greedysearch-dm/extractors/common.mjs +408 -32
  154. package/extensions/greedysearch-dm/extractors/consensus.mjs +376 -365
  155. package/extensions/greedysearch-dm/extractors/consent.mjs +303 -14
  156. package/extensions/greedysearch-dm/extractors/gemini.mjs +228 -592
  157. package/extensions/greedysearch-dm/extractors/google-ai.mjs +78 -499
  158. package/extensions/greedysearch-dm/extractors/logically.mjs +270 -347
  159. package/extensions/greedysearch-dm/extractors/perplexity.mjs +243 -581
  160. package/extensions/greedysearch-dm/extractors/selectors.mjs +32 -1
  161. package/extensions/greedysearch-dm/extractors/semantic-scholar.mjs +130 -317
  162. package/extensions/greedysearch-dm/index.js +123 -23
  163. package/extensions/greedysearch-dm/src/fetcher.mjs +576 -2
  164. package/extensions/greedysearch-dm/src/formatters/results.js +95 -10
  165. package/extensions/greedysearch-dm/src/formatters/sources.js +57 -1
  166. package/extensions/greedysearch-dm/src/formatters/synthesis.js +49 -1
  167. package/extensions/greedysearch-dm/src/github.mjs +222 -7
  168. package/extensions/greedysearch-dm/src/reddit.mjs +145 -14
  169. package/extensions/greedysearch-dm/src/search/browser-lifecycle.mjs +340 -9
  170. package/extensions/greedysearch-dm/src/search/challenge-detect.mjs +112 -4
  171. package/extensions/greedysearch-dm/src/search/chrome.mjs +486 -285
  172. package/extensions/greedysearch-dm/src/search/constants.mjs +109 -8
  173. package/extensions/greedysearch-dm/src/search/defaults.mjs +10 -1
  174. package/extensions/greedysearch-dm/src/search/engines.mjs +79 -9
  175. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +441 -349
  176. package/extensions/greedysearch-dm/src/search/file-sources.mjs +29 -7
  177. package/extensions/greedysearch-dm/src/search/minimize.mjs +86 -1
  178. package/extensions/greedysearch-dm/src/search/output.mjs +51 -5
  179. package/extensions/greedysearch-dm/src/search/paths.mjs +48 -1
  180. package/extensions/greedysearch-dm/src/search/pdf.mjs +63 -2
  181. package/extensions/greedysearch-dm/src/search/port-pid.mjs +69 -1
  182. package/extensions/greedysearch-dm/src/search/progress.mjs +109 -2
  183. package/extensions/greedysearch-dm/src/search/query.mjs +21 -1
  184. package/extensions/greedysearch-dm/src/search/recovery.mjs +49 -1
  185. package/extensions/greedysearch-dm/src/search/research.mjs +2227 -458
  186. package/extensions/greedysearch-dm/src/search/scale-aware.mjs +61 -11
  187. package/extensions/greedysearch-dm/src/search/simple-research.mjs +396 -805
  188. package/extensions/greedysearch-dm/src/search/sources.mjs +412 -1
  189. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +127 -12
  190. package/extensions/greedysearch-dm/src/search/synthesis.mjs +202 -12
  191. package/extensions/greedysearch-dm/src/tools/greedy-search-handler.js +209 -23
  192. package/extensions/greedysearch-dm/src/tools/shared.js +226 -10
  193. package/extensions/greedysearch-dm/src/utils/content.mjs +35 -4
  194. package/extensions/greedysearch-dm/src/utils/helpers.js +22 -1
  195. package/extensions/greedysearch-dm/src/utils/node-runtime.mjs +10 -1
  196. package/extensions/greedysearch-dm/src/utils/system-cmds.mjs +61 -1
  197. package/package.json +1 -1
@@ -1,335 +1,41 @@
1
- #!/usr/bin/env node
2
- import{randomInt as Gt}from"node:crypto";import{spawn as Rt}from"node:child_process";import{basename as Ft}from"node:path";import{dirname as It,join as Et}from"node:path";import{fileURLToPath as te}from"node:url";function Lt(t=process.env,e=process.execPath){let n=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(n?.trim())return n.trim();let i=Ft(e||"").toLowerCase();if(i==="node"||i==="node.exe")return e;return"node"}var ee=It(te(import.meta.url)),ne=Et(ee,"..","bin","cdp.mjs"),re=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"]);function ie(t){if(!Array.isArray(t)||t.length===0)throw Error("cdp: args must be a non-empty array");if(t[0]==="test")return t.map((e,n)=>ct(e,n));if(!re.has(t[0]))throw Error(`cdp: unknown subcommand '${t[0]}'`);return t.map((e,n)=>ct(e,n))}function ct(t,e){if(typeof t!=="string")throw Error(`cdp: argv[${e}] must be a string (got ${typeof t})`);if(t.includes("\x00"))throw Error(`cdp: argv[${e}] contains a null byte`);return t}function s(t,e=30000){return oe(t,null,e)}function oe(t,e=null,n=30000){let i=ie(t);return new Promise((r,o)=>{let l=Rt(Lt(),[ne,...i],{stdio:[e==null?"ignore":"pipe","pipe","pipe"]});if(e!=null)l.stdin.write(e),l.stdin.end();let u="",a="";l.stdout.on("data",(c)=>u+=c),l.stderr.on("data",(c)=>a+=c);let f=setTimeout(()=>{l.kill(),o(Error(`cdp timeout: ${t[0]}`))},n);l.on("close",(c)=>{if(clearTimeout(f),c===0)r(u.trim());else o(Error(a.trim()||`cdp exit ${c}`))})})}function gt(t,e){let n=(l)=>String(l??"").replace(/\s+/g," ").trim(),i=n(t),r=n(e);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 pt(t){if(t)return t;let e=(await s(["list"])).split(`
3
- `)[0]?.slice(0,8);if(!e)throw Error("No Chrome tabs found. Is Chrome running with --remote-debugging-port=9222?");let n=await s(["evalraw",e,"Target.createTarget",'{"url":"about:blank"}']),i;try{i=JSON.parse(n)}catch(l){throw Error(`Target.createTarget returned invalid JSON: ${l.message}`)}let{targetId:r}=i;if(!r)throw Error("Target.createTarget did not return a targetId");await s(["list"]);let o=r.slice(0,8);try{await ht(o)}catch(l){process.stderr.write(`[getOrOpenTab] stealth injection failed: ${l.message}
4
- `)}return o}async function ht(t){await s(["evalraw",t,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
5
- (function() {
6
- // ── Runtime.enable / CDP detection masking ──────────────
7
- try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
8
- try { delete window.__REBROWSER_DEVTOOLS; } catch(_) {}
9
- try { delete window.__nightmare; } catch(_) {}
10
- try { delete window.__phantom; } catch(_) {}
11
- try { delete window.callPhantom; } catch(_) {}
12
- try { delete window._phantom; } catch(_) {}
13
- try { delete window.Buffer; } catch(_) {}
14
-
15
- // Real Chrome without automation should not expose navigator.webdriver at all.
16
- // A literal false or an own-property getter returning undefined is itself a
17
- // common stealth tell; remove both instance and prototype properties when the
18
- // descriptor is configurable (as it is with --disable-blink-features).
19
- try { delete navigator.webdriver; } catch(_) {}
20
- try { delete Navigator.prototype.webdriver; } catch(_) {}
21
- Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
22
- Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
23
- Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
24
- Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
25
- Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
26
- Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
27
- var __greedyMimeTypes = null;
28
- function __makeMimeTypes() {
29
- var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
30
- var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
31
- try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
32
- try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
33
- var m = [pdf, textPdf];
34
- try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
35
- m.item = function item(i) { return this[i] || null; };
36
- m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
37
- return m;
38
- }
39
- Object.defineProperty(navigator, 'plugins', {
40
- get: () => {
41
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
42
- var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
43
- var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
44
- var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
45
- try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
46
- try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
47
- try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
48
- var p = [plugin0, plugin1, plugin2];
49
- p.item = function item(i) { return this[i] || null; };
50
- p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
51
- p.refresh = function refresh() {};
52
- try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
53
- try {
54
- __greedyMimeTypes[0].enabledPlugin = p[0];
55
- __greedyMimeTypes[1].enabledPlugin = p[0];
56
- } catch(_) {}
57
- return p;
58
- },
59
- configurable: true,
60
- });
61
- Object.defineProperty(navigator, 'mimeTypes', {
62
- get: () => {
63
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
64
- return __greedyMimeTypes;
65
- },
66
- configurable: true,
67
- });
68
- Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
69
- try {
70
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
71
- } catch(_) {}
72
- if (!navigator.mediaDevices) {
73
- Object.defineProperty(navigator, 'mediaDevices', {
74
- get: () => ({
75
- enumerateDevices: () => Promise.resolve([
76
- { deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
77
- { deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
78
- { deviceId: '', kind: 'videoinput', label: '', groupId: '' },
79
- ]),
80
- getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
81
- getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
82
- }),
83
- configurable: true,
84
- });
85
- }
86
- // ── Missing platform APIs (headless often lacks these) ─
87
- try {
88
- if (!navigator.share) {
89
- navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
90
- }
91
- } catch(_) {}
92
- try {
93
- if (!navigator.contentIndex) {
94
- Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
95
- }
96
- } catch(_) {}
97
-
98
- if (!window.chrome) {
99
- window.chrome = {
100
- app: { isInstalled: false, InstallState: {}, RunningState: {} },
101
- runtime: {
102
- OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
103
- connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
104
- },
105
- 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' }; },
106
- csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
107
- };
108
- }
109
- var __greedyNativeFns = [];
110
- function __markNative(fn) { try { __greedyNativeFns.push(fn); } catch(_) {} return fn; }
111
-
112
- var origQuery = navigator.permissions?.query;
113
- if (origQuery) {
114
- navigator.permissions.query = __markNative(function query(params) {
115
- if (params && params.name === 'notifications') return Promise.resolve({ state: Notification.permission || 'default', onchange: null });
116
- return origQuery.apply(this, arguments);
117
- });
118
- }
119
- try {
120
- var getParam = WebGLRenderingContext.prototype.getParameter;
121
- WebGLRenderingContext.prototype.getParameter = __markNative(function getParameter(p) {
122
- if (p === 37445) return 'Intel Inc.';
123
- if (p === 37446) return 'Intel Iris OpenGL Engine';
124
- return getParam.call(this, p);
125
- });
126
- } catch(_) {}
127
- // ── WebGL readPixels noise ──────────────────────────
128
- // CreepJS and other fingerprinters draw content with WebGL and read back the
129
- // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
130
- try {
131
- var origReadPixels = WebGLRenderingContext.prototype.readPixels;
132
- WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
133
- var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
134
- if (pixels && pixels.length > 0) {
135
- pixels[0] ^= 1;
136
- }
137
- return result;
138
- });
139
- } catch(_) {}
140
- Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
141
- Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
142
-
143
- // ── Canvas fingerprint noise ─────────────────────────
144
- // Headless rendering engines produce slightly different canvas output
145
- // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
146
- try {
147
- var __canvasNoise = ((Date.now() & 0xFF) | 1);
148
- var origFill = CanvasRenderingContext2D.prototype.fillText;
149
- CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
150
- this.globalAlpha = 0.9995;
151
- return origFill.apply(this, arguments);
152
- });
153
- } catch(_) {}
154
- try {
155
- var origStroke = CanvasRenderingContext2D.prototype.strokeText;
156
- CanvasRenderingContext2D.prototype.strokeText = __markNative(function strokeText() {
157
- this.globalAlpha = 0.9995;
158
- return origStroke.apply(this, arguments);
159
- });
160
- } catch(_) {}
161
- try {
162
- var origToDataURL = HTMLCanvasElement.prototype.toDataURL;
163
- HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
164
- var ctx = this.getContext('2d');
165
- if (ctx) {
166
- // Spread noise across canvas to break hash-based fingerprinting.
167
- // Uses a deterministic pattern so it's consistent per page load
168
- // but varies between sessions.
169
- var w = this.width, h = this.height;
170
- if (w > 0 && h > 0) {
171
- var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
172
- if (imgData && imgData.data) {
173
- for (var __i = 0; __i < imgData.data.length; __i += 4) {
174
- imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
175
- }
176
- ctx.putImageData(imgData, 0, 0);
177
- }
178
- }
179
- }
180
- return origToDataURL.apply(this, arguments);
181
- });
182
- } catch(_) {}
183
-
184
- // ── AudioContext fingerprint noise ────────────────────
185
- // Headless Chrome's AudioContext produces slightly different output.
186
- // Subtle noise breaks audio-based fingerprinting.
187
- try {
188
- var __audioSeed = ((Date.now() & 0x1F) | 1);
189
- var origGetChannelData = AudioBuffer.prototype.getChannelData;
190
- AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
191
- var data = origGetChannelData.call(this, channel);
192
- for (var __i = 0; __i < data.length; __i += 64) {
193
- data[__i] *= 0.99999;
194
- }
195
- return data;
196
- });
197
- } catch(_) {}
198
-
199
- // ── window outer dimensions ──────────────────────────
200
- // outerWidth/Height = 0 in headless — a well-known bot signal.
201
- // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
202
- try {
203
- if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
204
- if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
205
- } catch(_) {}
206
-
207
- // ── screen properties ─────────────────────────────────
208
- // Headless Chrome often reports an 800x600 screen even when the viewport is
209
- // 1920x1080. Keep screen metrics internally consistent with our launch flags.
210
- try {
211
- Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
212
- Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
213
- Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
214
- Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
215
- Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
216
- Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
217
- } catch(_) {}
218
-
219
- // ── navigator.userAgentData (UA Client Hints) ─────────
220
- // Derive version from the UA string already set by --user-agent flag so the
221
- // two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
222
- try {
223
- var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
224
- var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
225
- var _brands = [
226
- { brand: 'Not)A;Brand', version: '99' },
227
- { brand: 'Google Chrome', version: _uaMajor },
228
- { brand: 'Chromium', version: _uaMajor },
229
- ];
230
- Object.defineProperty(navigator, 'userAgentData', {
231
- get: function() {
232
- return {
233
- brands: _brands, mobile: false, platform: 'Windows',
234
- getHighEntropyValues: function() {
235
- return Promise.resolve({
236
- architecture: 'x86', bitness: '64',
237
- brands: _brands,
238
- fullVersionList: [
239
- { brand: 'Not)A;Brand', version: '99.0.0.0' },
240
- { brand: 'Google Chrome', version: _uaFull },
241
- { brand: 'Chromium', version: _uaFull },
242
- ],
243
- mobile: false, model: '', platform: 'Windows',
244
- platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
245
- });
246
- },
247
- toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
248
- };
249
- },
250
- configurable: true,
251
- });
252
- } catch(_) {}
253
-
254
- // ── CDP Runtime serialization guard ──────────────────
255
- // Sites detect CDP by putting a getter on Error.prototype.stack
256
- // and checking if console.log triggers it (only happens when
257
- // Runtime domain is enabled). We monkey-patch console methods to
258
- // strip custom getters from arguments before they reach CDP.
259
- try {
260
- var _origLog = console.log, _origError = console.error,
261
- _origWarn = console.warn, _origDebug = console.debug,
262
- _origInfo = console.info;
263
- var _safeArg = function(a) {
264
- if (a instanceof Error) {
265
- try { return new Error(a.message); } catch(_) { return a; }
266
- }
267
- return a;
268
- };
269
- console.log = __markNative(function log() { return _origLog.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
270
- console.error = __markNative(function error() { return _origError.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
271
- console.warn = __markNative(function warn() { return _origWarn.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
272
- console.debug = __markNative(function debug() { return _origDebug.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
273
- console.info = __markNative(function info() { return _origInfo.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
274
- } catch(_) {}
275
-
276
- // ── Native function masking ──────────────────────────
277
- // Patched APIs should not stringify as user-defined stealth code.
278
- try {
279
- var __nativeToString = Function.prototype.toString;
280
- Function.prototype.toString = function toString() {
281
- if (__greedyNativeFns.indexOf(this) !== -1) {
282
- var name = this.name || '';
283
- return 'function ' + name + '() { [native code] }';
284
- }
285
- return __nativeToString.call(this);
286
- };
287
- } catch(_) {}
288
- })();
289
- `})])}var tt={postNav:800,postNavSlow:1200,postClick:300,postType:300,inputPoll:400,copyPoll:600,afterVerify:1500};function U(t){let e=t*0.2,n=Gt(-Math.floor(e),Math.floor(e)+1);return Math.max(50,Math.round(t+n))}async function bt(t,e,n=15000,i=500){let r=String.raw`
290
- new Promise((resolve) => {
291
- const _deadline = Date.now() + ${n};
292
- const _baseInterval = ${i};
293
-
294
- function _jitter(ms) {
295
- return Math.max(50, ms + (Math.random() * ms * 0.4 - ms * 0.2));
296
- }
297
-
298
- function _poll() {
299
- try {
300
- if (document.querySelector('${e}')) { resolve(true); return; }
301
- if (Date.now() < _deadline) { setTimeout(_poll, _jitter(_baseInterval)); }
302
- else { resolve(false); }
303
- } catch(_) { resolve(false); }
304
- }
305
-
306
- _poll();
307
- })
308
- `;return await s(["eval",t,r],n+5000)==="true"}async function yt(t){let e=t.indexOf("--stdin");if(e===-1)return t;let n=await new Promise((r)=>{let o="";process.stdin.setEncoding("utf8"),process.stdin.on("data",(l)=>o+=l),process.stdin.on("end",()=>r(o.trim()))}),i=[...t];return i[e]=n,i}function wt(t){let e=t.includes("--short"),n=t.filter((u)=>u!=="--short"),i=n.indexOf("--tab"),r=i===-1?null:n[i+1];if(i!==-1)n=n.filter((u,a)=>a!==i&&a!==i+1);let o=n.indexOf("--locale"),l=o===-1?null:n[o+1];if(o!==-1)n=n.filter((u,a)=>a!==o&&a!==o+1);return{query:n.join(" "),tabPrefix:r,short:e,locale:l}}function mt(t,e){if(!t.length||t[0]==="--help")process.stderr.write(e),process.exit(1)}function vt(t,e,n=300){if(!e||t.length<=n)return t;let i=t.slice(0,n),r=i.lastIndexOf(" ");return r>0?`${i.slice(0,r)}…`:`${i}…`}function xt(t){process.stdout.write(`${JSON.stringify(t,null,2)}
309
- `)}function b(t,e,n=null){if(!t||typeof t!=="object")return;let i=n?` (+${Date.now()-n}ms)`:"";if(t.lastStage=e,!Array.isArray(t.stages))t.stages=[];t.stages.push({stage:e,at:Date.now()});let r=t.engine||"extractor";console.error(`[${r}] stage: ${e}${i}`)}function et({engine:t,mode:e="headless",clipboardEmpty:n=null,fallbackUsed:i=null,blockedBy:r=null,verificationResult:o=null,inputReady:l=null,durationMs:u=null,lastStage:a=null,stages:f=null}={}){return{engine:t,mode:e,clipboardEmpty:n,fallbackUsed:i,blockedBy:r,verificationResult:o,inputReady:l,durationMs:u,lastStage:a,stages:f}}function _t(t,e=null){if(e){let n=JSON.stringify({_envelope:e,error:t.message});process.stdout.write(`${n}
310
- `)}process.stderr.write(`Error: ${t.message}
311
- `),process.exit(1)}import{readFileSync as Ye}from"node:fs";import{tmpdir as Ke}from"node:os";import{spawn as de,execFileSync as at,execSync as Yn}from"node:child_process";import{basename as le}from"node:path";function $t(t=process.env,e=process.execPath){let n=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(n?.trim())return n.trim();let i=le(e||"").toLowerCase();if(i==="node"||i==="node.exe")return e;return"node"}import{existsSync as Dt,readFileSync as st,renameSync as He,unlinkSync as v,writeFileSync as G}from"node:fs";import ft from"node:http";import{platform as Tt}from"node:os";import{existsSync as Wt}from"node:fs";import{platform as ue}from"node:os";import{join as W}from"node:path";function w(t){let e=ue()==="win32",n=process.env.SystemRoot||"C:\\Windows",i={win32:{powershell:W(n,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:W(n,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:W(n,"System32","netstat.exe"),taskkill:W(n,"System32","taskkill.exe"),tasklist:W(n,"System32","tasklist.exe"),cmd:W(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=e?i.win32:i.unix,o=t.toLowerCase();if(r[o]&&Wt(r[o]))return r[o];if(e&&o==="netstat"){let l=W(n,"Sysnative","netstat.exe");if(Wt(l))return l}return t}import{execFileSync as ae}from"node:child_process";import{platform as se}from"node:os";function fe(t,e){return ae(w(t),e,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5000})}function ce(t){let e=String(t||"").match(/\b(\d+)\b/);return e?Number.parseInt(e[1],10):null}function ge(t){return ce(t)}function pe(t,e){for(let n of String(t||"").split(/\r?\n/)){if(!/\bLISTEN\b/i.test(n))continue;if(!n.trim().split(/\s+/).slice(0,6).some((o)=>o.endsWith(`:${e}`)))continue;let r=n.match(/\bpid=(\d+)\b/);if(r)return Number.parseInt(r[1],10)}return null}function he(t,e){for(let n of String(t||"").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(`:${e}`))continue;let r=Number.parseInt(i.at(-1),10);if(Number.isInteger(r)&&r>0)return r}return null}function nt(t,e,n){try{return t(e,n)}catch{return null}}function M(t,{platformName:e=se(),run:n=fe}={}){if(e==="win32")return he(nt(n,"netstat",["-ano","-p","TCP"]),t);let i=nt(n,"lsof",["-nP",`-iTCP:${t}`,"-sTCP:LISTEN","-t"]),r=ge(i);if(r)return r;if(e!=="linux")return null;return pe(nt(n,"ss",["-ltnp"]),t)}import{existsSync as jt}from"node:fs";import{dirname as be,join as Z}from"node:path";import{fileURLToPath as ye}from"node:url";function kt(t){return ye(new URL(".",t)).replace(/^\/([A-Z]:)/,"$1")}function we(t,e=jt){let n=new Set;for(let i of t.filter(Boolean)){if(n.has(i))continue;if(n.add(i),e(i))return i}return t.filter(Boolean).at(-1)}function Jt({moduleDir:t,entrypoint:e=process.argv[1],env:n=process.env,exists:i=jt}={}){let r=e?be(e):null,o=n.GREEDY_SEARCH_EXTENSION_DIR?.trim()||null;return we([t?Z(t,"..","..","bin","launch.mjs"):null,t?Z(t,"launch.mjs"):null,o?Z(o,"bin","launch.mjs"):null,r?Z(r,"launch.mjs"):null,r?Z(r,"..","bin","launch.mjs"):null],i)}import{existsSync as z,mkdirSync as me,readFileSync as Xt,writeFileSync as ve}from"node:fs";import{homedir as xe}from"node:os";import{join as Zt}from"node:path";import{tmpdir as _e}from"node:os";function $e(t,e=9222){let n=Number.parseInt(String(t??""),10);return Number.isInteger(n)&&n>1024&&n<65535?n:e}var We=_e().replaceAll("\\","/"),g=$e(process.env.GREEDY_SEARCH_PORT),p=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${We}/greedysearch-chrome-profile`).replaceAll("\\","/"),q=`${p}/DevToolsActivePort`,A=process.env.GREEDY_SEARCH_PID_FILE||`${p}/browser.pid`,je=process.env.CDP_PAGES_CACHE||`${p}/cdp-pages.json`,$=process.env.GREEDY_SEARCH_MODE_FILE||`${p}/browser-mode`,qt=process.env.GREEDY_SEARCH_METADATA_FILE||`${p}/browser-metadata.json`,Bt=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${p}/browser-launch.lock`,O=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${p}/browser-last-activity`,Zn=(process.env.CDP_SOCKET_DIR||`${p}/cdp-sockets`).replaceAll("\\","/"),qn=`${p}/visible-recovery.jsonl`,it=Zt(xe(),".dm"),m=Zt(it,"greedyconfig"),ot=["perplexity","google","chatgpt","gemini"],lt="gemini";function ke(){try{if(z(m)){let t=Xt(m,"utf8"),e=JSON.parse(t);if(Array.isArray(e.engines)&&e.engines.length>0&&e.engines.every((n)=>typeof n==="string")){let n=e.engines.filter((r)=>rt[r]),i=e.engines.filter((r)=>!rt[r]);if(i.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${m}: ${i.join(", ")}
312
- [greedysearch] Available engines: ${Object.keys(rt).join(", ")}
313
- `);if(n.length>0)return n;process.stderr.write(`[greedysearch] Warning: no valid engines in ${m}, falling back to defaults: ${ot.join(", ")}
314
- `)}}}catch{}return ot}function Je(){try{if(!z(it))me(it,{recursive:!0});if(!z(m))ve(m,JSON.stringify({engines:ot,synthesizer:lt},null,2)+`
315
- `,"utf8")}catch{}}Je();var Nt=["gemini","chatgpt"];function Ne(){try{if(z(m)){let t=Xt(m,"utf8"),e=JSON.parse(t);if(typeof e.synthesizer==="string"){let n=e.synthesizer.toLowerCase();if(Nt.includes(n))return n;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${e.synthesizer}" in ${m}
316
- [greedysearch] Available synthesizers: ${Nt.join(", ")}
317
- [greedysearch] Falling back to default: ${lt}
318
- `)}}}catch{}return lt}var rt={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"},Bn=ke();var Qn=Ne(),Vn=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=p;import{execFileSync as Qt,execSync as Un}from"node:child_process";import{existsSync as D,mkdirSync as Xe,readFileSync as N,unlinkSync as k,writeFileSync as J}from"node:fs";import{platform as Ze}from"node:os";var T=qt,j=Bt,qe=15000,P=A,C=$,B=O;function Q(t){if(!Number.isInteger(t)||t<=0)return!1;try{return process.kill(t,0),!0}catch{return!1}}function Be(t){if(!Q(t))return null;try{if(Ze()==="win32")return Qt(w("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${t}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return Qt(w("ps"),["-p",String(t),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Qe(t,e,n=g){if(!t)return!1;let i=(l)=>String(l||"").replaceAll("\\","/").toLowerCase(),r=i(t),o=i(e);return r.includes(o)&&r.includes(`--remote-debugging-port=${n}`)&&!r.includes("--type=")}function Vt(t,e,n=g){return Qe(Be(t),e,n)}function Ve(t=g){return M(t)}function V(){try{if(D(T)){let t=N(T,"utf8"),e=JSON.parse(t);if(e&&typeof e.tempDir==="string"&&typeof e.debugPort==="number")return{browserPid:Number.isInteger(e.browserPid)?e.browserPid:void 0,debugPort:e.debugPort,tempDir:e.tempDir,clientPids:Array.isArray(e.clientPids)?e.clientPids.filter((n)=>Number.isInteger(n)&&n>0):[],sessionMode:e.sessionMode==="visible"?"visible":"headless",lastActivity:Number.isFinite(e.lastActivity)?e.lastActivity:0,launchedAt:Number.isFinite(e.launchedAt)?e.launchedAt:0}}}catch{}try{let t=D(P)?Number.parseInt(N(P,"utf8").trim(),10)||void 0:void 0,e=D(C)?N(C,"utf8").trim()==="visible"?"visible":"headless":"headless",n=D(B)?Number.parseInt(N(B,"utf8").trim(),10)||0:0;return{browserPid:t,debugPort:g,tempDir:p,clientPids:t?[t]:[],sessionMode:e,lastActivity:n,launchedAt:0}}catch{return null}}function Y(t){try{J(T,JSON.stringify({browserPid:t.browserPid,debugPort:t.debugPort,tempDir:t.tempDir,clientPids:[...new Set(t.clientPids.filter((e)=>e>0))],sessionMode:t.sessionMode,lastActivity:t.lastActivity,launchedAt:t.launchedAt},null,2),"utf8")}catch{}try{if(t.browserPid)J(P,String(t.browserPid),"utf8")}catch{}try{J(C,t.sessionMode,"utf8")}catch{}try{J(B,String(t.lastActivity),"utf8")}catch{}}function dt(){try{k(T)}catch{}try{k(P)}catch{}try{k(C)}catch{}try{k(B)}catch{}}function ut(t){if(!t)return t;let e={...t,clientPids:[...new Set([...t.clientPids,process.pid].filter((n)=>Q(n)||n===process.pid))]};return Y(e),e}function K(t){let e=Date.now();try{if(t)Y({...t,lastActivity:e});else J(B,String(e),"utf8")}catch{}}var Tn=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Ht=!1;function Ut(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD)return;if(Ht)return;Ht=!0;let t=V();if(!t)return;if(t.browserPid){if(!Q(t.browserPid)){dt();return}if(!Vt(t.browserPid,t.tempDir,t.debugPort))dt();else Y({...t,clientPids:t.clientPids.filter((r)=>Q(r))})}let e=Ve();if(e&&e!==t.browserPid)if(Vt(e,p,g))Y({browserPid:e,debugPort:g,tempDir:p,clientPids:[e],sessionMode:t.sessionMode,lastActivity:Date.now(),launchedAt:Date.now()});else process.stderr.write(`[greedysearch] Refusing to kill unverified listener ${e} on port ${g}.
319
- `)}function Mt(){Xe(p,{recursive:!0});try{let t=JSON.stringify({pid:process.pid,ts:Date.now()});return J(j,t,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{let e=N(j,"utf8");if(JSON.parse(e).pid===process.pid)k(j)}catch{}}}}catch(t){if(t?.code!=="EEXIST")return{acquired:!1,release:()=>{}}}try{let t=N(j,"utf8"),e=JSON.parse(t),n=Date.now()-(e.ts||0);if(!Q(e.pid)||n>qe){try{k(j)}catch{}try{let r=JSON.stringify({pid:process.pid,ts:Date.now()});return J(j,r,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{k(j)}catch{}}}}catch{return{acquired:!1,release:()=>{}}}}}catch{}return{acquired:!1,release:()=>{}}}var Ue=kt(import.meta.url),zt=A,d=O,Me=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,ze=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;function Ae(t,e=g){let n=String(t||"").toLowerCase();if(!n.includes(`--remote-debugging-port=${e}`)||n.includes("--type="))return null;return n.includes("--headless")}function Pt(){try{let t=F(),e=t?Ct(t):null,n=Ae(e);if(n!==null){try{G($,n?"headless":"visible","utf8")}catch{}return n}}catch{}try{if(!Dt($))return!0;return st($,"utf8").trim()==="headless"}catch{return!0}}function Oe(){try{G(d,String(Date.now()),"utf8")}catch{}try{let t=V();if(t)K(t)}catch{}}function Ct(t){try{if(Tt()==="win32")return at(w("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${t}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return at(w("ps"),["-p",String(t),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function De(t){let e=String(t||"").replaceAll("\\","/"),n=p.replaceAll("\\","/");return e.includes(`--remote-debugging-port=${g}`)&&e.includes(`--user-data-dir=${n}`)&&!e.includes("--type=")}function F(){return M(g)}function R(){let t=F();return t&&De(Ct(t))?t:null}async function Te(t=1500){let e=R();if(!e)return process.stderr.write(`[greedysearch] Refusing to close an unverified listener.
320
- `),!1;try{let i=await new Promise((o,l)=>{let u=ft.get(`http://localhost:${g}/json/version`,(a)=>{let f="";a.on("data",(c)=>f+=c),a.on("end",()=>{try{o(JSON.parse(f))}catch{l(Error("bad JSON"))}})});u.on("error",l),u.setTimeout(1000,()=>{u.destroy(),l(Error("timeout"))})}),r=new globalThis.WebSocket(i.webSocketDebuggerUrl);await new Promise((o)=>{r.onopen=()=>{if(R()!==e){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()+t;while(Date.now()<n){let i=F();if(!i)return!0;if(i!==e)return!1;await new Promise((r)=>setTimeout(r,150))}return Pe(e)}function Pe(t=null){try{let e=R();if(!e||t&&e!==t)return!1;if(Tt()==="win32")at(w("taskkill"),["/F","/PID",String(e)],{stdio:"ignore",windowsHide:!0});else process.kill(e,"SIGKILL");return!0}catch{return!1}}async function Yt(){if(!R()){if(F())process.stderr.write(`[greedysearch] Refusing to kill an unverified listener.
321
- `);return!1}if(!await x(500)){try{v(zt)}catch{}try{v(d)}catch{}try{v($)}catch{}return!1}let e=await Te(1500);try{v(zt)}catch{}try{v(d)}catch{}try{v($)}catch{}if(e)process.stderr.write(`[greedysearch] Killed Chrome on port ${g}.
322
- `);return e}var At=Yt;async function Ce(){let e=Pt()?Me:ze;if(e<=0)return!1;if(!Dt(d))return Oe(),!1;try{let n=Number.parseInt(st(d,"utf8").trim(),10);if(!n)return!1;if((Date.now()-n)/60000>=e)return Yt()}catch{}return!1}function x(t=3000){return new Promise((e)=>{let n=ft.get(`http://localhost:${g}/json/version`,(i)=>{i.resume(),e(i.statusCode===200)});n.on("error",()=>e(!1)),n.setTimeout(t,()=>{n.destroy(),e(!1)})})}async function Ot(t=3000,e=200){let n=Date.now()+t;while(Date.now()<n){if(!await x(300))return!0;await new Promise((i)=>setTimeout(i,e))}return!await x(300)}async function S(){let t=`${q}.lock`,e=`${q}.tmp`,n=5000,i=1000,r=await new Promise((o)=>{let l=Date.now(),u=()=>{try{let a=JSON.stringify({pid:process.pid,ts:Date.now()});G(t,a,{encoding:"utf8",flag:"wx"}),o(!0)}catch(a){if(a?.code!=="EEXIST"){if(Date.now()-l<1000)setTimeout(u,50);else o(!1);return}try{let f=st(t,"utf8").trim(),c=f.startsWith("{")?JSON.parse(f):{ts:Number(f)},_=Number(c?.ts)||0;if(_>0&&Date.now()-_>5000)try{v(t)}catch{}if(Date.now()-l<1000)setTimeout(u,50);else o(!1)}catch{if(Date.now()-l<1000)setTimeout(u,50);else o(!1)}}};u()});try{let o=await new Promise((a,f)=>{let c=ft.get(`http://localhost:${g}/json/version`,(_)=>{let X="";_.on("data",(L)=>X+=L),_.on("end",()=>a(X))});c.on("error",f),c.setTimeout(3000,()=>{c.destroy(),f(Error("timeout"))})}),{webSocketDebuggerUrl:l}=JSON.parse(o),u=new URL(l).pathname;if(r){G(e,`${g}
323
- ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}async function Kt(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD&&await x()){await S();try{let o=V();if(o)K(o),ut(o)}catch{}return}Ut();let t=await Ce(),e=t?!1:await x();if(!e&&!t)await new Promise((o)=>setTimeout(o,500)),e=await x();let n=!1;if(e){let o=Pt(),l=process.env.GREEDY_SEARCH_VISIBLE==="1";if(!l&&!o)process.stderr.write(`[greedysearch] Visible Chrome detected — switching to headless mode...
324
- `),await At(),await Ot(),n=!0;else if(l&&o)process.stderr.write(`[greedysearch] Headless Chrome detected — switching to visible mode...
325
- `),await At(),await Ot(),n=!0}if(n?!1:await x()){await S();try{let o=V();if(o)K(o),ut(o)}catch{}return}let r=Mt();if(!r.acquired){let o=Date.now()+12000,l=!1;while(Date.now()<o){if(l=await x(500),l)break;await new Promise((u)=>setTimeout(u,250))}if(l){await S();return}}try{if(await x(1000)){await S();return}process.stderr.write(`GreedySearch Chrome not running on port ${g} — auto-launching...
326
- `);let u=[Jt({moduleDir:Ue,entrypoint:process.argv[1],env:process.env})];if(process.env.GREEDY_SEARCH_VISIBLE!=="1")u.push("--headless");await new Promise((a,f)=>{de($t(),u,{stdio:["ignore",process.stderr,process.stderr]}).on("close",(_)=>_===0?a():f(Error("launch.mjs failed")))})}finally{r.release()}}var Se="https://logically.app/research-assistant/",y={input:'div.ProseMirror[contenteditable="true"]',submitButton:'.chat-control button[class*="MuiButton-black"], button[type="submit"]',answerContainer:'#last-message .chat-content, [class*="chat-content"]',citationSpan:'#last-message .chat-content span[title], [class*="chat-content"] span[title]'};async function Ge(t){return s(["eval",t,`(() => {
1
+ import {
2
+ buildEnvelope,
3
+ cdp,
4
+ formatAnswer,
5
+ getOrOpenTab,
6
+ handleError,
7
+ jitter,
8
+ logStage,
9
+ outputJson,
10
+ parseArgs,
11
+ prepareArgs,
12
+ TIMING,
13
+ validateQuery,
14
+ verifyInputText,
15
+ waitForSelector
16
+ } from "./common.mjs";
17
+ import { readFileSync } from "node:fs";
18
+ import { tmpdir } from "node:os";
19
+ import { ensureChrome } from "../src/search/chrome.mjs";
20
+ const START_URL = "https://logically.app/research-assistant/";
21
+ const SELECTORS = {
22
+ input: 'div.ProseMirror[contenteditable="true"]',
23
+ submitButton: '.chat-control button[class*="MuiButton-black"], button[type="submit"]',
24
+ answerContainer: '#last-message .chat-content, [class*="chat-content"]',
25
+ citationSpan: '#last-message .chat-content span[title], [class*="chat-content"] span[title]'
26
+ };
27
+ async function startNewChat(tab) {
28
+ const code = `(() => {
327
29
  const buttons = Array.from(document.querySelectorAll('button'));
328
30
  const create = buttons.find((b) => (b.innerText || '').trim() === 'Create');
329
31
  if (!create) return 'missing';
330
32
  create.click();
331
33
  return 'clicked';
332
- })()`],5000).catch(()=>"error")}async function Re(t){return await s(["eval",t,`(() => {
34
+ })()`;
35
+ return cdp(["eval", tab, code], 5000).catch(() => "error");
36
+ }
37
+ async function detectLoginWall(tab) {
38
+ const code = `(() => {
333
39
  const url = document.location.href || '';
334
40
  if (url.includes('/login') || url.includes('/signup') || url.includes('/sign-up')) return true;
335
41
  const modalText = Array.from(document.querySelectorAll('[role="dialog"], .MuiModal-root'))
@@ -337,8 +43,33 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
337
43
  .join('
338
44
  ');
339
45
  return /create a free account|continue with google|have an account[?] log in|log in|sign up/i.test(modalText);
340
- })()`],5000).catch(()=>"false")==="true"}async function Fe(t){try{await s(["list"]);let e=`${Ke().replaceAll("\\\\","/")}/cdp-pages.json`,i=JSON.parse(Ye(e,"utf8")).find((r)=>r.targetId?.startsWith(t))?.targetId;if(i)await s(["browse",t,"Target.activateTarget",JSON.stringify({targetId:i})]).catch(()=>null),await new Promise((r)=>setTimeout(r,250))}catch{}}async function Le(t,e){await Fe(t);let n=await s(["eval",t,`(() => {
341
- const inputs = Array.from(document.querySelectorAll('${y.input}'));
46
+ })()`;
47
+ return await cdp(["eval", tab, code], 5000).catch(() => "false") === "true";
48
+ }
49
+ async function activateTab(tab) {
50
+ try {
51
+ await cdp(["list"]);
52
+ const cachePath = `${tmpdir().replaceAll("\\\\", "/")}/cdp-pages.json`;
53
+ const pages = JSON.parse(readFileSync(cachePath, "utf8"));
54
+ const fullTargetId = pages.find((p) => p.targetId?.startsWith(tab))?.targetId;
55
+ if (fullTargetId) {
56
+ await cdp([
57
+ "browse",
58
+ tab,
59
+ "Target.activateTarget",
60
+ JSON.stringify({ targetId: fullTargetId })
61
+ ]).catch(() => null);
62
+ await new Promise((r) => setTimeout(r, 250));
63
+ }
64
+ } catch {}
65
+ }
66
+ async function typeIntoLogically(tab, text) {
67
+ await activateTab(tab);
68
+ const pointRaw = await cdp([
69
+ "eval",
70
+ tab,
71
+ `(() => {
72
+ const inputs = Array.from(document.querySelectorAll('${SELECTORS.input}'));
342
73
  const input = inputs.find((el) => {
343
74
  const r = el.getBoundingClientRect();
344
75
  return r.width > 20 && r.height > 5;
@@ -347,19 +78,64 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
347
78
  input.scrollIntoView({ block: 'center', inline: 'center' });
348
79
  const r = input.getBoundingClientRect();
349
80
  return JSON.stringify({ x: Math.round(r.left + Math.min(80, r.width / 2)), y: Math.round(r.top + r.height / 2) });
350
- })()`]);if(!n)throw Error("Logically visible input not found");let i;try{i=JSON.parse(n)}catch{throw Error("Logically input coordinates were invalid")}await s(["click",t,y.input]).catch(()=>null),await new Promise((a)=>setTimeout(a,U(120))),await s(["clickxy",t,String(i.x),String(i.y)]),await new Promise((a)=>setTimeout(a,U(tt.postClick)));let r=async()=>{let a=await s(["eval",t,`(() => {
351
- const ed = document.querySelector('${y.input}');
81
+ })()`
82
+ ]);
83
+ if (!pointRaw)
84
+ throw new Error("Logically visible input not found");
85
+ let point;
86
+ try {
87
+ point = JSON.parse(pointRaw);
88
+ } catch {
89
+ throw new Error("Logically input coordinates were invalid");
90
+ }
91
+ await cdp(["click", tab, SELECTORS.input]).catch(() => null);
92
+ await new Promise((r) => setTimeout(r, jitter(120)));
93
+ await cdp(["clickxy", tab, String(point.x), String(point.y)]);
94
+ await new Promise((r) => setTimeout(r, jitter(TIMING.postClick)));
95
+ const type = async () => {
96
+ const typeResult = await cdp([
97
+ "eval",
98
+ tab,
99
+ `(() => {
100
+ const ed = document.querySelector('${SELECTORS.input}');
352
101
  if (!ed) return 'no-input';
353
102
  ed.focus();
354
103
  if (!ed.editor || !ed.editor.commands) {
355
104
  // Fallback to execCommand for non-tiptap editors
356
- const ok = document.execCommand('insertText', false, ${JSON.stringify(e)});
105
+ const ok = document.execCommand('insertText', false, ${JSON.stringify(text)});
357
106
  return ok ? 'ok' : 'exec-failed';
358
107
  }
359
- const ok = ed.editor.commands.insertContent(${JSON.stringify(e)});
108
+ const ok = ed.editor.commands.insertContent(${JSON.stringify(text)});
360
109
  return ok ? 'ok' : 'tiptap-failed';
361
- })()`],5000);if(a!=="ok")throw Error(`Logically type failed: ${a}`);await new Promise((f)=>setTimeout(f,U(tt.postType)))},o=async()=>{let a=await s(["eval",t,`JSON.stringify(Array.from(document.querySelectorAll('${y.input}')).map((el) => el.innerText || el.textContent || ''))`]);try{return JSON.parse(a)}catch{return[]}},l=async()=>{return(await o()).some((f)=>gt(f,e))},u=async()=>{await s(["eval",t,`(() => {
362
- const ed = document.querySelector('${y.input}');
110
+ })()`
111
+ ], 5000);
112
+ if (typeResult !== "ok") {
113
+ throw new Error(`Logically type failed: ${typeResult}`);
114
+ }
115
+ await new Promise((r) => setTimeout(r, jitter(TIMING.postType)));
116
+ };
117
+ const readInput = async () => {
118
+ const raw = await cdp([
119
+ "eval",
120
+ tab,
121
+ `JSON.stringify(Array.from(document.querySelectorAll('${SELECTORS.input}')).map((el) => el.innerText || el.textContent || ''))`
122
+ ]);
123
+ try {
124
+ return JSON.parse(raw);
125
+ } catch {
126
+ return [];
127
+ }
128
+ };
129
+ const verify = async () => {
130
+ const contents = await readInput();
131
+ return contents.some((content) => verifyInputText(content, text));
132
+ };
133
+ const clear = async () => {
134
+ await cdp([
135
+ "eval",
136
+ tab,
137
+ `(() => {
138
+ const ed = document.querySelector('${SELECTORS.input}');
363
139
  if (!ed) return false;
364
140
  ed.focus();
365
141
  if (ed.editor?.commands?.clearContent) {
@@ -373,14 +149,27 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
373
149
  selection.addRange(range);
374
150
  document.execCommand('delete');
375
151
  return true;
376
- })()`])};if(await r(),await l())return;if(await u(),await r(),!await l())throw Error("Logically input did not accept text — input verification failed")}async function Ie(t,e=90000){let n=String.raw`
152
+ })()`
153
+ ]);
154
+ };
155
+ await type();
156
+ if (await verify())
157
+ return;
158
+ await clear();
159
+ await type();
160
+ if (!await verify()) {
161
+ throw new Error("Logically input did not accept text — input verification failed");
162
+ }
163
+ }
164
+ async function waitForLogicallyAnswer(tab, timeoutMs = 90000) {
165
+ const code = String.raw`
377
166
  new Promise((resolve, reject) => {
378
- const deadline = Date.now() + ${e};
167
+ const deadline = Date.now() + ${timeoutMs};
379
168
  let last = '';
380
169
  let stable = 0;
381
170
  function poll() {
382
171
  try {
383
- const answer = document.querySelector('${y.answerContainer}');
172
+ const answer = document.querySelector('${SELECTORS.answerContainer}');
384
173
  const text = (answer?.innerText || '').trim();
385
174
  const body = document.body.innerText || '';
386
175
  const stillGenerating = /Generating answer|Thinking\.\.\.|Searching the internet|Discovered \d+/.test(body) && text.length < 200;
@@ -390,12 +179,16 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
390
179
  if (stable >= 3) { resolve(text.length); return; }
391
180
  }
392
181
  if (Date.now() < deadline) setTimeout(poll, 700 + Math.random() * 250);
393
- else reject(new Error('Logically answer did not stabilise within ${e}ms'));
182
+ else reject(new Error('Logically answer did not stabilise within ${timeoutMs}ms'));
394
183
  } catch (e) { reject(e); }
395
184
  }
396
185
  poll();
397
- })`;return s(["eval",t,n],e+1e4)}async function Ee(t){let e=`(() => {
398
- const el = document.querySelector('${y.answerContainer}');
186
+ })`;
187
+ return cdp(["eval", tab, code], timeoutMs + 1e4);
188
+ }
189
+ async function extractAnswer(tab) {
190
+ const code = `(() => {
191
+ const el = document.querySelector('${SELECTORS.answerContainer}');
399
192
  if (!el) return JSON.stringify({ answer: '', answerHtml: '' });
400
193
  const clone = el.cloneNode(true);
401
194
  clone.querySelectorAll('svg').forEach((n) => n.remove());
@@ -406,7 +199,15 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
406
199
  answer: (el.innerText || '').trim(),
407
200
  answerHtml: clone.innerHTML,
408
201
  });
409
- })()`;try{return JSON.parse(await s(["eval",t,e],1e4))}catch{return{answer:"",answerHtml:""}}}async function tn(t){let e=String.raw`
202
+ })()`;
203
+ try {
204
+ return JSON.parse(await cdp(["eval", tab, code], 1e4));
205
+ } catch {
206
+ return { answer: "", answerHtml: "" };
207
+ }
208
+ }
209
+ async function extractFullCitationSources(tab) {
210
+ const code = String.raw`
410
211
  (async () => {
411
212
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
412
213
 
@@ -546,10 +347,19 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
546
347
  webCaptured: webSources.length,
547
348
  },
548
349
  });
549
- })()`,n=await s(["eval",t,e],20000);try{return JSON.parse(n)}catch{return{sources:[],summary:{expectedTotal:0,reason:"invalid-json"}}}}async function en(t){let e=String.raw`
350
+ })()`;
351
+ const raw = await cdp(["eval", tab, code], 20000);
352
+ try {
353
+ return JSON.parse(raw);
354
+ } catch {
355
+ return { sources: [], summary: { expectedTotal: 0, reason: "invalid-json" } };
356
+ }
357
+ }
358
+ async function extractCitationSources(tab) {
359
+ const code = String.raw`
550
360
  (async () => {
551
361
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
552
- const answer = document.querySelector('${y.answerContainer}');
362
+ const answer = document.querySelector('${SELECTORS.answerContainer}');
553
363
  if (!answer) return JSON.stringify([]);
554
364
 
555
365
  function parseUrlFromId(id) {
@@ -650,8 +460,64 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
650
460
  }
651
461
  }
652
462
  return JSON.stringify(sources);
653
- })()`,n=await s(["eval",t,e],45000);try{return JSON.parse(n)}catch{return[]}}var nn=`Usage: node extractors/logically.mjs "<query>" [--tab <prefix>]
654
- `;async function rn(){let t=await yt(process.argv.slice(2));mt(t,nn);let{query:e,tabPrefix:n,short:i}=wt(t),r=Date.now(),l={engine:"logically",mode:process.env.GREEDY_SEARCH_VISIBLE==="1"?"visible":"headless",clipboardEmpty:null,fallbackUsed:null,blockedBy:null,verificationResult:null,inputReady:null};try{if(process.env.GREEDY_SEARCH_VISIBLE!=="1"&&process.env.GREEDY_SEARCH_ALWAYS_VISIBLE!=="1")process.env.GREEDY_SEARCH_HEADLESS="1";if(await Kt(),!n)await s(["list"]);let u=await pt(n),a=await s(["eval",u,"document.location.href"]).catch(()=>""),f=!1;try{let h=new URL(a).hostname.toLowerCase();f=h==="logically.app"||h.endsWith(".logically.app")}catch{}if(!f)b(l,"nav",r),await s(["nav",u,Se],25000),await new Promise((h)=>setTimeout(h,900));b(l,"new-chat",r),await Ge(u),await new Promise((h)=>setTimeout(h,700)),b(l,"input-wait",r);let c=await bt(u,y.input,20000,400);if(l.inputReady=c,!c)throw Error("Logically input not found — page may not have loaded or is in unexpected state");if(process.env.GREEDY_SEARCH_HEADLESS==="1"){let h=await s(["eval",u,`(() => {
463
+ })()`;
464
+ const raw = await cdp(["eval", tab, code], 45000);
465
+ try {
466
+ return JSON.parse(raw);
467
+ } catch {
468
+ return [];
469
+ }
470
+ }
471
+ const USAGE = `Usage: node extractors/logically.mjs "<query>" [--tab <prefix>]
472
+ `;
473
+ async function main() {
474
+ const args = await prepareArgs(process.argv.slice(2));
475
+ validateQuery(args, USAGE);
476
+ const { query, tabPrefix, short } = parseArgs(args);
477
+ const startTime = Date.now();
478
+ const mode = process.env.GREEDY_SEARCH_VISIBLE === "1" ? "visible" : "headless";
479
+ const env = {
480
+ engine: "logically",
481
+ mode,
482
+ clipboardEmpty: null,
483
+ fallbackUsed: null,
484
+ blockedBy: null,
485
+ verificationResult: null,
486
+ inputReady: null
487
+ };
488
+ try {
489
+ if (process.env.GREEDY_SEARCH_VISIBLE !== "1" && process.env.GREEDY_SEARCH_ALWAYS_VISIBLE !== "1") {
490
+ process.env.GREEDY_SEARCH_HEADLESS = "1";
491
+ }
492
+ await ensureChrome();
493
+ if (!tabPrefix)
494
+ await cdp(["list"]);
495
+ const tab = await getOrOpenTab(tabPrefix);
496
+ const currentUrl = await cdp(["eval", tab, "document.location.href"]).catch(() => "");
497
+ let onLogically = false;
498
+ try {
499
+ const host = new URL(currentUrl).hostname.toLowerCase();
500
+ onLogically = host === "logically.app" || host.endsWith(".logically.app");
501
+ } catch {}
502
+ if (!onLogically) {
503
+ logStage(env, "nav", startTime);
504
+ await cdp(["nav", tab, START_URL], 25000);
505
+ await new Promise((r) => setTimeout(r, 900));
506
+ }
507
+ logStage(env, "new-chat", startTime);
508
+ await startNewChat(tab);
509
+ await new Promise((r) => setTimeout(r, 700));
510
+ logStage(env, "input-wait", startTime);
511
+ const inputReady = await waitForSelector(tab, SELECTORS.input, 20000, 400);
512
+ env.inputReady = inputReady;
513
+ if (!inputReady) {
514
+ throw new Error("Logically input not found — page may not have loaded or is in unexpected state");
515
+ }
516
+ if (process.env.GREEDY_SEARCH_HEADLESS === "1") {
517
+ const quotaResult = await cdp([
518
+ "eval",
519
+ tab,
520
+ `(() => {
655
521
  const text = document.body?.innerText || '';
656
522
  const m = text.match(/Chat messages\\s*\\n?\\s*(\\d+)\\s*\\/\\s*(\\d+)/i);
657
523
  if (m && parseInt(m[1], 10) >= parseInt(m[2], 10)) {
@@ -663,4 +529,61 @@ ${u}`,"utf8");try{v(q)}catch{}He(e,q)}}catch{}finally{if(r)try{v(t)}catch{}}}asy
663
529
  );
664
530
  if (createBtn && createBtn.disabled) return 'create-disabled';
665
531
  return 'ok';
666
- })()`],5000).catch(()=>"ok");if(h==="quota-exceeded"||h==="create-disabled")throw console.error("[logically] Rate Limited — skipping (visible retry won't help)"),l.blockedBy="rate-limit",Error("Rate Limited — Logically free message quota exhausted. Wait until reset.")}if(b(l,"type-and-submit",r),await Le(u,e),await s(["eval",u,`(() => { const btn = document.querySelector('${y.submitButton}'); if (!btn) return 'missing'; btn.click(); return 'clicked'; })()`])!=="clicked")throw Error("Logically submit button not found");if(await new Promise((h)=>setTimeout(h,1500)),await Re(u))throw l.blockedBy="signin",l.verificationResult="needs-human",Error("Logically login required — please log in or create a free account in the visible browser window. Once signed in, cookies persist for future runs.");b(l,"answer-wait",r),await Ie(u,90000),b(l,"extract-answer-html",r);let{answer:X,answerHtml:L}=await Ee(u);if(!X)throw Error("No answer extracted — Logically may not have responded");b(l,"extract-full-citations",r);let H=await tn(u),I=[],E=H.sources?.length?H.sources:null;if(!E)b(l,"extract-inline-citations",r),I=await en(u),E=I;let St=await s(["eval",u,"document.location.href"]).catch(()=>"");l.durationMs=Date.now()-r,l.sourcePath=H.sources?.length?"citations-popover":"inline-citation-popovers",b(l,"done",r),xt({query:e,url:St,answer:vt(X,i),answerHtml:L,sources:E,inlineSources:I,citationSummary:H.summary,_envelope:et(l)})}catch(u){l.durationMs=Date.now()-r,_t(u,et(l))}}rn();
532
+ })()`
533
+ ], 5000).catch(() => "ok");
534
+ if (quotaResult === "quota-exceeded" || quotaResult === "create-disabled") {
535
+ console.error("[logically] Rate Limited — skipping (visible retry won't help)");
536
+ env.blockedBy = "rate-limit";
537
+ throw new Error("Rate Limited — Logically free message quota exhausted. Wait until reset.");
538
+ }
539
+ }
540
+ logStage(env, "type-and-submit", startTime);
541
+ await typeIntoLogically(tab, query);
542
+ const submitted = await cdp([
543
+ "eval",
544
+ tab,
545
+ `(() => { const btn = document.querySelector('${SELECTORS.submitButton}'); if (!btn) return 'missing'; btn.click(); return 'clicked'; })()`
546
+ ]);
547
+ if (submitted !== "clicked")
548
+ throw new Error("Logically submit button not found");
549
+ await new Promise((r) => setTimeout(r, 1500));
550
+ if (await detectLoginWall(tab)) {
551
+ env.blockedBy = "signin";
552
+ env.verificationResult = "needs-human";
553
+ throw new Error("Logically login required — please log in or create a free account in the visible browser window. Once signed in, cookies persist for future runs.");
554
+ }
555
+ logStage(env, "answer-wait", startTime);
556
+ await waitForLogicallyAnswer(tab, 90000);
557
+ logStage(env, "extract-answer-html", startTime);
558
+ const { answer, answerHtml } = await extractAnswer(tab);
559
+ if (!answer)
560
+ throw new Error("No answer extracted — Logically may not have responded");
561
+ logStage(env, "extract-full-citations", startTime);
562
+ const fullCitations = await extractFullCitationSources(tab);
563
+ let inlineSources = [];
564
+ let sources = fullCitations.sources?.length ? fullCitations.sources : null;
565
+ if (!sources) {
566
+ logStage(env, "extract-inline-citations", startTime);
567
+ inlineSources = await extractCitationSources(tab);
568
+ sources = inlineSources;
569
+ }
570
+ const finalUrl = await cdp(["eval", tab, "document.location.href"]).catch(() => "");
571
+ env.durationMs = Date.now() - startTime;
572
+ env.sourcePath = fullCitations.sources?.length ? "citations-popover" : "inline-citation-popovers";
573
+ logStage(env, "done", startTime);
574
+ outputJson({
575
+ query,
576
+ url: finalUrl,
577
+ answer: formatAnswer(answer, short),
578
+ answerHtml,
579
+ sources,
580
+ inlineSources,
581
+ citationSummary: fullCitations.summary,
582
+ _envelope: buildEnvelope(env)
583
+ });
584
+ } catch (e) {
585
+ env.durationMs = Date.now() - startTime;
586
+ handleError(e, buildEnvelope(env));
587
+ }
588
+ }
589
+ main();