@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,359 +1,356 @@
1
- import{createRequire as Ne}from"node:module";var I=Ne(import.meta.url);import{createRequire as Re}from"node:module";var Bt=Re(import.meta.url),S=null;async function Ce(){if(S)return S;let[{Readability:e},{JSDOM:t},{default:r}]=await Promise.all([import("@mozilla/readability"),import("jsdom"),import("turndown")]),n=new r({headingStyle:"atx",bulletListMarker:"-",codeBlockStyle:"fenced"});return n.addRule("removeDataUrls",{filter:(i)=>i.tagName==="IMG"&&i.getAttribute("src")?.startsWith("data:"),replacement:()=>""}),S={Readability:e,JSDOM:t,turndown:n},S}var ne="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",ie={"user-agent":ne,accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8","accept-language":"en-US,en;q=0.9","accept-encoding":"gzip, deflate, br","cache-control":"no-cache",pragma:"no-cache","sec-ch-ua":'"Chromium";v="122", "Not(A:Brand";v="24", "Google Chrome";v="122"',"sec-ch-ua-mobile":"?0","sec-ch-ua-platform":'"Windows"',"sec-fetch-dest":"document","sec-fetch-mode":"navigate","sec-fetch-site":"none","sec-fetch-user":"?1","upgrade-insecure-requests":"1"},ae=[/^localhost$/i,/^127\.\d+\.\d+\.\d+$/,/^0\.0\.0\.0$/,/^\[::1\]$/,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^fc00:/i,/^fe80:/i,/\.local$/i,/\.internal$/i,/\.localhost$/i],Le=/^::ffff:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/i,Oe=/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i,Te=/^(?:0x[0-9a-f]+|0[0-7]*|[1-9][0-9]*)$/i;function Fe(e){if(!e||e.includes(":"))return null;let t=e.split(".");if(t.length<1||t.length>4)return null;if(!t.every((i)=>Te.test(i)))return null;let r=t.map((i)=>{if(/^0x/i.test(i))return parseInt(i,16);if(/^0[0-7]+$/.test(i))return parseInt(i,8);return parseInt(i,10)});if(r.some((i)=>!Number.isFinite(i)||i<0))return null;let n;if(r.length===1){if(r[0]>4294967295)return null;n=[r[0]>>>24&255,r[0]>>>16&255,r[0]>>>8&255,r[0]&255]}else if(r.length===2){if(r[0]>255||r[1]>16777215)return null;n=[r[0],r[1]>>>16&255,r[1]>>>8&255,r[1]&255]}else if(r.length===3){if(r[0]>255||r[1]>255||r[2]>65535)return null;n=[r[0],r[1],r[2]>>>8&255,r[2]&255]}else{if(r.some((i)=>i>255))return null;n=r}return n.join(".")}function xe(e){let t=e.match(Le);if(t)return`${t[1]}.${t[2]}.${t[3]}.${t[4]}`;let r=e.match(Oe);if(r){let n=parseInt(r[1],16),i=parseInt(r[2],16);if(n>65535||i>65535)return null;return[n>>>8&255,n&255,i>>>8&255,i&255].join(".")}return null}function te(e){return ae.some((t)=>t.test(e))}function oe(e={}){return{...ie,...e}}function j(e){try{if(typeof e!=="string"||!e.trim())return{blocked:!0,reason:"URL must be a non-empty string"};let t=new URL(e);if(t.protocol!=="http:"&&t.protocol!=="https:")return{blocked:!0,reason:`Protocol not allowed: ${t.protocol}`};let r=t.hostname.toLowerCase();for(let i of ae)if(i.test(r))return{blocked:!0,reason:`Private/internal address: ${r}`};if(r.startsWith("[")&&r.endsWith("]")){let i=r.slice(1,-1),a=xe(i);if(a&&te(a))return{blocked:!0,reason:`Private/internal address: ${r} (maps to ${a})`}}let n=Fe(r);if(n&&te(n))return{blocked:!0,reason:`Private/internal address: ${r} (normalizes to ${n})`};return{blocked:!1}}catch(t){return{blocked:!0,reason:`Invalid URL: ${t.message}`}}}function Ge(e){try{let t=new URL(e);if(!(t.hostname==="github.com"||t.hostname.endsWith(".github.com")))return e;let r=t.pathname.split("/").filter(Boolean);if(r.length<5)return e;let[n,i,a,o,...s]=r;if(a!=="blob")return e;let l=s.join("/");return`https://raw.githubusercontent.com/${n}/${i}/${o}/${l}`}catch{return e}}async function se(e,t={}){let r=j(e);if(r.blocked)return{ok:!1,url:e,finalUrl:e,status:403,error:`Blocked: ${r.reason}`,needsBrowser:!1};let n=e;if(e=Ge(e),e!==n)console.error(`[fetcher] Rewrote GitHub URL: ${n.slice(0,60)}... → raw.githubusercontent.com`);let{timeoutMs:i=15000,userAgent:a,signal:o}=t,s=new AbortController,l=setTimeout(()=>s.abort(),i);if(o)o.addEventListener("abort",()=>s.abort(),{once:!0});try{let c=await fetch(e,{method:"GET",headers:{...ie,"user-agent":a||ne},redirect:"follow",signal:s.signal});clearTimeout(l);let u=c.headers.get("content-type")||"",f=c.url,d=c.headers.get("last-modified")||"",p=j(f);if(p.blocked)return{ok:!1,url:e,finalUrl:f,status:c.status,error:`Blocked: ${p.reason}`,needsBrowser:!1};let h=!1;try{h=new URL(f).hostname.toLowerCase()==="raw.githubusercontent.com"}catch{}if(u.includes("text/plain")&&h){let T=await c.text();return{ok:!0,url:n,finalUrl:f,status:c.status,title:f.split("/").pop()||"GitHub File",byline:"",siteName:"GitHub",lang:"",publishedTime:d,lastModified:d,markdown:T,contentLength:T.length,excerpt:T.slice(0,300).replaceAll(/\n/g," "),needsBrowser:!1}}if(!u.includes("text/html")&&!u.includes("application/xhtml"))return{ok:!1,url:e,finalUrl:f,status:c.status,error:`Unsupported content type: ${u}`,needsBrowser:!1};let y=await c.text(),m=F(c.status,y,f,e);if(m.blocked)return{ok:!1,url:e,finalUrl:f,status:c.status,error:`Blocked: ${m.reason}`,needsBrowser:!0};let w=await x(y,f),ee=G(w);if(!ee.ok)return{ok:!1,url:e,finalUrl:f,status:c.status,error:`Low quality content: ${ee.reason}`,needsBrowser:!0};return{ok:!0,url:e,finalUrl:f,status:c.status,title:w.title,byline:w.byline,siteName:w.siteName,lang:w.lang,publishedTime:w.publishedTime||d,lastModified:d,markdown:w.markdown,excerpt:w.excerpt,contentLength:w.markdown.length,needsBrowser:!1}}catch(c){clearTimeout(l);let u=Be(c);return{ok:!1,url:e,finalUrl:e,status:0,error:c.message,needsBrowser:u}}}function F(e,t,r,n){let i=t.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1]?.toLowerCase()||"",a=t.slice(0,30000).toLowerCase(),o=`${i} ${a}`;if(e===403||e===429||e===503)return{blocked:!0,reason:`HTTP ${e}`};let s=[{pattern:/class=["'][^"']*captcha["']|<div[^>]*id=["']captcha/i,reason:"captcha"},{pattern:/g-recaptcha|data-sitekey|i['"]m not a robot/i,reason:"captcha"},{pattern:/checking your browser.{0,100}please wait|cf-browser-verification/i,reason:"cloudflare challenge"},{pattern:/just a moment.{0,50}security check|ddos protection by cloudflare/i,reason:"cloudflare challenge"},{pattern:/unusual traffic.{0,50}from your computer network/i,reason:"unusual traffic"},{pattern:/bot detected|automated.{0,20}request/i,reason:"bot detection"},{pattern:/enable\s+javascript\s+to\s+view|javascript\s+is\s+required.{0,50}enabled/i,reason:"requires javascript"},{pattern:/access denied|accessdenied/i,reason:"access denied"},{pattern:/protected by anubis|anubis uses a proof-of-work/i,reason:"anubis challenge"}];for(let c of s)if(c.pattern.test(o))return{blocked:!0,reason:c.reason};let l=Ye(n,r,t);if(l)return{blocked:!0,reason:l};return{blocked:!1}}var He=["accounts.google.com","login.microsoftonline.com","login.live.com","auth0.com","okta.com","auth.mozilla.auth0.com","id.atlassian.com"],Me=["login.","signin.","auth.","sso.","accounts.","idp."],We=["sign in to continue","log in to continue","authentication required","create an account to continue","subscribe to continue reading","members only"];function Ye(e,t,r){try{let n=new URL(e),i=new URL(t);if(n.hostname.toLowerCase()===i.hostname.toLowerCase())return;let a=i.hostname.toLowerCase();if(He.some((s)=>a===s||a.endsWith(`.${s}`)))return`redirected to login (${i.hostname})`;if(Me.some((s)=>a.startsWith(s)))return`redirected to login (${i.hostname})`;let o=r.slice(0,20000).toLowerCase();if(We.some((s)=>o.includes(s)))return`redirected to login page (${i.hostname})`}catch{}return}function Be(e){let t=e.message.toLowerCase();return t.includes("fetch failed")||t.includes("unable to verify")||t.includes("certificate")||t.includes("timeout")}function re(e){let t=['meta[property="article:published_time"]','meta[name="article:published_time"]','meta[property="og:published_time"]','meta[name="publication_date"]','meta[name="date"]','meta[itemprop="datePublished"]','time[itemprop="datePublished"]','meta[name="DC.date"]'];for(let r of t){let n=e.querySelector(r),i=n?.getAttribute("content")||n?.getAttribute("datetime")||"";if(i)return i}return""}async function x(e,t){let{Readability:r,JSDOM:n,turndown:i}=await Ce(),a=new n(e,{url:t});try{let o=a.window.document,s=new r(o).parse();if(s&&s.content){let c=i.turndown(s.content).replaceAll(/\n{3,}/g,`
2
-
3
- `).trim(),u=s.publishedTime||re(o)||"";return{title:s.title||o.title||t,byline:s.byline||"",siteName:s.siteName||"",lang:s.lang||"",publishedTime:u,markdown:c,excerpt:c.slice(0,300).replaceAll(/\n/g," ")}}let l=o.body;if(l){let c=l.cloneNode(!0);c.querySelectorAll("script, style, nav, footer, header, aside").forEach((f)=>f.remove());let u=(c.textContent||"").replaceAll(/\s+/g," ").trim();return{title:o.title||t,byline:"",siteName:"",lang:"",publishedTime:re(o),markdown:u,excerpt:u.slice(0,300)}}return{title:t,byline:"",siteName:"",lang:"",publishedTime:"",markdown:"",excerpt:""}}finally{a.window.close()}}function G(e){let t=e.markdown.trim().toLowerCase(),r=(e.title||"").toLowerCase();if(e.markdown.trim().length<100)return{ok:!1,reason:"content too short (< 100 chars)"};let n=t.toLowerCase(),i=[{check:()=>n.includes("loading")&&n.includes("please wait"),desc:"loading page"},{check:()=>n.includes("please ensure javascript is enabled"),desc:"requires javascript"},{check:()=>n.includes("enable javascript to view"),desc:"requires javascript"},{check:()=>n.includes("just a moment"),desc:"cloudflare challenge detected in content"},{check:()=>n.includes("verify you are human"),desc:"human verification"},{check:()=>n.includes("captcha required"),desc:"captcha in extracted content"},{check:()=>n.includes("access denied"),desc:"access denied in content"},{check:()=>/^\s{0,10}sign\s{1,5}in\s{0,10}$|^\s{0,10}log\s{1,5}in\s{0,10}$/im.test(t),desc:"login form only"}];for(let{check:a,desc:o}of i)if(a())return{ok:!1,reason:o};if(r.includes("just a moment")||r.includes("checking your browser"))return{ok:!1,reason:"cloudflare challenge page detected in title"};return{ok:!0}}var ce={"user-agent":"GreedySearch/1.0",accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"};function k(e){try{let t=new URL(e);if(!(t.hostname==="github.com"||t.hostname.endsWith(".github.com")))return null;let r=t.pathname.split("/").filter(Boolean);if(r.length<2)return null;let[n,i]=r;if(r.length===2)return{owner:n,repo:i,type:"root"};if(r.length>=4&&(r[2]==="blob"||r[2]==="tree")){let a=r[2],o=r[3],s=r.slice(4).join("/");return{owner:n,repo:i,type:a,ref:o,path:s}}return null}catch{return null}}async function b(e,t=1e4){let r=new AbortController,n=setTimeout(()=>r.abort(),t);try{let i=await fetch(`https://api.github.com${e}`,{headers:ce,signal:r.signal});if(clearTimeout(n),!i.ok)throw Error(`GitHub API ${i.status}: ${e}`);return await i.json()}catch(i){throw clearTimeout(n),i}}async function Ue(e,t){try{let r=await b(`/repos/${e}/${t}/readme`);if(r.content&&r.encoding==="base64")return Buffer.from(r.content,"base64").toString("utf8");return""}catch{return""}}async function le(e,t,r="HEAD",n="",i){try{let a;if(r==="HEAD")if(i)a=await b(`/repos/${e}/${t}/git/ref/heads/${i}`).catch(()=>null);else a=await Promise.any([b(`/repos/${e}/${t}/git/ref/heads/main`),b(`/repos/${e}/${t}/git/ref/heads/master`)]).catch(()=>null);else a=await b(`/repos/${e}/${t}/git/ref/heads/${r}`).catch(()=>b(`/repos/${e}/${t}/git/ref/heads/master`).catch(()=>null));if(!a?.object?.sha)return[];let o=(await b(`/repos/${e}/${t}/git/commits/${a.object.sha}`)).tree.sha,s=(await b(`/repos/${e}/${t}/git/trees/${o}`)).tree||[];if(n)s=s.filter((l)=>l.path.startsWith(n));return s.slice(0,50).map((l)=>({path:l.path,type:l.type==="tree"?"dir":"file",size:l.size}))}catch{return[]}}async function Je(e,t,r,n,i=1e4,a){let o=async(l)=>{let c=new AbortController,u=setTimeout(()=>c.abort(),i);try{let f=await fetch(l,{headers:{"user-agent":ce["user-agent"]},signal:c.signal});if(clearTimeout(u),f.ok)return await f.text();throw Error("not ok")}catch{throw clearTimeout(u),Error("failed")}};if(!r||r==="HEAD"){if(a)try{return await o(`https://raw.githubusercontent.com/${e}/${t}/${a}/${n}`)}catch{return null}try{return await Promise.any([o(`https://raw.githubusercontent.com/${e}/${t}/main/${n}`),o(`https://raw.githubusercontent.com/${e}/${t}/master/${n}`)])}catch{return null}}let s=[`https://raw.githubusercontent.com/${e}/${t}/${r}/${n}`,`https://raw.githubusercontent.com/${e}/${t}/master/${n}`];for(let l of s)try{return await o(l)}catch{}return null}async function ue(e){let t=k(e);if(!t)return{ok:!1,error:"Not a valid GitHub URL"};let{owner:r,repo:n,type:i,ref:a,path:o}=t;try{if(i==="root"||i==="tree"&&!o){let s=await b(`/repos/${r}/${n}`),[l,c]=await Promise.allSettled([Ue(r,n),le(r,n,a||"HEAD","",s.default_branch)]),u=l.status==="fulfilled"?l.value:"",f=c.status==="fulfilled"?c.value:[],d=s?.description?`
4
-
5
- > ${s.description}`:"",p=s?.stargazers_count==null?"":` ⭐ ${s.stargazers_count}`,h=s?.language?` · ${s.language}`:"",y=`# ${r}/${n}${p}${h}${d}
6
-
7
- `;if(u)y+=u.slice(0,6000);else y+=`[No README found]
8
-
9
- Files:
10
- ${f.map((m)=>` ${m.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${m.path}`).join(`
11
- `)}`;return{ok:!0,title:`${r}/${n}`,content:y,tree:f.slice(0,30)}}if(i==="blob"&&o){let s;if(!a||a==="HEAD")try{s=(await b(`/repos/${r}/${n}`)).default_branch}catch{s=void 0}let l=await Je(r,n,a,o,1e4,s);if(l===null)return{ok:!1,error:`File not found: ${o}`};return{ok:!0,title:`${r}/${n}: ${o}`,content:l}}if(i==="tree"&&o){let s;if(!a||a==="HEAD")try{s=(await b(`/repos/${r}/${n}`)).default_branch}catch{s=void 0}let l=await le(r,n,a||"HEAD",o,s),c=l.map((u)=>` ${u.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${u.path}`).join(`
12
- `);return{ok:!0,title:`${r}/${n}/${o}`,content:`[Directory: ${o}]
13
-
14
- Files:
15
- ${c}`,tree:l}}return{ok:!1,error:"Unsupported GitHub URL type"}}catch(s){return{ok:!1,error:s.message}}}var qe={"user-agent":"GreedySearch/1.0 (Research Bot)",accept:"application/json"};function pe(e){try{let t=new URL(e),r=t.hostname.toLowerCase();if(!(r==="reddit.com"||r.endsWith(".reddit.com")))return null;let n=t.pathname;if(n.match(/^\/(u|user)\/[^/]+\/?$/i))return{type:"user",cleanUrl:fe(e)};if(n.match(/^\/r\/[^/]+\/comments\/[^/]+/i))return{type:"post",cleanUrl:fe(e)};return null}catch{return null}}function fe(e){try{let t=new URL(e);return`${t.protocol}//${t.hostname}${t.pathname}`}catch{return e}}async function ge(e,t=8000){let r=Date.now();try{let n=e.replace(/\/+$/,"")+".json",i=new AbortController,a=setTimeout(()=>i.abort(),15000),o=await fetch(n,{headers:qe,signal:i.signal});if(clearTimeout(a),!o.ok)throw Error(`Reddit API ${o.status}`);let s=await o.json();if(!Array.isArray(s)||s.length<1)throw Error("Invalid Reddit API response structure");let l=s[0],c=s[1],u=l?.data?.children?.[0]?.data;if(!u)throw Error("No post data in Reddit response");let f=Ve(u,c,t);return{ok:!0,url:e,finalUrl:e,status:200,contentType:"text/markdown",lastModified:"",title:u.title||"Reddit Post",byline:`u/${u.author}`,siteName:`r/${u.subreddit}`,lang:"en",publishedTime:new Date(u.created_utc*1000).toISOString(),excerpt:u.selftext?.slice(0,300).replace(/\n/g," ")||"",markdown:f,contentLength:f.length,needsBrowser:!1,duration:Date.now()-r}}catch(n){return{ok:!1,url:e,finalUrl:e,status:0,error:`Reddit fetch failed: ${n.message}`,needsBrowser:!1,duration:Date.now()-r}}}function Ve(e,t,r){let n="";if(n+=`# ${e.title}
16
-
17
- `,n+=`**Subreddit:** r/${e.subreddit} | **Author:** u/${e.author} | **Score:** ${e.score}
18
-
19
- `,e.selftext)n+=e.selftext,n+=`
20
-
21
- `;else if(e.url)try{let i=new URL(e.url).hostname.toLowerCase();if(i!=="reddit.com"&&!i.endsWith(".reddit.com"))n+=`**Link:** ${e.url}
22
-
23
- `}catch{n+=`**Link:** ${e.url}
24
-
25
- `}if(t?.data?.children?.length>0){n+=`---
26
-
27
- ## Comments
28
-
29
- `;let i=t.data.children.filter((a)=>a.kind==="t1").slice(0,10);for(let a of i)n+=de(a.data,0),n+=`
30
- `}if(n.length>r)n=n.slice(0,r).trim()+`
31
-
32
- ... (truncated)`;return n}function de(e,t){if(!e||e.body==="[deleted]"||e.body==="[removed]")return"";let r="> ".repeat(t),n="";if(n+=`${r}**u/${e.author}** (${e.score} pts)
33
- `,n+=`${r}${e.body.replaceAll(`
34
- `,`
35
- `+r)}
36
- `,t<3&&e.replies?.data?.children){let i=e.replies.data.children.filter((a)=>a.kind==="t1");for(let a of i.slice(0,5))n+=`
37
- `+de(a.data,t+1)}return n}function A(e,t=8000){if(!e||e.length<=t)return e;let r=`
38
-
39
- [...content trimmed...]
40
-
41
- `,n=t-r.length,i=Math.floor(n*0.75),a=n-i,o=i;while(o>i-100&&e[o]!==`
42
- `)o--;if(o<=i-100)o=i;let s=e.length-a;while(s<e.length-a+100&&e[s]!==`
43
- `)s++;if(s>=e.length-a+100)s=e.length-a;let l=e.slice(0,o).trimEnd(),c=e.slice(s).trimStart();return`${l}${r}${c}`}import{spawn as Ze}from"node:child_process";import{basename as Xe}from"node:path";import{dirname as Qe,join as Ke}from"node:path";import{fileURLToPath as ze}from"node:url";import{fileURLToPath as ot}from"node:url";import{existsSync as N,mkdirSync as lt,readFileSync as ve,writeFileSync as ct}from"node:fs";import{homedir as ut}from"node:os";import{join as _e}from"node:path";import{tmpdir as ft}from"node:os";import{existsSync as R,mkdirSync as yt,readFileSync as Ee,writeFileSync as wt}from"node:fs";import{homedir as bt}from"node:os";import{join as $e}from"node:path";import{tmpdir as vt}from"node:os";function et(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=Xe(t||"").toLowerCase();if(n==="node"||n==="node.exe")return t;return"node"}var tt=Qe(ze(import.meta.url)),rt=Ke(tt,"..","bin","cdp.mjs"),nt=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"]);function it(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(!nt.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 be(e,t=30000){return at(e,null,t)}function at(e,t=null,r=30000){let n=it(e);return new Promise((i,a)=>{let o=Ze(et(),[rt,...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 c=setTimeout(()=>{o.kill(),a(Error(`cdp timeout: ${e[0]}`))},r);o.on("close",(u)=>{if(clearTimeout(c),u===0)i(s.trim());else a(Error(l.trim()||`cdp exit ${u}`))})})}async function he(e){await be(["evalraw",e,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
44
- (function() {
45
- // ── Runtime.enable / CDP detection masking ──────────────
46
- try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
47
- try { delete window.__REBROWSER_DEVTOOLS; } catch(_) {}
48
- try { delete window.__nightmare; } catch(_) {}
49
- try { delete window.__phantom; } catch(_) {}
50
- try { delete window.callPhantom; } catch(_) {}
51
- try { delete window._phantom; } catch(_) {}
52
- try { delete window.Buffer; } catch(_) {}
53
-
54
- // Real Chrome without automation should not expose navigator.webdriver at all.
55
- // A literal false or an own-property getter returning undefined is itself a
56
- // common stealth tell; remove both instance and prototype properties when the
57
- // descriptor is configurable (as it is with --disable-blink-features).
58
- try { delete navigator.webdriver; } catch(_) {}
59
- try { delete Navigator.prototype.webdriver; } catch(_) {}
60
- Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
61
- Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
62
- Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
63
- Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
64
- Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
65
- Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
66
- var __greedyMimeTypes = null;
67
- function __makeMimeTypes() {
68
- var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
69
- var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
70
- try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
71
- try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
72
- var m = [pdf, textPdf];
73
- try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
74
- m.item = function item(i) { return this[i] || null; };
75
- m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
76
- return m;
77
- }
78
- Object.defineProperty(navigator, 'plugins', {
79
- get: () => {
80
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
81
- var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
82
- var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
83
- var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
84
- try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
85
- try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
86
- try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
87
- var p = [plugin0, plugin1, plugin2];
88
- p.item = function item(i) { return this[i] || null; };
89
- p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
90
- p.refresh = function refresh() {};
91
- try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
1
+ import {
2
+ fetchSourceHttp,
3
+ extractContent,
4
+ detectBotBlock,
5
+ checkContentQuality,
6
+ defaultFetchHeaders,
7
+ isPrivateUrl
8
+ } from "../fetcher.mjs";
9
+ import { fetchGitHubContent, parseGitHubUrl } from "../github.mjs";
10
+ import { fetchRedditContent, parseRedditUrl } from "../reddit.mjs";
11
+ import { trimContentHeadTail } from "../utils/content.mjs";
12
+ import { cdp, closeTab, openNewTab } from "./chrome.mjs";
13
+ import { SOURCE_FETCH_CONCURRENCY } from "./constants.mjs";
14
+ import { extractPdfMarkdown } from "./pdf.mjs";
15
+ import { trimText } from "./sources.mjs";
16
+ async function fetchSourceViaChrome(tab, url, maxChars = 8000) {
17
+ const start = Date.now();
18
+ try {
19
+ const frames = await cdp(["evalraw", tab, "Page.getFrameTree", "{}"]).then((r) => JSON.parse(r)).catch(() => null);
20
+ const frameId = frames?.frameTree?.frame?.id || undefined;
21
+ const raw = await cdp([
22
+ "evalraw",
23
+ tab,
24
+ "Network.loadNetworkResource",
25
+ JSON.stringify({
26
+ frameId,
27
+ url,
28
+ options: { disableCache: true, includeCredentials: false }
29
+ })
30
+ ], 20000);
31
+ const result = JSON.parse(raw);
32
+ const resource = result.resource;
33
+ if (!resource?.success || !resource.httpStatusCode) {
34
+ return {
35
+ url,
36
+ error: resource?.netErrorName || resource?.netError || "loadNetworkResource failed",
37
+ source: "chrome",
38
+ duration: Date.now() - start,
39
+ needsFallback: true
40
+ };
41
+ }
42
+ let body = "";
43
+ if (resource.stream) {
92
44
  try {
93
- __greedyMimeTypes[0].enabledPlugin = p[0];
94
- __greedyMimeTypes[1].enabledPlugin = p[0];
95
- } catch(_) {}
96
- return p;
97
- },
98
- configurable: true,
99
- });
100
- Object.defineProperty(navigator, 'mimeTypes', {
101
- get: () => {
102
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
103
- return __greedyMimeTypes;
104
- },
105
- configurable: true,
106
- });
107
- Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
45
+ const ioRaw = await cdp([
46
+ "evalraw",
47
+ tab,
48
+ "IO.read",
49
+ JSON.stringify({ handle: resource.stream })
50
+ ], 1e4);
51
+ const ioResult = JSON.parse(ioRaw);
52
+ body = ioResult.data || "";
53
+ await cdp([
54
+ "evalraw",
55
+ tab,
56
+ "IO.close",
57
+ JSON.stringify({ handle: resource.stream })
58
+ ]).catch(() => {});
59
+ } catch {}
60
+ }
61
+ if (!body || body.length < 100) {
62
+ return {
63
+ url,
64
+ error: "Empty response body from Network.loadNetworkResource",
65
+ source: "chrome",
66
+ duration: Date.now() - start,
67
+ needsFallback: true
68
+ };
69
+ }
70
+ const botCheck = detectBotBlock(resource.httpStatusCode, body, url, url);
71
+ if (botCheck.blocked) {
72
+ return {
73
+ url,
74
+ status: resource.httpStatusCode,
75
+ error: `Blocked: ${botCheck.reason}`,
76
+ source: "chrome",
77
+ duration: Date.now() - start,
78
+ needsBrowser: true
79
+ };
80
+ }
81
+ const extracted = await extractContent(body, url);
82
+ const quality = checkContentQuality(extracted);
83
+ if (!quality.ok) {
84
+ return {
85
+ url,
86
+ status: resource.httpStatusCode,
87
+ error: `Low quality: ${quality.reason}`,
88
+ source: "chrome",
89
+ duration: Date.now() - start,
90
+ needsBrowser: true
91
+ };
92
+ }
93
+ const content = trimContentHeadTail(extracted.markdown, maxChars);
94
+ return {
95
+ url,
96
+ finalUrl: url,
97
+ status: resource.httpStatusCode,
98
+ contentType: "text/markdown",
99
+ lastModified: "",
100
+ publishedTime: extracted.publishedTime || "",
101
+ byline: extracted.byline || "",
102
+ siteName: extracted.siteName || "",
103
+ lang: extracted.lang || "",
104
+ title: extracted.title || url,
105
+ snippet: extracted.excerpt,
106
+ content,
107
+ contentChars: content.length,
108
+ source: "chrome",
109
+ duration: Date.now() - start
110
+ };
111
+ } catch (error) {
112
+ return {
113
+ url,
114
+ error: error.message,
115
+ source: "chrome",
116
+ duration: Date.now() - start,
117
+ needsFallback: true
118
+ };
119
+ }
120
+ }
121
+ function isLikelyPdfUrl(url) {
108
122
  try {
109
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
110
- } catch(_) {}
111
- if (!navigator.mediaDevices) {
112
- Object.defineProperty(navigator, 'mediaDevices', {
113
- get: () => ({
114
- enumerateDevices: () => Promise.resolve([
115
- { deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
116
- { deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
117
- { deviceId: '', kind: 'videoinput', label: '', groupId: '' },
118
- ]),
119
- getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
120
- getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
121
- }),
122
- configurable: true,
123
- });
123
+ const parsed = new URL(url);
124
+ return parsed.pathname.toLowerCase().endsWith(".pdf");
125
+ } catch {
126
+ return false;
127
+ }
128
+ }
129
+ async function fetchPdfSourceHttp(url, maxChars = 8000) {
130
+ const privateCheck = isPrivateUrl(url);
131
+ if (privateCheck.blocked) {
132
+ return {
133
+ url,
134
+ finalUrl: url,
135
+ status: 403,
136
+ error: `Blocked: ${privateCheck.reason}`,
137
+ source: "pdf-http"
138
+ };
124
139
  }
125
- // ── Missing platform APIs (headless often lacks these) ─
140
+ const controller = new AbortController;
141
+ const timeoutId = setTimeout(() => controller.abort(), 20000);
142
+ const start = Date.now();
126
143
  try {
127
- if (!navigator.share) {
128
- navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
144
+ const response = await fetch(url, {
145
+ method: "GET",
146
+ redirect: "follow",
147
+ signal: controller.signal,
148
+ headers: defaultFetchHeaders({
149
+ accept: "application/pdf,application/octet-stream;q=0.9,*/*;q=0.5"
150
+ })
151
+ });
152
+ clearTimeout(timeoutId);
153
+ const contentType = response.headers.get("content-type") || "";
154
+ const finalUrl = response.url || url;
155
+ const contentLength = Number.parseInt(response.headers.get("content-length") || "0", 10);
156
+ if (response.status >= 400) {
157
+ return {
158
+ url,
159
+ finalUrl,
160
+ status: response.status,
161
+ error: `HTTP ${response.status}`,
162
+ source: "pdf-http",
163
+ duration: Date.now() - start
164
+ };
129
165
  }
130
- } catch(_) {}
131
- try {
132
- if (!navigator.contentIndex) {
133
- Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
166
+ if (!contentType.toLowerCase().includes("application/pdf") && !isLikelyPdfUrl(finalUrl)) {
167
+ return null;
168
+ }
169
+ if (contentLength > 30 * 1024 * 1024) {
170
+ return {
171
+ url,
172
+ finalUrl,
173
+ status: response.status,
174
+ error: `PDF too large: ${contentLength} bytes`,
175
+ source: "pdf-http",
176
+ duration: Date.now() - start
177
+ };
134
178
  }
135
- } catch(_) {}
136
-
137
- if (!window.chrome) {
138
- window.chrome = {
139
- app: { isInstalled: false, InstallState: {}, RunningState: {} },
140
- runtime: {
141
- OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
142
- connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
143
- },
144
- 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' }; },
145
- csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
179
+ const buffer = Buffer.from(await response.arrayBuffer());
180
+ const pdf = await extractPdfMarkdown(buffer, finalUrl);
181
+ if (!pdf || pdf.error) {
182
+ return {
183
+ url,
184
+ finalUrl,
185
+ status: response.status,
186
+ error: pdf?.error || "PDF text extraction failed",
187
+ source: "pdf-http",
188
+ duration: Date.now() - start
189
+ };
190
+ }
191
+ const content = trimContentHeadTail(pdf.content, maxChars);
192
+ return {
193
+ url,
194
+ finalUrl,
195
+ status: response.status,
196
+ contentType: "application/pdf",
197
+ lastModified: response.headers.get("last-modified") || "",
198
+ title: pdf.title,
199
+ snippet: trimText(content, 320),
200
+ content,
201
+ contentChars: content.length,
202
+ pages: pdf.pages,
203
+ source: "pdf-http",
204
+ duration: Date.now() - start
205
+ };
206
+ } catch (error) {
207
+ clearTimeout(timeoutId);
208
+ return {
209
+ url,
210
+ finalUrl: url,
211
+ error: error.message || String(error),
212
+ source: "pdf-http",
213
+ duration: Date.now() - start
146
214
  };
147
215
  }
148
- var __greedyNativeFns = [];
149
- function __markNative(fn) { try { __greedyNativeFns.push(fn); } catch(_) {} return fn; }
150
-
151
- var origQuery = navigator.permissions?.query;
152
- if (origQuery) {
153
- navigator.permissions.query = __markNative(function query(params) {
154
- if (params && params.name === 'notifications') return Promise.resolve({ state: Notification.permission || 'default', onchange: null });
155
- return origQuery.apply(this, arguments);
156
- });
216
+ }
217
+ export async function fetchSourceContent(url, maxChars = 8000) {
218
+ const start = Date.now();
219
+ if (isLikelyPdfUrl(url)) {
220
+ const pdfResult = await fetchPdfSourceHttp(url, maxChars);
221
+ if (pdfResult?.content || pdfResult?.status === 403)
222
+ return pdfResult;
157
223
  }
158
- try {
159
- var getParam = WebGLRenderingContext.prototype.getParameter;
160
- WebGLRenderingContext.prototype.getParameter = __markNative(function getParameter(p) {
161
- if (p === 37445) return 'Intel Inc.';
162
- if (p === 37446) return 'Intel Iris OpenGL Engine';
163
- return getParam.call(this, p);
164
- });
165
- } catch(_) {}
166
- // ── WebGL readPixels noise ──────────────────────────
167
- // CreepJS and other fingerprinters draw content with WebGL and read back the
168
- // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
169
- try {
170
- var origReadPixels = WebGLRenderingContext.prototype.readPixels;
171
- WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
172
- var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
173
- if (pixels && pixels.length > 0) {
174
- pixels[0] ^= 1;
175
- }
176
- return result;
177
- });
178
- } catch(_) {}
179
- Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
180
- Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
181
-
182
- // ── Canvas fingerprint noise ─────────────────────────
183
- // Headless rendering engines produce slightly different canvas output
184
- // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
185
- try {
186
- var __canvasNoise = ((Date.now() & 0xFF) | 1);
187
- var origFill = CanvasRenderingContext2D.prototype.fillText;
188
- CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
189
- this.globalAlpha = 0.9995;
190
- return origFill.apply(this, arguments);
191
- });
192
- } catch(_) {}
193
- try {
194
- var origStroke = CanvasRenderingContext2D.prototype.strokeText;
195
- CanvasRenderingContext2D.prototype.strokeText = __markNative(function strokeText() {
196
- this.globalAlpha = 0.9995;
197
- return origStroke.apply(this, arguments);
198
- });
199
- } catch(_) {}
200
- try {
201
- var origToDataURL = HTMLCanvasElement.prototype.toDataURL;
202
- HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
203
- var ctx = this.getContext('2d');
204
- if (ctx) {
205
- // Spread noise across canvas to break hash-based fingerprinting.
206
- // Uses a deterministic pattern so it's consistent per page load
207
- // but varies between sessions.
208
- var w = this.width, h = this.height;
209
- if (w > 0 && h > 0) {
210
- var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
211
- if (imgData && imgData.data) {
212
- for (var __i = 0; __i < imgData.data.length; __i += 4) {
213
- imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
214
- }
215
- ctx.putImageData(imgData, 0, 0);
216
- }
217
- }
218
- }
219
- return origToDataURL.apply(this, arguments);
220
- });
221
- } catch(_) {}
222
-
223
- // ── AudioContext fingerprint noise ────────────────────
224
- // Headless Chrome's AudioContext produces slightly different output.
225
- // Subtle noise breaks audio-based fingerprinting.
226
- try {
227
- var __audioSeed = ((Date.now() & 0x1F) | 1);
228
- var origGetChannelData = AudioBuffer.prototype.getChannelData;
229
- AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
230
- var data = origGetChannelData.call(this, channel);
231
- for (var __i = 0; __i < data.length; __i += 64) {
232
- data[__i] *= 0.99999;
233
- }
234
- return data;
235
- });
236
- } catch(_) {}
237
-
238
- // ── window outer dimensions ──────────────────────────
239
- // outerWidth/Height = 0 in headless — a well-known bot signal.
240
- // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
241
- try {
242
- if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
243
- if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
244
- } catch(_) {}
245
-
246
- // ── screen properties ─────────────────────────────────
247
- // Headless Chrome often reports an 800x600 screen even when the viewport is
248
- // 1920x1080. Keep screen metrics internally consistent with our launch flags.
249
- try {
250
- Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
251
- Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
252
- Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
253
- Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
254
- Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
255
- Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
256
- } catch(_) {}
257
-
258
- // ── navigator.userAgentData (UA Client Hints) ─────────
259
- // Derive version from the UA string already set by --user-agent flag so the
260
- // two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
261
- try {
262
- var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
263
- var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
264
- var _brands = [
265
- { brand: 'Not)A;Brand', version: '99' },
266
- { brand: 'Google Chrome', version: _uaMajor },
267
- { brand: 'Chromium', version: _uaMajor },
268
- ];
269
- Object.defineProperty(navigator, 'userAgentData', {
270
- get: function() {
224
+ if (parseGitHubUrl(url)) {
225
+ const parsed = parseGitHubUrl(url);
226
+ if (parsed && (parsed.type === "root" || parsed.type === "tree" || parsed.type === "blob" && !parsed.path?.includes("."))) {
227
+ const ghResult = await fetchGitHubContent(url);
228
+ if (ghResult.ok) {
229
+ const content = trimContentHeadTail(ghResult.content, maxChars);
271
230
  return {
272
- brands: _brands, mobile: false, platform: 'Windows',
273
- getHighEntropyValues: function() {
274
- return Promise.resolve({
275
- architecture: 'x86', bitness: '64',
276
- brands: _brands,
277
- fullVersionList: [
278
- { brand: 'Not)A;Brand', version: '99.0.0.0' },
279
- { brand: 'Google Chrome', version: _uaFull },
280
- { brand: 'Chromium', version: _uaFull },
281
- ],
282
- mobile: false, model: '', platform: 'Windows',
283
- platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
284
- });
285
- },
286
- toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
231
+ url,
232
+ finalUrl: url,
233
+ status: 200,
234
+ contentType: "text/markdown",
235
+ lastModified: "",
236
+ title: ghResult.title,
237
+ snippet: content.slice(0, 320),
238
+ content,
239
+ contentChars: content.length,
240
+ source: "github-api",
241
+ ...ghResult.tree && { tree: ghResult.tree },
242
+ duration: Date.now() - start
287
243
  };
288
- },
289
- configurable: true,
290
- });
291
- } catch(_) {}
292
-
293
- // ── CDP Runtime serialization guard ──────────────────
294
- // Sites detect CDP by putting a getter on Error.prototype.stack
295
- // and checking if console.log triggers it (only happens when
296
- // Runtime domain is enabled). We monkey-patch console methods to
297
- // strip custom getters from arguments before they reach CDP.
298
- try {
299
- var _origLog = console.log, _origError = console.error,
300
- _origWarn = console.warn, _origDebug = console.debug,
301
- _origInfo = console.info;
302
- var _safeArg = function(a) {
303
- if (a instanceof Error) {
304
- try { return new Error(a.message); } catch(_) { return a; }
305
244
  }
306
- return a;
245
+ process.stderr.write(`[greedysearch] GitHub API fetch failed, trying HTTP: ${ghResult.error}
246
+ `);
247
+ }
248
+ }
249
+ const redditInfo = parseRedditUrl(url);
250
+ if (redditInfo?.type === "post") {
251
+ process.stderr.write(`[greedysearch] Using Reddit JSON API for: ${url.slice(0, 60)}...
252
+ `);
253
+ const redditResult = await fetchRedditContent(url, maxChars);
254
+ if (redditResult.ok) {
255
+ const content = trimContentHeadTail(redditResult.markdown, maxChars);
256
+ return {
257
+ url,
258
+ finalUrl: redditResult.finalUrl,
259
+ status: redditResult.status,
260
+ contentType: "text/markdown",
261
+ lastModified: redditResult.lastModified || "",
262
+ publishedTime: redditResult.publishedTime || "",
263
+ byline: redditResult.byline || "",
264
+ siteName: redditResult.siteName || "",
265
+ lang: redditResult.lang || "",
266
+ title: redditResult.title,
267
+ snippet: redditResult.excerpt,
268
+ content,
269
+ contentChars: content.length,
270
+ source: "reddit-api",
271
+ duration: Date.now() - start
272
+ };
273
+ }
274
+ process.stderr.write(`[greedysearch] Reddit API fetch failed, falling back to HTTP: ${redditResult.error}
275
+ `);
276
+ }
277
+ const httpResult = await fetchSourceHttp(url, { timeoutMs: 1e4 });
278
+ if (httpResult.ok) {
279
+ const content = trimContentHeadTail(httpResult.markdown, maxChars);
280
+ return {
281
+ url,
282
+ finalUrl: httpResult.finalUrl,
283
+ status: httpResult.status,
284
+ contentType: "text/markdown",
285
+ lastModified: httpResult.lastModified || "",
286
+ publishedTime: httpResult.publishedTime || "",
287
+ byline: httpResult.byline || "",
288
+ siteName: httpResult.siteName || "",
289
+ lang: httpResult.lang || "",
290
+ title: httpResult.title,
291
+ snippet: httpResult.excerpt,
292
+ content,
293
+ contentChars: content.length,
294
+ source: "http",
295
+ duration: Date.now() - start
307
296
  };
308
- console.log = __markNative(function log() { return _origLog.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
309
- console.error = __markNative(function error() { return _origError.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
310
- console.warn = __markNative(function warn() { return _origWarn.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
311
- console.debug = __markNative(function debug() { return _origDebug.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
312
- console.info = __markNative(function info() { return _origInfo.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
313
- } catch(_) {}
314
-
315
- // ── Native function masking ──────────────────────────
316
- // Patched APIs should not stringify as user-defined stealth code.
317
- try {
318
- var __nativeToString = Function.prototype.toString;
319
- Function.prototype.toString = function toString() {
320
- if (__greedyNativeFns.indexOf(this) !== -1) {
321
- var name = this.name || '';
322
- return 'function ' + name + '() { [native code] }';
297
+ }
298
+ if (httpResult.needsBrowser) {
299
+ try {
300
+ const chromeTab = await openNewTab();
301
+ try {
302
+ const chromeResult = await fetchSourceViaChrome(chromeTab, url, maxChars);
303
+ if (chromeResult.content && chromeResult.content.length > 100) {
304
+ return chromeResult;
305
+ }
306
+ } finally {
307
+ await closeTab(chromeTab);
323
308
  }
324
- return __nativeToString.call(this);
309
+ } catch {}
310
+ }
311
+ process.stderr.write(`[greedysearch] HTTP failed for ${url.slice(0, 60)}, trying browser...
312
+ `);
313
+ return await fetchSourceContentBrowser(url, maxChars);
314
+ }
315
+ async function waitForPageReady(tab, timeoutMs = 4000, intervalMs = 200) {
316
+ const deadline = Date.now() + timeoutMs;
317
+ while (Date.now() < deadline) {
318
+ try {
319
+ const ready = await cdp([
320
+ "eval",
321
+ tab,
322
+ `document.readyState === "complete" && !!document.body && document.body.innerText.length > 500`
323
+ ]);
324
+ if (ready.trim() === "true")
325
+ return;
326
+ } catch {}
327
+ await new Promise((r) => setTimeout(r, intervalMs));
328
+ }
329
+ }
330
+ async function fetchSourceContentBrowser(url, maxChars = 8000) {
331
+ const start = Date.now();
332
+ let tab;
333
+ try {
334
+ tab = await openNewTab();
335
+ } catch (e) {
336
+ return {
337
+ url,
338
+ title: "",
339
+ content: null,
340
+ snippet: "",
341
+ contentChars: 0,
342
+ error: `openNewTab failed: ${e.message}`,
343
+ source: "browser",
344
+ duration: Date.now() - start
325
345
  };
326
- } catch(_) {}
327
- })();
328
- `})])}function st(e){return ot(new URL(".",e)).replace(/^\/([A-Z]:)/,"$1")}function pt(e,t=9222){let r=Number.parseInt(String(e??""),10);return Number.isInteger(r)&&r>1024&&r<65535?r:t}var gt=ft().replaceAll("\\","/"),ir=pt(process.env.GREEDY_SEARCH_PORT),v=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${gt}/greedysearch-chrome-profile`).replaceAll("\\","/"),ar=`${v}/DevToolsActivePort`,or=process.env.GREEDY_SEARCH_PID_FILE||`${v}/browser.pid`,sr=process.env.CDP_PAGES_CACHE||`${v}/cdp-pages.json`,lr=process.env.GREEDY_SEARCH_MODE_FILE||`${v}/browser-mode`,cr=process.env.GREEDY_SEARCH_METADATA_FILE||`${v}/browser-metadata.json`,ur=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${v}/browser-launch.lock`,fr=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${v}/browser-last-activity`,pr=(process.env.CDP_SOCKET_DIR||`${v}/cdp-sockets`).replaceAll("\\","/"),gr=`${v}/visible-recovery.jsonl`,W=_e(ut(),".dm"),$=_e(W,"greedyconfig"),Y=["perplexity","google","chatgpt","gemini"],B="gemini";function dt(){try{if(N($)){let e=ve($,"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)=>H[i]),n=t.engines.filter((i)=>!H[i]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${$}: ${n.join(", ")}
329
- [greedysearch] Available engines: ${Object.keys(H).join(", ")}
330
- `);if(r.length>0)return r;process.stderr.write(`[greedysearch] Warning: no valid engines in ${$}, falling back to defaults: ${Y.join(", ")}
331
- `)}}}catch{}return Y}function mt(){try{if(!N(W))lt(W,{recursive:!0});if(!N($))ct($,JSON.stringify({engines:Y,synthesizer:B},null,2)+`
332
- `,"utf8")}catch{}}mt();var ye=["gemini","chatgpt"];function ht(){try{if(N($)){let e=ve($,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let r=t.synthesizer.toLowerCase();if(ye.includes(r))return r;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${$}
333
- [greedysearch] Available synthesizers: ${ye.join(", ")}
334
- [greedysearch] Falling back to default: ${B}
335
- `)}}}catch{}return B}var H={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"},dr=dt(),mr=ht(),hr=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=v;function _t(e,t=9222){let r=Number.parseInt(String(e??""),10);return Number.isInteger(r)&&r>1024&&r<65535?r:t}var Et=vt().replaceAll("\\","/"),_r=_t(process.env.GREEDY_SEARCH_PORT),_=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${Et}/greedysearch-chrome-profile`).replaceAll("\\","/"),Er=`${_}/DevToolsActivePort`,$r=process.env.GREEDY_SEARCH_PID_FILE||`${_}/browser.pid`,Dr=process.env.CDP_PAGES_CACHE||`${_}/cdp-pages.json`,Pr=process.env.GREEDY_SEARCH_MODE_FILE||`${_}/browser-mode`,Ar=process.env.GREEDY_SEARCH_METADATA_FILE||`${_}/browser-metadata.json`,Ir=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${_}/browser-launch.lock`,Sr=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${_}/browser-last-activity`,jr=(process.env.CDP_SOCKET_DIR||`${_}/cdp-sockets`).replaceAll("\\","/"),kr=`${_}/visible-recovery.jsonl`,U=$e(bt(),".dm"),D=$e(U,"greedyconfig"),J=["perplexity","google","chatgpt","gemini"],q="gemini";function $t(){try{if(R(D)){let e=Ee(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)=>M[i]),n=t.engines.filter((i)=>!M[i]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${D}: ${n.join(", ")}
336
- [greedysearch] Available engines: ${Object.keys(M).join(", ")}
337
- `);if(r.length>0)return r;process.stderr.write(`[greedysearch] Warning: no valid engines in ${D}, falling back to defaults: ${J.join(", ")}
338
- `)}}}catch{}return J}function Dt(){try{if(!R(U))yt(U,{recursive:!0});if(!R(D))wt(D,JSON.stringify({engines:J,synthesizer:q},null,2)+`
339
- `,"utf8")}catch{}}Dt();var we=["gemini","chatgpt"];function Pt(){try{if(R(D)){let e=Ee(D,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let r=t.synthesizer.toLowerCase();if(we.includes(r))return r;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${D}
340
- [greedysearch] Available synthesizers: ${we.join(", ")}
341
- [greedysearch] Falling back to default: ${q}
342
- `)}}}catch{}return q}var M={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"},Nr=$t(),Rr=Pt(),Cr=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=_;var Lr=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5;var Or=st(import.meta.url);var Tr=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,Fr=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60;var g=be;async function De(){let e=(await g(["list"])).split(`
343
- `)[0];if(!e)throw Error("No Chrome tabs found");return e.slice(0,8)}async function C(e="about:blank"){let t=await De(),r=new URL(e).hostname;if(r==="copilot.microsoft.com"||r==="www.perplexity.ai"||r==="perplexity.ai"||r.endsWith(".perplexity.ai")){let a=await g(["evalraw",t,"Target.createTarget",JSON.stringify({url:"about:blank"})]),{targetId:o}=JSON.parse(a),s=o.slice(0,8);if(await g(["list"]).catch(()=>null),r==="copilot.microsoft.com")await he(s);else he(s).catch(()=>{});return await g(["list"]).catch(()=>null),o}let n=await g(["evalraw",t,"Target.createTarget",JSON.stringify({url:e})]),{targetId:i}=JSON.parse(n);return await g(["list"]).catch(()=>null),i}async function L(e){try{let t=await De();await g(["evalraw",t,"Target.closeTarget",JSON.stringify({targetId:e})])}catch{}}import{existsSync as O,mkdirSync as At,readFileSync as Ae,writeFileSync as It}from"node:fs";import{homedir as St}from"node:os";import{join as Ie}from"node:path";import{tmpdir as jt}from"node:os";function kt(e,t=9222){let r=Number.parseInt(String(e??""),10);return Number.isInteger(r)&&r>1024&&r<65535?r:t}var Nt=jt().replaceAll("\\","/"),Yr=kt(process.env.GREEDY_SEARCH_PORT),E=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${Nt}/greedysearch-chrome-profile`).replaceAll("\\","/"),Br=`${E}/DevToolsActivePort`,Ur=process.env.GREEDY_SEARCH_PID_FILE||`${E}/browser.pid`,Jr=process.env.CDP_PAGES_CACHE||`${E}/cdp-pages.json`,qr=process.env.GREEDY_SEARCH_MODE_FILE||`${E}/browser-mode`,Vr=process.env.GREEDY_SEARCH_METADATA_FILE||`${E}/browser-metadata.json`,Zr=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${E}/browser-launch.lock`,Xr=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${E}/browser-last-activity`,Qr=(process.env.CDP_SOCKET_DIR||`${E}/cdp-sockets`).replaceAll("\\","/"),Kr=`${E}/visible-recovery.jsonl`,Z=Ie(St(),".dm"),P=Ie(Z,"greedyconfig"),X=["perplexity","google","chatgpt","gemini"],Q="gemini";function Rt(){try{if(O(P)){let e=Ae(P,"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)=>V[i]),n=t.engines.filter((i)=>!V[i]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${P}: ${n.join(", ")}
344
- [greedysearch] Available engines: ${Object.keys(V).join(", ")}
345
- `);if(r.length>0)return r;process.stderr.write(`[greedysearch] Warning: no valid engines in ${P}, falling back to defaults: ${X.join(", ")}
346
- `)}}}catch{}return X}function Ct(){try{if(!O(Z))At(Z,{recursive:!0});if(!O(P))It(P,JSON.stringify({engines:X,synthesizer:Q},null,2)+`
347
- `,"utf8")}catch{}}Ct();var Pe=["gemini","chatgpt"];function Lt(){try{if(O(P)){let e=Ae(P,"utf8"),t=JSON.parse(e);if(typeof t.synthesizer==="string"){let r=t.synthesizer.toLowerCase();if(Pe.includes(r))return r;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${t.synthesizer}" in ${P}
348
- [greedysearch] Available synthesizers: ${Pe.join(", ")}
349
- [greedysearch] Falling back to default: ${Q}
350
- `)}}}catch{}return Q}var V={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"},zr=Rt();var en=Lt(),K=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=E;function Ot(){if(typeof globalThis.DOMMatrix>"u")globalThis.DOMMatrix=class{constructor(t=void 0){}multiplySelf(){return this}preMultiplySelf(){return this}translateSelf(){return this}scaleSelf(){return this}rotateSelf(){return this}};if(typeof globalThis.ImageData>"u")globalThis.ImageData=class{constructor(t=void 0,r=0,n=0){this.data=t,this.width=r,this.height=n}};if(typeof globalThis.Path2D>"u")globalThis.Path2D=class{constructor(t=void 0){}}}async function Tt(){Ot();let e=await import("pdf-parse"),t=e.PDFParse??e.default;if(!t)throw Error("pdf-parse did not export PDFParse");return t}async function Se(e,t){try{let n=new(await Tt())({data:new Uint8Array(e)});await n.load();let i=await n.getText(),a=i.text?.trim();if(!a)return null;return{title:new URL(t).pathname.split("/").pop()||"Document.pdf",content:`## PDF Content (${i.total} pages)
351
-
352
- ${a}`,pages:i.total}}catch(r){return{error:r.message||String(r)}}}function z(e="",t=240){let r=String(e).replaceAll(/\s+/g," ").trim();if(r.length<=t)return r;let n=r.slice(0,t),i=n.lastIndexOf(" ");return i>0?`${n.slice(0,i)}...`:`${n}...`}async function Ft(e,t,r=8000){let n=Date.now();try{let a=(await g(["evalraw",e,"Page.getFrameTree","{}"]).then((h)=>JSON.parse(h)).catch(()=>null))?.frameTree?.frame?.id||void 0,o=await g(["evalraw",e,"Network.loadNetworkResource",JSON.stringify({frameId:a,url:t,options:{disableCache:!0,includeCredentials:!1}})],20000),l=JSON.parse(o).resource;if(!l?.success||!l.httpStatusCode)return{url:t,error:l?.netErrorName||l?.netError||"loadNetworkResource failed",source:"chrome",duration:Date.now()-n,needsFallback:!0};let c="";if(l.stream)try{let h=await g(["evalraw",e,"IO.read",JSON.stringify({handle:l.stream})],1e4);c=JSON.parse(h).data||"",await g(["evalraw",e,"IO.close",JSON.stringify({handle:l.stream})]).catch(()=>{})}catch{}if(!c||c.length<100)return{url:t,error:"Empty response body from Network.loadNetworkResource",source:"chrome",duration:Date.now()-n,needsFallback:!0};let u=F(l.httpStatusCode,c,t,t);if(u.blocked)return{url:t,status:l.httpStatusCode,error:`Blocked: ${u.reason}`,source:"chrome",duration:Date.now()-n,needsBrowser:!0};let f=await x(c,t),d=G(f);if(!d.ok)return{url:t,status:l.httpStatusCode,error:`Low quality: ${d.reason}`,source:"chrome",duration:Date.now()-n,needsBrowser:!0};let p=A(f.markdown,r);return{url:t,finalUrl:t,status:l.httpStatusCode,contentType:"text/markdown",lastModified:"",publishedTime:f.publishedTime||"",byline:f.byline||"",siteName:f.siteName||"",lang:f.lang||"",title:f.title||t,snippet:f.excerpt,content:p,contentChars:p.length,source:"chrome",duration:Date.now()-n}}catch(i){return{url:t,error:i.message,source:"chrome",duration:Date.now()-n,needsFallback:!0}}}function je(e){try{return new URL(e).pathname.toLowerCase().endsWith(".pdf")}catch{return!1}}async function xt(e,t=8000){let r=j(e);if(r.blocked)return{url:e,finalUrl:e,status:403,error:`Blocked: ${r.reason}`,source:"pdf-http"};let n=new AbortController,i=setTimeout(()=>n.abort(),20000),a=Date.now();try{let o=await fetch(e,{method:"GET",redirect:"follow",signal:n.signal,headers:oe({accept:"application/pdf,application/octet-stream;q=0.9,*/*;q=0.5"})});clearTimeout(i);let s=o.headers.get("content-type")||"",l=o.url||e,c=Number.parseInt(o.headers.get("content-length")||"0",10);if(o.status>=400)return{url:e,finalUrl:l,status:o.status,error:`HTTP ${o.status}`,source:"pdf-http",duration:Date.now()-a};if(!s.toLowerCase().includes("application/pdf")&&!je(l))return null;if(c>31457280)return{url:e,finalUrl:l,status:o.status,error:`PDF too large: ${c} bytes`,source:"pdf-http",duration:Date.now()-a};let u=Buffer.from(await o.arrayBuffer()),f=await Se(u,l);if(!f||f.error)return{url:e,finalUrl:l,status:o.status,error:f?.error||"PDF text extraction failed",source:"pdf-http",duration:Date.now()-a};let d=A(f.content,t);return{url:e,finalUrl:l,status:o.status,contentType:"application/pdf",lastModified:o.headers.get("last-modified")||"",title:f.title,snippet:z(d,320),content:d,contentChars:d.length,pages:f.pages,source:"pdf-http",duration:Date.now()-a}}catch(o){return clearTimeout(i),{url:e,finalUrl:e,error:o.message||String(o),source:"pdf-http",duration:Date.now()-a}}}async function Gt(e,t=8000){let r=Date.now();if(je(e)){let a=await xt(e,t);if(a?.content||a?.status===403)return a}if(k(e)){let a=k(e);if(a&&(a.type==="root"||a.type==="tree"||a.type==="blob"&&!a.path?.includes("."))){let o=await ue(e);if(o.ok){let s=A(o.content,t);return{url:e,finalUrl:e,status:200,contentType:"text/markdown",lastModified:"",title:o.title,snippet:s.slice(0,320),content:s,contentChars:s.length,source:"github-api",...o.tree&&{tree:o.tree},duration:Date.now()-r}}process.stderr.write(`[greedysearch] GitHub API fetch failed, trying HTTP: ${o.error}
353
- `)}}if(pe(e)?.type==="post"){process.stderr.write(`[greedysearch] Using Reddit JSON API for: ${e.slice(0,60)}...
354
- `);let a=await ge(e,t);if(a.ok){let o=A(a.markdown,t);return{url:e,finalUrl:a.finalUrl,status:a.status,contentType:"text/markdown",lastModified:a.lastModified||"",publishedTime:a.publishedTime||"",byline:a.byline||"",siteName:a.siteName||"",lang:a.lang||"",title:a.title,snippet:a.excerpt,content:o,contentChars:o.length,source:"reddit-api",duration:Date.now()-r}}process.stderr.write(`[greedysearch] Reddit API fetch failed, falling back to HTTP: ${a.error}
355
- `)}let i=await se(e,{timeoutMs:1e4});if(i.ok){let a=A(i.markdown,t);return{url:e,finalUrl:i.finalUrl,status:i.status,contentType:"text/markdown",lastModified:i.lastModified||"",publishedTime:i.publishedTime||"",byline:i.byline||"",siteName:i.siteName||"",lang:i.lang||"",title:i.title,snippet:i.excerpt,content:a,contentChars:a.length,source:"http",duration:Date.now()-r}}if(i.needsBrowser)try{let a=await C();try{let o=await Ft(a,e,t);if(o.content&&o.content.length>100)return o}finally{await L(a)}}catch{}return process.stderr.write(`[greedysearch] HTTP failed for ${e.slice(0,60)}, trying browser...
356
- `),await Ht(e,t)}async function ke(e,t=4000,r=200){let n=Date.now()+t;while(Date.now()<n){try{if((await g(["eval",e,'document.readyState === "complete" && !!document.body && document.body.innerText.length > 500'])).trim()==="true")return}catch{}await new Promise((i)=>setTimeout(i,r))}}async function Ht(e,t=8000){let r=Date.now(),n;try{n=await C()}catch(i){return{url:e,title:"",content:null,snippet:"",contentChars:0,error:`openNewTab failed: ${i.message}`,source:"browser",duration:Date.now()-r}}try{await g(["nav",n,e],30000),await ke(n);let i=await g(["eval",n,String.raw`
346
+ }
347
+ try {
348
+ await cdp(["nav", tab, url], 30000);
349
+ await waitForPageReady(tab);
350
+ const content = await cdp([
351
+ "eval",
352
+ tab,
353
+ String.raw`
357
354
  (function(){
358
355
  var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
359
356
  var text = (el || document.body).innerText;
@@ -363,16 +360,111 @@ ${a}`,pages:i.total}}catch(r){return{error:r.message||String(r)}}}function z(e="
363
360
  url: location.href
364
361
  });
