@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,375 +1,400 @@
1
- #!/usr/bin/env node
2
- import{createRequire as l0}from"node:module";var u0=Object.defineProperty;var m0=($)=>$;function c0($,Q){this[$]=m0.bind(null,Q)}var i0=($,Q)=>{for(var X in Q)u0($,X,{get:Q[X],enumerable:!0,configurable:!0,set:c0.bind(Q,X)})};var U=($,Q)=>()=>($&&(Q=$($=0)),Q);var L=l0(import.meta.url);import{basename as d0}from"node:path";function F($=process.env,Q=process.execPath){let X=$.GREEDY_SEARCH_NODE||$.NODE_BINARY||$.NODE;if(X?.trim())return X.trim();let W=d0(Q||"").toLowerCase();if(W==="node"||W==="node.exe")return Q;return"node"}var P=()=>{};async function n0(){if(y)return y;let[{Readability:$},{JSDOM:Q},{default:X}]=await Promise.all([import("@mozilla/readability"),import("jsdom"),import("turndown")]),W=new X({headingStyle:"atx",bulletListMarker:"-",codeBlockStyle:"fenced"});return W.addRule("removeDataUrls",{filter:(Z)=>Z.tagName==="IMG"&&Z.getAttribute("src")?.startsWith("data:"),replacement:()=>""}),y={Readability:$,JSDOM:Q,turndown:W},y}function r0($){if(!$||$.includes(":"))return null;let Q=$.split(".");if(Q.length<1||Q.length>4)return null;if(!Q.every((Z)=>a0.test(Z)))return null;let X=Q.map((Z)=>{if(/^0x/i.test(Z))return parseInt(Z,16);if(/^0[0-7]+$/.test(Z))return parseInt(Z,8);return parseInt(Z,10)});if(X.some((Z)=>!Number.isFinite(Z)||Z<0))return null;let W;if(X.length===1){if(X[0]>4294967295)return null;W=[X[0]>>>24&255,X[0]>>>16&255,X[0]>>>8&255,X[0]&255]}else if(X.length===2){if(X[0]>255||X[1]>16777215)return null;W=[X[0],X[1]>>>16&255,X[1]>>>8&255,X[1]&255]}else if(X.length===3){if(X[0]>255||X[1]>255||X[2]>65535)return null;W=[X[0],X[1],X[2]>>>8&255,X[2]&255]}else{if(X.some((Z)=>Z>255))return null;W=X}return W.join(".")}function t0($){let Q=$.match(o0);if(Q)return`${Q[1]}.${Q[2]}.${Q[3]}.${Q[4]}`;let X=$.match(s0);if(X){let W=parseInt(X[1],16),Z=parseInt(X[2],16);if(W>65535||Z>65535)return null;return[W>>>8&255,W&255,Z>>>8&255,Z&255].join(".")}return null}function $0($){return Z0.some((Q)=>Q.test($))}function J0($={}){return{...W0,...$}}function S($){try{if(typeof $!=="string"||!$.trim())return{blocked:!0,reason:"URL must be a non-empty string"};let Q=new URL($);if(Q.protocol!=="http:"&&Q.protocol!=="https:")return{blocked:!0,reason:`Protocol not allowed: ${Q.protocol}`};let X=Q.hostname.toLowerCase();for(let Z of Z0)if(Z.test(X))return{blocked:!0,reason:`Private/internal address: ${X}`};if(X.startsWith("[")&&X.endsWith("]")){let Z=X.slice(1,-1),K=t0(Z);if(K&&$0(K))return{blocked:!0,reason:`Private/internal address: ${X} (maps to ${K})`}}let W=r0(X);if(W&&$0(W))return{blocked:!0,reason:`Private/internal address: ${X} (normalizes to ${W})`};return{blocked:!1}}catch(Q){return{blocked:!0,reason:`Invalid URL: ${Q.message}`}}}function e0($){try{let Q=new URL($);if(!(Q.hostname==="github.com"||Q.hostname.endsWith(".github.com")))return $;let X=Q.pathname.split("/").filter(Boolean);if(X.length<5)return $;let[W,Z,K,J,...q]=X;if(K!=="blob")return $;let V=q.join("/");return`https://raw.githubusercontent.com/${W}/${Z}/${J}/${V}`}catch{return $}}async function K0($,Q={}){let X=S($);if(X.blocked)return{ok:!1,url:$,finalUrl:$,status:403,error:`Blocked: ${X.reason}`,needsBrowser:!1};let W=$;if($=e0($),$!==W)console.error(`[fetcher] Rewrote GitHub URL: ${W.slice(0,60)}... → raw.githubusercontent.com`);let{timeoutMs:Z=15000,userAgent:K,signal:J}=Q,q=new AbortController,V=setTimeout(()=>q.abort(),Z);if(J)J.addEventListener("abort",()=>q.abort(),{once:!0});try{let B=await fetch($,{method:"GET",headers:{...W0,"user-agent":K||X0},redirect:"follow",signal:q.signal});clearTimeout(V);let j=B.headers.get("content-type")||"",H=B.url,Y=B.headers.get("last-modified")||"",N=S(H);if(N.blocked)return{ok:!1,url:$,finalUrl:H,status:B.status,error:`Blocked: ${N.reason}`,needsBrowser:!1};let A=!1;try{A=new URL(H).hostname.toLowerCase()==="raw.githubusercontent.com"}catch{}if(j.includes("text/plain")&&A){let T=await B.text();return{ok:!0,url:W,finalUrl:H,status:B.status,title:H.split("/").pop()||"GitHub File",byline:"",siteName:"GitHub",lang:"",publishedTime:Y,lastModified:Y,markdown:T,contentLength:T.length,excerpt:T.slice(0,300).replaceAll(/\n/g," "),needsBrowser:!1}}if(!j.includes("text/html")&&!j.includes("application/xhtml"))return{ok:!1,url:$,finalUrl:H,status:B.status,error:`Unsupported content type: ${j}`,needsBrowser:!1};let M=await B.text(),z=h(B.status,M,H,$);if(z.blocked)return{ok:!1,url:$,finalUrl:H,status:B.status,error:`Blocked: ${z.reason}`,needsBrowser:!0};let k=await p(M,H),e=u(k);if(!e.ok)return{ok:!1,url:$,finalUrl:H,status:B.status,error:`Low quality content: ${e.reason}`,needsBrowser:!0};return{ok:!0,url:$,finalUrl:H,status:B.status,title:k.title,byline:k.byline,siteName:k.siteName,lang:k.lang,publishedTime:k.publishedTime||Y,lastModified:Y,markdown:k.markdown,excerpt:k.excerpt,contentLength:k.markdown.length,needsBrowser:!1}}catch(B){clearTimeout(V);let j=Z1(B);return{ok:!1,url:$,finalUrl:$,status:0,error:B.message,needsBrowser:j}}}function h($,Q,X,W){let Z=Q.match(/<title[^>]*>([^<]*)<\/title>/i)?.[1]?.toLowerCase()||"",K=Q.slice(0,30000).toLowerCase(),J=`${Z} ${K}`;if($===403||$===429||$===503)return{blocked:!0,reason:`HTTP ${$}`};let q=[{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 B of q)if(B.pattern.test(J))return{blocked:!0,reason:B.reason};let V=W1(W,X,Q);if(V)return{blocked:!0,reason:V};return{blocked:!1}}function W1($,Q,X){try{let W=new URL($),Z=new URL(Q);if(W.hostname.toLowerCase()===Z.hostname.toLowerCase())return;let K=Z.hostname.toLowerCase();if($1.some((q)=>K===q||K.endsWith(`.${q}`)))return`redirected to login (${Z.hostname})`;if(Q1.some((q)=>K.startsWith(q)))return`redirected to login (${Z.hostname})`;let J=X.slice(0,20000).toLowerCase();if(X1.some((q)=>J.includes(q)))return`redirected to login page (${Z.hostname})`}catch{}return}function Z1($){let Q=$.message.toLowerCase();return Q.includes("fetch failed")||Q.includes("unable to verify")||Q.includes("certificate")||Q.includes("timeout")}function Q0($){let Q=['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 X of Q){let W=$.querySelector(X),Z=W?.getAttribute("content")||W?.getAttribute("datetime")||"";if(Z)return Z}return""}async function p($,Q){let{Readability:X,JSDOM:W,turndown:Z}=await n0(),K=new W($,{url:Q});try{let J=K.window.document,V=new X(J).parse();if(V&&V.content){let H=Z.turndown(V.content).replaceAll(/\n{3,}/g,`
3
-
4
- `).trim(),Y=V.publishedTime||Q0(J)||"";return{title:V.title||J.title||Q,byline:V.byline||"",siteName:V.siteName||"",lang:V.lang||"",publishedTime:Y,markdown:H,excerpt:H.slice(0,300).replaceAll(/\n/g," ")}}let B=J.body;if(B){let j=B.cloneNode(!0);j.querySelectorAll("script, style, nav, footer, header, aside").forEach((N)=>N.remove());let Y=(j.textContent||"").replaceAll(/\s+/g," ").trim();return{title:J.title||Q,byline:"",siteName:"",lang:"",publishedTime:Q0(J),markdown:Y,excerpt:Y.slice(0,300)}}return{title:Q,byline:"",siteName:"",lang:"",publishedTime:"",markdown:"",excerpt:""}}finally{K.window.close()}}function u($){let Q=$.markdown.trim().toLowerCase(),X=($.title||"").toLowerCase();if($.markdown.trim().length<100)return{ok:!1,reason:"content too short (< 100 chars)"};let W=Q.toLowerCase(),Z=[{check:()=>W.includes("loading")&&W.includes("please wait"),desc:"loading page"},{check:()=>W.includes("please ensure javascript is enabled"),desc:"requires javascript"},{check:()=>W.includes("enable javascript to view"),desc:"requires javascript"},{check:()=>W.includes("just a moment"),desc:"cloudflare challenge detected in content"},{check:()=>W.includes("verify you are human"),desc:"human verification"},{check:()=>W.includes("captcha required"),desc:"captcha in extracted content"},{check:()=>W.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(Q),desc:"login form only"}];for(let{check:K,desc:J}of Z)if(K())return{ok:!1,reason:J};if(X.includes("just a moment")||X.includes("checking your browser"))return{ok:!1,reason:"cloudflare challenge page detected in title"};return{ok:!0}}var y=null,X0="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",W0,Z0,o0,s0,a0,$1,Q1,X1;var q0=U(()=>{W0={"user-agent":X0,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"},Z0=[/^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],o0=/^::ffff:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/i,s0=/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i,a0=/^(?:0x[0-9a-f]+|0[0-7]*|[1-9][0-9]*)$/i;$1=["accounts.google.com","login.microsoftonline.com","login.live.com","auth0.com","okta.com","auth.mozilla.auth0.com","id.atlassian.com"],Q1=["login.","signin.","auth.","sso.","accounts.","idp."],X1=["sign in to continue","log in to continue","authentication required","create an account to continue","subscribe to continue reading","members only"]});function C($){try{let Q=new URL($);if(!(Q.hostname==="github.com"||Q.hostname.endsWith(".github.com")))return null;let X=Q.pathname.split("/").filter(Boolean);if(X.length<2)return null;let[W,Z]=X;if(X.length===2)return{owner:W,repo:Z,type:"root"};if(X.length>=4&&(X[2]==="blob"||X[2]==="tree")){let K=X[2],J=X[3],q=X.slice(4).join("/");return{owner:W,repo:Z,type:K,ref:J,path:q}}return null}catch{return null}}async function D($,Q=1e4){let X=new AbortController,W=setTimeout(()=>X.abort(),Q);try{let Z=await fetch(`https://api.github.com${$}`,{headers:B0,signal:X.signal});if(clearTimeout(W),!Z.ok)throw Error(`GitHub API ${Z.status}: ${$}`);return await Z.json()}catch(Z){throw clearTimeout(W),Z}}async function J1($,Q){try{let X=await D(`/repos/${$}/${Q}/readme`);if(X.content&&X.encoding==="base64")return Buffer.from(X.content,"base64").toString("utf8");return""}catch{return""}}async function V0($,Q,X="HEAD",W="",Z){try{let K;if(X==="HEAD")if(Z)K=await D(`/repos/${$}/${Q}/git/ref/heads/${Z}`).catch(()=>null);else K=await Promise.any([D(`/repos/${$}/${Q}/git/ref/heads/main`),D(`/repos/${$}/${Q}/git/ref/heads/master`)]).catch(()=>null);else K=await D(`/repos/${$}/${Q}/git/ref/heads/${X}`).catch(()=>D(`/repos/${$}/${Q}/git/ref/heads/master`).catch(()=>null));if(!K?.object?.sha)return[];let q=(await D(`/repos/${$}/${Q}/git/commits/${K.object.sha}`)).tree.sha,B=(await D(`/repos/${$}/${Q}/git/trees/${q}`)).tree||[];if(W)B=B.filter((j)=>j.path.startsWith(W));return B.slice(0,50).map((j)=>({path:j.path,type:j.type==="tree"?"dir":"file",size:j.size}))}catch{return[]}}async function K1($,Q,X,W,Z=1e4,K){let J=async(V)=>{let B=new AbortController,j=setTimeout(()=>B.abort(),Z);try{let H=await fetch(V,{headers:{"user-agent":B0["user-agent"]},signal:B.signal});if(clearTimeout(j),H.ok)return await H.text();throw Error("not ok")}catch{throw clearTimeout(j),Error("failed")}};if(!X||X==="HEAD"){if(K)try{return await J(`https://raw.githubusercontent.com/${$}/${Q}/${K}/${W}`)}catch{return null}try{return await Promise.any([J(`https://raw.githubusercontent.com/${$}/${Q}/main/${W}`),J(`https://raw.githubusercontent.com/${$}/${Q}/master/${W}`)])}catch{return null}}let q=[`https://raw.githubusercontent.com/${$}/${Q}/${X}/${W}`,`https://raw.githubusercontent.com/${$}/${Q}/master/${W}`];for(let V of q)try{return await J(V)}catch{}return null}async function j0($){let Q=C($);if(!Q)return{ok:!1,error:"Not a valid GitHub URL"};let{owner:X,repo:W,type:Z,ref:K,path:J}=Q;try{if(Z==="root"||Z==="tree"&&!J){let q=await D(`/repos/${X}/${W}`),[V,B]=await Promise.allSettled([J1(X,W),V0(X,W,K||"HEAD","",q.default_branch)]),j=V.status==="fulfilled"?V.value:"",H=B.status==="fulfilled"?B.value:[],Y=q?.description?`
5
-
6
- > ${q.description}`:"",N=q?.stargazers_count==null?"":` ⭐ ${q.stargazers_count}`,A=q?.language?` · ${q.language}`:"",M=`# ${X}/${W}${N}${A}${Y}
7
-
8
- `;if(j)M+=j.slice(0,6000);else M+=`[No README found]
9
-
10
- Files:
11
- ${H.map((z)=>` ${z.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${z.path}`).join(`
12
- `)}`;return{ok:!0,title:`${X}/${W}`,content:M,tree:H.slice(0,30)}}if(Z==="blob"&&J){let q;if(!K||K==="HEAD")try{q=(await D(`/repos/${X}/${W}`)).default_branch}catch{q=void 0}let V=await K1(X,W,K,J,1e4,q);if(V===null)return{ok:!1,error:`File not found: ${J}`};return{ok:!0,title:`${X}/${W}: ${J}`,content:V}}if(Z==="tree"&&J){let q;if(!K||K==="HEAD")try{q=(await D(`/repos/${X}/${W}`)).default_branch}catch{q=void 0}let V=await V0(X,W,K||"HEAD",J,q),B=V.map((j)=>` ${j.type==="dir"?"\uD83D\uDCC1":"\uD83D\uDCC4"} ${j.path}`).join(`
13
- `);return{ok:!0,title:`${X}/${W}/${J}`,content:`[Directory: ${J}]
14
-
15
- Files:
16
- ${B}`,tree:V}}return{ok:!1,error:"Unsupported GitHub URL type"}}catch(q){return{ok:!1,error:q.message}}}var B0;var H0=U(()=>{B0={"user-agent":"GreedySearch/1.0",accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}});function N0($){try{let Q=new URL($),X=Q.hostname.toLowerCase();if(!(X==="reddit.com"||X.endsWith(".reddit.com")))return null;let W=Q.pathname;if(W.match(/^\/(u|user)\/[^/]+\/?$/i))return{type:"user",cleanUrl:Y0($)};if(W.match(/^\/r\/[^/]+\/comments\/[^/]+/i))return{type:"post",cleanUrl:Y0($)};return null}catch{return null}}function Y0($){try{let Q=new URL($);return`${Q.protocol}//${Q.hostname}${Q.pathname}`}catch{return $}}async function z0($,Q=8000){let X=Date.now();try{let W=$.replace(/\/+$/,"")+".json",Z=new AbortController,K=setTimeout(()=>Z.abort(),15000),J=await fetch(W,{headers:q1,signal:Z.signal});if(clearTimeout(K),!J.ok)throw Error(`Reddit API ${J.status}`);let q=await J.json();if(!Array.isArray(q)||q.length<1)throw Error("Invalid Reddit API response structure");let V=q[0],B=q[1],j=V?.data?.children?.[0]?.data;if(!j)throw Error("No post data in Reddit response");let H=V1(j,B,Q);return{ok:!0,url:$,finalUrl:$,status:200,contentType:"text/markdown",lastModified:"",title:j.title||"Reddit Post",byline:`u/${j.author}`,siteName:`r/${j.subreddit}`,lang:"en",publishedTime:new Date(j.created_utc*1000).toISOString(),excerpt:j.selftext?.slice(0,300).replace(/\n/g," ")||"",markdown:H,contentLength:H.length,needsBrowser:!1,duration:Date.now()-X}}catch(W){return{ok:!1,url:$,finalUrl:$,status:0,error:`Reddit fetch failed: ${W.message}`,needsBrowser:!1,duration:Date.now()-X}}}function V1($,Q,X){let W="";if(W+=`# ${$.title}
17
-
18
- `,W+=`**Subreddit:** r/${$.subreddit} | **Author:** u/${$.author} | **Score:** ${$.score}
19
-
20
- `,$.selftext)W+=$.selftext,W+=`
21
-
22
- `;else if($.url)try{let Z=new URL($.url).hostname.toLowerCase();if(Z!=="reddit.com"&&!Z.endsWith(".reddit.com"))W+=`**Link:** ${$.url}
23
-
24
- `}catch{W+=`**Link:** ${$.url}
25
-
26
- `}if(Q?.data?.children?.length>0){W+=`---
27
-
28
- ## Comments
29
-
30
- `;let Z=Q.data.children.filter((K)=>K.kind==="t1").slice(0,10);for(let K of Z)W+=G0(K.data,0),W+=`
31
- `}if(W.length>X)W=W.slice(0,X).trim()+`
32
-
33
- ... (truncated)`;return W}function G0($,Q){if(!$||$.body==="[deleted]"||$.body==="[removed]")return"";let X="> ".repeat(Q),W="";if(W+=`${X}**u/${$.author}** (${$.score} pts)
34
- `,W+=`${X}${$.body.replaceAll(`
35
- `,`
36
- `+X)}
37
- `,Q<3&&$.replies?.data?.children){let Z=$.replies.data.children.filter((K)=>K.kind==="t1");for(let K of Z.slice(0,5))W+=`
38
- `+G0(K.data,Q+1)}return W}var q1;var A0=U(()=>{q1={"user-agent":"GreedySearch/1.0 (Research Bot)",accept:"application/json"}});function b($,Q=8000){if(!$||$.length<=Q)return $;let X=`
39
-
40
- [...content trimmed...]
41
-
42
- `,W=Q-X.length,Z=Math.floor(W*0.75),K=W-Z,J=Z;while(J>Z-100&&$[J]!==`
43
- `)J--;if(J<=Z-100)J=Z;let q=$.length-K;while(q<$.length-K+100&&$[q]!==`
44
- `)q++;if(q>=$.length-K+100)q=$.length-K;let V=$.slice(0,J).trimEnd(),B=$.slice(q).trimStart();return`${V}${X}${B}`}import{spawn as B1}from"node:child_process";import{dirname as j1,join as H1}from"node:path";import{fileURLToPath as Y1}from"node:url";function A1($){if(!Array.isArray($)||$.length===0)throw Error("cdp: args must be a non-empty array");if($[0]==="test")return $.map((Q,X)=>M0(Q,X));if(!G1.has($[0]))throw Error(`cdp: unknown subcommand '${$[0]}'`);return $.map((Q,X)=>M0(Q,X))}function M0($,Q){if(typeof $!=="string")throw Error(`cdp: argv[${Q}] must be a string (got ${typeof $})`);if($.includes("\x00"))throw Error(`cdp: argv[${Q}] contains a null byte`);return $}function c($,Q=30000){return M1($,null,Q)}function M1($,Q=null,X=30000){let W=A1($);return new Promise((Z,K)=>{let J=B1(F(),[z1,...W],{stdio:[Q==null?"ignore":"pipe","pipe","pipe"]});if(Q!=null)J.stdin.write(Q),J.stdin.end();let q="",V="";J.stdout.on("data",(j)=>q+=j),J.stderr.on("data",(j)=>V+=j);let B=setTimeout(()=>{J.kill(),K(Error(`cdp timeout: ${$[0]}`))},X);J.on("close",(j)=>{if(clearTimeout(B),j===0)Z(q.trim());else K(Error(V.trim()||`cdp exit ${j}`))})})}async function i($){await c(["evalraw",$,"Page.addScriptToEvaluateOnNewDocument",JSON.stringify({source:`
45
- (function() {
46
- // ── Runtime.enable / CDP detection masking ──────────────
47
- try { delete window.__REBROWSER_RUNTIME_ENABLE; } catch(_) {}
48
- try { delete window.__REBROWSER_DEVTOOLS; } catch(_) {}
49
- try { delete window.__nightmare; } catch(_) {}
50
- try { delete window.__phantom; } catch(_) {}
51
- try { delete window.callPhantom; } catch(_) {}
52
- try { delete window._phantom; } catch(_) {}
53
- try { delete window.Buffer; } catch(_) {}
54
-
55
- // Real Chrome without automation should not expose navigator.webdriver at all.
56
- // A literal false or an own-property getter returning undefined is itself a
57
- // common stealth tell; remove both instance and prototype properties when the
58
- // descriptor is configurable (as it is with --disable-blink-features).
59
- try { delete navigator.webdriver; } catch(_) {}
60
- try { delete Navigator.prototype.webdriver; } catch(_) {}
61
- Object.defineProperty(navigator, 'vendor', { get: () => 'Google Inc.', configurable: true });
62
- Object.defineProperty(navigator, 'platform', { get: () => 'Win32', configurable: true });
63
- Object.defineProperty(navigator, 'maxTouchPoints', { get: () => 0, configurable: true });
64
- Object.defineProperty(navigator, 'pdfViewerEnabled', { get: () => true, configurable: true });
65
- Object.defineProperty(navigator, 'productSub', { get: () => '20030107', configurable: true });
66
- Object.defineProperty(navigator, 'product', { get: () => 'Gecko', configurable: true });
67
- var __greedyMimeTypes = null;
68
- function __makeMimeTypes() {
69
- var pdf = { type: 'application/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
70
- var textPdf = { type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format', enabledPlugin: null };
71
- try { Object.setPrototypeOf(pdf, MimeType.prototype); } catch(_) {}
72
- try { Object.setPrototypeOf(textPdf, MimeType.prototype); } catch(_) {}
73
- var m = [pdf, textPdf];
74
- try { Object.setPrototypeOf(m, MimeTypeArray.prototype); } catch(_) {}
75
- m.item = function item(i) { return this[i] || null; };
76
- m.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.type === name; }) || null; };
77
- return m;
78
- }
79
- Object.defineProperty(navigator, 'plugins', {
80
- get: () => {
81
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
82
- var plugin0 = { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer', description: 'Portable Document Format' };
83
- var plugin1 = { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '' };
84
- var plugin2 = { name: 'Native Client', filename: 'internal-nacl-plugin', description: '' };
85
- try { Object.setPrototypeOf(plugin0, Plugin.prototype); } catch(_) {}
86
- try { Object.setPrototypeOf(plugin1, Plugin.prototype); } catch(_) {}
87
- try { Object.setPrototypeOf(plugin2, Plugin.prototype); } catch(_) {}
88
- var p = [plugin0, plugin1, plugin2];
89
- p.item = function item(i) { return this[i] || null; };
90
- p.namedItem = function namedItem(name) { return Array.prototype.find.call(this, function(x) { return x && x.name === name; }) || null; };
91
- p.refresh = function refresh() {};
92
- try { Object.setPrototypeOf(p, PluginArray.prototype); } catch(_) {}
93
- try {
94
- __greedyMimeTypes[0].enabledPlugin = p[0];
95
- __greedyMimeTypes[1].enabledPlugin = p[0];
96
- } catch(_) {}
97
- return p;
1
+ import { spawn } from "node:child_process";
2
+ import { nodeRuntimeCommand } from "../src/utils/node-runtime.mjs";
3
+ import { createInterface } from "node:readline";
4
+ import { fileURLToPath } from "node:url";
5
+ import { dirname, join } from "node:path";
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const SEARCH_BIN = join(__dirname, "search.mjs");
8
+ const PROTOCOL_VERSION = "2025-06-18";
9
+ const SERVER_INFO = { name: "greedysearch", version: "1.0.0" };
10
+ const DEFAULT_TIMEOUT_MS = 6 * 60 * 1000;
11
+ function log(...args) {
12
+ process.stderr.write(`[greedysearch-mcp] ${args.join(" ")}
13
+ `);
14
+ }
15
+ function send(message) {
16
+ process.stdout.write(`${JSON.stringify(message)}
17
+ `);
18
+ }
19
+ function sendResult(id, result) {
20
+ if (id === undefined || id === null)
21
+ return;
22
+ send({ jsonrpc: "2.0", id, result });
23
+ }
24
+ function sendError(id, code, message, data) {
25
+ if (id === undefined || id === null)
26
+ return;
27
+ send({ jsonrpc: "2.0", id, error: { code, message, ...data ? { data } : {} } });
28
+ }
29
+ const ENGINE_DESCRIPTION = 'Engine to use: "all" (default, fans out to configured engines and fetches top sources), ' + '"perplexity" (p), "google" (g), "chatgpt" (gpt), "gemini" (gem), "bing" (b). ' + 'Research engines: "semantic-scholar" (s2) and "logically" (log).';
30
+ const GREEDY_SEARCH_SCHEMA = {
31
+ type: "object",
32
+ properties: {
33
+ query: { type: "string", description: "The search query" },
34
+ engine: {
35
+ type: "string",
36
+ default: "all",
37
+ description: ENGINE_DESCRIPTION
98
38
  },
99
- configurable: true,
100
- });
101
- Object.defineProperty(navigator, 'mimeTypes', {
102
- get: () => {
103
- __greedyMimeTypes = __greedyMimeTypes || __makeMimeTypes();
104
- return __greedyMimeTypes;
39
+ synthesize: {
40
+ type: "boolean",
41
+ default: false,
42
+ description: 'Only for engine="all": synthesize the multi-engine results and fetched sources.'
105
43
  },
106
- configurable: true,
107
- });
108
- Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true });
109
- try {
110
- Object.defineProperty(navigator, 'connection', { get: () => ({ effectiveType: '4g', rtt: 50, downlink: 10, downlinkMax: Infinity, saveData: false }), configurable: true });
111
- } catch(_) {}
112
- if (!navigator.mediaDevices) {
113
- Object.defineProperty(navigator, 'mediaDevices', {
114
- get: () => ({
115
- enumerateDevices: () => Promise.resolve([
116
- { deviceId: 'default', kind: 'audioinput', label: '', groupId: 'default' },
117
- { deviceId: 'default', kind: 'audiooutput', label: '', groupId: 'default' },
118
- { deviceId: '', kind: 'videoinput', label: '', groupId: '' },
119
- ]),
120
- getUserMedia: () => Promise.reject(new DOMException('NotAllowedError')),
121
- getDisplayMedia: () => Promise.reject(new DOMException('NotAllowedError')),
122
- }),
123
- configurable: true,
124
- });
125
- }
126
- // ── Missing platform APIs (headless often lacks these) ─
127
- try {
128
- if (!navigator.share) {
129
- navigator.share = function() { return Promise.reject(new Error('NotAllowedError')); };
44
+ synthesizer: {
45
+ type: "string",
46
+ description: 'Synthesis engine for synthesize=true. Defaults to ~/.dm/greedyconfig synthesizer ("gemini" by default). Supported: "gemini", "chatgpt".'
47
+ },
48
+ depth: {
49
+ type: "string",
50
+ description: 'Use "research" for the iterative research workflow. Legacy values: "fast" skips source fetching; "standard"/"deep" alias synthesize=true.'
51
+ },
52
+ breadth: {
53
+ type: "number",
54
+ default: 3,
55
+ description: 'Only for depth="research": number of parallel research directions per round, 1-5.'
56
+ },
57
+ iterations: {
58
+ type: "number",
59
+ default: 2,
60
+ description: 'Only for depth="research": number of iterative research rounds, 1-3.'
61
+ },
62
+ maxSources: {
63
+ type: "number",
64
+ description: 'Only for depth="research": maximum fetched sources for the final report, 3-12.'
65
+ },
66
+ researchOutDir: {
67
+ type: "string",
68
+ description: 'Only for depth="research": optional directory for the structured research bundle.'
69
+ },
70
+ writeResearchBundle: {
71
+ type: "boolean",
72
+ default: true,
73
+ description: 'Only for depth="research": write the structured research bundle to disk.'
74
+ },
75
+ fullAnswer: {
76
+ type: "boolean",
77
+ default: false,
78
+ description: "When true, returns the complete answer instead of a truncated preview."
79
+ },
80
+ locale: {
81
+ type: "string",
82
+ description: 'Force results language (e.g. "en", "de", "fr"). Defaults to GREEDY_SEARCH_LOCALE or "en".'
83
+ },
84
+ visible: {
85
+ type: "boolean",
86
+ default: false,
87
+ description: "Set to true to always use visible Chrome for this search (e.g. to solve a login/captcha challenge)."
130
88
  }
131
- } catch(_) {}
132
- try {
133
- if (!navigator.contentIndex) {
134
- Object.defineProperty(navigator, 'contentIndex', { get: () => ({ add: function() {}, delete: function() {}, getAll: function() { return Promise.resolve([]); } }), configurable: true });
89
+ },
90
+ required: ["query"]
91
+ };
92
+ const GREEDY_FETCH_SCHEMA = {
93
+ type: "object",
94
+ properties: {
95
+ url: { type: "string", description: "URL to fetch and extract content from" },
96
+ maxChars: {
97
+ type: "number",
98
+ default: 8000,
99
+ description: "Maximum characters of extracted content to return."
135
100
  }
136
- } catch(_) {}
137
-
138
- if (!window.chrome) {
139
- window.chrome = {
140
- app: { isInstalled: false, InstallState: {}, RunningState: {} },
141
- runtime: {
142
- OnInstalledReason: {}, OnRestartRequiredReason: {}, PlatformArch: {}, PlatformNaclArch: {}, PlatformOs: {}, RequestUpdateCheckStatus: {},
143
- connect: () => ({}), sendMessage: () => {}, onMessage: { addListener: () => {} }
144
- },
145
- 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' }; },
146
- csi: function() { var t = Date.now(); return { onloadT: t - 2000, startE: t - 5000, pageT: 'back', tran: 2 }; },
147
- };
101
+ },
102
+ required: ["url"]
103
+ };
104
+ const TOOLS = [
105
+ {
106
+ name: "greedy_search",
107
+ description: "WEB/RESEARCH SEARCH ONLY — searches live web via Perplexity, Google AI, ChatGPT, and Gemini, " + "plus opt-in research through Semantic Scholar and Logically, using local headless Chrome automation " + '(no API keys needed). Research mode (depth: "research") plans follow-up actions, fetches sources, ' + "audits citations, and writes a structured research bundle on disk. Searches take roughly 1-5 minutes.",
108
+ inputSchema: GREEDY_SEARCH_SCHEMA
109
+ },
110
+ {
111
+ name: "greedy_fetch",
112
+ description: "Fetch a single URL and extract its readable content (title, byline, markdown body). " + "Uses HTTP first, falling back to Chrome/browser rendering for JS-heavy or blocked pages.",
113
+ inputSchema: GREEDY_FETCH_SCHEMA
148
114
  }
149
- var __greedyNativeFns = [];
150
- function __markNative(fn) { try { __greedyNativeFns.push(fn); } catch(_) {} return fn; }
151
-
152
- var origQuery = navigator.permissions?.query;
153
- if (origQuery) {
154
- navigator.permissions.query = __markNative(function query(params) {
155
- if (params && params.name === 'notifications') return Promise.resolve({ state: Notification.permission || 'default', onchange: null });
156
- return origQuery.apply(this, arguments);
157
- });
115
+ ];
116
+ function buildSearchFlags(args) {
117
+ const engine = String(args.engine ?? "all").trim() || "all";
118
+ const depthRaw = String(args.depth ?? "").trim();
119
+ const researchMode = depthRaw === "research";
120
+ const legacyFast = depthRaw === "fast";
121
+ const legacySynthesisDepth = depthRaw === "standard" || depthRaw === "deep";
122
+ const synthesize = engine === "all" && !legacyFast && (args.synthesize === true || legacySynthesisDepth);
123
+ const effectiveEngine = researchMode ? "all" : engine;
124
+ const visible = args.visible === true || process.env.GREEDY_SEARCH_VISIBLE === "1";
125
+ const flags = [];
126
+ const fullAnswer = args.fullAnswer ?? effectiveEngine !== "all";
127
+ if (fullAnswer)
128
+ flags.push("--full");
129
+ if (researchMode) {
130
+ flags.push("--depth", "research");
131
+ if (typeof args.breadth === "number")
132
+ flags.push("--breadth", String(args.breadth));
133
+ if (typeof args.iterations === "number")
134
+ flags.push("--iterations", String(args.iterations));
135
+ if (typeof args.maxSources === "number")
136
+ flags.push("--max-sources", String(args.maxSources));
137
+ if (typeof args.researchOutDir === "string")
138
+ flags.push("--research-out-dir", args.researchOutDir);
139
+ if (args.writeResearchBundle === false)
140
+ flags.push("--no-research-bundle");
141
+ } else if (legacyFast) {
142
+ flags.push("--fast");
143
+ } else if (depthRaw === "deep") {
144
+ flags.push("--depth", "deep");
145
+ } else if (synthesize) {
146
+ flags.push("--synthesize");
158
147
  }
159
- try {
160
- var getParam = WebGLRenderingContext.prototype.getParameter;
161
- WebGLRenderingContext.prototype.getParameter = __markNative(function getParameter(p) {
162
- if (p === 37445) return 'Intel Inc.';
163
- if (p === 37446) return 'Intel Iris OpenGL Engine';
164
- return getParam.call(this, p);
165
- });
166
- } catch(_) {}
167
- // ── WebGL readPixels noise ──────────────────────────
168
- // CreepJS and other fingerprinters draw content with WebGL and read back the
169
- // rendered pixels. Adding subtle noise breaks rendering-based fingerprinting.
170
- try {
171
- var origReadPixels = WebGLRenderingContext.prototype.readPixels;
172
- WebGLRenderingContext.prototype.readPixels = __markNative(function readPixels(x, y, width, height, format, type, pixels) {
173
- var result = origReadPixels.call(this, x, y, width, height, format, type, pixels);
174
- if (pixels && pixels.length > 0) {
175
- pixels[0] ^= 1;
176
- }
177
- return result;
178
- });
179
- } catch(_) {}
180
- Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8, configurable: true });
181
- Object.defineProperty(navigator, 'deviceMemory', { get: () => 8, configurable: true });
182
-
183
- // ── Canvas fingerprint noise ─────────────────────────
184
- // Headless rendering engines produce slightly different canvas output
185
- // than headed Chrome. Subtle noise breaks hash-based fingerprinting.
186
- try {
187
- var __canvasNoise = ((Date.now() & 0xFF) | 1);
188
- var origFill = CanvasRenderingContext2D.prototype.fillText;
189
- CanvasRenderingContext2D.prototype.fillText = __markNative(function fillText() {
190
- this.globalAlpha = 0.9995;
191
- return origFill.apply(this, arguments);
148
+ if (synthesize && typeof args.synthesizer === "string") {
149
+ flags.push("--synthesizer", args.synthesizer);
150
+ }
151
+ if (typeof args.locale === "string" && args.locale) {
152
+ flags.push("--locale", args.locale);
153
+ }
154
+ if (visible)
155
+ flags.push("--always-visible");
156
+ else
157
+ flags.push("--headless");
158
+ return { engine: effectiveEngine, flags, visible };
159
+ }
160
+ function runSearch(query, args) {
161
+ return new Promise((resolve, reject) => {
162
+ const { engine, flags, visible } = buildSearchFlags(args);
163
+ const procEnv = { ...process.env };
164
+ if (visible) {
165
+ procEnv.GREEDY_SEARCH_VISIBLE = "1";
166
+ procEnv.GREEDY_SEARCH_ALWAYS_VISIBLE = "1";
167
+ }
168
+ const proc = spawn(nodeRuntimeCommand(), [SEARCH_BIN, engine, "--inline", "--stdin", ...flags], { stdio: ["pipe", "pipe", "pipe"], env: procEnv });
169
+ proc.stdin.write(query);
170
+ proc.stdin.end();
171
+ let out = "";
172
+ let err = "";
173
+ const MAX_ERR = 50 * 1024;
174
+ let settled = false;
175
+ const parsedTimeout = parseInt(process.env.GREEDY_SEARCH_TIMEOUT_MS || "", 10);
176
+ const timeoutMs = Number.isNaN(parsedTimeout) ? DEFAULT_TIMEOUT_MS : parsedTimeout;
177
+ const timer = setTimeout(() => {
178
+ if (settled)
179
+ return;
180
+ settled = true;
181
+ if (process.platform === "win32")
182
+ proc.kill();
183
+ else
184
+ proc.kill("SIGTERM");
185
+ reject(new Error(`greedy_search timed out after ${timeoutMs}ms`));
186
+ }, timeoutMs);
187
+ timer.unref();
188
+ proc.stderr.on("data", (d) => {
189
+ err += d;
190
+ if (err.length > MAX_ERR)
191
+ err = err.slice(-MAX_ERR);
192
+ log(d.toString().trimEnd());
192
193
  });
193
- } catch(_) {}
194
- try {
195
- var origStroke = CanvasRenderingContext2D.prototype.strokeText;
196
- CanvasRenderingContext2D.prototype.strokeText = __markNative(function strokeText() {
197
- this.globalAlpha = 0.9995;
198
- return origStroke.apply(this, arguments);
194
+ proc.stdout.on("data", (d) => out += d);
195
+ proc.on("error", (e) => {
196
+ if (settled)
197
+ return;
198
+ settled = true;
199
+ clearTimeout(timer);
200
+ reject(e);
199
201
  });
200
- } catch(_) {}
201
- try {
202
- var origToDataURL = HTMLCanvasElement.prototype.toDataURL;
203
- HTMLCanvasElement.prototype.toDataURL = __markNative(function toDataURL() {
204
- var ctx = this.getContext('2d');
205
- if (ctx) {
206
- // Spread noise across canvas to break hash-based fingerprinting.
207
- // Uses a deterministic pattern so it's consistent per page load
208
- // but varies between sessions.
209
- var w = this.width, h = this.height;
210
- if (w > 0 && h > 0) {
211
- var imgData = ctx.getImageData(0, 0, Math.min(w, 4), Math.min(h, 4));
212
- if (imgData && imgData.data) {
213
- for (var __i = 0; __i < imgData.data.length; __i += 4) {
214
- imgData.data[__i] ^= (__canvasNoise + __i) & 0xFF;
215
- }
216
- ctx.putImageData(imgData, 0, 0);
217
- }
218
- }
202
+ proc.on("close", (code) => {
203
+ if (settled)
204
+ return;
205
+ settled = true;
206
+ clearTimeout(timer);
207
+ if (code !== 0) {
208
+ reject(new Error(err.trim() || `search.mjs exited with code ${code}`));
209
+ return;
219
210
  }
220
- return origToDataURL.apply(this, arguments);
221
- });
222
- } catch(_) {}
223
-
224
- // ── AudioContext fingerprint noise ────────────────────
225
- // Headless Chrome's AudioContext produces slightly different output.
226
- // Subtle noise breaks audio-based fingerprinting.
227
- try {
228
- var __audioSeed = ((Date.now() & 0x1F) | 1);
229
- var origGetChannelData = AudioBuffer.prototype.getChannelData;
230
- AudioBuffer.prototype.getChannelData = __markNative(function getChannelData(channel) {
231
- var data = origGetChannelData.call(this, channel);
232
- for (var __i = 0; __i < data.length; __i += 64) {
233
- data[__i] *= 0.99999;
211
+ try {
212
+ resolve(JSON.parse(out.trim()));
213
+ } catch {
214
+ reject(new Error(`Invalid JSON from search.mjs: ${out.slice(0, 200)}`));
234
215
  }
235
- return data;
236
- });
237
- } catch(_) {}
238
-
239
- // ── window outer dimensions ──────────────────────────
240
- // outerWidth/Height = 0 in headless — a well-known bot signal.
241
- // Mirror innerWidth/Height (set by --window-size flag) so the ratio is sane.
242
- try {
243
- if (!window.outerWidth) Object.defineProperty(window, 'outerWidth', { get: () => window.innerWidth || 1920, configurable: true });
244
- if (!window.outerHeight) Object.defineProperty(window, 'outerHeight', { get: () => window.innerHeight || 1080, configurable: true });
245
- } catch(_) {}
246
-
247
- // ── screen properties ─────────────────────────────────
248
- // Headless Chrome often reports an 800x600 screen even when the viewport is
249
- // 1920x1080. Keep screen metrics internally consistent with our launch flags.
250
- try {
251
- Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
252
- Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
253
- Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
254
- Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true });
255
- Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
256
- Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
257
- } catch(_) {}
258
-
259
- // ── navigator.userAgentData (UA Client Hints) ─────────
260
- // Derive version from the UA string already set by --user-agent flag so the
261
- // two APIs are always consistent. Removes any "HeadlessChrome" brand entry.
262
- try {
263
- var _uaMajor = (navigator.userAgent.match(new RegExp('Chrome/([0-9]+)')) || [])[1] || '136';
264
- var _uaFull = (navigator.userAgent.match(new RegExp('Chrome/([0-9.]+)')) || [])[1] || (_uaMajor + '.0.0.0');
265
- var _brands = [
266
- { brand: 'Not)A;Brand', version: '99' },
267
- { brand: 'Google Chrome', version: _uaMajor },
268
- { brand: 'Chromium', version: _uaMajor },
269
- ];
270
- Object.defineProperty(navigator, 'userAgentData', {
271
- get: function() {
272
- return {
273
- brands: _brands, mobile: false, platform: 'Windows',
274
- getHighEntropyValues: function() {
275
- return Promise.resolve({
276
- architecture: 'x86', bitness: '64',
277
- brands: _brands,
278
- fullVersionList: [
279
- { brand: 'Not)A;Brand', version: '99.0.0.0' },
280
- { brand: 'Google Chrome', version: _uaFull },
281
- { brand: 'Chromium', version: _uaFull },
282
- ],
283
- mobile: false, model: '', platform: 'Windows',
284
- platformVersion: '15.0.0', uaFullVersion: _uaFull, wow64: false,
285
- });
286
- },
287
- toJSON: function() { return { brands: _brands, mobile: false, platform: 'Windows' }; },
288
- };
289
- },
290
- configurable: true,
291
216
  });
292
- } catch(_) {}
293
-
294
- // ── CDP Runtime serialization guard ──────────────────
295
- // Sites detect CDP by putting a getter on Error.prototype.stack
296
- // and checking if console.log triggers it (only happens when
297
- // Runtime domain is enabled). We monkey-patch console methods to
298
- // strip custom getters from arguments before they reach CDP.
299
- try {
300
- var _origLog = console.log, _origError = console.error,
301
- _origWarn = console.warn, _origDebug = console.debug,
302
- _origInfo = console.info;
303
- var _safeArg = function(a) {
304
- if (a instanceof Error) {
305
- try { return new Error(a.message); } catch(_) { return a; }
217
+ });
218
+ }
219
+ function formatSummary(engine, data) {
220
+ const lines = [];
221
+ const needsHuman = data._needsHumanVerification;
222
+ if (needsHuman) {
223
+ lines.push("## Manual verification required");
224
+ lines.push(String(needsHuman.message || "Visible Chrome is open. Solve the verification challenge, then rerun the same search."));
225
+ }
226
+ const synthesis = data._synthesis;
227
+ if (synthesis?.answer) {
228
+ lines.push(String(synthesis.answer));
229
+ const sources = Array.isArray(data._sources) ? data._sources : [];
230
+ if (sources.length > 0) {
231
+ lines.push(`
232
+ Sources:`);
233
+ for (const s of sources.slice(0, 8)) {
234
+ lines.push(`- [${s.title || s.url}](${s.url})`);
306
235
  }
307
- return a;
308
- };
309
- console.log = __markNative(function log() { return _origLog.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
310
- console.error = __markNative(function error() { return _origError.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
311
- console.warn = __markNative(function warn() { return _origWarn.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
312
- console.debug = __markNative(function debug() { return _origDebug.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
313
- console.info = __markNative(function info() { return _origInfo.apply(console, Array.prototype.map.call(arguments, _safeArg)); });
314
- } catch(_) {}
315
-
316
- // ── Native function masking ──────────────────────────
317
- // Patched APIs should not stringify as user-defined stealth code.
318
- try {
319
- var __nativeToString = Function.prototype.toString;
320
- Function.prototype.toString = function toString() {
321
- if (__greedyNativeFns.indexOf(this) !== -1) {
322
- var name = this.name || '';
323
- return 'function ' + name + '() { [native code] }';
236
+ }
237
+ return lines.join(`
238
+ `).trim();
239
+ }
240
+ if (typeof data.answer === "string") {
241
+ lines.push(data.answer);
242
+ const sources = Array.isArray(data.sources) ? data.sources : [];
243
+ if (sources.length > 0) {
244
+ lines.push(`
245
+ Sources:`);
246
+ for (const s of sources.slice(0, 8)) {
247
+ lines.push(`- [${s.title || s.url}](${s.url})`);
324
248
  }
325
- return __nativeToString.call(this);
249
+ }
250
+ return lines.join(`
251
+ `).trim();
252
+ }
253
+ const engineKeys = Object.keys(data).filter((k) => !k.startsWith("_") && data[k] && typeof data[k] === "object");
254
+ for (const key of engineKeys) {
255
+ const eng = data[key];
256
+ if (engineKeys.length > 1) {
257
+ lines.push(`
258
+ ## ${key}`);
259
+ }
260
+ if (eng.error) {
261
+ lines.push(`Error: ${eng.error}`);
262
+ continue;
263
+ }
264
+ if (eng.answer)
265
+ lines.push(String(eng.answer));
266
+ const sources = Array.isArray(eng.sources) ? eng.sources : [];
267
+ if (sources.length > 0) {
268
+ lines.push(`
269
+ Sources:`);
270
+ for (const s of sources.slice(0, 5)) {
271
+ lines.push(`- [${s.title || s.url}](${s.url})`);
272
+ }
273
+ }
274
+ }
275
+ return lines.join(`
276
+ `).trim() || "No results returned.";
277
+ }
278
+ async function callGreedySearch(args) {
279
+ if (!args || typeof args.query !== "string" || !args.query.trim()) {
280
+ throw new Error("query is required");
281
+ }
282
+ const data = await runSearch(args.query, args);
283
+ const summary = formatSummary(args.engine ?? "all", data);
284
+ return {
285
+ content: [
286
+ { type: "text", text: summary || "No results returned." },
287
+ { type: "text", text: JSON.stringify(data) }
288
+ ]
289
+ };
290
+ }
291
+ let fetchSourceContentPromise;
292
+ function getFetchSourceContent() {
293
+ if (!fetchSourceContentPromise) {
294
+ fetchSourceContentPromise = import("../src/search/fetch-source.mjs").then((m) => m.fetchSourceContent);
295
+ }
296
+ return fetchSourceContentPromise;
297
+ }
298
+ async function callGreedyFetch(args) {
299
+ if (!args || typeof args.url !== "string" || !args.url.trim()) {
300
+ throw new Error("url is required");
301
+ }
302
+ const maxChars = typeof args.maxChars === "number" ? args.maxChars : 8000;
303
+ const fetchSourceContent = await getFetchSourceContent();
304
+ const result = await fetchSourceContent(args.url, maxChars);
305
+ if (result?.error && !result.content) {
306
+ return {
307
+ content: [{ type: "text", text: `Fetch failed: ${result.error}` }],
308
+ isError: true
326
309
  };
327
- } catch(_) {}
328
- })();
329
- `})])}var N1,z1,G1;var U0=U(()=>{P();N1=j1(Y1(import.meta.url)),z1=H1(N1,"..","bin","cdp.mjs"),G1=new Set(["list","snap","eval","shot","html","nav","net","click","clickxy","type","loadall","evalraw","browse","stop","--tab"])});var x=()=>{};var l=U(()=>{x()});import{fileURLToPath as U1}from"node:url";function k0($){return U1(new URL(".",$)).replace(/^\/([A-Z]:)/,"$1")}var D0=()=>{};import{existsSync as I,mkdirSync as O1,readFileSync as b0,writeFileSync as k1}from"node:fs";import{homedir as D1}from"node:os";import{join as F0}from"node:path";import{tmpdir as v1}from"node:os";function b1($,Q=9222){let X=Number.parseInt(String($??""),10);return Number.isInteger(X)&&X>1024&&X<65535?X:Q}function y1(){try{if(I(v)){let $=b0(v,"utf8"),Q=JSON.parse($);if(Array.isArray(Q.engines)&&Q.engines.length>0&&Q.engines.every((X)=>typeof X==="string")){let X=Q.engines.filter((Z)=>d[Z]),W=Q.engines.filter((Z)=>!d[Z]);if(W.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${v}: ${W.join(", ")}
330
- [greedysearch] Available engines: ${Object.keys(d).join(", ")}
331
- `);if(X.length>0)return X;process.stderr.write(`[greedysearch] Warning: no valid engines in ${v}, falling back to defaults: ${o.join(", ")}
332
- `)}}}catch{}return o}function S1(){try{if(!I(n))O1(n,{recursive:!0});if(!I(v))k1(v,JSON.stringify({engines:o,synthesizer:s},null,2)+`
333
- `,"utf8")}catch{}}function C1(){try{if(I(v)){let $=b0(v,"utf8"),Q=JSON.parse($);if(typeof Q.synthesizer==="string"){let X=Q.synthesizer.toLowerCase();if(v0.includes(X))return X;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${Q.synthesizer}" in ${v}
334
- [greedysearch] Available synthesizers: ${v0.join(", ")}
335
- [greedysearch] Falling back to default: ${s}
336
- `)}}}catch{}return s}var F1,w0,O,w1,T0,T1,L0,L1,P1,P0,y$,S$,n,v,o,s="gemini",v0,d,C$,x$,a;var _=U(()=>{F1=v1().replaceAll("\\","/"),w0=b1(process.env.GREEDY_SEARCH_PORT),O=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${F1}/greedysearch-chrome-profile`).replaceAll("\\","/"),w1=`${O}/DevToolsActivePort`,T0=process.env.GREEDY_SEARCH_PID_FILE||`${O}/browser.pid`,T1=process.env.CDP_PAGES_CACHE||`${O}/cdp-pages.json`,L0=process.env.GREEDY_SEARCH_MODE_FILE||`${O}/browser-mode`,L1=process.env.GREEDY_SEARCH_METADATA_FILE||`${O}/browser-metadata.json`,P1=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${O}/browser-launch.lock`,P0=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${O}/browser-last-activity`,y$=(process.env.CDP_SOCKET_DIR||`${O}/cdp-sockets`).replaceAll("\\","/"),S$=`${O}/visible-recovery.jsonl`,n=F0(D1(),".dm"),v=F0(n,"greedyconfig"),o=["perplexity","google","chatgpt","gemini"];S1();v0=["gemini","chatgpt"];d={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"},C$=y1(),x$=C1(),a=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=O});var g$;var y0=U(()=>{_();x();l();g$=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5});async function S0(){let Q=(await G(["list"])).split(`
337
- `)[0];if(!Q)throw Error("No Chrome tabs found");return Q.slice(0,8)}async function f($="about:blank"){let Q=await S0(),X=new URL($).hostname;if(X==="copilot.microsoft.com"||X==="www.perplexity.ai"||X==="perplexity.ai"||X.endsWith(".perplexity.ai")){let J=await G(["evalraw",Q,"Target.createTarget",JSON.stringify({url:"about:blank"})]),{targetId:q}=JSON.parse(J),V=q.slice(0,8);if(await G(["list"]).catch(()=>null),X==="copilot.microsoft.com")await i(V);else i(V).catch(()=>{});return await G(["list"]).catch(()=>null),q}let Z=await G(["evalraw",Q,"Target.createTarget",JSON.stringify({url:$})]),{targetId:K}=JSON.parse(Z);return await G(["list"]).catch(()=>null),K}async function R($){try{let Q=await S0();await G(["evalraw",Q,"Target.closeTarget",JSON.stringify({targetId:$})])}catch{}}var t$,e$,$2,G;var C0=U(()=>{P();U0();x();l();D0();_();y0();t$=k0(import.meta.url),e$=Number.parseInt(process.env.GREEDY_SEARCH_IDLE_TIMEOUT_MINUTES||"5",10)||5,$2=Number.parseInt(process.env.GREEDY_SEARCH_VISIBLE_IDLE_TIMEOUT_MINUTES||"60",10)||60,G=c});function I1(){if(typeof globalThis.DOMMatrix>"u")globalThis.DOMMatrix=class{constructor(Q=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(Q=void 0,X=0,W=0){this.data=Q,this.width=X,this.height=W}};if(typeof globalThis.Path2D>"u")globalThis.Path2D=class{constructor(Q=void 0){}}}async function _1(){I1();let $=await import("pdf-parse"),Q=$.PDFParse??$.default;if(!Q)throw Error("pdf-parse did not export PDFParse");return Q}async function x0($,Q){try{let W=new(await _1())({data:new Uint8Array($)});await W.load();let Z=await W.getText(),K=Z.text?.trim();if(!K)return null;return{title:new URL(Q).pathname.split("/").pop()||"Document.pdf",content:`## PDF Content (${Z.total} pages)
338
-
339
- ${K}`,pages:Z.total}}catch(X){return{error:X.message||String(X)}}}function r($="",Q=240){let X=String($).replaceAll(/\s+/g," ").trim();if(X.length<=Q)return X;let W=X.slice(0,Q),Z=W.lastIndexOf(" ");return Z>0?`${W.slice(0,Z)}...`:`${W}...`}var I0=()=>{};var g0={};i0(g0,{fetchTopSource:()=>h1,fetchSourceContent:()=>f0,fetchMultipleSources:()=>E1});async function f1($,Q,X=8000){let W=Date.now();try{let K=(await G(["evalraw",$,"Page.getFrameTree","{}"]).then((A)=>JSON.parse(A)).catch(()=>null))?.frameTree?.frame?.id||void 0,J=await G(["evalraw",$,"Network.loadNetworkResource",JSON.stringify({frameId:K,url:Q,options:{disableCache:!0,includeCredentials:!1}})],20000),V=JSON.parse(J).resource;if(!V?.success||!V.httpStatusCode)return{url:Q,error:V?.netErrorName||V?.netError||"loadNetworkResource failed",source:"chrome",duration:Date.now()-W,needsFallback:!0};let B="";if(V.stream)try{let A=await G(["evalraw",$,"IO.read",JSON.stringify({handle:V.stream})],1e4);B=JSON.parse(A).data||"",await G(["evalraw",$,"IO.close",JSON.stringify({handle:V.stream})]).catch(()=>{})}catch{}if(!B||B.length<100)return{url:Q,error:"Empty response body from Network.loadNetworkResource",source:"chrome",duration:Date.now()-W,needsFallback:!0};let j=h(V.httpStatusCode,B,Q,Q);if(j.blocked)return{url:Q,status:V.httpStatusCode,error:`Blocked: ${j.reason}`,source:"chrome",duration:Date.now()-W,needsBrowser:!0};let H=await p(B,Q),Y=u(H);if(!Y.ok)return{url:Q,status:V.httpStatusCode,error:`Low quality: ${Y.reason}`,source:"chrome",duration:Date.now()-W,needsBrowser:!0};let N=b(H.markdown,X);return{url:Q,finalUrl:Q,status:V.httpStatusCode,contentType:"text/markdown",lastModified:"",publishedTime:H.publishedTime||"",byline:H.byline||"",siteName:H.siteName||"",lang:H.lang||"",title:H.title||Q,snippet:H.excerpt,content:N,contentChars:N.length,source:"chrome",duration:Date.now()-W}}catch(Z){return{url:Q,error:Z.message,source:"chrome",duration:Date.now()-W,needsFallback:!0}}}function _0($){try{return new URL($).pathname.toLowerCase().endsWith(".pdf")}catch{return!1}}async function R1($,Q=8000){let X=S($);if(X.blocked)return{url:$,finalUrl:$,status:403,error:`Blocked: ${X.reason}`,source:"pdf-http"};let W=new AbortController,Z=setTimeout(()=>W.abort(),20000),K=Date.now();try{let J=await fetch($,{method:"GET",redirect:"follow",signal:W.signal,headers:J0({accept:"application/pdf,application/octet-stream;q=0.9,*/*;q=0.5"})});clearTimeout(Z);let q=J.headers.get("content-type")||"",V=J.url||$,B=Number.parseInt(J.headers.get("content-length")||"0",10);if(J.status>=400)return{url:$,finalUrl:V,status:J.status,error:`HTTP ${J.status}`,source:"pdf-http",duration:Date.now()-K};if(!q.toLowerCase().includes("application/pdf")&&!_0(V))return null;if(B>31457280)return{url:$,finalUrl:V,status:J.status,error:`PDF too large: ${B} bytes`,source:"pdf-http",duration:Date.now()-K};let j=Buffer.from(await J.arrayBuffer()),H=await x0(j,V);if(!H||H.error)return{url:$,finalUrl:V,status:J.status,error:H?.error||"PDF text extraction failed",source:"pdf-http",duration:Date.now()-K};let Y=b(H.content,Q);return{url:$,finalUrl:V,status:J.status,contentType:"application/pdf",lastModified:J.headers.get("last-modified")||"",title:H.title,snippet:r(Y,320),content:Y,contentChars:Y.length,pages:H.pages,source:"pdf-http",duration:Date.now()-K}}catch(J){return clearTimeout(Z),{url:$,finalUrl:$,error:J.message||String(J),source:"pdf-http",duration:Date.now()-K}}}async function f0($,Q=8000){let X=Date.now();if(_0($)){let K=await R1($,Q);if(K?.content||K?.status===403)return K}if(C($)){let K=C($);if(K&&(K.type==="root"||K.type==="tree"||K.type==="blob"&&!K.path?.includes("."))){let J=await j0($);if(J.ok){let q=b(J.content,Q);return{url:$,finalUrl:$,status:200,contentType:"text/markdown",lastModified:"",title:J.title,snippet:q.slice(0,320),content:q,contentChars:q.length,source:"github-api",...J.tree&&{tree:J.tree},duration:Date.now()-X}}process.stderr.write(`[greedysearch] GitHub API fetch failed, trying HTTP: ${J.error}
340
- `)}}if(N0($)?.type==="post"){process.stderr.write(`[greedysearch] Using Reddit JSON API for: ${$.slice(0,60)}...
341
- `);let K=await z0($,Q);if(K.ok){let J=b(K.markdown,Q);return{url:$,finalUrl:K.finalUrl,status:K.status,contentType:"text/markdown",lastModified:K.lastModified||"",publishedTime:K.publishedTime||"",byline:K.byline||"",siteName:K.siteName||"",lang:K.lang||"",title:K.title,snippet:K.excerpt,content:J,contentChars:J.length,source:"reddit-api",duration:Date.now()-X}}process.stderr.write(`[greedysearch] Reddit API fetch failed, falling back to HTTP: ${K.error}
342
- `)}let Z=await K0($,{timeoutMs:1e4});if(Z.ok){let K=b(Z.markdown,Q);return{url:$,finalUrl:Z.finalUrl,status:Z.status,contentType:"text/markdown",lastModified:Z.lastModified||"",publishedTime:Z.publishedTime||"",byline:Z.byline||"",siteName:Z.siteName||"",lang:Z.lang||"",title:Z.title,snippet:Z.excerpt,content:K,contentChars:K.length,source:"http",duration:Date.now()-X}}if(Z.needsBrowser)try{let K=await f();try{let J=await f1(K,$,Q);if(J.content&&J.content.length>100)return J}finally{await R(K)}}catch{}return process.stderr.write(`[greedysearch] HTTP failed for ${$.slice(0,60)}, trying browser...
343
- `),await g1($,Q)}async function R0($,Q=4000,X=200){let W=Date.now()+Q;while(Date.now()<W){try{if((await G(["eval",$,'document.readyState === "complete" && !!document.body && document.body.innerText.length > 500'])).trim()==="true")return}catch{}await new Promise((Z)=>setTimeout(Z,X))}}async function g1($,Q=8000){let X=Date.now(),W;try{W=await f()}catch(Z){return{url:$,title:"",content:null,snippet:"",contentChars:0,error:`openNewTab failed: ${Z.message}`,source:"browser",duration:Date.now()-X}}try{await G(["nav",W,$],30000),await R0(W);let Z=await G(["eval",W,String.raw`
344
- (function(){
345
- var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
346
- var text = (el || document.body).innerText;
347
- return JSON.stringify({
348
- title: document.title,
349
- content: text.replace(/\s+/g, ' ').trim(),
350
- url: location.href
351
- });
352
- })()
353
- `]),K=JSON.parse(Z),J=b(K.content,Q);return{url:$,finalUrl:K.url||$,status:200,contentType:"text/plain",lastModified:"",title:K.title,snippet:r(J,320),content:J,contentChars:J.length,source:"browser",duration:Date.now()-X}}catch(Z){return{url:$,title:"",content:null,snippet:"",contentChars:0,error:Z.message,source:"browser",duration:Date.now()-X}}finally{await R(W)}}async function E1($,Q=5,X=8000,W=a){let Z=$.slice(0,Q);if(Z.length===0)return[];let K=Math.min(Z.length,Math.max(1,Number.parseInt(String(W),10)||a));process.stderr.write(`[greedysearch] Fetching content from ${Z.length} sources via HTTP (concurrency ${K})...
354
- `);let J=Array(Z.length),q=0,V=0;async function B(){while(!0){let N=q++;if(N>=Z.length)return;let A=Z[N],M=A.canonicalUrl||A.url;process.stderr.write(`[greedysearch] [${N+1}/${Z.length}] Fetching: ${M.slice(0,60)}...
355
- `);let z=await f0(M,X).catch((k)=>({url:M,title:"",content:null,snippet:"",contentChars:0,error:k.message,source:"error",duration:0}));if(J[N]={id:A.id,...z},z.content&&z.content.length>100)process.stderr.write(`[greedysearch] ✓ ${z.source}: ${z.content.length} chars
356
- `);else if(z.error)process.stderr.write(`[greedysearch] ✗ ${z.error.slice(0,80)}
357
- `);V+=1,process.stderr.write(`PROGRESS:fetch:${V}/${Z.length}
358
- `)}}await Promise.all(Array.from({length:K},()=>B()));let j=J.filter((N)=>N.content&&N.content.length>100),H=J.filter((N)=>N.source==="http").length,Y=J.filter((N)=>N.source==="browser").length;return process.stderr.write(`[greedysearch] Fetched ${j.length}/${J.length} sources (HTTP: ${H}, Browser: ${Y})
359
- `),J}async function h1($){let Q=await f();try{await G(["nav",Q,$],30000),await R0(Q);let X=await G(["eval",Q,String.raw`
360
- (function(){
361
- var el = document.querySelector('article, [role="main"], main, .post-content, .article-body, #content, .content');
362
- var text = (el || document.body).innerText;
363
- return text.replace(/\s+/g, ' ').trim();
364
- })()
365
- `]);return{url:$,content:X}}catch(X){return{url:$,content:null,error:X.message}}finally{await R(Q)}}var E0=U(()=>{q0();H0();A0();C0();_();I0()});P();import{spawn as p1}from"node:child_process";import{createInterface as u1}from"node:readline";import{fileURLToPath as m1}from"node:url";import{dirname as c1,join as i1}from"node:path";var l1=c1(m1(import.meta.url)),h0=i1(l1,"search.mjs"),d1="2025-06-18",n1={name:"greedysearch",version:"1.0.0"},o1=360000;function g(...$){process.stderr.write(`[greedysearch-mcp] ${$.join(" ")}
366
- `)}function p0($){process.stdout.write(`${JSON.stringify($)}
367
- `)}function w($,Q){if($===void 0||$===null)return;p0({jsonrpc:"2.0",id:$,result:Q})}function E($,Q,X,W){if($===void 0||$===null)return;p0({jsonrpc:"2.0",id:$,error:{code:Q,message:X,...W?{data:W}:{}}})}var s1='Engine to use: "all" (default, fans out to configured engines and fetches top sources), "perplexity" (p), "google" (g), "chatgpt" (gpt), "gemini" (gem), "bing" (b). Research engines: "semantic-scholar" (s2) and "logically" (log).',a1={type:"object",properties:{query:{type:"string",description:"The search query"},engine:{type:"string",default:"all",description:s1},synthesize:{type:"boolean",default:!1,description:'Only for engine="all": synthesize the multi-engine results and fetched sources.'},synthesizer:{type:"string",description:'Synthesis engine for synthesize=true. Defaults to ~/.dm/greedyconfig synthesizer ("gemini" by default). Supported: "gemini", "chatgpt".'},depth:{type:"string",description:'Use "research" for the iterative research workflow. Legacy values: "fast" skips source fetching; "standard"/"deep" alias synthesize=true.'},breadth:{type:"number",default:3,description:'Only for depth="research": number of parallel research directions per round, 1-5.'},iterations:{type:"number",default:2,description:'Only for depth="research": number of iterative research rounds, 1-3.'},maxSources:{type:"number",description:'Only for depth="research": maximum fetched sources for the final report, 3-12.'},researchOutDir:{type:"string",description:'Only for depth="research": optional directory for the structured research bundle.'},writeResearchBundle:{type:"boolean",default:!0,description:'Only for depth="research": write the structured research bundle to disk.'},fullAnswer:{type:"boolean",default:!1,description:"When true, returns the complete answer instead of a truncated preview."},locale:{type:"string",description:'Force results language (e.g. "en", "de", "fr"). Defaults to GREEDY_SEARCH_LOCALE or "en".'},visible:{type:"boolean",default:!1,description:"Set to true to always use visible Chrome for this search (e.g. to solve a login/captcha challenge)."}},required:["query"]},r1={type:"object",properties:{url:{type:"string",description:"URL to fetch and extract content from"},maxChars:{type:"number",default:8000,description:"Maximum characters of extracted content to return."}},required:["url"]},t1=[{name:"greedy_search",description:"WEB/RESEARCH SEARCH ONLY — searches live web via Perplexity, Google AI, ChatGPT, and Gemini, "+'plus opt-in research through Semantic Scholar and Logically, using local headless Chrome automation (no API keys needed). Research mode (depth: "research") plans follow-up actions, fetches sources, audits citations, and writes a structured research bundle on disk. Searches take roughly 1-5 minutes.',inputSchema:a1},{name:"greedy_fetch",description:"Fetch a single URL and extract its readable content (title, byline, markdown body). Uses HTTP first, falling back to Chrome/browser rendering for JS-heavy or blocked pages.",inputSchema:r1}];function e1($){let Q=String($.engine??"all").trim()||"all",X=String($.depth??"").trim(),W=X==="research",Z=X==="fast",K=X==="standard"||X==="deep",J=Q==="all"&&!Z&&($.synthesize===!0||K),q=W?"all":Q,V=$.visible===!0||process.env.GREEDY_SEARCH_VISIBLE==="1",B=[];if($.fullAnswer??q!=="all")B.push("--full");if(W){if(B.push("--depth","research"),typeof $.breadth==="number")B.push("--breadth",String($.breadth));if(typeof $.iterations==="number")B.push("--iterations",String($.iterations));if(typeof $.maxSources==="number")B.push("--max-sources",String($.maxSources));if(typeof $.researchOutDir==="string")B.push("--research-out-dir",$.researchOutDir);if($.writeResearchBundle===!1)B.push("--no-research-bundle")}else if(Z)B.push("--fast");else if(X==="deep")B.push("--depth","deep");else if(J)B.push("--synthesize");if(J&&typeof $.synthesizer==="string")B.push("--synthesizer",$.synthesizer);if(typeof $.locale==="string"&&$.locale)B.push("--locale",$.locale);if(V)B.push("--always-visible");else B.push("--headless");return{engine:q,flags:B,visible:V}}function $$($,Q){return new Promise((X,W)=>{let{engine:Z,flags:K,visible:J}=e1(Q),q={...process.env};if(J)q.GREEDY_SEARCH_VISIBLE="1",q.GREEDY_SEARCH_ALWAYS_VISIBLE="1";let V=p1(F(),[h0,Z,"--inline","--stdin",...K],{stdio:["pipe","pipe","pipe"],env:q});V.stdin.write($),V.stdin.end();let B="",j="",H=51200,Y=!1,N=parseInt(process.env.GREEDY_SEARCH_TIMEOUT_MS||"",10),A=Number.isNaN(N)?o1:N,M=setTimeout(()=>{if(Y)return;if(Y=!0,process.platform==="win32")V.kill();else V.kill("SIGTERM");W(Error(`greedy_search timed out after ${A}ms`))},A);M.unref(),V.stderr.on("data",(z)=>{if(j+=z,j.length>H)j=j.slice(-H);g(z.toString().trimEnd())}),V.stdout.on("data",(z)=>B+=z),V.on("error",(z)=>{if(Y)return;Y=!0,clearTimeout(M),W(z)}),V.on("close",(z)=>{if(Y)return;if(Y=!0,clearTimeout(M),z!==0){W(Error(j.trim()||`search.mjs exited with code ${z}`));return}try{X(JSON.parse(B.trim()))}catch{W(Error(`Invalid JSON from search.mjs: ${B.slice(0,200)}`))}})})}function Q$($,Q){let X=[],W=Q._needsHumanVerification;if(W)X.push("## Manual verification required"),X.push(String(W.message||"Visible Chrome is open. Solve the verification challenge, then rerun the same search."));let Z=Q._synthesis;if(Z?.answer){X.push(String(Z.answer));let J=Array.isArray(Q._sources)?Q._sources:[];if(J.length>0){X.push(`
368
- Sources:`);for(let q of J.slice(0,8))X.push(`- [${q.title||q.url}](${q.url})`)}return X.join(`
369
- `).trim()}if(typeof Q.answer==="string"){X.push(Q.answer);let J=Array.isArray(Q.sources)?Q.sources:[];if(J.length>0){X.push(`
370
- Sources:`);for(let q of J.slice(0,8))X.push(`- [${q.title||q.url}](${q.url})`)}return X.join(`
371
- `).trim()}let K=Object.keys(Q).filter((J)=>!J.startsWith("_")&&Q[J]&&typeof Q[J]==="object");for(let J of K){let q=Q[J];if(K.length>1)X.push(`
372
- ## ${J}`);if(q.error){X.push(`Error: ${q.error}`);continue}if(q.answer)X.push(String(q.answer));let V=Array.isArray(q.sources)?q.sources:[];if(V.length>0){X.push(`
373
- Sources:`);for(let B of V.slice(0,5))X.push(`- [${B.title||B.url}](${B.url})`)}}return X.join(`
374
- `).trim()||"No results returned."}async function X$($){if(!$||typeof $.query!=="string"||!$.query.trim())throw Error("query is required");let Q=await $$($.query,$);return{content:[{type:"text",text:Q$($.engine??"all",Q)||"No results returned."},{type:"text",text:JSON.stringify(Q)}]}}var t;function W$(){if(!t)t=Promise.resolve().then(() => (E0(),g0)).then(($)=>$.fetchSourceContent);return t}async function Z$($){if(!$||typeof $.url!=="string"||!$.url.trim())throw Error("url is required");let Q=typeof $.maxChars==="number"?$.maxChars:8000,W=await(await W$())($.url,Q);if(W?.error&&!W.content)return{content:[{type:"text",text:`Fetch failed: ${W.error}`}],isError:!0};return{content:[{type:"text",text:[`# ${W.title||$.url}`,"",W.byline?`By ${W.byline}`:null,W.siteName?`Source: ${W.siteName}`:null,"",W.content||"(no content extracted)"].filter((K)=>K!==null).join(`
375
- `)},{type:"text",text:JSON.stringify(W)}]}}async function J$($){let{id:Q,method:X,params:W}=$;switch(X){case"initialize":{let Z=W?.protocolVersion;w(Q,{protocolVersion:typeof Z==="string"?Z:d1,capabilities:{tools:{}},serverInfo:n1});return}case"notifications/initialized":case"initialized":return;case"ping":w(Q,{});return;case"tools/list":w(Q,{tools:t1});return;case"tools/call":{let Z=W?.name,K=W?.arguments??{};try{let J;if(Z==="greedy_search")J=await X$(K);else if(Z==="greedy_fetch")J=await Z$(K);else{E(Q,-32602,`Unknown tool: ${Z}`);return}w(Q,J)}catch(J){w(Q,{content:[{type:"text",text:`Error: ${J.message||String(J)}`}],isError:!0})}return}default:if(X&&X.startsWith("notifications/"))return;E(Q,-32601,`Method not found: ${X}`)}}function K$(){let $=u1({input:process.stdin,terminal:!1});$.on("line",(Q)=>{let X=Q.trim();if(!X)return;let W;try{W=JSON.parse(X)}catch{E(null,-32700,"Parse error");return}J$(W).catch((Z)=>{g("Unhandled error:",Z?.stack||String(Z)),E(W?.id,-32603,"Internal error",String(Z?.message||Z))})}),$.on("close",()=>process.exit(0)),process.on("uncaughtException",(Q)=>{g("Uncaught exception:",Q?.stack||String(Q))}),g(`GreedySearch MCP server ready (${h0})`)}K$();
310
+ }
311
+ const summary = [
312
+ `# ${result.title || args.url}`,
313
+ "",
314
+ result.byline ? `By ${result.byline}` : null,
315
+ result.siteName ? `Source: ${result.siteName}` : null,
316
+ "",
317
+ result.content || "(no content extracted)"
318
+ ].filter((l) => l !== null).join(`
319
+ `);
320
+ return {
321
+ content: [
322
+ { type: "text", text: summary },
323
+ { type: "text", text: JSON.stringify(result) }
324
+ ]
325
+ };
326
+ }
327
+ async function handleRequest(msg) {
328
+ const { id, method, params } = msg;
329
+ switch (method) {
330
+ case "initialize": {
331
+ const clientVersion = params?.protocolVersion;
332
+ sendResult(id, {
333
+ protocolVersion: typeof clientVersion === "string" ? clientVersion : PROTOCOL_VERSION,
334
+ capabilities: { tools: {} },
335
+ serverInfo: SERVER_INFO
336
+ });
337
+ return;
338
+ }
339
+ case "notifications/initialized":
340
+ case "initialized":
341
+ return;
342
+ case "ping":
343
+ sendResult(id, {});
344
+ return;
345
+ case "tools/list":
346
+ sendResult(id, { tools: TOOLS });
347
+ return;
348
+ case "tools/call": {
349
+ const name = params?.name;
350
+ const toolArgs = params?.arguments ?? {};
351
+ try {
352
+ let result;
353
+ if (name === "greedy_search")
354
+ result = await callGreedySearch(toolArgs);
355
+ else if (name === "greedy_fetch")
356
+ result = await callGreedyFetch(toolArgs);
357
+ else {
358
+ sendError(id, -32602, `Unknown tool: ${name}`);
359
+ return;
360
+ }
361
+ sendResult(id, result);
362
+ } catch (e) {
363
+ sendResult(id, {
364
+ content: [{ type: "text", text: `Error: ${e.message || String(e)}` }],
365
+ isError: true
366
+ });
367
+ }
368
+ return;
369
+ }
370
+ default:
371
+ if (method && method.startsWith("notifications/"))
372
+ return;
373
+ sendError(id, -32601, `Method not found: ${method}`);
374
+ }
375
+ }
376
+ function main() {
377
+ const rl = createInterface({ input: process.stdin, terminal: false });
378
+ rl.on("line", (line) => {
379
+ const trimmed = line.trim();
380
+ if (!trimmed)
381
+ return;
382
+ let msg;
383
+ try {
384
+ msg = JSON.parse(trimmed);
385
+ } catch {
386
+ sendError(null, -32700, "Parse error");
387
+ return;
388
+ }
389
+ handleRequest(msg).catch((e) => {
390
+ log("Unhandled error:", e?.stack || String(e));
391
+ sendError(msg?.id, -32603, "Internal error", String(e?.message || e));
392
+ });
393
+ });
394
+ rl.on("close", () => process.exit(0));
395
+ process.on("uncaughtException", (e) => {
396
+ log("Uncaught exception:", e?.stack || String(e));
397
+ });
398
+ log(`GreedySearch MCP server ready (${SEARCH_BIN})`);
399
+ }
400
+ main();