@duckmind/dm-windows-x64 0.60.4 → 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 +1,412 @@
1
- var b=["fbclid","gclid","ref","ref_src","ref_url","source","utm_campaign","utm_content","utm_medium","utm_source","utm_term"],C=["dev.to","hashnode.com","medium.com","reddit.com","stackoverflow.com","stackexchange.com","substack.com"],k=["arstechnica.com","techcrunch.com","theverge.com","venturebeat.com","wired.com","zdnet.com"],L=["facebook.com","instagram.com","linkedin.com","pinterest.com","tiktok.com","twitter.com","x.com"];function w(F="",j=240){let B=String(F).replaceAll(/\s+/g," ").trim();if(B.length<=j)return B;let Q=B.slice(0,j),J=Q.lastIndexOf(" ");return J>0?`${Q.slice(0,J)}...`:`${Q}...`}function N(F=""){let j=w(F,180);if(!j)return"";if(/^https?:\/\//i.test(j))return"";let B=j.split(/\s+/).filter(Boolean).length,Q=/[A-Z]/.test(j),J=/\d/.test(j);return j===j.toLowerCase()&&B<=4&&!Q&&!J?"":j}function _(F="",j=""){let B=N(F),Q=N(j);if(!Q)return B;if(!B)return Q;let J=/^https?:\/\//i.test(B),Z=/^https?:\/\//i.test(Q);if(J&&!Z)return Q;if(!J&&Z)return B;return Q.length>B.length?Q:B}function y(F){if(!F)return null;try{let j=new URL(F);if(!["http:","https:"].includes(j.protocol))return null;if(j.hash="",j.hostname=j.hostname.toLowerCase(),j.protocol==="https:"&&j.port==="443"||j.protocol==="http:"&&j.port==="80")j.port="";for(let J of[...j.searchParams.keys()]){let Z=J.toLowerCase();if(b.includes(Z)||Z.startsWith("utm_"))j.searchParams.delete(J)}j.searchParams.sort();let B=j.pathname.replace(/\/{1,10}$/,"")||"/";j.pathname=B;let Q=j.toString();return B==="/"?Q.replace(/\/$/,""):Q}catch{return null}}function g(F){try{return new URL(F).hostname.toLowerCase().replace(/^www\./,"")}catch{return""}}function v(F,j){return j.some((B)=>F===B||F.endsWith(`.${B}`))}function U(F,j="",B=""){let Q=j.toLowerCase(),J=B.toLowerCase();if(F==="github.com"||F==="gitlab.com")return"repo";if(F==="arxiv.org"||F==="doi.org"||F==="semanticscholar.org"||F.endsWith(".semanticscholar.org")||J.includes("/paper/")||J.includes("/pdf/"))return"academic";if(v(F,L))return"social";if(v(F,C))return"community";if(v(F,k))return"news";if(F.startsWith("docs.")||F.startsWith("developer.")||F.startsWith("developers.")||F.startsWith("api.")||Q.includes("documentation")||Q.includes("docs")||Q.includes("reference")||J.includes("/docs/")||J.includes("/reference/")||J.includes("/api/"))return"official-docs";if(F.startsWith("blog.")||J.includes("/blog/"))return"maintainer-blog";return"website"}function p(F){switch(F){case"official-docs":return 5;case"repo":return 4;case"academic":return 4;case"maintainer-blog":return 3;case"website":return 2;case"community":return 1;case"news":return 0;case"social":return-6;default:return 0}}function x(F){let j=Object.values(F.perEngine||{}).map((B)=>B?.rank||99);return j.length?Math.min(...j):99}var T=["reddit.com","news.ycombinator.com","lobste.rs"];function q(F){return F.smartScore*3+F.engineCount*5+p(F.sourceType)*2+Math.max(0,7-x(F))}function f(F){let j=F.toLowerCase(),B=[];if(j.includes("openai")||j.includes("gpt")||j.includes("chatgpt"))B.push("openai.com","platform.openai.com","help.openai.com");if(j.includes("anthropic")||j.includes("claude"))B.push("anthropic.com","docs.anthropic.com");if(j.includes("bun"))B.push("bun.sh","bun.com");if(j.includes("next.js")||j.includes("nextjs"))B.push("nextjs.org","vercel.com");if(j.includes("playwright"))B.push("playwright.dev");if(j.includes("supabase"))B.push("supabase.com","supabase.io");if(j.includes("prisma"))B.push("prisma.io");if(j.includes("tailwind"))B.push("tailwindcss.com");if(j.includes("vite"))B.push("vitejs.dev","vite.dev");if(j.includes("astro"))B.push("astro.build");if(j.includes("svelte"))B.push("svelte.dev");if(j.includes("solid"))B.push("solidjs.com");if(j.includes("vue")||j.includes("nuxt"))B.push("vuejs.org","nuxt.com");if(j.includes("react")||j.includes("react native"))B.push("react.dev","reactnative.dev");if(j.includes("angular"))B.push("angular.io","angular.dev");if(j.includes("node.js")||j.includes("nodejs"))B.push("nodejs.org","nodejs.dev","npmjs.com");if(/\bgo\b/.test(j)||j.includes("golang"))B.push("go.dev","golang.org","pkg.go.dev");if(j.includes("deno"))B.push("deno.land","deno.com");if(j.includes("fresh"))B.push("fresh.deno.dev");if(j.includes("typescript")||j.includes("ts"))B.push("typescriptlang.org");if(j.includes("python"))B.push("python.org","docs.python.org");if(j.includes("rust"))B.push("rust-lang.org","docs.rs","crates.io");if(j.includes("zig"))B.push("ziglang.org");if(j.includes("docker"))B.push("docker.com","docs.docker.com","hub.docker.com");if(j.includes("kubernetes")||j.includes("k8s"))B.push("kubernetes.io","k8s.io");if(j.includes("postgres")||j.includes("postgresql"))B.push("postgresql.org","neon.tech","supabase.com");if(j.includes("redis"))B.push("redis.io");if(j.includes("sqlite"))B.push("sqlite.org");if(j.includes("cloudflare"))B.push("developers.cloudflare.com","cloudflare.com");if(j.includes("vercel"))B.push("vercel.com","nextjs.org");if(j.includes("netlify"))B.push("netlify.com","docs.netlify.com");if(j.includes("stripe"))B.push("stripe.com","docs.stripe.com");if(j.includes("github"))B.push("github.com","docs.github.com");if(j.includes("gitlab"))B.push("gitlab.com","docs.gitlab.com");if(j.includes("aws"))B.push("aws.amazon.com","docs.aws.amazon.com");if(j.includes("azure"))B.push("azure.microsoft.com","learn.microsoft.com");if(j.includes("gcp")||j.includes("google cloud"))B.push("cloud.google.com","developers.google.com");if(j.includes("gemini")||j.includes("google ai"))B.push("ai.google.dev","developers.google.com");for(let Q of L){let J=Q.replace(/\.com$/,"");if(j.includes(J))B.push(Q)}return[...new Set(B)]}function P(F,j){return F===j||F.endsWith(`.${j}`)}function z(F,j=""){let B=new Map,Q=Object.keys(F||{}).filter((V)=>!V.startsWith("_")),J=f(j);for(let V of Q){let $=F[V];if(!$?.sources)continue;for(let E=0;E<$.sources.length;E++){let R=$.sources[E],G=y(R.url);if(!G||G.length<10)continue;let A=N(R.title||""),Y=g(G),K=U(Y,A,G),W=0;if(J.some((M)=>P(Y,M)))W+=10;if(K==="official-docs")W+=3;let O=G.toLowerCase();if(/\/docs\/|\/documentation\/|\.dev\/|\/api\/|\/reference\//.test(O))W+=2;let D=J.some((M)=>P(Y,M));if(K==="social"&&!D)W-=20;if(J.length>0){if(v(Y,T))W-=3;else if(K==="community"&&!v(Y,["stackoverflow.com","stackexchange.com"]))W-=1}let X=B.get(G)||{id:"",canonicalUrl:G,displayUrl:R.url||G,domain:Y,title:"",engines:[],engineCount:0,perEngine:{},sourceType:K,isOfficial:K==="official-docs",smartScore:0};if(X.title=_(X.title,A),X.displayUrl=X.displayUrl||R.url||G,X.sourceType=X.sourceType||K,X.isOfficial=X.isOfficial||K==="official-docs",X.smartScore=Math.max(X.smartScore,W),!X.engines.includes(V))X.engines.push(V);X.perEngine[V]={rank:E+1,title:_(X.perEngine[V]?.title||"",A)},B.set(G,X)}}let Z=Array.from(B.values()).map((V)=>({...V,engineCount:V.engines.length})),I=Z.filter((V)=>V.sourceType!=="social"),H=Z.filter((V)=>V.sourceType==="social");return I.sort((V,$)=>{let E=q($)-q(V);if(E!==0)return E;return V.domain.localeCompare($.domain)}),H.sort((V,$)=>{let E=q($)-q(V);if(E!==0)return E;return V.domain.localeCompare($.domain)}),[...I,...H].slice(0,12).map((V,$)=>({...V,id:`S${$+1}`,title:V.title||V.domain||V.canonicalUrl}))}function h(F,j){let B=new Map(j.map((Q)=>[Q.id,Q]));return F.map((Q)=>{let J=B.get(Q.id);if(!J)return Q;let Z=_(Q.title,J.title||"");return{...Q,title:Z||Q.title,fetch:{attempted:!0,ok:!J.error&&J.contentChars>100,status:J.status||null,finalUrl:J.finalUrl||J.url||Q.canonicalUrl,contentType:J.contentType||"",lastModified:J.lastModified||"",publishedTime:J.publishedTime||"",byline:J.byline||"",siteName:J.siteName||"",lang:J.lang||"",title:J.title||"",snippet:J.snippet||"",contentChars:J.contentChars||0,source:J.source||"unknown",duration:J.duration||0,error:J.error||""}}})}export{w as trimText,p as sourceTypePriority,_ as pickPreferredTitle,y as normalizeUrl,N as normalizeSourceTitle,h as mergeFetchDataIntoSources,v as matchesDomain,f as inferPreferredDomains,g as getDomain,P as domainMatches,q as computeCompositeScore,U as classifySourceType,z as buildSourceRegistry,x as bestRank,b as TRACKING_PARAMS,L as SOCIAL_HOSTS,k as NEWS_HOSTS,C as COMMUNITY_HOSTS};
1
+ export const TRACKING_PARAMS = [
2
+ "fbclid",
3
+ "gclid",
4
+ "ref",
5
+ "ref_src",
6
+ "ref_url",
7
+ "source",
8
+ "utm_campaign",
9
+ "utm_content",
10
+ "utm_medium",
11
+ "utm_source",
12
+ "utm_term"
13
+ ];
14
+ export const COMMUNITY_HOSTS = [
15
+ "dev.to",
16
+ "hashnode.com",
17
+ "medium.com",
18
+ "reddit.com",
19
+ "stackoverflow.com",
20
+ "stackexchange.com",
21
+ "substack.com"
22
+ ];
23
+ export const NEWS_HOSTS = [
24
+ "arstechnica.com",
25
+ "techcrunch.com",
26
+ "theverge.com",
27
+ "venturebeat.com",
28
+ "wired.com",
29
+ "zdnet.com"
30
+ ];
31
+ export const SOCIAL_HOSTS = [
32
+ "facebook.com",
33
+ "instagram.com",
34
+ "linkedin.com",
35
+ "pinterest.com",
36
+ "tiktok.com",
37
+ "twitter.com",
38
+ "x.com"
39
+ ];
40
+ export function trimText(text = "", maxChars = 240) {
41
+ const clean = String(text).replaceAll(/\s+/g, " ").trim();
42
+ if (clean.length <= maxChars)
43
+ return clean;
44
+ const truncated = clean.slice(0, maxChars);
45
+ const lastSpace = truncated.lastIndexOf(" ");
46
+ return lastSpace > 0 ? `${truncated.slice(0, lastSpace)}...` : `${truncated}...`;
47
+ }
48
+ export function normalizeSourceTitle(title = "") {
49
+ const clean = trimText(title, 180);
50
+ if (!clean)
51
+ return "";
52
+ if (/^https?:\/\//i.test(clean))
53
+ return "";
54
+ const wordCount = clean.split(/\s+/).filter(Boolean).length;
55
+ const hasUppercase = /[A-Z]/.test(clean);
56
+ const hasDigit = /\d/.test(clean);
57
+ const looksLikeFragment = clean === clean.toLowerCase() && wordCount <= 4 && !hasUppercase && !hasDigit;
58
+ return looksLikeFragment ? "" : clean;
59
+ }
60
+ export function pickPreferredTitle(currentTitle = "", nextTitle = "") {
61
+ const current = normalizeSourceTitle(currentTitle);
62
+ const next = normalizeSourceTitle(nextTitle);
63
+ if (!next)
64
+ return current;
65
+ if (!current)
66
+ return next;
67
+ const currentLooksLikeUrl = /^https?:\/\//i.test(current);
68
+ const nextLooksLikeUrl = /^https?:\/\//i.test(next);
69
+ if (currentLooksLikeUrl && !nextLooksLikeUrl)
70
+ return next;
71
+ if (!currentLooksLikeUrl && nextLooksLikeUrl)
72
+ return current;
73
+ return next.length > current.length ? next : current;
74
+ }
75
+ export function normalizeUrl(rawUrl) {
76
+ if (!rawUrl)
77
+ return null;
78
+ try {
79
+ const url = new URL(rawUrl);
80
+ if (!["http:", "https:"].includes(url.protocol))
81
+ return null;
82
+ url.hash = "";
83
+ url.hostname = url.hostname.toLowerCase();
84
+ if (url.protocol === "https:" && url.port === "443" || url.protocol === "http:" && url.port === "80") {
85
+ url.port = "";
86
+ }
87
+ for (const key of [...url.searchParams.keys()]) {
88
+ const lower = key.toLowerCase();
89
+ if (TRACKING_PARAMS.includes(lower) || lower.startsWith("utm_")) {
90
+ url.searchParams.delete(key);
91
+ }
92
+ }
93
+ url.searchParams.sort();
94
+ const normalizedPath = url.pathname.replace(/\/{1,10}$/, "") || "/";
95
+ url.pathname = normalizedPath;
96
+ const normalized = url.toString();
97
+ return normalizedPath === "/" ? normalized.replace(/\/$/, "") : normalized;
98
+ } catch {
99
+ return null;
100
+ }
101
+ }
102
+ export function getDomain(rawUrl) {
103
+ try {
104
+ const domain = new URL(rawUrl).hostname.toLowerCase();
105
+ return domain.replace(/^www\./, "");
106
+ } catch {
107
+ return "";
108
+ }
109
+ }
110
+ export function matchesDomain(domain, hosts) {
111
+ return hosts.some((host) => domain === host || domain.endsWith(`.${host}`));
112
+ }
113
+ export function classifySourceType(domain, title = "", rawUrl = "") {
114
+ const lowerTitle = title.toLowerCase();
115
+ const lowerUrl = rawUrl.toLowerCase();
116
+ if (domain === "github.com" || domain === "gitlab.com")
117
+ return "repo";
118
+ if (domain === "arxiv.org" || domain === "doi.org" || domain === "semanticscholar.org" || domain.endsWith(".semanticscholar.org") || lowerUrl.includes("/paper/") || lowerUrl.includes("/pdf/")) {
119
+ return "academic";
120
+ }
121
+ if (matchesDomain(domain, SOCIAL_HOSTS))
122
+ return "social";
123
+ if (matchesDomain(domain, COMMUNITY_HOSTS))
124
+ return "community";
125
+ if (matchesDomain(domain, NEWS_HOSTS))
126
+ return "news";
127
+ if (domain.startsWith("docs.") || domain.startsWith("developer.") || domain.startsWith("developers.") || domain.startsWith("api.") || lowerTitle.includes("documentation") || lowerTitle.includes("docs") || lowerTitle.includes("reference") || lowerUrl.includes("/docs/") || lowerUrl.includes("/reference/") || lowerUrl.includes("/api/")) {
128
+ return "official-docs";
129
+ }
130
+ if (domain.startsWith("blog.") || lowerUrl.includes("/blog/"))
131
+ return "maintainer-blog";
132
+ return "website";
133
+ }
134
+ export function sourceTypePriority(sourceType) {
135
+ switch (sourceType) {
136
+ case "official-docs":
137
+ return 5;
138
+ case "repo":
139
+ return 4;
140
+ case "academic":
141
+ return 4;
142
+ case "maintainer-blog":
143
+ return 3;
144
+ case "website":
145
+ return 2;
146
+ case "community":
147
+ return 1;
148
+ case "news":
149
+ return 0;
150
+ case "social":
151
+ return -6;
152
+ default:
153
+ return 0;
154
+ }
155
+ }
156
+ export function bestRank(source) {
157
+ const ranks = Object.values(source.perEngine || {}).map((v) => v?.rank || 99);
158
+ return ranks.length ? Math.min(...ranks) : 99;
159
+ }
160
+ const DISCUSSION_HOSTS = ["reddit.com", "news.ycombinator.com", "lobste.rs"];
161
+ export function computeCompositeScore(source) {
162
+ return source.smartScore * 3 + source.engineCount * 5 + sourceTypePriority(source.sourceType) * 2 + Math.max(0, 7 - bestRank(source));
163
+ }
164
+ export function inferPreferredDomains(query) {
165
+ const normalized = query.toLowerCase();
166
+ const matches = [];
167
+ if (normalized.includes("openai") || normalized.includes("gpt") || normalized.includes("chatgpt")) {
168
+ matches.push("openai.com", "platform.openai.com", "help.openai.com");
169
+ }
170
+ if (normalized.includes("anthropic") || normalized.includes("claude")) {
171
+ matches.push("anthropic.com", "docs.anthropic.com");
172
+ }
173
+ if (normalized.includes("bun")) {
174
+ matches.push("bun.sh", "bun.com");
175
+ }
176
+ if (normalized.includes("next.js") || normalized.includes("nextjs")) {
177
+ matches.push("nextjs.org", "vercel.com");
178
+ }
179
+ if (normalized.includes("playwright")) {
180
+ matches.push("playwright.dev");
181
+ }
182
+ if (normalized.includes("supabase")) {
183
+ matches.push("supabase.com", "supabase.io");
184
+ }
185
+ if (normalized.includes("prisma")) {
186
+ matches.push("prisma.io");
187
+ }
188
+ if (normalized.includes("tailwind")) {
189
+ matches.push("tailwindcss.com");
190
+ }
191
+ if (normalized.includes("vite")) {
192
+ matches.push("vitejs.dev", "vite.dev");
193
+ }
194
+ if (normalized.includes("astro")) {
195
+ matches.push("astro.build");
196
+ }
197
+ if (normalized.includes("svelte")) {
198
+ matches.push("svelte.dev");
199
+ }
200
+ if (normalized.includes("solid")) {
201
+ matches.push("solidjs.com");
202
+ }
203
+ if (normalized.includes("vue") || normalized.includes("nuxt")) {
204
+ matches.push("vuejs.org", "nuxt.com");
205
+ }
206
+ if (normalized.includes("react") || normalized.includes("react native")) {
207
+ matches.push("react.dev", "reactnative.dev");
208
+ }
209
+ if (normalized.includes("angular")) {
210
+ matches.push("angular.io", "angular.dev");
211
+ }
212
+ if (normalized.includes("node.js") || normalized.includes("nodejs")) {
213
+ matches.push("nodejs.org", "nodejs.dev", "npmjs.com");
214
+ }
215
+ if (/\bgo\b/.test(normalized) || normalized.includes("golang")) {
216
+ matches.push("go.dev", "golang.org", "pkg.go.dev");
217
+ }
218
+ if (normalized.includes("deno")) {
219
+ matches.push("deno.land", "deno.com");
220
+ }
221
+ if (normalized.includes("fresh")) {
222
+ matches.push("fresh.deno.dev");
223
+ }
224
+ if (normalized.includes("typescript") || normalized.includes("ts")) {
225
+ matches.push("typescriptlang.org");
226
+ }
227
+ if (normalized.includes("python")) {
228
+ matches.push("python.org", "docs.python.org");
229
+ }
230
+ if (normalized.includes("rust")) {
231
+ matches.push("rust-lang.org", "docs.rs", "crates.io");
232
+ }
233
+ if (normalized.includes("zig")) {
234
+ matches.push("ziglang.org");
235
+ }
236
+ if (normalized.includes("docker")) {
237
+ matches.push("docker.com", "docs.docker.com", "hub.docker.com");
238
+ }
239
+ if (normalized.includes("kubernetes") || normalized.includes("k8s")) {
240
+ matches.push("kubernetes.io", "k8s.io");
241
+ }
242
+ if (normalized.includes("postgres") || normalized.includes("postgresql")) {
243
+ matches.push("postgresql.org", "neon.tech", "supabase.com");
244
+ }
245
+ if (normalized.includes("redis")) {
246
+ matches.push("redis.io");
247
+ }
248
+ if (normalized.includes("sqlite")) {
249
+ matches.push("sqlite.org");
250
+ }
251
+ if (normalized.includes("cloudflare")) {
252
+ matches.push("developers.cloudflare.com", "cloudflare.com");
253
+ }
254
+ if (normalized.includes("vercel")) {
255
+ matches.push("vercel.com", "nextjs.org");
256
+ }
257
+ if (normalized.includes("netlify")) {
258
+ matches.push("netlify.com", "docs.netlify.com");
259
+ }
260
+ if (normalized.includes("stripe")) {
261
+ matches.push("stripe.com", "docs.stripe.com");
262
+ }
263
+ if (normalized.includes("github")) {
264
+ matches.push("github.com", "docs.github.com");
265
+ }
266
+ if (normalized.includes("gitlab")) {
267
+ matches.push("gitlab.com", "docs.gitlab.com");
268
+ }
269
+ if (normalized.includes("aws")) {
270
+ matches.push("aws.amazon.com", "docs.aws.amazon.com");
271
+ }
272
+ if (normalized.includes("azure")) {
273
+ matches.push("azure.microsoft.com", "learn.microsoft.com");
274
+ }
275
+ if (normalized.includes("gcp") || normalized.includes("google cloud")) {
276
+ matches.push("cloud.google.com", "developers.google.com");
277
+ }
278
+ if (normalized.includes("gemini") || normalized.includes("google ai")) {
279
+ matches.push("ai.google.dev", "developers.google.com");
280
+ }
281
+ for (const socialHost of SOCIAL_HOSTS) {
282
+ const bareName = socialHost.replace(/\.com$/, "");
283
+ if (normalized.includes(bareName))
284
+ matches.push(socialHost);
285
+ }
286
+ return [...new Set(matches)];
287
+ }
288
+ export function domainMatches(hostname, candidate) {
289
+ return hostname === candidate || hostname.endsWith(`.${candidate}`);
290
+ }
291
+ export function buildSourceRegistry(out, query = "") {
292
+ const seen = new Map;
293
+ const engineOrder = Object.keys(out || {}).filter((key) => !key.startsWith("_"));
294
+ const preferredDomains = inferPreferredDomains(query);
295
+ for (const engine of engineOrder) {
296
+ const result = out[engine];
297
+ if (!result?.sources)
298
+ continue;
299
+ for (let i = 0;i < result.sources.length; i++) {
300
+ const source = result.sources[i];
301
+ const canonicalUrl = normalizeUrl(source.url);
302
+ if (!canonicalUrl || canonicalUrl.length < 10)
303
+ continue;
304
+ const title = normalizeSourceTitle(source.title || "");
305
+ const domain = getDomain(canonicalUrl);
306
+ const sourceType = classifySourceType(domain, title, canonicalUrl);
307
+ let smartScore = 0;
308
+ if (preferredDomains.some((pd) => domainMatches(domain, pd))) {
309
+ smartScore += 10;
310
+ }
311
+ if (sourceType === "official-docs") {
312
+ smartScore += 3;
313
+ }
314
+ const lowerUrl = canonicalUrl.toLowerCase();
315
+ if (/\/docs\/|\/documentation\/|\.dev\/|\/api\/|\/reference\//.test(lowerUrl)) {
316
+ smartScore += 2;
317
+ }
318
+ const queryTargetsSocialHost = preferredDomains.some((pd) => domainMatches(domain, pd));
319
+ if (sourceType === "social" && !queryTargetsSocialHost) {
320
+ smartScore -= 20;
321
+ }
322
+ if (preferredDomains.length > 0) {
323
+ if (matchesDomain(domain, DISCUSSION_HOSTS)) {
324
+ smartScore -= 3;
325
+ } else if (sourceType === "community" && !matchesDomain(domain, ["stackoverflow.com", "stackexchange.com"])) {
326
+ smartScore -= 1;
327
+ }
328
+ }
329
+ const existing = seen.get(canonicalUrl) || {
330
+ id: "",
331
+ canonicalUrl,
332
+ displayUrl: source.url || canonicalUrl,
333
+ domain,
334
+ title: "",
335
+ engines: [],
336
+ engineCount: 0,
337
+ perEngine: {},
338
+ sourceType,
339
+ isOfficial: sourceType === "official-docs",
340
+ smartScore: 0
341
+ };
342
+ existing.title = pickPreferredTitle(existing.title, title);
343
+ existing.displayUrl = existing.displayUrl || source.url || canonicalUrl;
344
+ existing.sourceType = existing.sourceType || sourceType;
345
+ existing.isOfficial = existing.isOfficial || sourceType === "official-docs";
346
+ existing.smartScore = Math.max(existing.smartScore, smartScore);
347
+ if (!existing.engines.includes(engine)) {
348
+ existing.engines.push(engine);
349
+ }
350
+ existing.perEngine[engine] = {
351
+ rank: i + 1,
352
+ title: pickPreferredTitle(existing.perEngine[engine]?.title || "", title)
353
+ };
354
+ seen.set(canonicalUrl, existing);
355
+ }
356
+ }
357
+ const sources = Array.from(seen.values()).map((source) => ({
358
+ ...source,
359
+ engineCount: source.engines.length
360
+ }));
361
+ const nonSocial = sources.filter((s) => s.sourceType !== "social");
362
+ const socialSources = sources.filter((s) => s.sourceType === "social");
363
+ nonSocial.sort((a, b) => {
364
+ const diff = computeCompositeScore(b) - computeCompositeScore(a);
365
+ if (diff !== 0)
366
+ return diff;
367
+ return a.domain.localeCompare(b.domain);
368
+ });
369
+ socialSources.sort((a, b) => {
370
+ const diff = computeCompositeScore(b) - computeCompositeScore(a);
371
+ if (diff !== 0)
372
+ return diff;
373
+ return a.domain.localeCompare(b.domain);
374
+ });
375
+ const ordered = [...nonSocial, ...socialSources];
376
+ return ordered.slice(0, 12).map((source, index) => ({
377
+ ...source,
378
+ id: `S${index + 1}`,
379
+ title: source.title || source.domain || source.canonicalUrl
380
+ }));
381
+ }
382
+ export function mergeFetchDataIntoSources(sources, fetchedSources) {
383
+ const byId = new Map(fetchedSources.map((source) => [source.id, source]));
384
+ return sources.map((source) => {
385
+ const fetched = byId.get(source.id);
386
+ if (!fetched)
387
+ return source;
388
+ const title = pickPreferredTitle(source.title, fetched.title || "");
389
+ return {
390
+ ...source,
391
+ title: title || source.title,
392
+ fetch: {
393
+ attempted: true,
394
+ ok: !fetched.error && fetched.contentChars > 100,
395
+ status: fetched.status || null,
396
+ finalUrl: fetched.finalUrl || fetched.url || source.canonicalUrl,
397
+ contentType: fetched.contentType || "",
398
+ lastModified: fetched.lastModified || "",
399
+ publishedTime: fetched.publishedTime || "",
400
+ byline: fetched.byline || "",
401
+ siteName: fetched.siteName || "",
402
+ lang: fetched.lang || "",
403
+ title: fetched.title || "",
404
+ snippet: fetched.snippet || "",
405
+ contentChars: fetched.contentChars || 0,
406
+ source: fetched.source || "unknown",
407
+ duration: fetched.duration || 0,
408
+ error: fetched.error || ""
409
+ }
410
+ };
411
+ });
412
+ }
@@ -1,12 +1,127 @@
1
- import{spawn as Re}from"node:child_process";import{basename as q}from"node:path";function G(t=process.env,e=process.execPath){let i=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(i?.trim())return i.trim();let s=q(e||"").toLowerCase();if(s==="node"||s==="node.exe")return e;return"node"}import{existsSync as T,mkdirSync as V,readFileSync as S,writeFileSync as B}from"node:fs";import{homedir as F}from"node:os";import{join as Y}from"node:path";import{tmpdir as z}from"node:os";function ee(t,e=9222){let i=Number.parseInt(String(t??""),10);return Number.isInteger(i)&&i>1024&&i<65535?i:e}var ie=z().replaceAll("\\","/"),$e=ee(process.env.GREEDY_SEARCH_PORT),h=(process.env.GREEDY_SEARCH_PROFILE_DIR||process.env.CDP_PROFILE_DIR||`${ie}/greedysearch-chrome-profile`).replaceAll("\\","/"),Ae=`${h}/DevToolsActivePort`,Ge=process.env.GREEDY_SEARCH_PID_FILE||`${h}/browser.pid`,Se=process.env.CDP_PAGES_CACHE||`${h}/cdp-pages.json`,Ye=process.env.GREEDY_SEARCH_MODE_FILE||`${h}/browser-mode`,ye=process.env.GREEDY_SEARCH_METADATA_FILE||`${h}/browser-metadata.json`,He=process.env.GREEDY_SEARCH_LAUNCH_LOCK_FILE||`${h}/browser-launch.lock`,Ue=process.env.GREEDY_SEARCH_ACTIVITY_FILE||`${h}/browser-last-activity`,ke=(process.env.CDP_SOCKET_DIR||`${h}/cdp-sockets`).replaceAll("\\","/"),Pe=`${h}/visible-recovery.jsonl`,b=Y(F(),".dm"),d=Y(b,"greedyconfig"),w=["perplexity","google","chatgpt","gemini"],N="gemini";function te(){try{if(T(d)){let t=S(d,"utf8"),e=JSON.parse(t);if(Array.isArray(e.engines)&&e.engines.length>0&&e.engines.every((i)=>typeof i==="string")){let i=e.engines.filter((o)=>L[o]),s=e.engines.filter((o)=>!L[o]);if(s.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${d}: ${s.join(", ")}
2
- [greedysearch] Available engines: ${Object.keys(L).join(", ")}
3
- `);if(i.length>0)return i;process.stderr.write(`[greedysearch] Warning: no valid engines in ${d}, falling back to defaults: ${w.join(", ")}
4
- `)}}}catch{}return w}function ne(){try{if(!T(b))V(b,{recursive:!0});if(!T(d))B(d,JSON.stringify({engines:w,synthesizer:N},null,2)+`
5
- `,"utf8")}catch{}}ne();var C=["gemini","chatgpt"];function se(){try{if(T(d)){let t=S(d,"utf8"),e=JSON.parse(t);if(typeof e.synthesizer==="string"){let i=e.synthesizer.toLowerCase();if(C.includes(i))return i;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${e.synthesizer}" in ${d}
6
- [greedysearch] Available synthesizers: ${C.join(", ")}
7
- [greedysearch] Falling back to default: ${N}
8
- `)}}}catch{}return N}var L={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"},oe=te();var We=se(),Me=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=h;import{existsSync as y}from"node:fs";import{dirname as le,join as O}from"node:path";import{fileURLToPath as re}from"node:url";function H(t){return re(new URL(".",t)).replace(/^\/([A-Z]:)/,"$1")}function ce(t,e=y){let i=new Set;for(let s of t.filter(Boolean)){if(i.has(s))continue;if(i.add(s),e(s))return s}return t.filter(Boolean).at(-1)}function U(t,{moduleDir:e,entrypoint:i=process.argv[1],env:s=process.env,exists:o=y}={}){let c=i?le(i):null,p=s.GREEDY_SEARCH_EXTENSION_DIR?.trim()||null;return ce([e?O(e,"..","..","extractors",t):null,e?O(e,"..","extractors",t):null,p?O(p,"extractors",t):null,c?O(c,"..","extractors",t):null],o)}var ae=["fbclid","gclid","ref","ref_src","ref_url","source","utm_campaign","utm_content","utm_medium","utm_source","utm_term"],pe=["dev.to","hashnode.com","medium.com","reddit.com","stackoverflow.com","stackexchange.com","substack.com"],fe=["arstechnica.com","techcrunch.com","theverge.com","venturebeat.com","wired.com","zdnet.com"],W=["facebook.com","instagram.com","linkedin.com","pinterest.com","tiktok.com","twitter.com","x.com"];function v(t="",e=240){let i=String(t).replaceAll(/\s+/g," ").trim();if(i.length<=e)return i;let s=i.slice(0,e),o=s.lastIndexOf(" ");return o>0?`${s.slice(0,o)}...`:`${s}...`}function $(t=""){let e=v(t,180);if(!e)return"";if(/^https?:\/\//i.test(e))return"";let i=e.split(/\s+/).filter(Boolean).length,s=/[A-Z]/.test(e),o=/\d/.test(e);return e===e.toLowerCase()&&i<=4&&!s&&!o?"":e}function k(t="",e=""){let i=$(t),s=$(e);if(!s)return i;if(!i)return s;let o=/^https?:\/\//i.test(i),c=/^https?:\/\//i.test(s);if(o&&!c)return s;if(!o&&c)return i;return s.length>i.length?s:i}function ue(t){if(!t)return null;try{let e=new URL(t);if(!["http:","https:"].includes(e.protocol))return null;if(e.hash="",e.hostname=e.hostname.toLowerCase(),e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80")e.port="";for(let o of[...e.searchParams.keys()]){let c=o.toLowerCase();if(ae.includes(c)||c.startsWith("utm_"))e.searchParams.delete(o)}e.searchParams.sort();let i=e.pathname.replace(/\/{1,10}$/,"")||"/";e.pathname=i;let s=e.toString();return i==="/"?s.replace(/\/$/,""):s}catch{return null}}function ge(t){try{return new URL(t).hostname.toLowerCase().replace(/^www\./,"")}catch{return""}}function D(t,e){return e.some((i)=>t===i||t.endsWith(`.${i}`))}function me(t,e="",i=""){let s=e.toLowerCase(),o=i.toLowerCase();if(t==="github.com"||t==="gitlab.com")return"repo";if(t==="arxiv.org"||t==="doi.org"||t==="semanticscholar.org"||t.endsWith(".semanticscholar.org")||o.includes("/paper/")||o.includes("/pdf/"))return"academic";if(D(t,W))return"social";if(D(t,pe))return"community";if(D(t,fe))return"news";if(t.startsWith("docs.")||t.startsWith("developer.")||t.startsWith("developers.")||t.startsWith("api.")||s.includes("documentation")||s.includes("docs")||s.includes("reference")||o.includes("/docs/")||o.includes("/reference/")||o.includes("/api/"))return"official-docs";if(t.startsWith("blog.")||o.includes("/blog/"))return"maintainer-blog";return"website"}function he(t){switch(t){case"official-docs":return 5;case"repo":return 4;case"academic":return 4;case"maintainer-blog":return 3;case"website":return 2;case"community":return 1;case"news":return 0;case"social":return-6;default:return 0}}function Ee(t){let e=Object.values(t.perEngine||{}).map((i)=>i?.rank||99);return e.length?Math.min(...e):99}var _e=["reddit.com","news.ycombinator.com","lobste.rs"];function I(t){return t.smartScore*3+t.engineCount*5+he(t.sourceType)*2+Math.max(0,7-Ee(t))}function de(t){let e=t.toLowerCase(),i=[];if(e.includes("openai")||e.includes("gpt")||e.includes("chatgpt"))i.push("openai.com","platform.openai.com","help.openai.com");if(e.includes("anthropic")||e.includes("claude"))i.push("anthropic.com","docs.anthropic.com");if(e.includes("bun"))i.push("bun.sh","bun.com");if(e.includes("next.js")||e.includes("nextjs"))i.push("nextjs.org","vercel.com");if(e.includes("playwright"))i.push("playwright.dev");if(e.includes("supabase"))i.push("supabase.com","supabase.io");if(e.includes("prisma"))i.push("prisma.io");if(e.includes("tailwind"))i.push("tailwindcss.com");if(e.includes("vite"))i.push("vitejs.dev","vite.dev");if(e.includes("astro"))i.push("astro.build");if(e.includes("svelte"))i.push("svelte.dev");if(e.includes("solid"))i.push("solidjs.com");if(e.includes("vue")||e.includes("nuxt"))i.push("vuejs.org","nuxt.com");if(e.includes("react")||e.includes("react native"))i.push("react.dev","reactnative.dev");if(e.includes("angular"))i.push("angular.io","angular.dev");if(e.includes("node.js")||e.includes("nodejs"))i.push("nodejs.org","nodejs.dev","npmjs.com");if(/\bgo\b/.test(e)||e.includes("golang"))i.push("go.dev","golang.org","pkg.go.dev");if(e.includes("deno"))i.push("deno.land","deno.com");if(e.includes("fresh"))i.push("fresh.deno.dev");if(e.includes("typescript")||e.includes("ts"))i.push("typescriptlang.org");if(e.includes("python"))i.push("python.org","docs.python.org");if(e.includes("rust"))i.push("rust-lang.org","docs.rs","crates.io");if(e.includes("zig"))i.push("ziglang.org");if(e.includes("docker"))i.push("docker.com","docs.docker.com","hub.docker.com");if(e.includes("kubernetes")||e.includes("k8s"))i.push("kubernetes.io","k8s.io");if(e.includes("postgres")||e.includes("postgresql"))i.push("postgresql.org","neon.tech","supabase.com");if(e.includes("redis"))i.push("redis.io");if(e.includes("sqlite"))i.push("sqlite.org");if(e.includes("cloudflare"))i.push("developers.cloudflare.com","cloudflare.com");if(e.includes("vercel"))i.push("vercel.com","nextjs.org");if(e.includes("netlify"))i.push("netlify.com","docs.netlify.com");if(e.includes("stripe"))i.push("stripe.com","docs.stripe.com");if(e.includes("github"))i.push("github.com","docs.github.com");if(e.includes("gitlab"))i.push("gitlab.com","docs.gitlab.com");if(e.includes("aws"))i.push("aws.amazon.com","docs.aws.amazon.com");if(e.includes("azure"))i.push("azure.microsoft.com","learn.microsoft.com");if(e.includes("gcp")||e.includes("google cloud"))i.push("cloud.google.com","developers.google.com");if(e.includes("gemini")||e.includes("google ai"))i.push("ai.google.dev","developers.google.com");for(let s of W){let o=s.replace(/\.com$/,"");if(e.includes(o))i.push(s)}return[...new Set(i)]}function P(t,e){return t===e||t.endsWith(`.${e}`)}function M(t,e=""){let i=new Map,s=Object.keys(t||{}).filter((n)=>!n.startsWith("_")),o=de(e);for(let n of s){let r=t[n];if(!r?.sources)continue;for(let a=0;a<r.sources.length;a++){let E=r.sources[a],f=ue(E.url);if(!f||f.length<10)continue;let R=$(E.title||""),g=ge(f),_=me(g,R,f),m=0;if(o.some((j)=>P(g,j)))m+=10;if(_==="official-docs")m+=3;let Q=f.toLowerCase();if(/\/docs\/|\/documentation\/|\.dev\/|\/api\/|\/reference\//.test(Q))m+=2;let X=o.some((j)=>P(g,j));if(_==="social"&&!X)m-=20;if(o.length>0){if(D(g,_e))m-=3;else if(_==="community"&&!D(g,["stackoverflow.com","stackexchange.com"]))m-=1}let u=i.get(f)||{id:"",canonicalUrl:f,displayUrl:E.url||f,domain:g,title:"",engines:[],engineCount:0,perEngine:{},sourceType:_,isOfficial:_==="official-docs",smartScore:0};if(u.title=k(u.title,R),u.displayUrl=u.displayUrl||E.url||f,u.sourceType=u.sourceType||_,u.isOfficial=u.isOfficial||_==="official-docs",u.smartScore=Math.max(u.smartScore,m),!u.engines.includes(n))u.engines.push(n);u.perEngine[n]={rank:a+1,title:k(u.perEngine[n]?.title||"",R)},i.set(f,u)}}let c=Array.from(i.values()).map((n)=>({...n,engineCount:n.engines.length})),p=c.filter((n)=>n.sourceType!=="social"),l=c.filter((n)=>n.sourceType==="social");return p.sort((n,r)=>{let a=I(r)-I(n);if(a!==0)return a;return n.domain.localeCompare(r.domain)}),l.sort((n,r)=>{let a=I(r)-I(n);if(a!==0)return a;return n.domain.localeCompare(r.domain)}),[...p,...l].slice(0,12).map((n,r)=>({...n,id:`S${r+1}`,title:n.title||n.domain||n.canonicalUrl}))}function ve(t){let e="",i=!1,s=!1;for(let o of String(t)){if(s){e+=o,s=!1;continue}if(o==="\\"){e+=o,s=!0;continue}if(o==='"'){i=!i,e+=o;continue}if(i&&o===`
9
- `)e+="\\n";else if(i&&o==="\r")e+="\\r";else if(i&&o==="\t")e+="\\t";else e+=o}return e}function J(t){if(!t)return null;let e=String(t).trim(),i=e.indexOf("BEGIN_JSON"),s=e.indexOf("END_JSON");if(i!==-1&&s!==-1&&i<s)e=e.slice(i+10,s).trim();else{let l=e.indexOf("{");if(l>0)e=e.slice(l)}let o=[e,e.replace(/^```json\s*/i,"").replace(/^```\s*/i,"").replace(/```$/i,"").trim()],c=e.indexOf("{"),p=e.lastIndexOf("}");if(c!==-1&&p!==-1&&c<p)o.push(e.slice(c,p+1));for(let l of[...o]){let n=ve(l);if(n!==l)o.push(n)}for(let l of o)try{return JSON.parse(l)}catch{}return null}function Z(t,e,i=""){let s=new Set(e.map((n)=>n.id)),o=["high","medium","low","mixed","conflicting"].includes(t?.agreement?.level)?t.agreement.level:"mixed",c=Array.isArray(t?.claims)?t.claims.map((n)=>({claim:v(n?.claim||"",260),support:["strong","moderate","weak","conflicting"].includes(n?.support)?n.support:"moderate",sourceIds:Array.isArray(n?.sourceIds)?n.sourceIds.filter((r)=>s.has(r)):[]})).filter((n)=>n.claim):[],p=Array.isArray(t?.recommendedSources)?t.recommendedSources.filter((n)=>s.has(n)).slice(0,6):[],l="";if(i){let n=i.indexOf("{"),r=i.lastIndexOf("}");if(n!==-1&&r!==-1&&n<r)l=i.slice(n,r+1);else l=i}return{answer:v(t?.answer||l||i,4000),agreement:{level:o,summary:v(t?.agreement?.summary||"",280)},differences:Array.isArray(t?.differences)?t.differences.map((n)=>v(n,220)).filter(Boolean).slice(0,5):[],caveats:Array.isArray(t?.caveats)?t.caveats.map((n)=>v(n,220)).filter(Boolean).slice(0,5):[],claims:c,recommendedSources:p}}function x(t,e,i,{grounded:s=!1}={}){let o={};for(let l of["perplexity","bing","google"]){let n=e[l];if(!n)continue;if(n.error){o[l]={status:"error",error:String(n.error)};continue}o[l]={status:"ok",answer:v(n.answer||"",s?4500:2200),sourceIds:i.filter((r)=>r.engines.includes(l)).sort((r,a)=>(r.perEngine[l]?.rank||99)-(a.perEngine[l]?.rank||99)).map((r)=>r.id).slice(0,6)}}let c=s?700:300,p=i.slice(0,s?10:8).map((l)=>({id:l.id,title:l.title,domain:l.domain,canonicalUrl:l.canonicalUrl,sourceType:l.sourceType,isOfficial:l.isOfficial,engines:l.engines,engineCount:l.engineCount,fetch:l.fetch?.attempted?{ok:l.fetch.ok,publishedTime:l.fetch.publishedTime||"",byline:l.fetch.byline||"",snippet:v(l.fetch.snippet||"",c)}:void 0}));return["You are a research synthesizer. Combine these search engine results into a single authoritative answer.","",`Query: ${t}`,"",`Engine summaries:
10
- ${JSON.stringify(o,null,2)}`,"",`Source registry:
11
- ${JSON.stringify(p,null,2)}`,"","Instructions:","- Write a clear, direct answer in markdown (use headers/bullets where they help readability)","- Cite sources inline as [S1], [S2] etc. when making specific claims","- Prefer sources with content (fetch.ok=true and non-empty snippet) for citations","- Note where the engines agree or meaningfully disagree","- List any important caveats or limitations","- recommendedSources: the 2-4 source IDs most worth reading for this query","","Respond ONLY with a JSON object wrapped in BEGIN_JSON / END_JSON markers:","","BEGIN_JSON",JSON.stringify({answer:"<your markdown answer here>",agreement:{level:"high|medium|mixed|conflicting",summary:"<one sentence>"},differences:["<notable difference between engines, if any>"],caveats:["<important caveat or limitation>"],recommendedSources:["S1","S2"]},null,2),"END_JSON"].join(`
12
- `)}var Ce=H(import.meta.url),De={gemini:"gemini.mjs",chatgpt:"chatgpt.mjs"},Te={gemini:"https://gemini.google.com/app",chatgpt:"https://chatgpt.com/"};function A(t="gemini"){let e=String(t||"gemini").toLowerCase();if(e==="gem")return"gemini";if(e==="gpt")return"chatgpt";return e}function si(t="gemini"){return Te[A(t)]||"about:blank"}async function K(t,e,{tabPrefix:i=null,timeoutMs:s=180000,visible:o=null}={}){let c=A(t),p=De[c];if(!p||!C.includes(c))throw Error(`Unsupported synthesizer "${t}". Supported: ${C.join(", ")}`);return new Promise((l,n)=>{let r=U(p,{moduleDir:Ce}),a=i?["--tab",String(i)]:[],E={...process.env,CDP_PROFILE_DIR:h};if(o!==!0)delete E.GREEDY_SEARCH_VISIBLE,delete E.GREEDY_SEARCH_ALWAYS_VISIBLE;else E.GREEDY_SEARCH_VISIBLE="1",E.GREEDY_SEARCH_ALWAYS_VISIBLE="1";let f=Re(G(),[r,"--stdin",...a],{stdio:["pipe","pipe","pipe"],env:E});f.stdin.write(e),f.stdin.end();let R="",g="";f.stdout.on("data",(m)=>R+=m),f.stderr.on("data",(m)=>g+=m);let _=setTimeout(()=>{f.kill(),n(Error(`${c} prompt timed out after ${s/1000}s`))},s);f.on("close",(m)=>{if(clearTimeout(_),m!==0){n(Error(g.trim()||`${c} extractor failed`));return}try{l(JSON.parse(R.trim()))}catch{n(Error(`bad JSON from ${c}: ${R.slice(0,100)}`))}})})}async function oi(t,e={}){return K("gemini",t,e)}async function Oe(t,e,{grounded:i=!1,tabPrefix:s=null,visible:o=null,synthesizer:c="gemini"}={}){let p=A(c),l=Array.isArray(e._sources)?e._sources:M(e),n=x(t,e,l,{grounded:i}),r=await K(p,n,{tabPrefix:s,timeoutMs:180000,visible:o}),a=J(r.answer||""),f=a&&["answer","agreement","claims","differences","caveats"].some((g)=>(g in a));if(a&&["perplexity","bing","google","chatgpt","gemini"].some((g)=>(g in a))&&!f)a=null;return{...Z(a,l,r.answer||""),rawAnswer:r.answer||"",synthesizedBy:p,synthesizerSources:r.sources||[],geminiSources:p==="gemini"?r.sources||[]:[]}}async function li(t,e,i={}){return Oe(t,e,{...i,synthesizer:"gemini"})}export{li as synthesizeWithGemini,Oe as synthesizeResults,K as runSynthesisPrompt,oi as runGeminiPrompt,A as normalizeSynthesizer,si as getSynthesisStartUrl};
1
+ import { spawn } from "node:child_process";
2
+ import { nodeRuntimeCommand } from "../utils/node-runtime.mjs";
3
+ import { GREEDY_PROFILE_DIR, SUPPORTED_SYNTHESIZERS } from "./constants.mjs";
4
+ import {
5
+ moduleDirectory,
6
+ resolveGreedySearchExtractorScript
7
+ } from "./paths.mjs";
8
+ import {
9
+ buildSynthesisPrompt,
10
+ normalizeSynthesisPayload,
11
+ parseStructuredJson
12
+ } from "./synthesis.mjs";
13
+ import { buildSourceRegistry } from "./sources.mjs";
14
+ const __dir = moduleDirectory(import.meta.url);
15
+ const SYNTHESIS_EXTRACTORS = {
16
+ gemini: "gemini.mjs",
17
+ chatgpt: "chatgpt.mjs"
18
+ };
19
+ const SYNTHESIS_START_URLS = {
20
+ gemini: "https://gemini.google.com/app",
21
+ chatgpt: "https://chatgpt.com/"
22
+ };
23
+ export function normalizeSynthesizer(synthesizer = "gemini") {
24
+ const normalized = String(synthesizer || "gemini").toLowerCase();
25
+ if (normalized === "gem")
26
+ return "gemini";
27
+ if (normalized === "gpt")
28
+ return "chatgpt";
29
+ return normalized;
30
+ }
31
+ export function getSynthesisStartUrl(synthesizer = "gemini") {
32
+ return SYNTHESIS_START_URLS[normalizeSynthesizer(synthesizer)] || "about:blank";
33
+ }
34
+ export async function runSynthesisPrompt(synthesizer, prompt, { tabPrefix = null, timeoutMs = 180000, visible = null } = {}) {
35
+ const normalizedSynthesizer = normalizeSynthesizer(synthesizer);
36
+ const script = SYNTHESIS_EXTRACTORS[normalizedSynthesizer];
37
+ if (!script || !SUPPORTED_SYNTHESIZERS.includes(normalizedSynthesizer)) {
38
+ throw new Error(`Unsupported synthesizer "${synthesizer}". Supported: ${SUPPORTED_SYNTHESIZERS.join(", ")}`);
39
+ }
40
+ return new Promise((resolve, reject) => {
41
+ const extractorScript = resolveGreedySearchExtractorScript(script, {
42
+ moduleDir: __dir
43
+ });
44
+ const extraArgs = tabPrefix ? ["--tab", String(tabPrefix)] : [];
45
+ const childEnv = {
46
+ ...process.env,
47
+ CDP_PROFILE_DIR: GREEDY_PROFILE_DIR
48
+ };
49
+ if (visible !== true) {
50
+ delete childEnv.GREEDY_SEARCH_VISIBLE;
51
+ delete childEnv.GREEDY_SEARCH_ALWAYS_VISIBLE;
52
+ } else {
53
+ childEnv.GREEDY_SEARCH_VISIBLE = "1";
54
+ childEnv.GREEDY_SEARCH_ALWAYS_VISIBLE = "1";
55
+ }
56
+ const proc = spawn(nodeRuntimeCommand(), [extractorScript, "--stdin", ...extraArgs], {
57
+ stdio: ["pipe", "pipe", "pipe"],
58
+ env: childEnv
59
+ });
60
+ proc.stdin.write(prompt);
61
+ proc.stdin.end();
62
+ let out = "";
63
+ let err = "";
64
+ proc.stdout.on("data", (d) => out += d);
65
+ proc.stderr.on("data", (d) => err += d);
66
+ const t = setTimeout(() => {
67
+ proc.kill();
68
+ reject(new Error(`${normalizedSynthesizer} prompt timed out after ${timeoutMs / 1000}s`));
69
+ }, timeoutMs);
70
+ proc.on("close", (code) => {
71
+ clearTimeout(t);
72
+ if (code !== 0) {
73
+ reject(new Error(err.trim() || `${normalizedSynthesizer} extractor failed`));
74
+ return;
75
+ }
76
+ try {
77
+ resolve(JSON.parse(out.trim()));
78
+ } catch {
79
+ reject(new Error(`bad JSON from ${normalizedSynthesizer}: ${out.slice(0, 100)}`));
80
+ }
81
+ });
82
+ });
83
+ }
84
+ export async function runGeminiPrompt(prompt, options = {}) {
85
+ return runSynthesisPrompt("gemini", prompt, options);
86
+ }
87
+ export async function synthesizeResults(query, results, {
88
+ grounded = false,
89
+ tabPrefix = null,
90
+ visible = null,
91
+ synthesizer = "gemini"
92
+ } = {}) {
93
+ const normalizedSynthesizer = normalizeSynthesizer(synthesizer);
94
+ const sources = Array.isArray(results._sources) ? results._sources : buildSourceRegistry(results);
95
+ const prompt = buildSynthesisPrompt(query, results, sources, { grounded });
96
+ const raw = await runSynthesisPrompt(normalizedSynthesizer, prompt, {
97
+ tabPrefix,
98
+ timeoutMs: 180000,
99
+ visible
100
+ });
101
+ let structured = parseStructuredJson(raw.answer || "");
102
+ const SYNTHESIS_FIELDS = [
103
+ "answer",
104
+ "agreement",
105
+ "claims",
106
+ "differences",
107
+ "caveats"
108
+ ];
109
+ const hasSynthesisFields = structured && SYNTHESIS_FIELDS.some((f) => (f in structured));
110
+ const hasEngineKeys = structured && ["perplexity", "bing", "google", "chatgpt", "gemini"].some((e) => (e in structured));
111
+ if (hasEngineKeys && !hasSynthesisFields) {
112
+ structured = null;
113
+ }
114
+ return {
115
+ ...normalizeSynthesisPayload(structured, sources, raw.answer || ""),
116
+ rawAnswer: raw.answer || "",
117
+ synthesizedBy: normalizedSynthesizer,
118
+ synthesizerSources: raw.sources || [],
119
+ geminiSources: normalizedSynthesizer === "gemini" ? raw.sources || [] : []
120
+ };
121
+ }
122
+ export async function synthesizeWithGemini(query, results, options = {}) {
123
+ return synthesizeResults(query, results, {
124
+ ...options,
125
+ synthesizer: "gemini"
126
+ });
127
+ }