365
362
  })()
366
- `]),a=JSON.parse(i),o=A(a.content,t);return{url:e,finalUrl:a.url||e,status:200,contentType:"text/plain",lastModified:"",title:a.title,snippet:z(o,320),content:o,contentChars:o.length,source:"browser",duration:Date.now()-r}}catch(i){return{url:e,title:"",content:null,snippet:"",contentChars:0,error:i.message,source:"browser",duration:Date.now()-r}}finally{await L(n)}}async function gn(e,t=5,r=8000,n=K){let i=e.slice(0,t);if(i.length===0)return[];let a=Math.min(i.length,Math.max(1,Number.parseInt(String(n),10)||K));process.stderr.write(`[greedysearch] Fetching content from ${i.length} sources via HTTP (concurrency ${a})...
367
- `);let o=Array(i.length),s=0,l=0;async function c(){while(!0){let p=s++;if(p>=i.length)return;let h=i[p],y=h.canonicalUrl||h.url;process.stderr.write(`[greedysearch] [${p+1}/${i.length}] Fetching: ${y.slice(0,60)}...
368
- `);let m=await Gt(y,r).catch((w)=>({url:y,title:"",content:null,snippet:"",contentChars:0,error:w.message,source:"error",duration:0}));if(o[p]={id:h.id,...m},m.content&&m.content.length>100)process.stderr.write(`[greedysearch] ✓ ${m.source}: ${m.content.length} chars
369
- `);else if(m.error)process.stderr.write(`[greedysearch] ✗ ${m.error.slice(0,80)}
370
- `);l+=1,process.stderr.write(`PROGRESS:fetch:${l}/${i.length}
371
- `)}}await Promise.all(Array.from({length:a},()=>c()));let u=o.filter((p)=>p.content&&p.content.length>100),f=o.filter((p)=>p.source==="http").length,d=o.filter((p)=>p.source==="browser").length;return process.stderr.write(`[greedysearch] Fetched ${u.length}/${o.length} sources (HTTP: ${f}, Browser: ${d})
372
- `),o}async function dn(e){let t=await C();try{await g(["nav",t,e],30000),await ke(t);let r=await g(["eval",t,String.raw`
363
+ `
364
+ ]);
365
+ const parsed = JSON.parse(content);
366
+ const finalContent = trimContentHeadTail(parsed.content, maxChars);
367
+ return {
368
+ url,
369
+ finalUrl: parsed.url || url,
370
+ status: 200,
371
+ contentType: "text/plain",
372
+ lastModified: "",
373
+ title: parsed.title,
374
+ snippet: trimText(finalContent, 320),
375
+ content: finalContent,
376
+ contentChars: finalContent.length,
377
+ source: "browser",
378
+ duration: Date.now() - start
379
+ };
380
+ } catch (error) {
381
+ return {
382
+ url,
383
+ title: "",
384
+ content: null,
385
+ snippet: "",
386
+ contentChars: 0,
387
+ error: error.message,
388
+ source: "browser",
389
+ duration: Date.now() - start
390
+ };
391
+ } finally {
392
+ await closeTab(tab);
393
+ }
394
+ }
395
+ export async function fetchMultipleSources(sources, maxSources = 5, maxChars = 8000, concurrency = SOURCE_FETCH_CONCURRENCY) {
396
+ const toFetch = sources.slice(0, maxSources);
397
+ if (toFetch.length === 0)
398
+ return [];
399
+ const workerCount = Math.min(toFetch.length, Math.max(1, Number.parseInt(String(concurrency), 10) || SOURCE_FETCH_CONCURRENCY));
400
+ process.stderr.write(`[greedysearch] Fetching content from ${toFetch.length} sources via HTTP (concurrency ${workerCount})...
401
+ `);
402
+ const fetched = new Array(toFetch.length);
403
+ let nextIndex = 0;
404
+ let completed = 0;
405
+ async function worker() {
406
+ while (true) {
407
+ const index = nextIndex++;
408
+ if (index >= toFetch.length)
409
+ return;
410
+ const s = toFetch[index];
411
+ const url = s.canonicalUrl || s.url;
412
+ process.stderr.write(`[greedysearch] [${index + 1}/${toFetch.length}] Fetching: ${url.slice(0, 60)}...
413
+ `);
414
+ const result = await fetchSourceContent(url, maxChars).catch((e) => ({
415
+ url,
416
+ title: "",
417
+ content: null,
418
+ snippet: "",
419
+ contentChars: 0,
420
+ error: e.message,
421
+ source: "error",
422
+ duration: 0
423
+ }));
424
+ fetched[index] = {
425
+ id: s.id,
426
+ ...result
427
+ };
428
+ if (result.content && result.content.length > 100) {
429
+ process.stderr.write(`[greedysearch] ✓ ${result.source}: ${result.content.length} chars
430
+ `);
431
+ } else if (result.error) {
432
+ process.stderr.write(`[greedysearch] ✗ ${result.error.slice(0, 80)}
433
+ `);
434
+ }
435
+ completed += 1;
436
+ process.stderr.write(`PROGRESS:fetch:${completed}/${toFetch.length}
437
+ `);
438
+ }
439
+ }
440
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
441
+ const successful = fetched.filter((f) => f.content && f.content.length > 100);
442
+ const httpCount = fetched.filter((f) => f.source === "http").length;
443
+ const browserCount = fetched.filter((f) => f.source === "browser").length;
444
+ process.stderr.write(`[greedysearch] Fetched ${successful.length}/${fetched.length} sources ` + `(HTTP: ${httpCount}, Browser: ${browserCount})
445
+ `);
446
+ return fetched;
447
+ }
448
+ export async function fetchTopSource(url) {
449
+ const tab = await openNewTab();
450
+ try {
451
+ await cdp(["nav", tab, url], 30000);
452
+ await waitForPageReady(tab);
453
+ const content = await cdp([
454
+ "eval",
455
+ tab,
456
+ String.raw`
373
457
  (function(){
374
458
  var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
375
459
  var text = (el || document.body).innerText;
376
460
  return text.replace(/\s+/g, ' ').trim();
377
461
  })()
378
- `]);return{url:e,content:r}}catch(r){return{url:e,content:null,error:r.message}}finally{await L(t)}}export{dn as fetchTopSource,Gt as fetchSourceContent,gn as fetchMultipleSources};
462
+ `
463
+ ]);
464
+ return { url, content };
465
+ } catch (e) {
466
+ return { url, content: null, error: e.message };
467
+ } finally {
468
+ await closeTab(tab);
469
+ }
470
+ }