@duckmind/dm-windows-x64 0.60.6 → 0.60.9

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,309 +1,510 @@
1
- import{spawn as Gt,execFileSync as ue,execSync as cn}from"node:child_process";import{basename as Re}from"node:path";function de(e=process.env,t=process.execPath){let r=e.GREEDY_SEARCH_NODE||e.NODE_BINARY||e.NODE;if(r?.trim())return r.trim();let n=Re(t||"").toLowerCase();if(n==="node"||n==="node.exe")return t;return"node"}import{existsSync as ce,readFileSync as V,renameSync as Ft,unlinkSync as h,writeFileSync as R}from"node:fs";import fe from"node:http";import{platform as Ue}from"node:os";import{spawn as Le}from"node:child_process";import{basename as Ve}from"node:path";import{dirname as Ie,join as Ee}from"node:path";import{fileURLToPath as Ye}from"node:url";function ze(e=process.env,t=process.execPath){let r=e.GREEDY_SEARCH_NODE||e.NODE_BINARY||e.NODE;if(r?.trim())return r.trim();let n=Ve(t||"").toLowerCase();if(n==="node"||n==="node.exe")return t;return"node"}var Ge=Ie(Ye(import.meta.url)),Fe=Ee(Ge,"..","bin","cdp.mjs"),Ke=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"]);function et(e){if(!Array.isArray(e)||e.length===0)throw Error("cdp: args must be a non-empty array");if(e[0]==="test")return e.map((t,r)=>me(t,r));if(!Ke.has(e[0]))throw Error(`cdp: unknown subcommand '${e[0]}'`);return e.map((t,r)=>me(t,r))}function me(e,t){if(typeof e!=="string")throw Error(`cdp: argv[${t}] must be a string (got ${typeof e})`);if(e.includes("\x00"))throw Error(`cdp: argv[${t}] contains a null byte`);return e}function I(e,t=30000){return tt(e,null,t)}function tt(e,t=null,r=30000){let n=et(e);return new Promise((i,a)=>{let o=Le(ze(),[Fe,...n],{stdio:[t==null?"ignore":"pipe","pipe","pipe"]});if(t!=null)o.stdin.write(t),o.stdin.end();let s="",l="";o.stdout.on("data",(u)=>s+=u),o.stderr.on("data",(u)=>l+=u);let f=setTimeout(()=>{o.kill(),a(Error(`cdp timeout: ${e[0]}`))},r);o.on("close",(u)=>{if(clearTimeout(f),u===0)i(s.trim());else a(Error(l.trim()||`cdp exit ${u}`))})})}async function E(e){await I(["evalraw",e,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
2
- (function() {
3
- // ── Runtime.enable / CDP detection masking ──────────────
4
- try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
5
- try { delete window.__REBROWSER_DEVTOOLS; } catch(_) {}
6
- try { delete window.__nightmare; } catch(_) {}
7
- try { delete window.__phantom; } catch(_) {}
8
- try { delete window.callPhantom; } catch(_) {}
9
- try { delete window._phantom; } catch(_) {}
10
- try { delete window.Buffer; } catch(_) {}
11
-
12
- // Real Chrome without automation should not expose navigator.webdriver at all.
13
- // A literal false or an own-property getter returning undefined is itself a
14
- // common stealth tell; remove both instance and prototype properties when the
15
- // descriptor is configurable (as it is with --disable-blink-features).
16
- try { delete navigator.webdriver; } catch(_) {}
17
- try { delete Navigator.prototype.webdriver; } catch(_) {}
18
- Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
19
- Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
20
- Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
21
- Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
22
- Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
23
- Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
24
- var __greedyMimeTypes = null;
25
- function __makeMimeTypes() {
26
- var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
27
- var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
28
- try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
29
- try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
30
- var m = [pdf, textPdf];
31
- try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
32
- m.item = function item(i) { return this[i] || null; };
33
- m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
34
- return m;
1
+ import { spawn, execFileSync, execSync } from "node:child_process";
2
+ import { nodeRuntimeCommand } from "../utils/node-runtime.mjs";
3
+ import {
4
+ existsSync,
5
+ readFileSync,
6
+ renameSync,
7
+ unlinkSync,
8
+ writeFileSync
9
+ } from "node:fs";
10
+ import http from "node:http";
11
+ import { platform } from "node:os";
12
+ import { join } from "node:path";
13
+ import {
14
+ cdp as _cdp,
15
+ injectHeadlessStealth
16
+ } from "../../extractors/common.mjs";
17
+ import { resolveSystemCmd } from "../utils/system-cmds.mjs";
18
+ import { findListeningProcessPid } from "./port-pid.mjs";
19
+ import {
20
+ moduleDirectory,
21
+ resolveGreedySearchLaunchScript
22
+ } from "./paths.mjs";
23
+ import {
24
+ ACTIVE_PORT_FILE,
25
+ CHROME_MODE_FILE,
26
+ GREEDY_ACTIVITY_FILE,
27
+ GREEDY_PID_FILE,
28
+ GREEDY_PORT,
29
+ GREEDY_PROFILE_DIR,
30
+ PAGES_CACHE
31
+ } from "./constants.mjs";
32
+ import {
33
+ readMetadata,
34
+ touchActivity as touchActivityBL,
35
+ acquireLaunchLock,
36
+ cleanupStaleSessions,
37
+ registerClient
38
+ } from "./browser-lifecycle.mjs";
39
+ const __dir = moduleDirectory(import.meta.url);
40
+ const PID_FILE = GREEDY_PID_FILE;
41
+ const ACTIVITY_FILE = GREEDY_ACTIVITY_FILE;
42
+ const HEADLESS_IDLE_TIMEOUT_MINUTES = Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES || "5", 10) || 5;
43
+ const VISIBLE_IDLE_TIMEOUT_MINUTES = Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES || "60", 10) || 60;
44
+ export function detectHeadlessFromChromeCommandLine(cmdLine, debugPort = GREEDY_PORT) {
45
+ const normalized = String(cmdLine || "").toLowerCase();
46
+ if (!normalized.includes(`--remote-debugging-port=${debugPort}`) || normalized.includes("--type=")) {
47
+ return null;
35
48
  }
36
- Object.defineProperty(navigator, 'plugins', {
37
- get: () => {
38
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
39
- var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
40
- var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
41
- var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
42
- try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
43
- try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
44
- try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
45
- var p = [plugin0, plugin1, plugin2];
46
- p.item = function item(i) { return this[i] || null; };
47
- p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
48
- p.refresh = function refresh() {};
49
- try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
49
+ return normalized.includes("--headless");
50
+ }
51
+ export function isChromeHeadless() {
52
+ try {
53
+ const portPid = getPortPid();
54
+ const cmdLine = portPid ? getProcessCommandLine(portPid) : null;
55
+ const headless = detectHeadlessFromChromeCommandLine(cmdLine);
56
+ if (headless !== null) {
50
57
  try {
51
- __greedyMimeTypes[0].enabledPlugin = p[0];
52
- __greedyMimeTypes[1].enabledPlugin = p[0];
53
- } catch(_) {}
54
- return p;
55
- },
56
- configurable: true,
57
- });
58
- Object.defineProperty(navigator, 'mimeTypes', {
59
- get: () => {
60
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
61
- return __greedyMimeTypes;
62
- },
63
- configurable: true,
64
- });
65
- Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
58
+ writeFileSync(CHROME_MODE_FILE, headless ? "headless" : "visible", "utf8");
59
+ } catch {}
60
+ return headless;
61
+ }
62
+ } catch {}
66
63
  try {
67
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
68
- } catch(_) {}
69
- if (!navigator.mediaDevices) {
70
- Object.defineProperty(navigator, 'mediaDevices', {
71
- get: () => ({
72
- enumerateDevices: () => Promise.resolve([
73
- { deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
74
- { deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
75
- { deviceId: '', kind: 'videoinput', label: '', groupId: '' },
76
- ]),
77
- getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
78
- getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
79
- }),
80
- configurable: true,
81
- });
64
+ if (!existsSync(CHROME_MODE_FILE))
65
+ return true;
66
+ return readFileSync(CHROME_MODE_FILE, "utf8").trim() === "headless";
67
+ } catch {
68
+ return true;
82
69
  }
83
- // ── Missing platform APIs (headless often lacks these) ─
70
+ }
71
+ export function touchActivity() {
84
72
  try {
85
- if (!navigator.share) {
86
- navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
87
- }
88
- } catch(_) {}
73
+ writeFileSync(ACTIVITY_FILE, String(Date.now()), "utf8");
74
+ } catch {}
75
+ try {
76
+ const md = readMetadata();
77
+ if (md)
78
+ touchActivityBL(md);
79
+ } catch {}
80
+ }
81
+ function getProcessCommandLine(pid) {
89
82
  try {
90
- if (!navigator.contentIndex) {
91
- Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
83
+ if (platform() === "win32") {
84
+ const output = execFileSync(resolveSystemCmd("powershell"), [
85
+ "-NoProfile",
86
+ "-NonInteractive",
87
+ "-Command",
88
+ `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").CommandLine`
89
+ ], { encoding: "utf8", windowsHide: true, timeout: 5000 });
90
+ return output.trim() || null;
92
91
  }
93
- } catch(_) {}
94
-
95
- if (!window.chrome) {
96
- window.chrome = {
97
- app: { isInstalled: false, InstallState: {}, RunningState: {} },
98
- runtime: {
99
- OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
100
- connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
101
- },
102
- 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' }; },
103
- csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
104
- };
92
+ const output = execFileSync(resolveSystemCmd("ps"), ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 5000 });
93
+ return output.trim() || null;
94
+ } catch {
95
+ return null;
105
96
  }
106
- var __greedyNativeFns = [];
107
- function __markNative(fn) { try { __greedyNativeFns.push(fn); } catch(_) {} return fn; }
108
-
109
- var origQuery = navigator.permissions?.query;
110
- if (origQuery) {
111
- navigator.permissions.query = __markNative(function query(params) {
112
- if (params && params.name === 'notifications') return Promise.resolve({ state: Notification.permission || 'default', onchange: null });
113
- return origQuery.apply(this, arguments);
114
- });
97
+ }
98
+ function commandLineMatchesGreedyBrowser(commandLine) {
99
+ const normalized = String(commandLine || "").replaceAll("\\", "/");
100
+ const profile = GREEDY_PROFILE_DIR.replaceAll("\\", "/");
101
+ return normalized.includes(`--remote-debugging-port=${GREEDY_PORT}`) && normalized.includes(`--user-data-dir=${profile}`) && !normalized.includes("--type=");
102
+ }
103
+ function getPortPid() {
104
+ return findListeningProcessPid(GREEDY_PORT);
105
+ }
106
+ function getOwnedBrowserPid() {
107
+ const pid = getPortPid();
108
+ return pid && commandLineMatchesGreedyBrowser(getProcessCommandLine(pid)) ? pid : null;
109
+ }
110
+ async function gracefulCloseChrome(graceMs = 1500) {
111
+ const ownedPid = getOwnedBrowserPid();
112
+ if (!ownedPid) {
113
+ process.stderr.write(`[greedysearch] Refusing to close an unverified listener.
114
+ `);
115
+ return false;
115
116
  }
116
117
  try {
117
- var getParam = WebGLRenderingContext.prototype.getParameter;
118
- WebGLRenderingContext.prototype.getParameter = __markNative(function getParameter(p) {
119
- if (p === 37445) return 'Intel Inc.';
120
- if (p === 37446) return 'Intel Iris OpenGL Engine';
121
- return getParam.call(this, p);
118
+ const version = await new Promise((resolve, reject) => {
119
+ const req = http.get(`http://localhost:${GREEDY_PORT}/json/version`, (res) => {
120
+ let body = "";
121
+ res.on("data", (d) => body += d);
122
+ res.on("end", () => {
123
+ try {
124
+ resolve(JSON.parse(body));
125
+ } catch {
126
+ reject(new Error("bad JSON"));
127
+ }
128
+ });
129
+ });
130
+ req.on("error", reject);
131
+ req.setTimeout(1000, () => {
132
+ req.destroy();
133
+ reject(new Error("timeout"));
134
+ });
122
135
  });
123
- } catch(_) {}
124
- // ── WebGL readPixels noise ──────────────────────────
125
- // CreepJS and other fingerprinters draw content with WebGL and read back the
126
- // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
127
- try {
128
- var origReadPixels = WebGLRenderingContext.prototype.readPixels;
129
- WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
130
- var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
131
- if (pixels && pixels.length > 0) {
132
- pixels[0] ^= 1;
133
- }
134
- return result;
136
+ const ws = new globalThis.WebSocket(version.webSocketDebuggerUrl);
137
+ await new Promise((resolve) => {
138
+ ws.onopen = () => {
139
+ if (getOwnedBrowserPid() !== ownedPid) {
140
+ ws.close();
141
+ resolve();
142
+ return;
143
+ }
144
+ ws.send(JSON.stringify({ id: 1, method: "Browser.close" }));
145
+ setTimeout(() => {
146
+ ws.close();
147
+ resolve();
148
+ }, 200);
149
+ };
150
+ ws.onerror = () => resolve();
151
+ setTimeout(resolve, 1000);
135
152
  });
136
- } catch(_) {}
137
- Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
138
- Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
139
-
140
- // ── Canvas fingerprint noise ─────────────────────────
141
- // Headless rendering engines produce slightly different canvas output
142
- // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
153
+ } catch {}
154
+ const deadline = Date.now() + graceMs;
155
+ while (Date.now() < deadline) {
156
+ const pid = getPortPid();
157
+ if (!pid)
158
+ return true;
159
+ if (pid !== ownedPid)
160
+ return false;
161
+ await new Promise((r) => setTimeout(r, 150));
162
+ }
163
+ return killProcessOnPort(ownedPid);
164
+ }
165
+ function killProcessOnPort(expectedPid = null) {
143
166
  try {
144
- var __canvasNoise = ((Date.now() & 0xFF) | 1);
145
- var origFill = CanvasRenderingContext2D.prototype.fillText;
146
- CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
147
- this.globalAlpha = 0.9995;
148
- return origFill.apply(this, arguments);
149
- });
150
- } catch(_) {}
167
+ const pid = getOwnedBrowserPid();
168
+ if (!pid || expectedPid && pid !== expectedPid)
169
+ return false;
170
+ if (platform() === "win32") {
171
+ execFileSync(resolveSystemCmd("taskkill"), ["/F", "/PID", String(pid)], {
172
+ stdio: "ignore",
173
+ windowsHide: true
174
+ });
175
+ } else {
176
+ process.kill(pid, "SIGKILL");
177
+ }
178
+ return true;
179
+ } catch {
180
+ return false;
181
+ }
182
+ }
183
+ export async function killChrome() {
184
+ if (!getOwnedBrowserPid()) {
185
+ if (getPortPid()) {
186
+ process.stderr.write(`[greedysearch] Refusing to kill an unverified listener.
187
+ `);
188
+ }
189
+ return false;
190
+ }
191
+ const ready = await probeGreedyChrome(500);
192
+ if (!ready) {
193
+ try {
194
+ unlinkSync(PID_FILE);
195
+ } catch {}
196
+ try {
197
+ unlinkSync(ACTIVITY_FILE);
198
+ } catch {}
199
+ try {
200
+ unlinkSync(CHROME_MODE_FILE);
201
+ } catch {}
202
+ return false;
203
+ }
204
+ const killed = await gracefulCloseChrome(1500);
151
205
  try {
152
- var origStroke = CanvasRenderingContext2D.prototype.strokeText;
153
- CanvasRenderingContext2D.prototype.strokeText = __markNative(function strokeText() {
154
- this.globalAlpha = 0.9995;
155
- return origStroke.apply(this, arguments);
156
- });
157
- } catch(_) {}
206
+ unlinkSync(PID_FILE);
207
+ } catch {}
158
208
  try {
159
- var origToDataURL = HTMLCanvasElement.prototype.toDataURL;
160
- HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
161
- var ctx = this.getContext('2d');
162
- if (ctx) {
163
- // Spread noise across canvas to break hash-based fingerprinting.
164
- // Uses a deterministic pattern so it's consistent per page load
165
- // but varies between sessions.
166
- var w = this.width, h = this.height;
167
- if (w > 0 && h > 0) {
168
- var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
169
- if (imgData && imgData.data) {
170
- for (var __i = 0; __i < imgData.data.length; __i += 4) {
171
- imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
172
- }
173
- ctx.putImageData(imgData, 0, 0);
174
- }
175
- }
176
- }
177
- return origToDataURL.apply(this, arguments);
178
- });
179
- } catch(_) {}
180
-
181
- // ── AudioContext fingerprint noise ────────────────────
182
- // Headless Chrome's AudioContext produces slightly different output.
183
- // Subtle noise breaks audio-based fingerprinting.
209
+ unlinkSync(ACTIVITY_FILE);
210
+ } catch {}
184
211
  try {
185
- var __audioSeed = ((Date.now() & 0x1F) | 1);
186
- var origGetChannelData = AudioBuffer.prototype.getChannelData;
187
- AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
188
- var data = origGetChannelData.call(this, channel);
189
- for (var __i = 0; __i < data.length; __i += 64) {
190
- data[__i] *= 0.99999;
191
- }
192
- return data;
193
- });
194
- } catch(_) {}
195
-
196
- // ── window outer dimensions ──────────────────────────
197
- // outerWidth/Height = 0 in headless — a well-known bot signal.
198
- // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
212
+ unlinkSync(CHROME_MODE_FILE);
213
+ } catch {}
214
+ if (killed) {
215
+ process.stderr.write(`[greedysearch] Killed Chrome on port ${GREEDY_PORT}.
216
+ `);
217
+ }
218
+ return killed;
219
+ }
220
+ export const killHeadlessChrome = killChrome;
221
+ export async function checkAndKillIdle() {
222
+ const headless = isChromeHeadless();
223
+ const timeoutMinutes = headless ? HEADLESS_IDLE_TIMEOUT_MINUTES : VISIBLE_IDLE_TIMEOUT_MINUTES;
224
+ if (timeoutMinutes <= 0)
225
+ return false;
226
+ if (!existsSync(ACTIVITY_FILE)) {
227
+ touchActivity();
228
+ return false;
229
+ }
199
230
  try {
200
- if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
201
- if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
202
- } catch(_) {}
203
-
204
- // ── screen properties ─────────────────────────────────
205
- // Headless Chrome often reports an 800x600 screen even when the viewport is
206
- // 1920x1080. Keep screen metrics internally consistent with our launch flags.
231
+ const lastActivity = Number.parseInt(readFileSync(ACTIVITY_FILE, "utf8").trim(), 10);
232
+ if (!lastActivity)
233
+ return false;
234
+ const idleMs = Date.now() - lastActivity;
235
+ const idleMinutes = idleMs / 60000;
236
+ if (idleMinutes >= timeoutMinutes) {
237
+ return killChrome();
238
+ }
239
+ } catch {}
240
+ return false;
241
+ }
242
+ export const cdp = _cdp;
243
+ export async function getAnyTab() {
244
+ const list = await cdp(["list"]);
245
+ const first = list.split(`
246
+ `)[0];
247
+ if (!first)
248
+ throw new Error("No Chrome tabs found");
249
+ return first.slice(0, 8);
250
+ }
251
+ export async function openNewTab(url = "about:blank") {
252
+ const anchor = await getAnyTab();
253
+ const hostname = new URL(url).hostname;
254
+ const needsStealth = hostname === "copilot.microsoft.com" || hostname === "www.perplexity.ai" || hostname === "perplexity.ai" || hostname.endsWith(".perplexity.ai");
255
+ if (needsStealth) {
256
+ const raw = await cdp([
257
+ "evalraw",
258
+ anchor,
259
+ "Target.createTarget",
260
+ JSON.stringify({ url: "about:blank" })
261
+ ]);
262
+ const { targetId } = JSON.parse(raw);
263
+ const tid = targetId.slice(0, 8);
264
+ await cdp(["list"]).catch(() => null);
265
+ if (hostname === "copilot.microsoft.com") {
266
+ await injectHeadlessStealth(tid);
267
+ } else {
268
+ injectHeadlessStealth(tid).catch(() => {});
269
+ }
270
+ await cdp(["list"]).catch(() => null);
271
+ return targetId;
272
+ }
273
+ const raw = await cdp([
274
+ "evalraw",
275
+ anchor,
276
+ "Target.createTarget",
277
+ JSON.stringify({ url })
278
+ ]);
279
+ const { targetId } = JSON.parse(raw);
280
+ await cdp(["list"]).catch(() => null);
281
+ return targetId;
282
+ }
283
+ export async function activateTab(targetId) {
207
284
  try {
208
- Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
209
- Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
210
- Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
211
- Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
212
- Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
213
- Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
214
- } catch(_) {}
215
-
216
- // ── navigator.userAgentData (UA Client Hints) ─────────
217
- // Derive version from the UA string already set by --user-agent flag so the
218
- // two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
285
+ const anchor = await getAnyTab();
286
+ await cdp([
287
+ "evalraw",
288
+ anchor,
289
+ "Target.activateTarget",
290
+ JSON.stringify({ targetId })
291
+ ]);
292
+ } catch {}
293
+ }
294
+ export async function closeTab(targetId) {
219
295
  try {
220
- var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
221
- var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
222
- var _brands = [
223
- { brand: 'Not)A;Brand', version: '99' },
224
- { brand: 'Google Chrome', version: _uaMajor },
225
- { brand: 'Chromium', version: _uaMajor },
226
- ];
227
- Object.defineProperty(navigator, 'userAgentData', {
228
- get: function() {
229
- return {
230
- brands: _brands, mobile: false, platform: 'Windows',
231
- getHighEntropyValues: function() {
232
- return Promise.resolve({
233
- architecture: 'x86', bitness: '64',
234
- brands: _brands,
235
- fullVersionList: [
236
- { brand: 'Not)A;Brand', version: '99.0.0.0' },
237
- { brand: 'Google Chrome', version: _uaFull },
238
- { brand: 'Chromium', version: _uaFull },
239
- ],
240
- mobile: false, model: '', platform: 'Windows',
241
- platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
242
- });
243
- },
244
- toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
245
- };
246
- },
247
- configurable: true,
248
- });
249
- } catch(_) {}
250
-
251
- // ── CDP Runtime serialization guard ──────────────────
252
- // Sites detect CDP by putting a getter on Error.prototype.stack
253
- // and checking if console.log triggers it (only happens when
254
- // Runtime domain is enabled). We monkey-patch console methods to
255
- // strip custom getters from arguments before they reach CDP.
296
+ const anchor = await getAnyTab();
297
+ await cdp([
298
+ "evalraw",
299
+ anchor,
300
+ "Target.closeTarget",
301
+ JSON.stringify({ targetId })
302
+ ]);
303
+ } catch {}
304
+ }
305
+ export async function closeTabs(targetIds = []) {
306
+ await Promise.all(targetIds.filter(Boolean).map((tid) => closeTab(tid).catch(() => {})));
307
+ if (targetIds.length > 0) {
308
+ await cdp(["list"]).catch(() => null);
309
+ }
310
+ }
311
+ export function getFullTabFromCache(engine, engineDomains) {
256
312
  try {
257
- var _origLog = console.log, _origError = console.error,
258
- _origWarn = console.warn, _origDebug = console.debug,
259
- _origInfo = console.info;
260
- var _safeArg = function(a) {
261
- if (a instanceof Error) {
262
- try { return new Error(a.message); } catch(_) { return a; }
313
+ if (!existsSync(PAGES_CACHE))
314
+ return null;
315
+ const pages = JSON.parse(readFileSync(PAGES_CACHE, "utf8"));
316
+ const found = pages.find((p) => p.url.includes(engineDomains[engine]));
317
+ return found ? found.targetId : null;
318
+ } catch {
319
+ return null;
320
+ }
321
+ }
322
+ export function probeGreedyChrome(timeoutMs = 3000) {
323
+ return new Promise((resolve) => {
324
+ const req = http.get(`http://localhost:${GREEDY_PORT}/json/version`, (res) => {
325
+ res.resume();
326
+ resolve(res.statusCode === 200);
327
+ });
328
+ req.on("error", () => resolve(false));
329
+ req.setTimeout(timeoutMs, () => {
330
+ req.destroy();
331
+ resolve(false);
332
+ });
333
+ });
334
+ }
335
+ async function waitForPortDown(timeoutMs = 3000, intervalMs = 200) {
336
+ const deadline = Date.now() + timeoutMs;
337
+ while (Date.now() < deadline) {
338
+ if (!await probeGreedyChrome(300))
339
+ return true;
340
+ await new Promise((r) => setTimeout(r, intervalMs));
341
+ }
342
+ return !await probeGreedyChrome(300);
343
+ }
344
+ export async function refreshPortFile() {
345
+ const LOCK_FILE = `${ACTIVE_PORT_FILE}.lock`;
346
+ const TEMP_FILE = `${ACTIVE_PORT_FILE}.tmp`;
347
+ const LOCK_STALE_MS = 5000;
348
+ const LOCK_WAIT_MS = 1000;
349
+ const lockAcquired = await new Promise((resolve) => {
350
+ const start = Date.now();
351
+ const tryLock = () => {
352
+ try {
353
+ const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
354
+ writeFileSync(LOCK_FILE, payload, { encoding: "utf8", flag: "wx" });
355
+ resolve(true);
356
+ } catch (e) {
357
+ if (e?.code !== "EEXIST") {
358
+ if (Date.now() - start < LOCK_WAIT_MS) {
359
+ setTimeout(tryLock, 50);
360
+ } else {
361
+ resolve(false);
362
+ }
363
+ return;
364
+ }
365
+ try {
366
+ const lockRaw = readFileSync(LOCK_FILE, "utf8").trim();
367
+ const parsed = lockRaw.startsWith("{") ? JSON.parse(lockRaw) : { ts: Number(lockRaw) };
368
+ const lockTime = Number(parsed?.ts) || 0;
369
+ if (lockTime > 0 && Date.now() - lockTime > LOCK_STALE_MS) {
370
+ try {
371
+ unlinkSync(LOCK_FILE);
372
+ } catch {}
373
+ }
374
+ if (Date.now() - start < LOCK_WAIT_MS) {
375
+ setTimeout(tryLock, 50);
376
+ } else {
377
+ resolve(false);
378
+ }
379
+ } catch {
380
+ if (Date.now() - start < LOCK_WAIT_MS) {
381
+ setTimeout(tryLock, 50);
382
+ } else {
383
+ resolve(false);
384
+ }
385
+ }
263
386
  }
264
- return a;
265
387
  };
266
- console.log = __markNative(function log() { return _origLog.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
267
- console.error = __markNative(function error() { return _origError.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
268
- console.warn = __markNative(function warn() { return _origWarn.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
269
- console.debug = __markNative(function debug() { return _origDebug.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
270
- console.info = __markNative(function info() { return _origInfo.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
271
- } catch(_) {}
272
-
273
- // ── Native function masking ──────────────────────────
274
- // Patched APIs should not stringify as user-defined stealth code.
388
+ tryLock();
389
+ });
275
390
  try {
276
- var __nativeToString = Function.prototype.toString;
277
- Function.prototype.toString = function toString() {
278
- if (__greedyNativeFns.indexOf(this) !== -1) {
279
- var name = this.name || '';
280
- return 'function ' + name + '() { [native code] }';
391
+ const body = await new Promise((res, rej) => {
392
+ const req = http.get(`http://localhost:${GREEDY_PORT}/json/version`, (r) => {
393
+ let b = "";
394
+ r.on("data", (d) => b += d);
395
+ r.on("end", () => res(b));
396
+ });
397
+ req.on("error", rej);
398
+ req.setTimeout(3000, () => {
399
+ req.destroy();
400
+ rej(new Error("timeout"));
401
+ });
402
+ });
403
+ const { webSocketDebuggerUrl } = JSON.parse(body);
404
+ const wsPath = new URL(webSocketDebuggerUrl).pathname;
405
+ if (lockAcquired) {
406
+ writeFileSync(TEMP_FILE, `${GREEDY_PORT}
407
+ ${wsPath}`, "utf8");
408
+ try {
409
+ unlinkSync(ACTIVE_PORT_FILE);
410
+ } catch {}
411
+ renameSync(TEMP_FILE, ACTIVE_PORT_FILE);
412
+ }
413
+ } catch {} finally {
414
+ if (lockAcquired) {
415
+ try {
416
+ unlinkSync(LOCK_FILE);
417
+ } catch {}
418
+ }
419
+ }
420
+ }
421
+ export async function ensureChrome() {
422
+ if (process.env.GREEDY_SEARCH_RESEARCH_CHILD && await probeGreedyChrome()) {
423
+ await refreshPortFile();
424
+ try {
425
+ const md = readMetadata();
426
+ if (md) {
427
+ touchActivityBL(md);
428
+ registerClient(md);
281
429
  }
282
- return __nativeToString.call(this);
283
- };
284
- } catch(_) {}
285
- })();
286
- `})])}import{existsSync as he}from"node:fs";import{platform as rt}from"node:os";import{join as _}from"node:path";function C(e){let t=rt()==="win32",r=process.env.SystemRoot||"C:\\Windows",n={win32:{powershell:_(r,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:_(r,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:_(r,"System32","netstat.exe"),taskkill:_(r,"System32","taskkill.exe"),tasklist:_(r,"System32","tasklist.exe"),cmd:_(r,"System32","cmd.exe")},unix:{ps:"/usr/bin/ps",lsof:"/usr/bin/lsof",ss:"/usr/sbin/ss",grep:"/usr/bin/grep",kill:"/usr/bin/kill"}},i=t?n.win32:n.unix,a=e.toLowerCase();if(i[a]&&he(i[a]))return i[a];if(t&&a==="netstat"){let o=_(r,"Sysnative","netstat.exe");if(he(o))return o}return e}import{execFileSync as nt}from"node:child_process";import{platform as it}from"node:os";function at(e,t){return nt(C(e),t,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5000})}function ot(e){let t=String(e||"").match(/\b(\d+)\b/);return t?Number.parseInt(t[1],10):null}function st(e){return ot(e)}function lt(e,t){for(let r of String(e||"").split(/\r?\n/)){if(!/\bLISTEN\b/i.test(r))continue;if(!r.trim().split(/\s+/).slice(0,6).some((a)=>a.endsWith(`:${t}`)))continue;let i=r.match(/\bpid=(\d+)\b/);if(i)return Number.parseInt(i[1],10)}return null}function ut(e,t){for(let r of String(e||"").split(/\r?\n/)){let n=r.trim().split(/\s+/);if(n.length<5||n[0].toUpperCase()!=="TCP")continue;if(!n.at(-2)?.toUpperCase().startsWith("LISTEN"))continue;if(!n[1].endsWith(`:${t}`))continue;let i=Number.parseInt(n.at(-1),10);if(Number.isInteger(i)&&i>0)return i}return null}function Y(e,t,r){try{return e(t,r)}catch{return null}}function ye(e,{platformName:t=it(),run:r=at}={}){if(t==="win32")return ut(Y(r,"netstat",["-ano","-p","TCP"]),e);let n=Y(r,"lsof",["-nP",`-iTCP:${e}`,"-sTCP:LISTEN","-t"]),i=st(n);if(i)return i;if(t!=="linux")return null;return lt(Y(r,"ss",["-ltnp"]),e)}import{existsSync as be}from"node:fs";import{dirname as ct,join as k}from"node:path";import{fileURLToPath as ft}from"node:url";function we(e){return ft(new URL(".",e)).replace(/^\/([A-Z]:)/,"$1")}function pt(e,t=be){let r=new Set;for(let n of e.filter(Boolean)){if(r.has(n))continue;if(r.add(n),t(n))return n}return e.filter(Boolean).at(-1)}function _e({moduleDir:e,entrypoint:t=process.argv[1],env:r=process.env,exists:n=be}={}){let i=t?ct(t):null,a=r.GREEDY_SEARCH_EXTENSION_DIR?.trim()||null;return pt([e?k(e,"..","..","bin","launch.mjs"):null,e?k(e,"launch.mjs"):null,a?k(a,"bin","launch.mjs"):null,i?k(i,"launch.mjs"):null,i?k(i,"..","bin","launch.mjs"):null],n)}import{existsSync as O,mkdirSync as gt,readFileSync as xe,writeFileSync as dt}from"node:fs";import{homedir as mt}from"node:os";import{join as Pe}from"node:path";import{tmpdir as ht}from"node:os";function yt(e,t=9222){let r=Number.parseInt(String(e??""),10);return Number.isInteger(r)&&r>1024&&r<65535?r:t}var bt=ht().replaceAll("\\","/"),g=yt(process.env.GREEDY_SEARCH_PORT),p=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${bt}/greedysearch-chrome-profile`).replaceAll("\\","/"),D=`${p}/DevToolsActivePort`,Ae=process.env.GREEDY_SEARCH_PID_FILE||`${p}/browser.pid`,te=process.env.CDP_PAGES_CACHE||`${p}/cdp-pages.json`,j=process.env.GREEDY_SEARCH_MODE_FILE||`${p}/browser-mode`,Tr=process.env.GREEDY_SEARCH_METADATA_FILE||`${p}/browser-metadata.json`,Wr=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${p}/browser-launch.lock`,Se=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${p}/browser-last-activity`,Mr=(process.env.CDP_SOCKET_DIR||`${p}/cdp-sockets`).replaceAll("\\","/"),Or=`${p}/visible-recovery.jsonl`,F=Pe(mt(),".dm"),d=Pe(F,"greedyconfig"),K=["perplexity","google","chatgpt","gemini"],ee="gemini";function wt(){try{if(O(d)){let e=xe(d,"utf8"),t=JSON.parse(e);if(Array.isArray(t.engines)&&t.engines.length>0&&t.engines.every((r)=>typeof r==="string")){let r=t.engines.filter((i)=>G[i]),n=t.engines.filter((i)=>!G[i]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${d}: ${n.join(", ")}
287
- [greedysearch] Available engines: ${Object.keys(G).join(", ")}
288
- `);if(r.length>0)return r;process.stderr.write(`[greedysearch] Warning: no valid engines in ${d}, falling back to defaults: ${K.join(", ")}
289
- `)}}}catch{}return K}function _t(){try{if(!O(F))gt(F,{recursive:!0});if(!O(d))dt(d,JSON.stringify({engines:K,synthesizer:ee},null,2)+`
290
- `,"utf8")}catch{}}_t();var ve=["gemini","chatgpt"];function vt(){try{if(O(d)){let e=xe(d,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let r=t.synthesizer.toLowerCase();if(ve.includes(r))return r;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${d}
291
- [greedysearch] Available synthesizers: ${ve.join(", ")}
292
- [greedysearch] Falling back to default: ${ee}
293
- `)}}}catch{}return ee}var G={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"},Jr=wt();var qr=vt(),Hr=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=p;import{execFileSync as Ce,execSync as Br}from"node:child_process";import{existsSync as J,mkdirSync as xt,readFileSync as $,unlinkSync as P,writeFileSync as A}from"node:fs";import{platform as Pt}from"node:os";import{existsSync as q,mkdirSync as At,readFileSync as Te,writeFileSync as St}from"node:fs";import{homedir as Ct}from"node:os";import{join as We}from"node:path";import{tmpdir as jt}from"node:os";import{existsSync as $e}from"node:fs";import{platform as Ht}from"node:os";import{join as v}from"node:path";import{execFileSync as Ut}from"node:child_process";import{platform as Xt}from"node:os";function $t(e,t=9222){let r=Number.parseInt(String(e??""),10);return Number.isInteger(r)&&r>1024&&r<65535?r:t}var kt=jt().replaceAll("\\","/"),S=$t(process.env.GREEDY_SEARCH_PORT),c=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${kt}/greedysearch-chrome-profile`).replaceAll("\\","/"),Ir=`${c}/DevToolsActivePort`,Dt=process.env.GREEDY_SEARCH_PID_FILE||`${c}/browser.pid`,Er=process.env.CDP_PAGES_CACHE||`${c}/cdp-pages.json`,Nt=process.env.GREEDY_SEARCH_MODE_FILE||`${c}/browser-mode`,Tt=process.env.GREEDY_SEARCH_METADATA_FILE||`${c}/browser-metadata.json`,Wt=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${c}/browser-launch.lock`,Mt=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${c}/browser-last-activity`,Yr=(process.env.CDP_SOCKET_DIR||`${c}/cdp-sockets`).replaceAll("\\","/"),Gr=`${c}/visible-recovery.jsonl`,ie=We(Ct(),".dm"),m=We(ie,"greedyconfig"),ae=["perplexity","google","chatgpt","gemini"],oe="gemini";function Ot(){try{if(q(m)){let e=Te(m,"utf8"),t=JSON.parse(e);if(Array.isArray(t.engines)&&t.engines.length>0&&t.engines.every((r)=>typeof r==="string")){let r=t.engines.filter((i)=>re[i]),n=t.engines.filter((i)=>!re[i]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${m}: ${n.join(", ")}
294
- [greedysearch] Available engines: ${Object.keys(re).join(", ")}
295
- `);if(r.length>0)return r;process.stderr.write(`[greedysearch] Warning: no valid engines in ${m}, falling back to defaults: ${ae.join(", ")}
296
- `)}}}catch{}return ae}function Jt(){try{if(!q(ie))At(ie,{recursive:!0});if(!q(m))St(m,JSON.stringify({engines:ae,synthesizer:oe},null,2)+`
297
- `,"utf8")}catch{}}Jt();var je=["gemini","chatgpt"];function qt(){try{if(q(m)){let e=Te(m,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let r=t.synthesizer.toLowerCase();if(je.includes(r))return r;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${m}
298
- [greedysearch] Available synthesizers: ${je.join(", ")}
299
- [greedysearch] Falling back to default: ${oe}
300
- `)}}}catch{}return oe}var re={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},Fr=Ot(),Kr=qt(),en=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=c;function se(e){let t=Ht()==="win32",r=process.env.SystemRoot||"C:\\Windows",n={win32:{powershell:v(r,"System32","WindowsPowerShell","v1.0","powershell.exe"),powershell_ise:v(r,"System32","WindowsPowerShell","v1.0","powershell_ise.exe"),netstat:v(r,"System32","netstat.exe"),taskkill:v(r,"System32","taskkill.exe"),tasklist:v(r,"System32","tasklist.exe"),cmd:v(r,"System32","cmd.exe")},unix:{ps:"/usr/bin/ps",lsof:"/usr/bin/lsof",ss:"/usr/sbin/ss",grep:"/usr/bin/grep",kill:"/usr/bin/kill"}},i=t?n.win32:n.unix,a=e.toLowerCase();if(i[a]&&$e(i[a]))return i[a];if(t&&a==="netstat"){let o=v(r,"Sysnative","netstat.exe");if($e(o))return o}return e}function Bt(e,t){return Ut(se(e),t,{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:5000})}function Qt(e){let t=String(e||"").match(/\b(\d+)\b/);return t?Number.parseInt(t[1],10):null}function Zt(e){return Qt(e)}function Rt(e,t){for(let r of String(e||"").split(/\r?\n/)){if(!/\bLISTEN\b/i.test(r))continue;if(!r.trim().split(/\s+/).slice(0,6).some((i)=>i.endsWith(`:${t}`)))continue;let n=r.match(/\bpid=(\d+)\b/);if(n)return Number.parseInt(n[1],10)}return null}function Lt(e,t){for(let r of String(e||"").split(/\r?\n/)){let n=r.trim().split(/\s+/);if(n.length<5||n[0].toUpperCase()!=="TCP")continue;if(!n.at(-2)?.toUpperCase().startsWith("LISTEN"))continue;if(!n[1].endsWith(`:${t}`))continue;let i=Number.parseInt(n.at(-1),10);if(Number.isInteger(i)&&i>0)return i}return null}function ne(e,t,r){try{return e(t,r)}catch{return null}}function Vt(e,{platformName:t=Xt(),run:r=Bt}={}){if(t==="win32")return Lt(ne(r,"netstat",["-ano","-p","TCP"]),e);let n=ne(r,"lsof",["-nP",`-iTCP:${e}`,"-sTCP:LISTEN","-t"]),i=Zt(n);if(i)return i;if(t!=="linux")return null;return Rt(ne(r,"ss",["-ltnp"]),e)}var H=Tt,x=Wt,zt=15000,U=Dt,X=Nt,N=Mt;function T(e){if(!Number.isInteger(e)||e<=0)return!1;try{return process.kill(e,0),!0}catch{return!1}}function It(e){if(!T(e))return null;try{if(Pt()==="win32")return Ce(se("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return Ce(se("ps"),["-p",String(e),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function Et(e,t,r=S){if(!e)return!1;let n=(o)=>String(o||"").replaceAll("\\","/").toLowerCase(),i=n(e),a=n(t);return i.includes(a)&&i.includes(`--remote-debugging-port=${r}`)&&!i.includes("--type=")}function ke(e,t,r=S){return Et(It(e),t,r)}function Yt(e=S){return Vt(e)}function W(){try{if(J(H)){let e=$(H,"utf8"),t=JSON.parse(e);if(t&&typeof t.tempDir==="string"&&typeof t.debugPort==="number")return{browserPid:Number.isInteger(t.browserPid)?t.browserPid:void 0,debugPort:t.debugPort,tempDir:t.tempDir,clientPids:Array.isArray(t.clientPids)?t.clientPids.filter((r)=>Number.isInteger(r)&&r>0):[],sessionMode:t.sessionMode==="visible"?"visible":"headless",lastActivity:Number.isFinite(t.lastActivity)?t.lastActivity:0,launchedAt:Number.isFinite(t.launchedAt)?t.launchedAt:0}}}catch{}try{let e=J(U)?Number.parseInt($(U,"utf8").trim(),10)||void 0:void 0,t=J(X)?$(X,"utf8").trim()==="visible"?"visible":"headless":"headless",r=J(N)?Number.parseInt($(N,"utf8").trim(),10)||0:0;return{browserPid:e,debugPort:S,tempDir:c,clientPids:e?[e]:[],sessionMode:t,lastActivity:r,launchedAt:0}}catch{return null}}function B(e){try{A(H,JSON.stringify({browserPid:e.browserPid,debugPort:e.debugPort,tempDir:e.tempDir,clientPids:[...new Set(e.clientPids.filter((t)=>t>0))],sessionMode:e.sessionMode,lastActivity:e.lastActivity,launchedAt:e.launchedAt},null,2),"utf8")}catch{}try{if(e.browserPid)A(U,String(e.browserPid),"utf8")}catch{}try{A(X,e.sessionMode,"utf8")}catch{}try{A(N,String(e.lastActivity),"utf8")}catch{}}function De(){try{P(H)}catch{}try{P(U)}catch{}try{P(X)}catch{}try{P(N)}catch{}}function le(e){if(!e)return e;let t={...e,clientPids:[...new Set([...e.clientPids,process.pid].filter((r)=>T(r)||r===process.pid))]};return B(t),t}function Q(e){let t=Date.now();try{if(e)B({...e,lastActivity:t});else A(N,String(t),"utf8")}catch{}}var sn=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Ne=!1;function Me(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD)return;if(Ne)return;Ne=!0;let e=W();if(!e)return;if(e.browserPid){if(!T(e.browserPid)){De();return}if(!ke(e.browserPid,e.tempDir,e.debugPort))De();else B({...e,clientPids:e.clientPids.filter((r)=>T(r))})}let t=Yt();if(t&&t!==e.browserPid)if(ke(t,c,S))B({browserPid:t,debugPort:S,tempDir:c,clientPids:[t],sessionMode:e.sessionMode,lastActivity:Date.now(),launchedAt:Date.now()});else process.stderr.write(`[greedysearch] Refusing to kill unverified listener ${t} on port ${S}.
301
- `)}function Oe(){xt(c,{recursive:!0});try{let e=JSON.stringify({pid:process.pid,ts:Date.now()});return A(x,e,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{let t=$(x,"utf8");if(JSON.parse(t).pid===process.pid)P(x)}catch{}}}}catch(e){if(e?.code!=="EEXIST")return{acquired:!1,release:()=>{}}}try{let e=$(x,"utf8"),t=JSON.parse(e),r=Date.now()-(t.ts||0);if(!T(t.pid)||r>zt){try{P(x)}catch{}try{let n=JSON.stringify({pid:process.pid,ts:Date.now()});return A(x,n,{encoding:"utf8",flag:"wx"}),{acquired:!0,release:()=>{try{P(x)}catch{}}}}catch{return{acquired:!1,release:()=>{}}}}}catch{}return{acquired:!1,release:()=>{}}}var Kt=we(import.meta.url),Je=Ae,M=Se,er=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,tr=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;function rr(e,t=g){let r=String(e||"").toLowerCase();if(!r.includes(`--remote-debugging-port=${t}`)||r.includes("--type="))return null;return r.includes("--headless")}function Xe(){try{let e=z(),t=e?Be(e):null,r=rr(t);if(r!==null){try{R(j,r?"headless":"visible","utf8")}catch{}return r}}catch{}try{if(!ce(j))return!0;return V(j,"utf8").trim()==="headless"}catch{return!0}}function nr(){try{R(M,String(Date.now()),"utf8")}catch{}try{let e=W();if(e)Q(e)}catch{}}function Be(e){try{if(Ue()==="win32")return ue(C("powershell"),["-NoProfile","-NonInteractive","-Command",`(Get-CimInstance Win32_Process -Filter "ProcessId = ${e}").CommandLine`],{encoding:"utf8",windowsHide:!0,timeout:5000}).trim()||null;return ue(C("ps"),["-p",String(e),"-o","command="],{encoding:"utf8",timeout:5000}).trim()||null}catch{return null}}function ir(e){let t=String(e||"").replaceAll("\\","/"),r=p.replaceAll("\\","/");return t.includes(`--remote-debugging-port=${g}`)&&t.includes(`--user-data-dir=${r}`)&&!t.includes("--type=")}function z(){return ye(g)}function L(){let e=z();return e&&ir(Be(e))?e:null}async function ar(e=1500){let t=L();if(!t)return process.stderr.write(`[greedysearch] Refusing to close an unverified listener.
302
- `),!1;try{let n=await new Promise((a,o)=>{let s=fe.get(`http://localhost:${g}/json/version`,(l)=>{let f="";l.on("data",(u)=>f+=u),l.on("end",()=>{try{a(JSON.parse(f))}catch{o(Error("bad JSON"))}})});s.on("error",o),s.setTimeout(1000,()=>{s.destroy(),o(Error("timeout"))})}),i=new globalThis.WebSocket(n.webSocketDebuggerUrl);await new Promise((a)=>{i.onopen=()=>{if(L()!==t){i.close(),a();return}i.send(JSON.stringify({id:1,method:"Browser.close"})),setTimeout(()=>{i.close(),a()},200)},i.onerror=()=>a(),setTimeout(a,1000)})}catch{}let r=Date.now()+e;while(Date.now()<r){let n=z();if(!n)return!0;if(n!==t)return!1;await new Promise((i)=>setTimeout(i,150))}return or(t)}function or(e=null){try{let t=L();if(!t||e&&t!==e)return!1;if(Ue()==="win32")ue(C("taskkill"),["/F","/PID",String(t)],{stdio:"ignore",windowsHide:!0});else process.kill(t,"SIGKILL");return!0}catch{return!1}}async function Qe(){if(!L()){if(z())process.stderr.write(`[greedysearch] Refusing to kill an unverified listener.
303
- `);return!1}if(!await y(500)){try{h(Je)}catch{}try{h(M)}catch{}try{h(j)}catch{}return!1}let t=await ar(1500);try{h(Je)}catch{}try{h(M)}catch{}try{h(j)}catch{}if(t)process.stderr.write(`[greedysearch] Killed Chrome on port ${g}.
304
- `);return t}var qe=Qe;async function sr(){let t=Xe()?er:tr;if(t<=0)return!1;if(!ce(M))return nr(),!1;try{let r=Number.parseInt(V(M,"utf8").trim(),10);if(!r)return!1;if((Date.now()-r)/60000>=t)return Qe()}catch{}return!1}var b=I;async function pe(){let t=(await b(["list"])).split(`
305
- `)[0];if(!t)throw Error("No Chrome tabs found");return t.slice(0,8)}async function vn(e="about:blank"){let t=await pe(),r=new URL(e).hostname;if(r==="copilot.microsoft.com"||r==="www.perplexity.ai"||r==="perplexity.ai"||r.endsWith(".perplexity.ai")){let o=await b(["evalraw",t,"Target.createTarget",JSON.stringify({url:"about:blank"})]),{targetId:s}=JSON.parse(o),l=s.slice(0,8);if(await b(["list"]).catch(()=>null),r==="copilot.microsoft.com")await E(l);else E(l).catch(()=>{});return await b(["list"]).catch(()=>null),s}let i=await b(["evalraw",t,"Target.createTarget",JSON.stringify({url:e})]),{targetId:a}=JSON.parse(i);return await b(["list"]).catch(()=>null),a}async function xn(e){try{let t=await pe();await b(["evalraw",t,"Target.activateTarget",JSON.stringify({targetId:e})])}catch{}}async function lr(e){try{let t=await pe();await b(["evalraw",t,"Target.closeTarget",JSON.stringify({targetId:e})])}catch{}}async function Pn(e=[]){if(await Promise.all(e.filter(Boolean).map((t)=>lr(t).catch(()=>{}))),e.length>0)await b(["list"]).catch(()=>null)}function An(e,t){try{if(!ce(te))return null;let n=JSON.parse(V(te,"utf8")).find((i)=>i.url.includes(t[e]));return n?n.targetId:null}catch{return null}}function y(e=3000){return new Promise((t)=>{let r=fe.get(`http://localhost:${g}/json/version`,(n)=>{n.resume(),t(n.statusCode===200)});r.on("error",()=>t(!1)),r.setTimeout(e,()=>{r.destroy(),t(!1)})})}async function He(e=3000,t=200){let r=Date.now()+e;while(Date.now()<r){if(!await y(300))return!0;await new Promise((n)=>setTimeout(n,t))}return!await y(300)}async function Z(){let e=`${D}.lock`,t=`${D}.tmp`,r=5000,n=1000,i=await new Promise((a)=>{let o=Date.now(),s=()=>{try{let l=JSON.stringify({pid:process.pid,ts:Date.now()});R(e,l,{encoding:"utf8",flag:"wx"}),a(!0)}catch(l){if(l?.code!=="EEXIST"){if(Date.now()-o<1000)setTimeout(s,50);else a(!1);return}try{let f=V(e,"utf8").trim(),u=f.startsWith("{")?JSON.parse(f):{ts:Number(f)},w=Number(u?.ts)||0;if(w>0&&Date.now()-w>5000)try{h(e)}catch{}if(Date.now()-o<1000)setTimeout(s,50);else a(!1)}catch{if(Date.now()-o<1000)setTimeout(s,50);else a(!1)}}};s()});try{let a=await new Promise((l,f)=>{let u=fe.get(`http://localhost:${g}/json/version`,(w)=>{let ge="";w.on("data",(Ze)=>ge+=Ze),w.on("end",()=>l(ge))});u.on("error",f),u.setTimeout(3000,()=>{u.destroy(),f(Error("timeout"))})}),{webSocketDebuggerUrl:o}=JSON.parse(a),s=new URL(o).pathname;if(i){R(t,`${g}
306
- ${s}`,"utf8");try{h(D)}catch{}Ft(t,D)}}catch{}finally{if(i)try{h(e)}catch{}}}async function Sn(){if(process.env.GREEDY_SEARCH_RESEARCH_CHILD&&await y()){await Z();try{let a=W();if(a)Q(a),le(a)}catch{}return}Me();let e=await sr(),t=e?!1:await y();if(!t&&!e)await new Promise((a)=>setTimeout(a,500)),t=await y();let r=!1;if(t){let a=Xe(),o=process.env.GREEDY_SEARCH_VISIBLE==="1";if(!o&&!a)process.stderr.write(`[greedysearch] Visible Chrome detected — switching to headless mode...
307
- `),await qe(),await He(),r=!0;else if(o&&a)process.stderr.write(`[greedysearch] Headless Chrome detected — switching to visible mode...
308
- `),await qe(),await He(),r=!0}if(r?!1:await y()){await Z();try{let a=W();if(a)Q(a),le(a)}catch{}return}let i=Oe();if(!i.acquired){let a=Date.now()+12000,o=!1;while(Date.now()<a){if(o=await y(500),o)break;await new Promise((s)=>setTimeout(s,250))}if(o){await Z();return}}try{if(await y(1000)){await Z();return}process.stderr.write(`GreedySearch Chrome not running on port ${g} — auto-launching...
309
- `);let s=[_e({moduleDir:Kt,entrypoint:process.argv[1],env:process.env})];if(process.env.GREEDY_SEARCH_VISIBLE!=="1")s.push("--headless");await new Promise((l,f)=>{Gt(de(),s,{stdio:["ignore",process.stderr,process.stderr]}).on("close",(w)=>w===0?l():f(Error("launch.mjs failed")))})}finally{i.release()}}export{nr as touchActivity,Z as refreshPortFile,y as probeGreedyChrome,vn as openNewTab,qe as killHeadlessChrome,Qe as killChrome,Xe as isChromeHeadless,An as getFullTabFromCache,pe as getAnyTab,Sn as ensureChrome,rr as detectHeadlessFromChromeCommandLine,Pn as closeTabs,lr as closeTab,sr as checkAndKillIdle,b as cdp,xn as activateTab};
430
+ } catch {}
431
+ return;
432
+ }
433
+ cleanupStaleSessions();
434
+ const wasKilled = await checkAndKillIdle();
435
+ let ready = wasKilled ? false : await probeGreedyChrome();
436
+ if (!ready && !wasKilled) {
437
+ await new Promise((r) => setTimeout(r, 500));
438
+ ready = await probeGreedyChrome();
439
+ }
440
+ let forceRelaunch = false;
441
+ if (ready) {
442
+ const headless = isChromeHeadless();
443
+ const wantsVisible = process.env.GREEDY_SEARCH_VISIBLE === "1";
444
+ if (!wantsVisible && !headless) {
445
+ process.stderr.write(`[greedysearch] Visible Chrome detected — switching to headless mode...
446
+ `);
447
+ await killHeadlessChrome();
448
+ await waitForPortDown();
449
+ forceRelaunch = true;
450
+ } else if (wantsVisible && headless) {
451
+ process.stderr.write(`[greedysearch] Headless Chrome detected — switching to visible mode...
452
+ `);
453
+ await killHeadlessChrome();
454
+ await waitForPortDown();
455
+ forceRelaunch = true;
456
+ }
457
+ }
458
+ const readyAfterModeCheck = forceRelaunch ? false : await probeGreedyChrome();
459
+ if (readyAfterModeCheck) {
460
+ await refreshPortFile();
461
+ try {
462
+ const md = readMetadata();
463
+ if (md) {
464
+ touchActivityBL(md);
465
+ registerClient(md);
466
+ }
467
+ } catch {}
468
+ return;
469
+ }
470
+ const lock = acquireLaunchLock();
471
+ if (!lock.acquired) {
472
+ const deadline = Date.now() + 12000;
473
+ let reReady = false;
474
+ while (Date.now() < deadline) {
475
+ reReady = await probeGreedyChrome(500);
476
+ if (reReady)
477
+ break;
478
+ await new Promise((r) => setTimeout(r, 250));
479
+ }
480
+ if (reReady) {
481
+ await refreshPortFile();
482
+ return;
483
+ }
484
+ }
485
+ try {
486
+ const reCheck = await probeGreedyChrome(1000);
487
+ if (reCheck) {
488
+ await refreshPortFile();
489
+ return;
490
+ }
491
+ process.stderr.write(`GreedySearch Chrome not running on port ${GREEDY_PORT} — auto-launching...
492
+ `);
493
+ const launchScript = resolveGreedySearchLaunchScript({
494
+ moduleDir: __dir,
495
+ entrypoint: process.argv[1],
496
+ env: process.env
497
+ });
498
+ const launchArgs = [launchScript];
499
+ if (process.env.GREEDY_SEARCH_VISIBLE !== "1")
500
+ launchArgs.push("--headless");
501
+ await new Promise((resolve, reject) => {
502
+ const proc = spawn(nodeRuntimeCommand(), launchArgs, {
503
+ stdio: ["ignore", process.stderr, process.stderr]
504
+ });
505
+ proc.on("close", (code) => code === 0 ? resolve() : reject(new Error("launch.mjs failed")));
506
+ });
507
+ } finally {
508
+ lock.release();
509
+ }
510
+ }