@humain/terminal 0.1.1 → 0.2.1

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 (193) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/bundle/chunks/{anthropic-messages-XULXUBIG.js → anthropic-messages-QFCEKGI3.js} +1 -1
  3. package/dist/bundle/chunks/{azure-openai-responses-JEG2XOYC.js → azure-openai-responses-G4ZMHV37.js} +1 -1
  4. package/dist/bundle/chunks/chunk-7T6XCLJF.js +22 -0
  5. package/dist/bundle/chunks/chunk-D6HHRSB5.js +103 -0
  6. package/dist/bundle/chunks/chunk-EY4DWHQU.js +2 -0
  7. package/dist/bundle/chunks/{chunk-LYAMSPR2.js → chunk-I47ZWR55.js} +483 -506
  8. package/dist/bundle/chunks/{chunk-JUPSJTFQ.js → chunk-K4JAZYQH.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-HPPQHK3J.js → chunk-KKIB2TVR.js} +1 -1
  10. package/dist/bundle/chunks/chunk-LI2YVPWP.js +2 -0
  11. package/dist/bundle/chunks/{chunk-BZQ53VGE.js → chunk-XSR434CO.js} +1 -1
  12. package/dist/bundle/chunks/compat-QCV26HNS.js +2 -0
  13. package/dist/bundle/chunks/dist-PRPIUY3U.js +2 -0
  14. package/dist/bundle/chunks/esm-E7UVEYTO.js +4 -0
  15. package/dist/bundle/chunks/{extract-TRW5FBY6.js → extract-CTIFQZDJ.js} +15 -14
  16. package/dist/bundle/chunks/{google-generative-ai-OX6VSCA6.js → google-generative-ai-RSUU4MWO.js} +1 -1
  17. package/dist/bundle/chunks/{google-vertex-GW76GSS2.js → google-vertex-CKQPOITO.js} +1 -1
  18. package/dist/bundle/chunks/host-WP3MVKS2.js +2 -0
  19. package/dist/bundle/chunks/{node-KOIP55YZ.js → node-NF43OPII.js} +1 -1
  20. package/dist/bundle/chunks/{node-XY3CBY3C.js → node-UMFM7CDZ.js} +1 -1
  21. package/dist/bundle/chunks/{openai-codex-responses-NPLWP6ZC.js → openai-codex-responses-S34V5ZSD.js} +1 -1
  22. package/dist/bundle/chunks/{openai-completions-OT2GTJKC.js → openai-completions-T2IGVUEI.js} +1 -1
  23. package/dist/bundle/chunks/{openai-responses-5A6CR7GI.js → openai-responses-GYZODCT3.js} +1 -1
  24. package/dist/bundle/chunks/readability-LAGF34IB.js +3 -0
  25. package/dist/bundle/chunks/turndown.cjs-HRMZVRUL.js +2 -0
  26. package/dist/bundle/cli.js +1 -1
  27. package/dist/bundle/index.js +1 -1
  28. package/dist/bundle/rpc-entry.js +1 -1
  29. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  30. package/dist/core/tools/file-mutation-queue.js +21 -8
  31. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  32. package/dist/core/tools/subagent-env.d.ts +18 -0
  33. package/dist/core/tools/subagent-env.d.ts.map +1 -0
  34. package/dist/core/tools/subagent-env.js +43 -0
  35. package/dist/core/tools/subagent-env.js.map +1 -0
  36. package/dist/core/tools/subagent-scheduler.d.ts +31 -0
  37. package/dist/core/tools/subagent-scheduler.d.ts.map +1 -0
  38. package/dist/core/tools/subagent-scheduler.js +203 -0
  39. package/dist/core/tools/subagent-scheduler.js.map +1 -0
  40. package/dist/core/tools/subagent.d.ts +83 -3
  41. package/dist/core/tools/subagent.d.ts.map +1 -1
  42. package/dist/core/tools/subagent.js +214 -76
  43. package/dist/core/tools/subagent.js.map +1 -1
  44. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
  45. package/dist/humain/mcp-adapter/vendor/README.md +125 -19
  46. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +69 -30
  47. package/dist/humain/mcp-adapter/vendor/agent-plugin-provenance.ts +36 -0
  48. package/dist/humain/mcp-adapter/vendor/claude-plugin-loader.ts +365 -0
  49. package/dist/humain/mcp-adapter/vendor/commands.ts +13 -15
  50. package/dist/humain/mcp-adapter/vendor/config.ts +198 -30
  51. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +40 -9
  52. package/dist/humain/mcp-adapter/vendor/direct-tool-surface.ts +250 -0
  53. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +9 -228
  54. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +74 -32
  55. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -1
  56. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.d.ts +1 -0
  57. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js +31 -0
  58. package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js.map +1 -0
  59. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.d.ts +9 -0
  60. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js +362 -0
  61. package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js.map +1 -0
  62. package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +3 -1
  63. package/dist/humain/mcp-adapter/vendor/dist/config.js +189 -27
  64. package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
  65. package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +7 -16
  66. package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -1
  67. package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +5 -17
  68. package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -1
  69. package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +30 -4
  70. package/dist/humain/mcp-adapter/vendor/dist/types.js +26 -0
  71. package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
  72. package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +6 -0
  73. package/dist/humain/mcp-adapter/vendor/dist/utils.js +65 -6
  74. package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -1
  75. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +20 -19
  76. package/dist/humain/mcp-adapter/vendor/http-ca.ts +84 -0
  77. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +37102 -15103
  78. package/dist/humain/mcp-adapter/vendor/index.ts +828 -164
  79. package/dist/humain/mcp-adapter/vendor/init.ts +48 -10
  80. package/dist/humain/mcp-adapter/vendor/lazy-loader.ts +7 -0
  81. package/dist/humain/mcp-adapter/vendor/mcp-auth-fetch.ts +113 -0
  82. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +256 -77
  83. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +316 -54
  84. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +45 -18
  85. package/dist/humain/mcp-adapter/vendor/mcp-install.ts +60 -0
  86. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +70 -6
  87. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +53 -42
  88. package/dist/humain/mcp-adapter/vendor/mcp-panel-theme.ts +105 -0
  89. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +366 -331
  90. package/dist/humain/mcp-adapter/vendor/mcp-references.ts +9 -14
  91. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +3 -1
  92. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +383 -341
  93. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +5 -0
  94. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +7 -16
  95. package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +61 -3
  96. package/dist/humain/mcp-adapter/vendor/oauth.ts +6 -2
  97. package/dist/humain/mcp-adapter/vendor/package-mcp-loader.ts +5 -17
  98. package/dist/humain/mcp-adapter/vendor/package.json +13 -3
  99. package/dist/humain/mcp-adapter/vendor/prompts.ts +35 -3
  100. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +108 -7
  101. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +16 -1
  102. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +9 -32
  103. package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +20 -93
  104. package/dist/humain/mcp-adapter/vendor/server-manager.ts +227 -40
  105. package/dist/humain/mcp-adapter/vendor/session-approvals.ts +187 -0
  106. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +9 -1
  107. package/dist/humain/mcp-adapter/vendor/state.ts +10 -1
  108. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +10 -22
  109. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +14 -0
  110. package/dist/humain/mcp-adapter/vendor/types.ts +57 -4
  111. package/dist/humain/mcp-adapter/vendor/ui-server.ts +36 -28
  112. package/dist/humain/mcp-adapter/vendor/utils.ts +64 -6
  113. package/dist/humain/web-access/vendor/abortable.d.ts +3 -0
  114. package/dist/humain/web-access/vendor/abortable.d.ts.map +1 -0
  115. package/dist/humain/web-access/vendor/abortable.js +22 -0
  116. package/dist/humain/web-access/vendor/abortable.js.map +1 -0
  117. package/dist/humain/web-access/vendor/crawl4ai.d.ts +9 -0
  118. package/dist/humain/web-access/vendor/crawl4ai.d.ts.map +1 -0
  119. package/dist/humain/web-access/vendor/crawl4ai.js +187 -0
  120. package/dist/humain/web-access/vendor/crawl4ai.js.map +1 -0
  121. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
  122. package/dist/humain/web-access/vendor/credential-source.js +1 -0
  123. package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
  124. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
  125. package/dist/humain/web-access/vendor/curator-page.js +20 -2
  126. package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
  127. package/dist/humain/web-access/vendor/curator-run.d.ts +11 -0
  128. package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -0
  129. package/dist/humain/web-access/vendor/curator-run.js +38 -0
  130. package/dist/humain/web-access/vendor/curator-run.js.map +1 -0
  131. package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
  132. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
  133. package/dist/humain/web-access/vendor/curator-server.js +2 -0
  134. package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
  135. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
  136. package/dist/humain/web-access/vendor/duckduckgo.js +1 -1
  137. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
  138. package/dist/humain/web-access/vendor/extract.d.ts +1 -1
  139. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
  140. package/dist/humain/web-access/vendor/extract.js +58 -11
  141. package/dist/humain/web-access/vendor/extract.js.map +1 -1
  142. package/dist/humain/web-access/vendor/fetch-params.js +1 -1
  143. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
  144. package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
  145. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
  146. package/dist/humain/web-access/vendor/gemini-search.js +12 -5
  147. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
  148. package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
  149. package/dist/humain/web-access/vendor/index.js +23 -19
  150. package/dist/humain/web-access/vendor/index.js.map +1 -1
  151. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
  152. package/dist/humain/web-access/vendor/openai-search.js +40 -14
  153. package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
  154. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
  155. package/dist/humain/web-access/vendor/page-query.js +6 -2
  156. package/dist/humain/web-access/vendor/page-query.js.map +1 -1
  157. package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
  158. package/dist/humain/web-access/vendor/query-rewrite.js +6 -2
  159. package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
  160. package/dist/humain/web-access/vendor/serpapi.d.ts +4 -0
  161. package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -0
  162. package/dist/humain/web-access/vendor/serpapi.js +215 -0
  163. package/dist/humain/web-access/vendor/serpapi.js.map +1 -0
  164. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
  165. package/dist/humain/web-access/vendor/ssrf-protection.js +5 -1
  166. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
  167. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
  168. package/dist/humain/web-access/vendor/storage.js +9 -0
  169. package/dist/humain/web-access/vendor/storage.js.map +1 -1
  170. package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
  171. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
  172. package/dist/humain/web-access/vendor/summary-review.js +35 -24
  173. package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
  174. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
  175. package/dist/humain/web-access/vendor/utils.js +5 -3
  176. package/dist/humain/web-access/vendor/utils.js.map +1 -1
  177. package/dist/modes/json-event.d.ts +8 -0
  178. package/dist/modes/json-event.d.ts.map +1 -1
  179. package/dist/modes/json-event.js +17 -0
  180. package/dist/modes/json-event.js.map +1 -1
  181. package/dist/modes/print-mode.d.ts.map +1 -1
  182. package/dist/modes/print-mode.js +3 -2
  183. package/dist/modes/print-mode.js.map +1 -1
  184. package/docs/environment-variables.md +8 -0
  185. package/docs/json.md +16 -0
  186. package/npm-shrinkwrap.json +6 -6
  187. package/package.json +2 -2
  188. package/src/humain/mcp-adapter/UPSTREAM.md +56 -7
  189. package/src/humain/mcp-adapter/upstream.json +6 -4
  190. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
  191. package/src/humain/web-access/UPSTREAM.md +18 -8
  192. package/src/humain/web-access/upstream.json +6 -5
  193. package/dist/bundle/chunks/chunk-2LC3S3VV.js +0 -105
@@ -0,0 +1,103 @@
1
+ import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
+ import{getAgentDir}from"./chunk-LI2YVPWP.js";var Node=class{value;next;constructor(value){this.value=value}},Queue=class{#head;#tail;#size;constructor(){this.clear()}enqueue(value){let node=new Node(value);this.#head?(this.#tail.next=node,this.#tail=node):(this.#head=node,this.#tail=node),this.#size++}dequeue(){let current=this.#head;if(current)return this.#head=this.#head.next,this.#size--,this.#head||(this.#tail=void 0),current.value}peek(){if(this.#head)return this.#head.value}clear(){this.#head=void 0,this.#tail=void 0,this.#size=0}get size(){return this.#size}*[Symbol.iterator](){let current=this.#head;for(;current;)yield current.value,current=current.next}*drain(){for(;this.#head;)yield this.dequeue()}};function pLimit(concurrency){let rejectOnClear=!1;if(typeof concurrency=="object"&&({concurrency,rejectOnClear=!1}=concurrency),validateConcurrency(concurrency),typeof rejectOnClear!="boolean")throw new TypeError("Expected `rejectOnClear` to be a boolean");let queue=new Queue,activeCount=0,resumeNext=()=>{activeCount<concurrency&&queue.size>0&&(activeCount++,queue.dequeue().run())},next=()=>{activeCount--,resumeNext()},run=async(function_,resolve,arguments_)=>{let result=(async()=>function_(...arguments_))();resolve(result);try{await result}catch{}next()},enqueue=(function_,resolve,reject,arguments_)=>{let queueItem={reject};new Promise(internalResolve=>{queueItem.run=internalResolve,queue.enqueue(queueItem)}).then(run.bind(void 0,function_,resolve,arguments_)),activeCount<concurrency&&resumeNext()},generator=(function_,...arguments_)=>new Promise((resolve,reject)=>{enqueue(function_,resolve,reject,arguments_)});return Object.defineProperties(generator,{activeCount:{get:()=>activeCount},pendingCount:{get:()=>queue.size},clearQueue:{value(){if(!rejectOnClear){queue.clear();return}let abortError=AbortSignal.abort().reason;for(;queue.size>0;)queue.dequeue().reject(abortError)}},concurrency:{get:()=>concurrency,set(newConcurrency){validateConcurrency(newConcurrency),concurrency=newConcurrency,queueMicrotask(()=>{for(;activeCount<concurrency&&queue.size>0;)resumeNext()})}},map:{async value(iterable,function_){let promises=Array.from(iterable,(value,index)=>generator(function_,value,index));return Promise.all(promises)}}}),generator}function validateConcurrency(concurrency){if(!((Number.isInteger(concurrency)||concurrency===Number.POSITIVE_INFINITY)&&concurrency>0))throw new TypeError("Expected `concurrency` to be a number from 1 and up")}import{AsyncLocalStorage}from"node:async_hooks";import{spawn}from"node:child_process";import{existsSync,readFileSync}from"node:fs";import{mkdtemp,readFile,rm,writeFile}from"node:fs/promises";import{hostname,tmpdir}from"node:os";import{join}from"node:path";function getWebSearchConfigDir(){return getAgentDir()}function getWebSearchConfigPath(){return join(getWebSearchConfigDir(),"web-search.json")}function resolveApiBaseUrl(options){let fromEnvironment=options.environmentValue!==void 0,value=fromEnvironment?options.environmentValue:options.configuredValue;if(value===void 0)return options.defaultValue;let source=fromEnvironment?options.environmentKey:`${options.configKey} in ${getWebSearchConfigPath()}`;if(typeof value!="string"||value.trim().length===0)throw new Error(`${source} must be an absolute HTTP(S) URL`);let url;try{url=new URL(value.trim())}catch{throw new Error(`${source} must be an absolute HTTP(S) URL`)}if(url.protocol!=="https:")throw new Error(`${source} must be an absolute HTTPS URL`);if(url.username||url.password)throw new Error(`${source} must not include credentials`);if(url.search||url.hash)throw new Error(`${source} must not include query parameters or fragments`);return url.search="",url.hash="",url.pathname=url.pathname.replace(/\/+$/,""),url.toString().replace(/\/+$/,"")}var API_REDIRECT_STATUSES=new Set([301,302,303,307,308]),API_REQUEST_BODY_HEADERS=["Content-Encoding","Content-Language","Content-Location","Content-Type"],MAX_API_REDIRECTS=5;async function fetchWithCredentialRedirects(url,init,credentialHeaders){let current=new URL(url),requestInit=init;for(let redirects=0;;redirects++){let response=await fetch(current,{...requestInit,redirect:"manual"});if(!API_REDIRECT_STATUSES.has(response.status))return response;let location=response.headers.get("location");if(!location)return response;if(redirects===MAX_API_REDIRECTS)throw new Error(`Too many API redirects from ${url}`);let next=new URL(location,current);if(next.protocol!=="http:"&&next.protocol!=="https:")throw new Error(`API redirect from ${current.origin} must use HTTP(S)`);let method=requestInit.method?.toUpperCase()??"GET";if((response.status===301||response.status===302)&&method==="POST"||response.status===303&&method!=="GET"&&method!=="HEAD"){let headers=new Headers(requestInit.headers);for(let name of API_REQUEST_BODY_HEADERS)headers.delete(name);let{body:_body,...withoutBody}=requestInit;requestInit={...withoutBody,method:"GET",headers}}if(next.origin!==current.origin){let headers=new Headers(requestInit.headers);for(let name of credentialHeaders)headers.delete(name);requestInit={...requestInit,headers}}current=next}}var LOCAL_CURATOR_NETWORK_DEFAULTS={enabled:!1,host:"localhost",bind:"127.0.0.1"};function trimmedString(value){if(typeof value!="string")return;let trimmed=value.trim();return trimmed.length>0?trimmed:void 0}function resolveCuratorNetworkConfig(){let configPath=getWebSearchConfigPath();if(!existsSync(configPath))return LOCAL_CURATOR_NETWORK_DEFAULTS;let raw;try{raw=JSON.parse(readFileSync(configPath,"utf-8"))}catch{return LOCAL_CURATOR_NETWORK_DEFAULTS}if(!raw||typeof raw!="object"||Array.isArray(raw))return LOCAL_CURATOR_NETWORK_DEFAULTS;let curatorRemote=raw.curatorRemote;if(curatorRemote===!0)return{enabled:!0,host:hostname(),bind:"0.0.0.0"};if(curatorRemote&&typeof curatorRemote=="object"&&!Array.isArray(curatorRemote)){let obj=curatorRemote;return{enabled:!0,host:trimmedString(obj.host)??hostname(),bind:trimmedString(obj.bind)??"0.0.0.0"}}return LOCAL_CURATOR_NETWORK_DEFAULTS}function formatSeconds(s){let h=Math.floor(s/3600),m=Math.floor(s%3600/60),sec=s%60;return h>0?`${h}:${String(m).padStart(2,"0")}:${String(sec).padStart(2,"0")}`:`${m}:${String(sec).padStart(2,"0")}`}function readExecError(err){if(!err||typeof err!="object")return{stderr:"",message:String(err)};let code=err.code,message=err.message??"",stderrRaw=err.stderr,stderr=Buffer.isBuffer(stderrRaw)?stderrRaw.toString("utf-8"):typeof stderrRaw=="string"?stderrRaw:"";return{code,stderr,message}}function isTimeoutError(err){if(!err||typeof err!="object")return!1;if(err.killed)return!0;let name=err.name,code=err.code,message=err.message??"";return name==="AbortError"||code==="ETIMEDOUT"||message.toLowerCase().includes("timed out")}function trimErrorText(text){return text.replace(/\s+/g," ").trim().slice(0,200)}function mapFfmpegError(err){let{code,stderr,message}=readExecError(err);if(code==="ENOENT")return"ffmpeg is not installed. Install with: brew install ffmpeg";if(isTimeoutError(err))return"ffmpeg timed out extracting frame";if(stderr.includes("403"))return"Stream URL returned 403 \u2014 may have expired, try again";let snippet=trimErrorText(stderr||message);return snippet?`ffmpeg failed: ${snippet}`:"ffmpeg failed"}var proxyStorage=new AsyncLocalStorage;function normalizeProxyUrl(value,source){if(value==null)return null;if(typeof value!="string")throw new Error(`${source} must be an http(s) or socks proxy URL string`);let trimmed=value.trim();if(!trimmed)return null;let parsed;try{parsed=new URL(trimmed)}catch{throw new Error(`${source} must be a valid proxy URL: ${JSON.stringify(trimmed)}`)}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:"&&parsed.protocol!=="socks4:"&&parsed.protocol!=="socks4a:"&&parsed.protocol!=="socks5:"&&parsed.protocol!=="socks5h:")throw new Error(`${source} must use the http://, https://, or socks scheme: ${trimmed}`);if(!parsed.hostname)throw new Error(`${source} must include a proxy host: ${trimmed}`);return parsed.hash="",parsed.search="",parsed.toString()}function redactProxyUrl(value){let parsed=new URL(value);return parsed.username&&(parsed.username="redacted"),parsed.password&&(parsed.password="redacted"),parsed.toString()}function loadConfiguredProxy(){let configured,path=getWebSearchConfigPath();if(existsSync(path)){let raw;try{raw=JSON.parse(readFileSync(path,"utf-8"))}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to load proxy config from ${path}: ${message}`)}raw&&typeof raw=="object"&&!Array.isArray(raw)&&(configured=raw.proxy)}return configured===void 0?null:normalizeProxyUrl(configured,`proxy in ${getWebSearchConfigPath()}`)}function runWithProxy(proxy,fn){let normalized=proxy===void 0?loadConfiguredProxy():normalizeProxyUrl(proxy,"proxy");return proxyStorage.run(normalized,fn)}function getActiveProxy(){return proxyStorage.getStore()??null}function hasScopedProxyDecision(){return proxyStorage.getStore()!==void 0}function noProxyEntryMatches(hostname2,entry){if(!entry)return!1;if(entry==="*")return!0;let host=entry;if(host.startsWith("[")){let close=host.indexOf("]");close>0&&(host=host.slice(0,close+1))}else{let colon=host.lastIndexOf(":");colon>-1&&/^\d+$/.test(host.slice(colon+1))&&(host=host.slice(0,colon))}return host=host.toLowerCase().replace(/^\[|\]$/g,""),host?hostname2===host||hostname2.endsWith(host.startsWith(".")?host:`.${host}`):!1}function isProxyBypassedUrl(url){let hostname2=url.hostname.toLowerCase().replace(/^\[|\]$/g,"");if(hostname2==="localhost"||hostname2.endsWith(".localhost")||hostname2==="127.0.0.1"||hostname2==="::1")return!0;let noProxy=process.env.NO_PROXY||process.env.no_proxy;return!!(noProxy&&noProxy.split(",").some(entry=>noProxyEntryMatches(hostname2,entry.trim())))}function installGlobalProxyFetch(){let current=globalThis.fetch;if(typeof current!="function"||current.__piWebAccessProxyFetch===!0)return;let nativeFetch=current,wrapped=((input,init)=>{let proxy=init?.__proxy??(hasScopedProxyDecision()?getActiveProxy():null);if(!proxy)return nativeFetch(input,init);let url=null;try{url=new URL(typeof input=="string"||input instanceof URL?input:input.url)}catch{url=null}return!url||url.protocol!=="http:"&&url.protocol!=="https:"||isProxyBypassedUrl(url)?nativeFetch(input,init):fetchViaCurl(url,init??{},proxy)});wrapped.__piWebAccessProxyFetch=!0,globalThis.fetch=wrapped}function parseHeaderDump(dump){let blocks=dump.split(/\r?\n\r?\n/).filter(block2=>/^HTTP\/[\d.]+\s+\d{3}/.test(block2.trim())),lines=(blocks.length>0?blocks[blocks.length-1]:"").trim().split(/\r?\n/),status=0,statusText="",headers=[];for(let line of lines){let match=/^HTTP\/[\d.]+\s+(\d{3})(?:\s+(.*))?$/.exec(line.trim());if(match){status=Number(match[1]),statusText=match[2]??"",headers.length=0;continue}let separator=line.indexOf(":");if(separator>0){let name=line.slice(0,separator).trim();if(name.toLowerCase()==="content-encoding"||name.toLowerCase()==="content-length")continue;headers.push([name,line.slice(separator+1).trim()])}}return{status,statusText,headers}}var CurlTransportError=class extends Error{};function quoteCurlConfigValue(value,label){if(/[\0-\x08\x0c\x0e-\x1f\x7f]/.test(value))throw new Error(`${label} contains unsupported control characters`);return`"${value.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\v/g,"\\v")}"`}function curlConfigOption(name,value,label=name){return value===void 0?name:`${name} = ${quoteCurlConfigValue(value,label)}`}async function fetchViaCurl(url,init,proxyUrl){let current=url,currentInit=init;for(let redirects=0;;redirects++){let response=await fetchViaCurlOnce(current,currentInit,proxyUrl),location=response.headers.get("location");if(!location||![301,302,303,307,308].includes(response.status))return redirects>0&&Object.defineProperty(response,"redirected",{value:!0,configurable:!0}),response;if(currentInit.redirect==="manual")return response;if(currentInit.redirect==="error")throw new TypeError(`Proxy fetch redirect blocked from ${current.toString()}`);if(redirects===20)throw new Error(`Too many proxy redirects from ${url.toString()}`);let next=new URL(location,current);if(next.protocol!=="http:"&&next.protocol!=="https:")throw new Error(`Proxy redirect from ${current.origin} must use HTTP(S)`);let headers=new Headers(currentInit.headers),nextInit,method=currentInit.method?.toUpperCase()??"GET";if((response.status===301||response.status===302)&&method==="POST"||response.status===303&&method!=="GET"&&method!=="HEAD"){for(let name of["Content-Encoding","Content-Language","Content-Location","Content-Type"])headers.delete(name);let{body:_body,...withoutBody}=currentInit;nextInit={...withoutBody,method:"GET",headers}}else nextInit={...currentInit,headers};next.origin!==current.origin&&(headers=new Headers,nextInit={...nextInit,headers}),current=next,currentInit=nextInit}}async function fetchViaCurlOnce(url,init,proxyUrl){let method=(init.method??"GET").toUpperCase(),headers=new Headers(init.headers),dir=await mkdtemp(join(tmpdir(),"pi-web-access-proxy-")),headerFile=join(dir,"headers"),bodyFile=join(dir,"body"),requestBodyFile=join(dir,"request-body"),config=[curlConfigOption("silent"),curlConfigOption("show-error"),curlConfigOption("compressed"),curlConfigOption("connect-timeout","20"),curlConfigOption("proxy",proxyUrl,"proxy URL"),curlConfigOption("dump-header",headerFile),curlConfigOption("output",bodyFile),curlConfigOption("write-out","%{json}")];method!=="GET"&&method!=="HEAD"&&config.push(curlConfigOption("request",method));for(let[name,value]of headers.entries())value!==""&&config.push(curlConfigOption("header",`${name}: ${value}`,`header ${name}`));let body=init.body;if(body!=null){let buffer;if(typeof body=="string")buffer=Buffer.from(body,"utf-8");else if(body instanceof URLSearchParams)buffer=Buffer.from(body.toString(),"utf-8");else if(body instanceof ArrayBuffer)buffer=Buffer.from(body);else if(ArrayBuffer.isView(body))buffer=Buffer.from(body.buffer,body.byteOffset,body.byteLength);else throw new Error(`Unsupported request body type for proxy fetch: ${typeof body}`);await writeFile(requestBodyFile,buffer,{mode:384}),config.push(curlConfigOption("data-binary",`@${requestBodyFile}`)),method==="GET"&&config.push(curlConfigOption("request","GET"))}config.push(curlConfigOption("url",url.toString(),"request URL"));let configInput=`${config.join(`
3
+ `)}
4
+ `,signal=init.signal??null,stdout;try{stdout=await new Promise((resolve,reject)=>{if(signal?.aborted){reject(new DOMException("The operation was aborted.","AbortError"));return}let child=spawn("curl",["--config","-"],{windowsHide:!0,stdio:["pipe","pipe","pipe"]}),out="",stderr="",onAbort=()=>{try{child.kill()}catch{}};if(signal&&signal.addEventListener("abort",onAbort,{once:!0}),child.stdout?.on("data",chunk=>{out+=chunk.toString("utf-8")}),child.stderr?.on("data",chunk=>{stderr.length<4096&&(stderr+=chunk.toString("utf-8"))}),child.once("error",err=>{signal?.removeEventListener("abort",onAbort),reject(new CurlTransportError(err.code==="ENOENT"?"curl executable not found on PATH; proxy transport requires curl":`curl failed to start: ${err.message}`))}),child.once("close",code=>{if(signal?.removeEventListener("abort",onAbort),signal?.aborted)return reject(new DOMException("The operation was aborted.","AbortError"));if(code!==0&&!out.trim())return reject(new CurlTransportError(`curl exited with code ${code??"unknown"} via ${redactProxyUrl(proxyUrl)}${stderr.trim()?`: ${stderr.trim()}`:""}`));resolve(out)}),!child.stdin){child.kill(),reject(new CurlTransportError("curl stdin unavailable for protected proxy configuration"));return}child.stdin.on("error",err=>reject(new CurlTransportError(`curl stdin failed: ${err.message}`))),child.stdin.end(configInput)})}catch(err){throw await rm(dir,{recursive:!0,force:!0}).catch(()=>{}),err instanceof CurlTransportError?new Error(err.message):err}let bodyBuffer=Buffer.alloc(0),dump="";try{[dump,bodyBuffer]=await Promise.all([readFile(headerFile,"utf-8"),readFile(bodyFile)])}catch{}finally{await rm(dir,{recursive:!0,force:!0}).catch(()=>{})}let{status,statusText,headers:responseHeaders}=parseHeaderDump(dump);if(status===0)throw new Error(`Proxy fetch to ${url.toString()} via ${redactProxyUrl(proxyUrl)} returned no HTTP status`);let finalUrl=url.toString(),redirected=!1;try{let trimmed=stdout.trim();if(trimmed.startsWith("{")){let writeOut=JSON.parse(trimmed);writeOut.url_effective&&(finalUrl=writeOut.url_effective),redirected=(writeOut.num_redirects??0)>0}}catch{}let nullBody=status===204||status===205||status===304,response=new Response(nullBody?null:new Uint8Array(bodyBuffer),{status,statusText:statusText||void 0,headers:new Headers(responseHeaders)});return Object.defineProperty(response,"url",{value:finalUrl,configurable:!0}),Object.defineProperty(response,"redirected",{value:redirected,configurable:!0}),response}import{existsSync as existsSync2,readFileSync as readFileSync2}from"node:fs";var WEB_SEARCH_CONFIG_PATH=getWebSearchConfigPath(),AUTH_PROFILE_NAME_PATTERN=/^[A-Za-z][A-Za-z0-9_-]{0,63}$/;function resolveAuthFetchProfile(request){let profiles=loadAuthFetchProfiles();if(profiles.length===0)throw new Error(`auth requires at least one authFetch profile in ${WEB_SEARCH_CONFIG_PATH}`);if(request===!0){if(profiles.length!==1)throw new Error("auth: true requires exactly one authFetch profile; use a profile name instead");return profiles[0]}let name=request.trim(),profile=profiles.find(candidate=>candidate.name===name);if(!profile)throw new Error(`Unknown authFetch profile: ${name}`);return profile}function assertAuthFetchUrl(profile,rawUrl){let url;try{url=new URL(rawUrl)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Authenticated fetch requires an HTTPS URL: ${message}`)}if(url.protocol!=="https:")throw new Error("Authenticated fetch requires an HTTPS URL");let hostname2=normalizeHostname(url.hostname);if(!profile.hosts.some(host=>hostMatches(hostname2,host)))throw new Error(`URL host ${hostname2} is not allowed by authFetch profile ${profile.name}`);return url}function authFetchRedirectGuard(profile,from,to){if(profile.redirects==="same-origin"&&to.origin!==from.origin)throw new Error(`Authenticated fetch refused cross-origin redirect: ${from.origin} -> ${to.origin}`)}function loadAuthFetchProfiles(){if(!existsSync2(WEB_SEARCH_CONFIG_PATH))return[];let raw=readFileSync2(WEB_SEARCH_CONFIG_PATH,"utf-8"),parsed;try{let value=JSON.parse(raw);if(!value||typeof value!="object"||Array.isArray(value))throw new Error("expected a JSON object");parsed=value}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${WEB_SEARCH_CONFIG_PATH}: ${message}`)}if(parsed.authFetch===void 0||parsed.authFetch===null)return[];if(typeof parsed.authFetch!="object"||Array.isArray(parsed.authFetch))throw new Error(`authFetch in ${WEB_SEARCH_CONFIG_PATH} must be an object`);return Object.entries(parsed.authFetch).map(([name,value])=>parseProfile(name,value))}function parseProfile(name,value){if(!AUTH_PROFILE_NAME_PATTERN.test(name))throw new Error(`authFetch profile name ${JSON.stringify(name)} must start with a letter and contain only letters, numbers, underscores, or hyphens`);if(Array.isArray(value))return{name,hosts:parseHosts(value,`authFetch.${name}`),redirects:"same-origin",cache:"session"};if(!value||typeof value!="object")throw new Error(`authFetch.${name} in ${WEB_SEARCH_CONFIG_PATH} must be an array of hosts or an object`);let config=value;if(!Array.isArray(config.hosts))throw new Error(`authFetch.${name}.hosts in ${WEB_SEARCH_CONFIG_PATH} must be a non-empty array of hostnames`);let redirects=config.redirects??"same-origin";if(redirects!=="same-origin")throw new Error(`authFetch.${name}.redirects in ${WEB_SEARCH_CONFIG_PATH} must be "same-origin"`);let cache=config.cache??"session";if(cache!=="session"&&cache!=="off")throw new Error(`authFetch.${name}.cache in ${WEB_SEARCH_CONFIG_PATH} must be "session" or "off"`);let chromeProfile=parseChromeProfile(config.chromeProfile,`authFetch.${name}.chromeProfile`);return{name,hosts:parseHosts(config.hosts,`authFetch.${name}.hosts`),...chromeProfile?{chromeProfile}:{},redirects,cache}}function parseHosts(value,label){if(value.length===0)throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} must be a non-empty array of hostnames`);let hosts=value.map(entry=>{if(typeof entry!="string")throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} must contain only hostnames`);return parseHost(entry,label)});return[...new Set(hosts)]}function parseHost(value,label){let host=normalizeHostname(value.trim());if(!host||host.startsWith(".")||host.endsWith(".")||/\s|[\\/?:#@*]/.test(host))throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} contains an invalid hostname: ${JSON.stringify(value)}`);if(host.length>253||!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(host))throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} contains an invalid hostname: ${JSON.stringify(value)}`);return host}function parseChromeProfile(value,label){if(value==null)return;if(typeof value!="string")throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} must be a string`);let normalized=value.trim();if(!normalized||normalized==="."||normalized===".."||normalized.includes("/")||normalized.includes("\\"))throw new Error(`${label} in ${WEB_SEARCH_CONFIG_PATH} must be a profile directory name, not a path`);return normalized}function normalizeHostname(hostname2){return hostname2.toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"")}function hostMatches(hostname2,allowedHost){return hostname2===allowedHost||hostname2.endsWith(`.${allowedHost}`)}var ActivityMonitor=class{constructor(){this.entries=[],this.maxEntries=10,this.listeners=new Set,this.rateLimitInfo={used:0,max:10,oldestTimestamp:null,windowMs:6e4},this.nextId=1}logStart(partial){let id=`act-${this.nextId++}`,entry={...partial,id,startTime:Date.now(),status:null};return this.entries.push(entry),this.entries.length>this.maxEntries&&this.entries.shift(),this.notify(),id}logComplete(id,status){let entry=this.entries.find(e=>e.id===id);entry&&(entry.endTime=Date.now(),entry.status=status,this.notify())}logError(id,error){let entry=this.entries.find(e=>e.id===id);entry&&(entry.endTime=Date.now(),entry.error=error,this.notify())}getEntries(){return this.entries}getRateLimitInfo(){return this.rateLimitInfo}updateRateLimit(info){this.rateLimitInfo=info,this.notify()}onUpdate(callback){return this.listeners.add(callback),()=>this.listeners.delete(callback)}clear(){this.entries=[],this.rateLimitInfo={used:0,max:10,oldestTimestamp:null,windowMs:6e4},this.notify()}notify(){for(let cb of this.listeners)try{cb()}catch{}}},activityMonitor=new ActivityMonitor;import{chmodSync,closeSync,constants as fsConstants,existsSync as existsSync3,lstatSync,mkdirSync,mkdtempSync,openSync,readFileSync as readFileSync3,readSync,readdirSync,realpathSync,rmSync,statSync,unlinkSync,writeFileSync}from"node:fs";import{lstat as lstatAsync,open as openAsync,opendir as opendirAsync,readFile as readFileAsync,realpath as realpathAsync,rm as rmAsync}from"node:fs/promises";import{execFile as execFile2,spawn as spawn2}from"node:child_process";import{createHash}from"node:crypto";import{basename,dirname,extname,join as join2,resolve as resolvePath,sep as pathSep}from"node:path";import{execFile}from"node:child_process";var MAX_TREE_ENTRIES=200,MAX_INLINE_FILE_CHARS=1e5,ghAvailable=null,ghHintShown=!1;async function checkGhAvailable(signal){return ghAvailable!==null?ghAvailable:new Promise(resolve=>{execFile("gh",["--version"],{timeout:5e3,...signal?{signal}:{}},err=>{let available=!err;signal?.aborted||(ghAvailable=available),resolve(available)})})}function showGhHint(){ghHintShown||(ghHintShown=!0,console.error("[pi-web-access] Install `gh` CLI for better GitHub repo access including private repos."))}async function checkRepoSize(owner,repo){return await checkGhAvailable()?new Promise(resolve=>{execFile("gh",["api",`repos/${owner}/${repo}`,"--jq",".size"],{timeout:1e4},(err,stdout)=>{if(err){resolve(null);return}let kb=parseInt(stdout.trim(),10);resolve(Number.isNaN(kb)?null:kb)})}):null}async function getDefaultBranch(owner,repo){return await checkGhAvailable()?new Promise(resolve=>{execFile("gh",["api",`repos/${owner}/${repo}`,"--jq",".default_branch"],{timeout:1e4},(err,stdout)=>{if(err){resolve(null);return}let branch=stdout.trim();resolve(branch||null)})}):null}async function fetchTreeViaApi(owner,repo,ref){return await checkGhAvailable()?new Promise(resolve=>{execFile("gh",["api",`repos/${owner}/${repo}/git/trees/${ref}?recursive=1`,"--jq",".tree[].path"],{timeout:15e3,maxBuffer:5*1024*1024},(err,stdout)=>{if(err){resolve(null);return}let paths=stdout.trim().split(`
5
+ `).filter(Boolean);if(paths.length===0){resolve(null);return}let truncated=paths.length>MAX_TREE_ENTRIES,display=paths.slice(0,MAX_TREE_ENTRIES).join(`
6
+ `);resolve(truncated?display+`
7
+ ... (${paths.length} total entries)`:display)})}):null}async function fetchReadmeViaApi(owner,repo,ref){return await checkGhAvailable()?new Promise(resolve=>{execFile("gh",["api",`repos/${owner}/${repo}/readme?ref=${ref}`,"--jq",".content"],{timeout:1e4},(err,stdout)=>{if(err){resolve(null);return}try{let decoded=Buffer.from(stdout.trim(),"base64").toString("utf-8");resolve(decoded.length>8192?decoded.slice(0,8192)+`
8
+
9
+ [README truncated at 8K chars]`:decoded)}catch{resolve(null)}})}):null}async function fetchFileViaApi(owner,repo,path,ref){return await checkGhAvailable()?new Promise(resolve=>{execFile("gh",["api",`repos/${owner}/${repo}/contents/${path}?ref=${ref}`,"--jq",".content"],{timeout:1e4,maxBuffer:2*1024*1024},(err,stdout)=>{if(err){resolve(null);return}try{resolve(Buffer.from(stdout.trim(),"base64").toString("utf-8"))}catch{resolve(null)}})}):null}async function fetchViaApi(url,owner,repo,info,sizeNote){let ref=info.ref||await getDefaultBranch(owner,repo);if(!ref)return null;let lines=[];if(sizeNote&&(lines.push(sizeNote),lines.push("")),info.type==="blob"&&info.path){let content=await fetchFileViaApi(owner,repo,info.path,ref);return content?(lines.push(`## ${info.path}`),content.length>MAX_INLINE_FILE_CHARS?(lines.push(content.slice(0,MAX_INLINE_FILE_CHARS)),lines.push(`
10
+ [File truncated at 100K chars]`)):lines.push(content),{url,title:`${owner}/${repo} - ${info.path}`,content:lines.join(`
11
+ `),error:null}):null}let[tree,readme]=await Promise.all([fetchTreeViaApi(owner,repo,ref),fetchReadmeViaApi(owner,repo,ref)]);if(!tree&&!readme)return null;tree&&(lines.push("## Structure"),lines.push(tree),lines.push("")),readme&&(lines.push("## README.md"),lines.push(readme),lines.push("")),lines.push("This is an API-only view. Clone the repo or use `read`/`bash` for deeper exploration.");let title=info.path?`${owner}/${repo} - ${info.path}`:`${owner}/${repo}`;return{url,title,content:lines.join(`
12
+ `),error:null}}var CONFIG_PATH=getWebSearchConfigPath(),BINARY_EXTENSIONS=new Set([".png",".jpg",".jpeg",".gif",".bmp",".ico",".webp",".svg",".tiff",".tif",".mp3",".mp4",".avi",".mov",".mkv",".flv",".wmv",".wav",".ogg",".webm",".flac",".aac",".zip",".tar",".gz",".bz2",".xz",".7z",".rar",".zst",".exe",".dll",".so",".dylib",".bin",".o",".a",".lib",".woff",".woff2",".ttf",".otf",".eot",".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".sqlite",".db",".sqlite3",".pyc",".pyo",".class",".jar",".war",".iso",".img",".dmg"]),NOISE_DIRS=new Set(["node_modules","vendor",".next","dist","build","__pycache__",".venv","venv",".tox",".mypy_cache",".pytest_cache","target",".gradle",".idea",".vscode"]),MAX_INLINE_FILE_CHARS2=1e5,MAX_TREE_ENTRIES2=200,CLONE_RUNTIME_OWNER_FILENAME=".owner.json",CLONE_RUNTIME_OWNER_VERSION=1,MAX_CLONE_RUNTIME_OWNER_BYTES=1024,cloneCache=new Map,startedCloneRuntimeCleanups=new Set,cachedConfig=null,cloneRuntime=null;function normalizeEnabled(value,fallback){return typeof value=="boolean"?value:fallback}function normalizePositiveNumber(value,fallback){return typeof value!="number"||!Number.isFinite(value)?fallback:value>0?value:fallback}function expandPath(value){let expanded=value;return(expanded.startsWith("~/")||expanded==="~")&&(expanded=expanded.replace(/^~/,process.env.HOME||process.env.USERPROFILE||"")),expanded=expanded.replace(/\$([A-Z_][A-Z0-9_]*)/gi,(match,varName)=>process.env[varName]??match),expanded}function normalizeClonePath(value,fallback){if(typeof value!="string")return fallback;let normalized=value.trim();return normalized.length===0?fallback:expandPath(normalized)}function loadGitHubConfig(){if(cachedConfig)return cachedConfig;let defaults={enabled:!0,maxRepoSizeMB:350,cloneTimeoutSeconds:30,clonePath:"/tmp/pi-github-repos"};if(!existsSync3(CONFIG_PATH))return cachedConfig=defaults,cachedConfig;let rawText=readFileSync3(CONFIG_PATH,"utf-8"),raw;try{raw=JSON.parse(rawText)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`)}let gc=raw.githubClone??{};return cachedConfig={enabled:normalizeEnabled(gc.enabled,defaults.enabled),maxRepoSizeMB:normalizePositiveNumber(gc.maxRepoSizeMB,defaults.maxRepoSizeMB),cloneTimeoutSeconds:normalizePositiveNumber(gc.cloneTimeoutSeconds,defaults.cloneTimeoutSeconds),clonePath:normalizeClonePath(gc.clonePath,defaults.clonePath)},cachedConfig}var NON_CODE_SEGMENTS=new Set(["issues","pull","pulls","discussions","releases","wiki","actions","settings","security","projects","graphs","compare","commits","tags","branches","stargazers","watchers","network","forks","milestone","labels","packages","codespaces","contribute","community","sponsors","invitations","notifications","insights"]);function parseGitHubUrl(url){let parsed;try{parsed=new URL(url)}catch{return null}let host=parsed.hostname.toLowerCase();if(host!=="github.com"&&host!=="www.github.com")return null;let segments=[];for(let segment of parsed.pathname.split("/").filter(Boolean))try{segments.push(decodeURIComponent(segment))}catch{return null}if(segments.length<2)return null;let owner=segments[0],repo=segments[1].replace(/\.git$/,"");if(!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/.test(owner)||owner.includes("--")||!/^[A-Za-z0-9._-]{1,100}$/.test(repo)||repo==="."||repo===".."||NON_CODE_SEGMENTS.has(segments[2]?.toLowerCase()))return null;if(segments.length===2)return{owner,repo,refIsFullSha:!1,type:"root"};let action=segments[2];if(action!=="blob"&&action!=="tree"||segments.length<4)return null;let ref=segments[3];if(ref.length===0||ref.length>1024||/[\0-\x1f\x7f]/.test(ref))return null;let refIsFullSha=/^[0-9a-f]{40}$/.test(ref),pathParts=segments.slice(4),path=pathParts.length>0?pathParts.join("/"):"";return{owner,repo,ref,refIsFullSha,path,type:action}}function cacheKey(owner,repo,ref){return ref?`${owner}/${repo}@${ref}`:`${owner}/${repo}`}function readLinuxBootId(){try{let bootId=readFileSync3("/proc/sys/kernel/random/boot_id","utf-8").trim();return bootId.length>0?bootId:null}catch{return null}}async function readLinuxBootIdAsync(){try{let bootId=(await readFileAsync("/proc/sys/kernel/random/boot_id","utf-8")).trim();return bootId.length>0?bootId:null}catch{return null}}function parseLinuxProcessInfo(stat){let closingParen=stat.lastIndexOf(") ");if(closingParen<0)return null;let fields=stat.slice(closingParen+2).trim().split(/\s+/),state=fields[0],startTime=fields[19];return!state||!startTime||!/^\d+$/.test(startTime)?null:{state,startTime,dead:!1}}function readLinuxProcessInfo(pid){try{return parseLinuxProcessInfo(readFileSync3(`/proc/${pid}/stat`,"utf-8"))}catch(err){return err&&typeof err=="object"&&"code"in err&&err.code==="ENOENT"?{state:"",startTime:null,dead:!0}:null}}async function readLinuxProcessInfoAsync(pid){try{return parseLinuxProcessInfo(await readFileAsync(`/proc/${pid}/stat`,"utf-8"))}catch(err){return err&&typeof err=="object"&&"code"in err&&err.code==="ENOENT"?{state:"",startTime:null,dead:!0}:null}}function currentCloneRuntimeOwner(){let owner={version:CLONE_RUNTIME_OWNER_VERSION,pid:process.pid,platform:process.platform};if(process.platform==="linux"){let bootId=readLinuxBootId(),processInfo=readLinuxProcessInfo(process.pid);bootId&&processInfo?.startTime&&(owner.bootId=bootId,owner.startTime=processInfo.startTime)}return owner}function writeCloneRuntimeOwner(runtimePath){let ownerPath=join2(runtimePath,CLONE_RUNTIME_OWNER_FILENAME);writeFileSync(ownerPath,JSON.stringify(currentCloneRuntimeOwner()),{encoding:"utf-8",flag:"wx",mode:384})}function parseCloneRuntimeOwner(text){let parsed;try{parsed=JSON.parse(text)}catch{return null}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))return null;let record=parsed;if(record.version!==CLONE_RUNTIME_OWNER_VERSION||typeof record.pid!="number"||!Number.isSafeInteger(record.pid)||record.pid<=0||typeof record.platform!="string"||record.platform.length===0||record.platform.length>32)return null;let owner={version:CLONE_RUNTIME_OWNER_VERSION,pid:record.pid,platform:record.platform};if(record.bootId!==void 0){if(typeof record.bootId!="string"||record.bootId.length===0||record.bootId.length>256)return null;owner.bootId=record.bootId}if(record.startTime!==void 0){if(typeof record.startTime!="string"||!/^\d+$/.test(record.startTime))return null;owner.startTime=record.startTime}return owner}async function readCloneRuntimeOwner(runtimePath){let ownerPath=join2(runtimePath,CLONE_RUNTIME_OWNER_FILENAME),file;try{let entry=await lstatAsync(ownerPath);if(!entry.isFile()||entry.size>MAX_CLONE_RUNTIME_OWNER_BYTES)return null;let noFollow=fsConstants.O_NOFOLLOW??0;file=await openAsync(ownerPath,fsConstants.O_RDONLY|noFollow);let opened=await file.stat();return!opened.isFile()||opened.size>MAX_CLONE_RUNTIME_OWNER_BYTES?null:parseCloneRuntimeOwner(await file.readFile("utf-8"))}catch{return null}finally{if(file!==void 0)try{await file.close()}catch{}}}function processNonexistenceProven(pid){try{return process.kill(pid,0),!1}catch(err){return!!(err&&typeof err=="object"&&"code"in err&&err.code==="ESRCH")}}async function cloneRuntimeOwnerIsDead(owner,bootId){if(owner.platform!==process.platform)return!1;if(process.platform!=="linux")return processNonexistenceProven(owner.pid);if(!owner.bootId||!owner.startTime||!bootId)return!1;let processInfo=await readLinuxProcessInfoAsync(owner.pid);return processInfo?processInfo.dead||processInfo.state==="Z"||processInfo.state==="X"?!0:processInfo.startTime!==owner.startTime||bootId!==owner.bootId:!1}async function removeCloneRuntimeAsync(parentPath,runtimePath){let normalizedParentPath=resolvePath(parentPath),normalizedRuntimePath=resolvePath(runtimePath);if(!(dirname(normalizedRuntimePath)!==normalizedParentPath||!basename(normalizedRuntimePath).startsWith("runtime-")))try{let realRuntimePath=await realpathAsync(normalizedRuntimePath);if(dirname(realRuntimePath)!==normalizedParentPath||basename(realRuntimePath)!==basename(normalizedRuntimePath))return;let entry=await lstatAsync(normalizedRuntimePath);if(entry.isSymbolicLink()||!entry.isDirectory())return;await rmAsync(normalizedRuntimePath,{recursive:!0,force:!0})}catch{}}async function sweepStaleCloneRuntimes(parentPath){let normalizedParentPath=resolvePath(parentPath),bootId=process.platform==="linux"?await readLinuxBootIdAsync():null;try{let directory=await opendirAsync(normalizedParentPath);for await(let entry of directory)if(entry.name.startsWith("runtime-"))try{if(!entry.isDirectory()||entry.isSymbolicLink())continue;let runtimePath=resolvePath(normalizedParentPath,entry.name);if(dirname(runtimePath)!==normalizedParentPath)continue;let runtimeEntry=await lstatAsync(runtimePath);if(!runtimeEntry.isDirectory()||runtimeEntry.isSymbolicLink())continue;let realRuntimePath=await realpathAsync(runtimePath);if(dirname(realRuntimePath)!==normalizedParentPath||basename(realRuntimePath)!==basename(runtimePath))continue;let owner=await readCloneRuntimeOwner(runtimePath);if(!owner||!await cloneRuntimeOwnerIsDead(owner,bootId))continue;await removeCloneRuntimeAsync(normalizedParentPath,runtimePath)}catch{}}catch{}}function startStaleCloneRuntimeCleanup(parentPath){let normalizedParentPath=resolvePath(parentPath);startedCloneRuntimeCleanups.has(normalizedParentPath)||(startedCloneRuntimeCleanups.add(normalizedParentPath),sweepStaleCloneRuntimes(normalizedParentPath).catch(()=>{}))}function removeCloneRuntime(parentPath,runtimePath){let normalizedParentPath=resolvePath(parentPath),normalizedRuntimePath=resolvePath(runtimePath);if(!(dirname(normalizedRuntimePath)!==normalizedParentPath||!basename(normalizedRuntimePath).startsWith("runtime-")))try{lstatSync(normalizedRuntimePath).isSymbolicLink()?unlinkSync(normalizedRuntimePath):rmSync(normalizedRuntimePath,{recursive:!0,force:!0})}catch{}}function getCloneRuntimeRoot(config){if(cloneRuntime)return cloneRuntime.rootPath;let parentPath=null,runtimePath=null;try{let configuredPath=resolvePath(config.clonePath);mkdirSync(configuredPath,{recursive:!0}),parentPath=realpathSync(configuredPath),startStaleCloneRuntimeCleanup(parentPath),runtimePath=mkdtempSync(join2(parentPath,"runtime-")),chmodSync(runtimePath,448);let rootPath=realpathSync(runtimePath);return dirname(rootPath)!==parentPath?(removeCloneRuntime(parentPath,runtimePath),null):(writeCloneRuntimeOwner(rootPath),cloneRuntime={parentPath,rootPath},rootPath)}catch{return parentPath&&runtimePath&&removeCloneRuntime(parentPath,runtimePath),null}}function cloneDestination(config,owner,repo,ref){try{let rootPath=getCloneRuntimeRoot(config);if(!rootPath)return null;let digest=createHash("sha256").update(JSON.stringify([owner,repo,ref??null])).digest("hex"),localPath=resolvePath(rootPath,digest);return dirname(localPath)!==rootPath?null:{rootPath,localPath}}catch{return null}}function removeCloneDestination(destination){let rootPath=resolvePath(destination.rootPath),localPath=resolvePath(destination.localPath);if(dirname(localPath)!==rootPath||!/^[0-9a-f]{64}$/.test(basename(localPath)))return!1;try{return lstatSync(localPath).isSymbolicLink()?unlinkSync(localPath):rmSync(localPath,{recursive:!0,force:!0}),!0}catch(err){return!!(err&&typeof err=="object"&&"code"in err&&err.code==="ENOENT")}}var PROCESS_KILL_GRACE_MS=3e3;function terminateProcessTree(child){let pid=child.pid;if(!pid)return;if(process.platform==="win32"){execFile2("taskkill",["/pid",String(pid),"/T","/F"],{windowsHide:!0},err=>{err&&child.kill()}).unref();return}try{process.kill(-pid,"SIGTERM")}catch{child.kill()}setTimeout(()=>{try{process.kill(-pid,"SIGKILL")}catch{child.kill("SIGKILL")}},PROCESS_KILL_GRACE_MS).unref()}function execClone(args,destination,timeoutMs,signal){return new Promise(resolve=>{let{localPath}=destination,settled=!1,timeout,onAbort,finish=success=>{if(!settled){if(settled=!0,timeout&&clearTimeout(timeout),signal&&onAbort&&signal.removeEventListener("abort",onAbort),!success){removeCloneDestination(destination),resolve(null);return}resolve(localPath)}},child=spawn2(args[0],args.slice(1),{detached:process.platform!=="win32",env:{...process.env,GIT_TERMINAL_PROMPT:"0",GCM_INTERACTIVE:"Never",GH_PROMPT_DISABLED:"1"},stdio:"ignore",windowsHide:!0});child.once("error",()=>finish(!1)),child.once("close",code=>finish(code===0)),timeout=setTimeout(()=>terminateProcessTree(child),timeoutMs),timeout.unref(),signal&&(onAbort=()=>{timeout&&clearTimeout(timeout),terminateProcessTree(child)},signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}))})}async function cloneRepo(owner,repo,ref,config,destination,signal){let{localPath}=destination;if(!removeCloneDestination(destination))return null;let timeoutMs=config.cloneTimeoutSeconds*1e3;if(await checkGhAvailable()){let args2=["gh","repo","clone",`${owner}/${repo}`,localPath,"--","--depth","1","--single-branch"];return ref&&args2.push("--branch",ref),execClone(args2,destination,timeoutMs,signal)}showGhHint();let gitUrl=`https://github.com/${owner}/${repo}.git`,args=["git","clone","--depth","1","--single-branch"];return ref&&args.push("--branch",ref),args.push(gitUrl,localPath),execClone(args,destination,timeoutMs,signal)}function isBinaryFile(filePath){let ext=extname(filePath).toLowerCase();if(BINARY_EXTENSIONS.has(ext))return!0;let fd;try{fd=openSync(filePath,"r")}catch{return!1}try{let buf=Buffer.alloc(512),bytesRead=readSync(fd,buf,0,512,0);for(let i=0;i<bytesRead;i++)if(buf[i]===0)return!0}catch{return!1}finally{closeSync(fd)}return!1}function formatFileSize(bytes){return bytes<1024?`${bytes} B`:bytes<1024*1024?`${(bytes/1024).toFixed(1)} KB`:`${(bytes/(1024*1024)).toFixed(1)} MB`}function resolveWithinRepo(rootPath,relativePath){let normalizedRoot=resolvePath(rootPath),candidate=resolvePath(normalizedRoot,relativePath);if(candidate!==normalizedRoot){let rootPrefix=normalizedRoot.endsWith(pathSep)?normalizedRoot:normalizedRoot+pathSep;if(!candidate.startsWith(rootPrefix))return null}if(!existsSync3(candidate))return candidate;try{let realRoot=realpathSync(normalizedRoot),realCandidate=realpathSync(candidate);if(realCandidate===realRoot)return candidate;let realRootPrefix=realRoot.endsWith(pathSep)?realRoot:realRoot+pathSep;return realCandidate.startsWith(realRootPrefix)?candidate:null}catch{return null}}function readTextFile(path){try{return readFileSync3(path,"utf-8")}catch{return null}}function buildTree(rootPath){let entries=[];function walk(dir,relPath){if(entries.length>=MAX_TREE_ENTRIES2)return;let items;try{items=readdirSync(dir).sort()}catch{return}for(let item of items){if(entries.length>=MAX_TREE_ENTRIES2)return;if(item===".git")continue;let rel=relPath?`${relPath}/${item}`:item,safePath=resolveWithinRepo(rootPath,rel);if(!safePath){entries.push(`${rel} [outside repo skipped]`);continue}let stat;try{stat=statSync(safePath)}catch{continue}if(stat.isDirectory()){if(NOISE_DIRS.has(item)){entries.push(`${rel}/ [skipped]`);continue}entries.push(`${rel}/`),walk(safePath,rel)}else entries.push(rel)}}return walk(rootPath,""),entries.length>=MAX_TREE_ENTRIES2&&entries.push(`... (truncated at ${MAX_TREE_ENTRIES2} entries)`),entries.join(`
13
+ `)}function buildDirListing(rootPath,subPath){let targetPath=resolveWithinRepo(rootPath,subPath);if(!targetPath)return"(path escapes repository root)";let lines=[],items;try{items=readdirSync(targetPath).sort()}catch{return"(directory not readable)"}for(let item of items){if(item===".git")continue;let rel=subPath?`${subPath}/${item}`:item,safePath=resolveWithinRepo(rootPath,rel);if(!safePath){lines.push(` ${item} (outside repo)`);continue}try{let stat=statSync(safePath);stat.isDirectory()?lines.push(` ${item}/`):lines.push(` ${item} (${formatFileSize(stat.size)})`)}catch{lines.push(` ${item} (unreadable)`)}}return lines.join(`
14
+ `)}function readReadme(localPath){let candidates=["README.md","readme.md","README","README.txt","README.rst"];for(let name of candidates){let readmePath=join2(localPath,name);if(existsSync3(readmePath))try{let content=readFileSync3(readmePath,"utf-8");return content.length>8192?content.slice(0,8192)+`
15
+
16
+ [README truncated at 8K chars]`:content}catch{continue}}return null}function generateContent(localPath,info){let lines=[];if(lines.push(`Repository cloned to: ${localPath}`),lines.push(""),info.type==="root"){lines.push("## Structure"),lines.push(buildTree(localPath)),lines.push("");let readme=readReadme(localPath);return readme&&(lines.push("## README.md"),lines.push(readme),lines.push("")),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
17
+ `)}if(info.type==="tree"){let dirPath=info.path||"",fullDirPath=resolveWithinRepo(localPath,dirPath);return!fullDirPath||!existsSync3(fullDirPath)?(lines.push(`Path \`${dirPath}\` not found in clone. Showing repository root instead.`),lines.push(""),lines.push("## Structure"),lines.push(buildTree(localPath))):(lines.push(`## ${dirPath||"/"}`),lines.push(buildDirListing(localPath,dirPath))),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
18
+ `)}if(info.type==="blob"){let filePath=info.path||"",fullFilePath=resolveWithinRepo(localPath,filePath);if(!fullFilePath||!existsSync3(fullFilePath))return lines.push(`Path \`${filePath}\` not found in clone. Showing repository root instead.`),lines.push(""),lines.push("## Structure"),lines.push(buildTree(localPath)),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
19
+ `);let stat;try{stat=statSync(fullFilePath)}catch(err){let message=err instanceof Error?err.message:String(err);return lines.push(`Could not inspect \`${filePath}\`: ${message}`),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
20
+ `)}if(stat.isDirectory())return lines.push(`## ${filePath||"/"}`),lines.push(buildDirListing(localPath,filePath)),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
21
+ `);if(isBinaryFile(fullFilePath)){let ext=extname(filePath).replace(".","");return lines.push(`## ${filePath}`),lines.push(`Binary file (${ext}, ${formatFileSize(stat.size)}). Use \`read\` or \`bash\` tools at the path above to inspect.`),lines.join(`
22
+ `)}let content=readTextFile(fullFilePath);return content===null?(lines.push(`Could not read \`${filePath}\` as UTF-8 text.`),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
23
+ `)):(lines.push(`## ${filePath}`),content.length>MAX_INLINE_FILE_CHARS2?(lines.push(content.slice(0,MAX_INLINE_FILE_CHARS2)),lines.push(""),lines.push(`[File truncated at 100K chars. Full file: ${fullFilePath}]`)):lines.push(content),lines.push(""),lines.push("Use `read` and `bash` tools at the path above to explore further."),lines.join(`
24
+ `))}return lines.join(`
25
+ `)}async function awaitCachedClone(cached,url,owner,repo,info,signal){if(signal?.aborted)return null;let result=await cached.clonePromise;if(signal?.aborted)return null;if(result){let content=generateContent(result,info),title=info.path?`${owner}/${repo} - ${info.path}`:`${owner}/${repo}`;return{url,title,content,error:null}}return fetchViaApi(url,owner,repo,info)}async function extractGitHub(url,signal,forceClone){let info=parseGitHubUrl(url);if(!info||signal?.aborted)return null;let config=loadGitHubConfig();if(!config.enabled)return null;let{owner,repo}=info,key=cacheKey(owner,repo,info.ref),cached=cloneCache.get(key);if(cached)return awaitCachedClone(cached,url,owner,repo,info,signal);if(info.refIsFullSha)return signal?.aborted?null:fetchViaApi(url,owner,repo,info,"Note: Commit SHA URLs use the GitHub API instead of cloning.");let activityId=activityMonitor.logStart({type:"fetch",url:`github.com/${owner}/${repo}`});if(!forceClone){let sizeKB=await checkRepoSize(owner,repo);if(signal?.aborted)return activityMonitor.logComplete(activityId,0),null;if(sizeKB!==null){let sizeMB=sizeKB/1024;if(sizeMB>config.maxRepoSizeMB){if(signal?.aborted)return activityMonitor.logComplete(activityId,0),null;let sizeNote=`Note: Repository is ${Math.round(sizeMB)}MB (threshold: ${config.maxRepoSizeMB}MB). Showing API-fetched content instead of full clone. Ask the user if they'd like to clone the full repo -- if yes, call fetch_content again with the same URL and add forceClone: true to the params.`,apiView=await fetchViaApi(url,owner,repo,info,sizeNote);return apiView?(activityMonitor.logComplete(activityId,200),apiView):(activityMonitor.logError(activityId,"api fallback unavailable for oversized repository"),null)}}}if(signal?.aborted)return activityMonitor.logComplete(activityId,0),null;let cachedAfterSizeCheck=cloneCache.get(key);if(cachedAfterSizeCheck){let cachedResult=await awaitCachedClone(cachedAfterSizeCheck,url,owner,repo,info,signal);return signal?.aborted?activityMonitor.logComplete(activityId,0):cachedResult?activityMonitor.logComplete(activityId,200):activityMonitor.logError(activityId,"clone failed"),cachedResult}let destination=cloneDestination(config,owner,repo,info.ref);if(!destination){let apiFallback=await fetchViaApi(url,owner,repo,info);return apiFallback?activityMonitor.logComplete(activityId,200):activityMonitor.logError(activityId,"invalid clone destination"),apiFallback}let clonePromise=cloneRepo(owner,repo,info.ref,config,destination,signal);cloneCache.set(key,{destination,clonePromise});let result=await clonePromise;if(signal?.aborted)return result||cloneCache.delete(key),activityMonitor.logComplete(activityId,0),null;if(!result){if(cloneCache.delete(key),signal?.aborted)return activityMonitor.logComplete(activityId,0),null;let apiFallback=await fetchViaApi(url,owner,repo,info);return apiFallback?(activityMonitor.logComplete(activityId,200),apiFallback):(activityMonitor.logError(activityId,"clone and API fallback failed"),null)}activityMonitor.logComplete(activityId,200);let content=generateContent(result,info),title=info.path?`${owner}/${repo} - ${info.path}`:`${owner}/${repo}`;return{url,title,content,error:null}}function clearCloneCache(){for(let entry of cloneCache.values())removeCloneDestination(entry.destination);cloneCache.clear(),cloneRuntime&&removeCloneRuntime(cloneRuntime.parentPath,cloneRuntime.rootPath),cloneRuntime=null,cachedConfig=null}import{exec}from"node:child_process";import{promisify}from"node:util";var execAsync=promisify(exec),COMMAND_TIMEOUT_MS=5e3,MAX_CREDENTIAL_BYTES=16384,ENV_SOURCE=/^\$(?:([A-Za-z_][A-Za-z0-9_]*)|\{([A-Za-z_][A-Za-z0-9_]*)\})$/,OP_SESSION_NAME=/^OP_SESSION_[A-Za-z0-9_]+$/,COMMAND_ENVIRONMENT_NAMES=["HOME","USER","LOGNAME","OP_SERVICE_ACCOUNT_TOKEN","PATH","LANG","LC_ALL","LC_CTYPE","TERM","TMPDIR","XDG_CONFIG_HOME","XDG_RUNTIME_DIR","DBUS_SESSION_BUS_ADDRESS","SSH_AUTH_SOCK","WSL_DISTRO_NAME","WSL_INTEROP"],CredentialResolutionError=class extends Error{constructor(provider,category){let suffix=category==="command-aborted"?"aborted":category==="oauth-credential-rejected"?"OAuth token exchange rejected the credentials":category;super(`${provider} credential resolution failed: ${suffix}`),this.name="CredentialResolutionError",this.provider=provider,this.category=category}};function redactCredential(text,credential){return credential?text.split(credential).join("[redacted]"):text}function normalize(value){if(typeof value!="string")return null;let normalized=value.trim();return normalized.length>0?normalized:null}function commandEnvironment(source){let environment={};for(let name of COMMAND_ENVIRONMENT_NAMES){let value=source[name];value!==void 0&&(environment[name]=value)}for(let[name,value]of Object.entries(source))value!==void 0&&OP_SESSION_NAME.test(name)&&(environment[name]=value);return environment}function configuredSource(options){return normalize(options.configuredValue)}function explicitEnvironmentName(source){let match=source.match(ENV_SOURCE);return match?match[1]??match[2]:null}function escapedSource(source){return source.startsWith("$$")||source.startsWith("$!")?source.slice(1):null}function isMalformedExplicitSource(source){return source.startsWith("$")&&escapedSource(source)===null&&explicitEnvironmentName(source)===null}async function defaultRunCommand(command,options){return{stdout:(await execAsync(command,{encoding:"utf8",env:options.environment,maxBuffer:options.maxOutputBytes+1,signal:options.signal,timeout:options.timeoutMs,windowsHide:!0})).stdout}}function commandFailureCategory(error,signal){if(signal?.aborted)return"command-aborted";if(error&&typeof error=="object"){let code=error.code;if(code==="ERR_CHILD_PROCESS_STDIO_MAXBUFFER")return"command-output-too-large";if(error.killed||code==="ETIMEDOUT")return"command-timeout"}return"command-failed"}function hasCredentialSource(options){let source=configuredSource(options);return source?.startsWith("!")||source?.startsWith("$")?!0:normalize(options.environmentValue)!==null||source!==null}async function resolveCredential(options){let source=configuredSource(options),escaped=source?escapedSource(source):null;if(escaped!==null)return escaped;if(source?.startsWith("!")){let command=source.slice(1).trim();if(!command)throw new CredentialResolutionError(options.provider,"invalid-source");let result;try{result=await(options.runCommand??defaultRunCommand)(command,{signal:options.signal,timeoutMs:COMMAND_TIMEOUT_MS,maxOutputBytes:MAX_CREDENTIAL_BYTES,environment:commandEnvironment(options.environment??process.env)})}catch(error){throw new CredentialResolutionError(options.provider,commandFailureCategory(error,options.signal))}let stdout=Buffer.isBuffer(result.stdout)?result.stdout.toString("utf8"):result.stdout;if(Buffer.byteLength(stdout,"utf8")>MAX_CREDENTIAL_BYTES)throw new CredentialResolutionError(options.provider,"command-output-too-large");let value=stdout.trim();if(!value)throw new CredentialResolutionError(options.provider,"command-empty");if(/[\0-\x1f\x7f]/.test(value))throw new CredentialResolutionError(options.provider,"command-invalid-output");return value}if(source&&isMalformedExplicitSource(source))throw new CredentialResolutionError(options.provider,"invalid-source");if(source?.startsWith("$")){let name=explicitEnvironmentName(source);if(!name)throw new CredentialResolutionError(options.provider,"invalid-source");let value=normalize((options.environment??process.env)[name]);if(!value)throw new CredentialResolutionError(options.provider,"environment-empty");return value}return normalize(options.environmentValue)??source}import{execFile as execFile3}from"node:child_process";import{pbkdf2Sync,createDecipheriv}from"node:crypto";import{copyFileSync,existsSync as existsSync5,mkdtempSync as mkdtempSync2,readdirSync as readdirSync2,readFileSync as readFileSync5,realpathSync as realpathSync2,rmSync as rmSync2}from"node:fs";import{tmpdir as tmpdir2,homedir}from"node:os";import{isAbsolute,join as join3,sep}from"node:path";import{existsSync as existsSync4,readFileSync as readFileSync4}from"node:fs";var CONFIG_PATH2=getWebSearchConfigPath(),BROWSER_COOKIE_PRESETS=["helium","chrome","brave","arc","chromium","edge"],cachedConfig2=null;function normalizeChromeProfile(value){if(typeof value!="string")return;let normalized=value.trim();return normalized.length>0?normalized:void 0}function parseBrowserCookies(value){if(value===void 0)return;if(!value||typeof value!="object"||Array.isArray(value))throw new Error(`browserCookies in ${CONFIG_PATH2} must be an object`);let raw=value;if("profilePath"in raw)throw new Error(`browserCookies.profilePath is not supported; use a browser preset and profile directory name in ${CONFIG_PATH2}`);let browser;if(raw.browser!==void 0){if(typeof raw.browser!="string")throw new Error(`browserCookies.browser in ${CONFIG_PATH2} must be a supported browser name`);let normalized=raw.browser.trim().toLowerCase(),preset=BROWSER_COOKIE_PRESETS.find(candidate=>candidate===normalized);if(!preset)throw new Error(`Unsupported browserCookies.browser ${JSON.stringify(raw.browser)} in ${CONFIG_PATH2}`);browser=preset}if(raw.profile!==void 0&&typeof raw.profile!="string")throw new Error(`browserCookies.profile in ${CONFIG_PATH2} must be a profile directory name`);let profile=normalizeChromeProfile(raw.profile);if(profile&&(profile==="."||profile===".."||profile.includes("/")||profile.includes("\\")))throw new Error(`browserCookies.profile in ${CONFIG_PATH2} must be a profile directory name, not a path`);return{...browser?{browser}:{},...profile?{profile}:{}}}function loadConfig(){if(cachedConfig2)return cachedConfig2;if(!existsSync4(CONFIG_PATH2))return cachedConfig2={},cachedConfig2;let rawText=readFileSync4(CONFIG_PATH2,"utf-8"),raw;try{raw=JSON.parse(rawText)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH2}: ${message}`)}if(raw.chromeProfile!==void 0)throw new Error(`chromeProfile in ${CONFIG_PATH2} is no longer supported; use browserCookies.profile`);return cachedConfig2={browserCookies:parseBrowserCookies(raw.browserCookies),allowBrowserCookies:raw.allowBrowserCookies===!0},cachedConfig2}function getBrowserCookieSelectionFromConfig(){return{...loadConfig().browserCookies}}function isBrowserCookieAccessAllowed(){if(process.env.PI_ALLOW_BROWSER_COOKIES==="1"||process.env.FEYNMAN_ALLOW_BROWSER_COOKIES==="1")return!0;if(!existsSync4(CONFIG_PATH2))return!1;let rawText=readFileSync4(CONFIG_PATH2,"utf-8"),raw;try{raw=JSON.parse(rawText)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH2}: ${message}`)}return raw.allowBrowserCookies===!0}var GOOGLE_ORIGINS=["https://gemini.google.com","https://accounts.google.com","https://www.google.com"],ALL_COOKIE_NAMES=new Set(["__Secure-1PSID","__Secure-1PSIDTS","__Secure-1PSIDCC","__Secure-1PAPISID","NID","AEC","SOCS","__Secure-BUCKET","__Secure-ENID","SID","HSID","SSID","APISID","SAPISID","__Secure-3PSID","__Secure-3PSIDTS","__Secure-3PAPISID","SIDCC"]),MACOS_BROWSER_CONFIGS=[{id:"helium",name:"Helium",baseDir:"Library/Application Support/net.imput.helium",keychainService:"Helium Storage Key",keychainAccount:"Helium"},{id:"chrome",name:"Chrome",baseDir:"Library/Application Support/Google/Chrome",keychainService:"Chrome Safe Storage",keychainAccount:"Chrome"},{id:"brave",name:"Brave",baseDir:"Library/Application Support/BraveSoftware/Brave-Browser",keychainService:"Brave Safe Storage",keychainAccount:"Brave"},{id:"arc",name:"Arc",baseDir:"Library/Application Support/Arc/User Data",keychainService:"Arc Safe Storage",keychainAccount:"Arc"}],LINUX_BROWSER_CONFIGS=[{id:"chromium",name:"Chromium",baseDir:".config/chromium",secretToolApp:"chromium"},{id:"chrome",name:"Chrome",baseDir:".config/google-chrome",secretToolApp:"chrome"}],WINDOWS_BROWSER_CONFIGS=[{id:"chrome",name:"Chrome",baseDir:"Google/Chrome/User Data",usesLocalAppData:!0},{id:"edge",name:"Edge",baseDir:"Microsoft/Edge/User Data",usesLocalAppData:!0}],browserPasswordCache=new Map,lastCookieDiagnostic=null,lastCookieDiagnosticDetails=null,sqliteModule=null,sqliteImportAttempted=!1;function getLastGoogleCookieDiagnostic(){return lastCookieDiagnostic}function getLastBrowserCookieDiagnostic(){return lastCookieDiagnostic}function getLastGoogleCookieDiagnosticDetails(){return lastCookieDiagnosticDetails}async function getGoogleCookies(options){return getBrowserCookiesForHosts({hosts:GOOGLE_ORIGINS.map(origin=>new URL(origin).hostname),browser:options?.browser,profile:options?.profile,requiredCookies:options?.requiredCookies,cookieNames:ALL_COOKIE_NAMES,requiredLabel:"Gemini"})}async function getBrowserCookiesForHosts(options){if(lastCookieDiagnostic=null,lastCookieDiagnosticDetails=null,!isBrowserCookieAccessAllowed())return setCookieDiagnostic("Browser cookie access is disabled; enable allowBrowserCookies to use browser cookies."),null;let currentPlatform=process.platform,platformConfigs=currentPlatform==="darwin"?MACOS_BROWSER_CONFIGS:currentPlatform==="linux"?LINUX_BROWSER_CONFIGS:currentPlatform==="win32"?WINDOWS_BROWSER_CONFIGS:[],configs=options.browser?platformConfigs.filter(config=>config.id===options.browser):platformConfigs;if(options.browser&&configs.length===0)return setCookieDiagnostic(`Browser preset '${options.browser}' is not supported on this platform.`),null;if(configs.length===0)return setCookieDiagnostic("Chromium cookie extraction is unsupported on this platform."),null;let warningSet=new Set,rawProfile=typeof options.profile=="string"?options.profile.trim():"",requestedProfile=normalizeProfileName(options.profile);if(rawProfile&&!requestedProfile)return setCookieDiagnostic("Configured Chromium profile must be a profile directory name, not a path."),null;let requiredCookies=normalizeCookieNames(options.requiredCookies),cookieNames=normalizeCookieNames(options.cookieNames?[...options.cookieNames]:void 0),hosts=normalizeHosts(options.hosts);if(hosts.length===0)return setCookieDiagnostic("No valid cookie hosts were requested."),null;let attempts=[],home=currentPlatform==="win32"?process.env.USERPROFILE||homedir():homedir(),sawCookieDatabase=!1,sawRequiredCookies=!1,sawAnyHostCookie=!1,sawBackendFailure,sawUnsafeProfilePath=!1,sawWindowsAppBoundCookie=!1,sawDecryptionFailure=!1;for(let config of configs){let profiles=requestedProfile?[requestedProfile]:listBrowserProfiles(home,config);for(let profile of profiles){let profilePath=resolveProfilePath(home,config,profile);if(profilePath==="outside-root"){sawUnsafeProfilePath=!0,recordCookieAttempt(attempts,config,profile,"unsafe-profile");continue}if(!profilePath){recordCookieAttempt(attempts,config,profile,"missing-database");continue}let cookiesPath=cookieDatabasePath(profilePath,config);if(!cookiesPath){recordCookieAttempt(attempts,config,profile,"missing-database");continue}sawCookieDatabase=!0;let tempDir=mkdtempSync2(join3(tmpdir2(),"pi-chrome-cookies-"));try{let tempDb=join3(tempDir,"Cookies");if(copyFileSync(cookiesPath,tempDb),copySidecar(cookiesPath,tempDb,"-wal"),copySidecar(cookiesPath,tempDb,"-shm"),requiredCookies?.length){let preflight=await hasCookieNames(tempDb,hosts,requiredCookies);if(preflight.failure){sawBackendFailure=preflight.failure,recordCookieAttempt(attempts,config,profile,preflight.failure==="unavailable"?"sqlite-unavailable":"sqlite-query-failed");continue}if(!preflight.present){recordCookieAttempt(attempts,config,profile,"missing-required-cookies");continue}sawRequiredCookies=!0}let key=currentPlatform==="win32"?await readWindowsEncryptionKey(config,home):await readBrowserPassword(config,currentPlatform).then(password=>password?pbkdf2Sync(password,"saltysalt",currentPlatform==="darwin"?1003:1,16,"sha1"):null);if(!key){warningSet.add(currentPlatform==="win32"?`Could not read ${config.name} Windows cookie encryption key`:`Could not read ${config.name} cookie encryption password`),recordCookieAttempt(attempts,config,profile,"password-read-failed");continue}let metaVersion=await readMetaVersion(tempDb);if(metaVersion.failure&&(sawBackendFailure=metaVersion.failure,recordCookieAttempt(attempts,config,profile,metaVersion.failure==="unavailable"?"sqlite-unavailable":"sqlite-query-failed")),metaVersion.value===null)continue;let rowsResult=await queryCookieRows(tempDb,hosts,cookieNames??null,!!options.requestUrl);if(rowsResult.status==="failure"){sawBackendFailure=rowsResult.failure,recordCookieAttempt(attempts,config,profile,rowsResult.failure==="unavailable"?"sqlite-unavailable":"sqlite-query-failed");continue}let entries=[],cookies={},requiredDecryptFailures=new Set;for(let row of rowsResult.rows){let name=typeof row.name=="string"?row.name:"";if(!name)continue;let value=typeof row.value=="string"&&row.value.length>0?row.value:null;if(!value&&typeof row.encrypted_value_hex=="string"&&/^[0-9a-f]*$/i.test(row.encrypted_value_hex)){let encrypted=Buffer.from(row.encrypted_value_hex,"hex");currentPlatform==="win32"&&encrypted.subarray(0,3).toString("utf8")==="v20"&&(sawWindowsAppBoundCookie=!0),value=currentPlatform==="win32"?decryptWindowsCookieValue(encrypted,key,metaVersion.value>=24):decryptCookieValue(encrypted,key,metaVersion.value>=24),!value&&requiredCookies?.includes(name)&&requiredDecryptFailures.add(name)}if(!value)continue;let path=typeof row.path=="string"&&row.path.startsWith("/")?row.path:"/";options.requestUrl&&!pathMatches(options.requestUrl.pathname||"/",path)||(entries.push({name,value,path}),cookies[name]||(cookies[name]=value))}if(entries.length>0&&(sawAnyHostCookie=!0),requiredCookies?.length&&!requiredCookies.every(name=>!!cookies[name])){requiredCookies.some(name=>!cookies[name]&&requiredDecryptFailures.has(name))?(sawDecryptionFailure=!0,recordCookieAttempt(attempts,config,profile,"decryption-failed")):recordCookieAttempt(attempts,config,profile,"missing-required-cookies");continue}if(entries.length===0){recordCookieAttempt(attempts,config,profile,requiredDecryptFailures.size>0?"decryption-failed":"no-host-cookies"),requiredDecryptFailures.size>0&&(sawDecryptionFailure=!0);continue}return{cookies,warnings:[...warningSet],...options.requestUrl?{cookieHeader:buildCookieHeader(entries)}:{}}}finally{rmSync2(tempDir,{recursive:!0,force:!0})}}}return sawBackendFailure==="unavailable"?setCookieDiagnostic("SQLite backend unavailable: install sqlite3 or use a runtime with SQLite support.",attempts):sawBackendFailure==="query"?setCookieDiagnostic("SQLite query failed while reading the copied Chromium cookie database.",attempts):sawUnsafeProfilePath?setCookieDiagnostic("Configured Chromium profile must resolve inside the browser profile root.",attempts):sawCookieDatabase?requiredCookies?.length&&!sawRequiredCookies?setCookieDiagnostic(`No detected Chromium profile contains the required ${options.requiredLabel??"browser"} cookies.`,attempts):sawWindowsAppBoundCookie?setCookieDiagnostic("Windows Chromium v20 app-bound cookies are not supported.",attempts):warningSet.size>0?setCookieDiagnostic([...warningSet][0],attempts):setCookieDiagnostic(sawDecryptionFailure?`Required ${options.requiredLabel??"browser"} cookies could not be decrypted.`:sawAnyHostCookie?"Required Gemini cookies were not available or could not be decrypted.":options.requestUrl?"No detected Chromium profile contains cookies for the requested URL.":"No detected Chromium profile contains cookies for the requested host.",attempts):setCookieDiagnostic(requestedProfile?`Chromium profile '${requestedProfile}' does not contain a cookie database.`:"No detected Chromium profile contains a cookie database.",attempts),null}function setCookieDiagnostic(message,attempts=[]){lastCookieDiagnostic=message,lastCookieDiagnosticDetails={message,attempts}}function recordCookieAttempt(attempts,config,profile,status){attempts.push({browser:config.name,profile,status})}function normalizeProfileName(value){if(typeof value!="string")return;let normalized=value.trim();if(normalized&&!(isAbsolute(normalized)||normalized==="."||normalized===".."||normalized.includes("/")||normalized.includes("\\")))return normalized}function resolveProfilePath(home,config,profile){let basePath=browserBasePath(home,config),profilePath=join3(basePath,profile);if(!cookieDatabasePath(profilePath,config))return null;try{let baseRealPath=realpathSync2(basePath),profileRealPath=realpathSync2(profilePath);return profileRealPath!==baseRealPath&&!profileRealPath.startsWith(`${baseRealPath}${sep}`)?"outside-root":profileRealPath}catch{return null}}function cookieDatabasePath(profilePath,config){let networkCookies=join3(profilePath,"Network","Cookies");if(config.usesLocalAppData&&existsSync5(networkCookies))return networkCookies;let legacyCookies=join3(profilePath,"Cookies");return existsSync5(legacyCookies)?legacyCookies:null}function browserBasePath(home,config){return config.usesLocalAppData?join3(process.env.LOCALAPPDATA||join3(home,"AppData","Local"),config.baseDir):join3(home,config.baseDir)}function normalizeCookieNames(names){if(!names?.length)return;let normalized=names.filter(name=>typeof name=="string").map(name=>name.trim()).filter(Boolean);return normalized.length>0?[...new Set(normalized)]:void 0}function normalizeHosts(hosts){return[...new Set(hosts.map(host=>host.trim().toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"")).filter(Boolean))]}function listBrowserProfiles(home,config){let basePath=browserBasePath(home,config);if(!existsSync5(basePath))return["Default"];let profiles=new Set;try{for(let entry of readdirSync2(basePath,{withFileTypes:!0}))entry.isDirectory()&&cookieDatabasePath(join3(basePath,entry.name),config)&&profiles.add(entry.name)}catch{}return profiles.size===0?["Default"]:[...profiles].sort(compareProfileNames)}function compareProfileNames(a,b){let key=name=>{if(name==="Default")return[0,0];let profile=/^Profile\s+(\d+)$/i.exec(name);if(profile)return[1,Number(profile[1])];let person=/^Person\s+(\d+)$/i.exec(name);return person?[2,Number(person[1])]:[3,Number.MAX_SAFE_INTEGER]},[ap,ai]=key(a),[bp,bi]=key(b);return ap-bp||ai-bi||a.localeCompare(b,void 0,{sensitivity:"base",numeric:!0})}function decryptCookieValue(encrypted,key,stripHash){let buf=Buffer.from(encrypted);if(buf.length<3||!/^v\d\d$/.test(buf.subarray(0,3).toString("utf8")))return null;let ciphertext=buf.subarray(3);if(!ciphertext.length)return"";try{let decipher=createDecipheriv("aes-128-cbc",key,Buffer.alloc(16,32));decipher.setAutoPadding(!1);let unpadded=removePkcs7Padding(Buffer.concat([decipher.update(ciphertext),decipher.final()])),bytes=stripHash&&unpadded.length>=32?unpadded.subarray(32):unpadded,decoded=new TextDecoder("utf-8",{fatal:!0}).decode(bytes),i=0;for(;i<decoded.length&&decoded.charCodeAt(i)<32;)i++;return decoded.slice(i)}catch{return null}}function decryptWindowsCookieValue(encrypted,key,stripHash){let buf=Buffer.from(encrypted);if(buf.subarray(0,3).toString("utf8")!=="v10"||buf.length<31)return null;try{let nonce=buf.subarray(3,15),ciphertext=buf.subarray(15,-16),decipher=createDecipheriv("aes-256-gcm",key,nonce);decipher.setAuthTag(buf.subarray(-16));let plaintext=Buffer.concat([decipher.update(ciphertext),decipher.final()]);return new TextDecoder("utf-8",{fatal:!0}).decode(stripHash&&plaintext.length>=32?plaintext.subarray(32):plaintext)}catch{return null}}function removePkcs7Padding(buf){if(!buf.length)return buf;let padding=buf[buf.length-1];return!padding||padding>16?buf:buf.subarray(0,buf.length-padding)}function readBrowserPassword(config,currentPlatform){let cacheKey2=`${currentPlatform}:${config.name}`,cached=browserPasswordCache.get(cacheKey2);if(cached)return cached;let passwordPromise=(currentPlatform==="darwin"?config.keychainAccount&&config.keychainService?readKeychainPassword(config.keychainAccount,config.keychainService).then(password=>({password,cacheable:!!password})):Promise.resolve({password:null,cacheable:!1}):currentPlatform==="linux"?readLinuxPassword(config.secretToolApp):Promise.resolve({password:null,cacheable:!1})).then(({password,cacheable})=>(cacheable||browserPasswordCache.delete(cacheKey2),password),error=>{throw browserPasswordCache.delete(cacheKey2),error});return browserPasswordCache.set(cacheKey2,passwordPromise),passwordPromise}async function readWindowsEncryptionKey(config,home){try{let encodedKey=JSON.parse(readFileSync5(join3(browserBasePath(home,config),"Local State"),"utf8")).os_crypt?.encrypted_key;if(typeof encodedKey!="string")return null;let protectedKey=Buffer.from(encodedKey,"base64");if(protectedKey.subarray(0,5).toString("utf8")!=="DPAPI")return null;let decrypted=await unprotectWindowsData(protectedKey.subarray(5));return decrypted?.length===32?decrypted:null}catch{return null}}function unprotectWindowsData(protectedData){return new Promise(resolve=>{let encoded=Buffer.from("Add-Type -AssemblyName System.Security;$data=[Convert]::FromBase64String($env:PIWA_PROTECTED);$clear=[System.Security.Cryptography.ProtectedData]::Unprotect($data,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Write([Convert]::ToBase64String($clear))","utf16le").toString("base64");execFile3("powershell.exe",["-NoProfile","-NonInteractive","-EncodedCommand",encoded],{timeout:5e3,maxBuffer:1024*1024,env:{...process.env,PIWA_PROTECTED:protectedData.toString("base64")}},(err,stdout)=>{if(err){resolve(null);return}try{resolve(Buffer.from(stdout.trim(),"base64"))}catch{resolve(null)}})})}function readKeychainPassword(account,service){return new Promise(resolve=>{execFile3("security",["find-generic-password","-w","-a",account,"-s",service],{timeout:5e3},(err,stdout)=>{if(err){resolve(null);return}resolve(stdout.trim()||null)})})}function readLinuxPassword(secretToolApp){return secretToolApp?new Promise(resolve=>{execFile3("secret-tool",["lookup","application",secretToolApp],{timeout:5e3},(err,stdout)=>{if(err){resolve({password:"peanuts",cacheable:!1});return}let password=stdout.trim();resolve(password?{password,cacheable:!0}:{password:"peanuts",cacheable:!1})})}):Promise.resolve({password:"peanuts",cacheable:!0})}async function importSqlite(){if(process.env.PI_WEB_ACCESS_DISABLE_NODE_SQLITE==="1")return null;if(sqliteImportAttempted)return sqliteModule;sqliteImportAttempted=!0;let orig=process.emitWarning.bind(process);process.emitWarning=((warning,...args)=>{if(!(typeof warning=="string"?warning:warning?.message??"").includes("SQLite is an experimental feature"))return orig(warning,...args)});try{sqliteModule=await import("node:sqlite")}catch{sqliteModule=null}finally{process.emitWarning=orig}return sqliteModule}async function runSqliteQuery(dbPath,sql){let sqlite=await importSqlite(),queryFailed=!1;if(sqlite)try{let db=new sqlite.DatabaseSync(dbPath,{readOnly:!0});try{return{status:"success",rows:db.prepare(sql).all()}}finally{db.close()}}catch{queryFailed=!0}let cli=await runSqliteCli(dbPath,sql);if(cli.status==="success")return cli;cli.failure==="query"&&(queryFailed=!0);let python=await runPythonSqlite(dbPath,sql);return python.status==="success"?python:(python.failure==="query"&&(queryFailed=!0),{status:"failure",failure:queryFailed?"query":"unavailable"})}function runSqliteCli(dbPath,sql){return new Promise(resolve=>{execFile3("sqlite3",["-readonly","-json",dbPath,sql],{timeout:5e3,maxBuffer:1024*1024},(err,stdout)=>{if(err){resolve({status:"failure",failure:err.code==="ENOENT"?"unavailable":"query"});return}try{let parsed=JSON.parse(stdout||"[]");resolve(Array.isArray(parsed)?{status:"success",rows:parsed}:{status:"failure",failure:"query"})}catch{resolve({status:"failure",failure:"query"})}})})}function runPythonSqlite(dbPath,sql){let script=`import json,sqlite3,sys
26
+ try:
27
+ c=sqlite3.connect('file:'+sys.argv[1]+'?mode=ro',uri=True)
28
+ c.row_factory=sqlite3.Row
29
+ print(json.dumps([dict(r) for r in c.execute(sys.argv[2]).fetchall()]))
30
+ except Exception:
31
+ sys.exit(1)`;return new Promise(resolve=>{execFile3("python3",["-c",script,dbPath,sql],{timeout:5e3,maxBuffer:1024*1024},(err,stdout)=>{if(err){resolve({status:"failure",failure:err.code==="ENOENT"?"unavailable":"query"});return}try{let parsed=JSON.parse(stdout||"[]");resolve(Array.isArray(parsed)?{status:"success",rows:parsed}:{status:"failure",failure:"query"})}catch{resolve({status:"failure",failure:"query"})}})})}async function readMetaVersion(dbPath){let result=await runSqliteQuery(dbPath,"SELECT value FROM meta WHERE key = 'version'");if(result.status==="failure")return result.failure==="unavailable"?{value:null,failure:result.failure}:{value:0};let value=result.rows[0]?.value;return typeof value=="number"?{value:Math.floor(value)}:typeof value=="string"?{value:parseInt(value,10)||0}:{value:0}}async function hasCookieNames(dbPath,hosts,names){let result=await runSqliteQuery(dbPath,`SELECT DISTINCT name FROM cookies WHERE ${buildCookieWhere(hosts,names)}`);if(result.status==="failure")return{present:!1,failure:result.failure};let present=new Set(result.rows.map(row=>typeof row.name=="string"?row.name:""));return{present:names.every(name=>present.has(name))}}async function queryCookieRows(dbPath,hosts,names,filterExpired){let columns=await readCookieColumns(dbPath);if(columns.status==="failure")return columns;let pathExpr=columns.columns.has("path")?"path":"'/' AS path",expiresExpr=columns.columns.has("expires_utc")?chromeExpiryMillisExpr():"0",expiryFilter=filterExpired&&columns.columns.has("expires_utc")?` AND (${expiresExpr} = 0 OR ${expiresExpr} > ${chromeExpiryNowMillis()})`:"",partitionFilter=filterExpired?unpartitionedCookieFilter(columns.columns):"";return runSqliteQuery(dbPath,`SELECT name, value, host_key, ${pathExpr}, ${expiresExpr} AS expires_utc, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts,names??void 0)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, ${expiresExpr} ASC`)}async function readCookieColumns(dbPath){let result=await runSqliteQuery(dbPath,"PRAGMA table_info(cookies)");return result.status==="failure"?result:{status:"success",columns:new Set(result.rows.map(row=>typeof row.name=="string"?row.name:""))}}function chromeExpiryMillisExpr(){return"CASE WHEN expires_utc = 0 THEN 0 ELSE CAST(expires_utc / 1000 AS INTEGER) + CASE WHEN expires_utc % 1000 = 0 THEN 0 ELSE 1 END END"}function chromeExpiryNowMillis(){return Date.now()+116444736e5}function unpartitionedCookieFilter(columns){let clauses=[];return columns.has("top_frame_site_key")&&clauses.push("(top_frame_site_key IS NULL OR top_frame_site_key = '')"),columns.has("partition_key")&&clauses.push("(partition_key IS NULL OR partition_key = '')"),columns.has("is_partitioned")&&clauses.push("(is_partitioned IS NULL OR is_partitioned = 0)"),clauses.length>0?` AND ${clauses.join(" AND ")}`:""}function buildCookieHeader(entries){return entries.sort((a,b)=>b.path.length-a.path.length).map(({name,value})=>`${name}=${value}`).join("; ")}function pathMatches(requestPath,cookiePath){return requestPath===cookiePath?!0:requestPath.startsWith(cookiePath)?cookiePath.endsWith("/")?!0:requestPath[cookiePath.length]==="/":!1}function buildCookieWhere(hosts,cookieNames){let hostClauses=[];for(let host of hosts){let escapedHost=escapeSqlString(host);hostClauses.push(`host_key = '${escapedHost}'`);for(let candidate of domainCookieHosts(host))hostClauses.push(`host_key = '.${escapeSqlString(candidate)}'`)}let where=`(${[...new Set(hostClauses)].join(" OR ")})`,names=cookieNames?[...cookieNames].filter(Boolean):[];return names.length&&(where+=` AND name IN (${names.map(name=>`'${escapeSqlString(name)}'`).join(", ")})`),where}function escapeSqlString(value){return value.replaceAll("'","''")}function domainCookieHosts(host){let parts=host.split(".").filter(Boolean);if(parts.length<=1)return[];let candidates=new Set;for(let i=0;i<=parts.length-2;i++)candidates.add(parts.slice(i).join("."));return[...candidates]}function copySidecar(srcDb,targetDb,suffix){let sidecar=`${srcDb}${suffix}`;if(existsSync5(sidecar))try{copyFileSync(sidecar,`${targetDb}${suffix}`)}catch{}}import{existsSync as existsSync6,readFileSync as readFileSync6}from"node:fs";var PARALLEL_SEARCH_URL="https://api.parallel.ai/v1/search",PARALLEL_EXTRACT_URL="https://api.parallel.ai/v1/extract",CONFIG_PATH3=getWebSearchConfigPath(),MIN_PARALLEL_API_KEY_LENGTH=8,MIN_USEFUL_CONTENT=500,SEARCH_TIMEOUT_MS=6e4,PLACEHOLDER_API_KEY_DENYLIST=new Set(["replace_with_your_parallel_api_key","parallel_api_key","your-key","your-key-here","your-api-key-here","dummy","placeholder","changeme","insert-your-key","insert-your-key-here","api-key","xxx"]),cachedConfig3=null;function loadConfig2(){if(cachedConfig3)return cachedConfig3;if(!existsSync6(CONFIG_PATH3))return cachedConfig3={},cachedConfig3;let raw=readFileSync6(CONFIG_PATH3,"utf-8");try{return cachedConfig3=JSON.parse(raw),cachedConfig3}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH3}: ${message}`)}}function normalizeApiKey(value){if(typeof value!="string")return null;let normalized=value.trim();return normalized.length>0?normalized:null}function isPlaceholderApiKey(key){let normalized=key.trim();return normalized.length<MIN_PARALLEL_API_KEY_LENGTH||PLACEHOLDER_API_KEY_DENYLIST.has(normalized.toLowerCase())}async function resolveParallelApiKey(signal){let configKey=normalizeApiKey(loadConfig2().parallelApiKey);if(configKey?.startsWith("$")||configKey?.startsWith("!")){let resolved=await resolveCredential({provider:"Parallel",configuredValue:configKey,environmentValue:process.env.PARALLEL_API_KEY,signal});return resolved&&!isPlaceholderApiKey(resolved)?resolved:null}let envKey=normalizeApiKey(process.env.PARALLEL_API_KEY);return envKey&&!isPlaceholderApiKey(envKey)?envKey:configKey&&!isPlaceholderApiKey(configKey)?configKey:null}function hasConfiguredApiKey(){let configKey=normalizeApiKey(loadConfig2().parallelApiKey);if(configKey?.startsWith("$")||configKey?.startsWith("!"))return hasCredentialSource({provider:"Parallel",configuredValue:configKey,environmentValue:process.env.PARALLEL_API_KEY});let envKey=normalizeApiKey(process.env.PARALLEL_API_KEY);return envKey!==null&&!isPlaceholderApiKey(envKey)||configKey!==null&&!isPlaceholderApiKey(configKey)}async function getApiKey(signal){let key=await resolveParallelApiKey(signal);if(!key)throw new Error(`Parallel API key not found. Either:
32
+ 1. Create ${CONFIG_PATH3} with { "parallelApiKey": "your-key" }
33
+ 2. Set PARALLEL_API_KEY environment variable
34
+ Get a key at https://platform.parallel.ai`);return key}function hasParallelApiKey(){return hasConfiguredApiKey()}function isParallelAvailable(){return hasParallelApiKey()}function requestSignal(signal){let timeout=AbortSignal.timeout(SEARCH_TIMEOUT_MS);return signal?AbortSignal.any([signal,timeout]):timeout}function errorMessage(err){return err instanceof Error?err.message:String(err)}function activityContext(url,body){if(typeof body.objective=="string"&&body.objective.trim().length>0)return{type:"api",query:body.objective};let searchQueries=body.search_queries;if(Array.isArray(searchQueries)&&typeof searchQueries[0]=="string")return{type:"api",query:searchQueries[0]};let urls=body.urls;return Array.isArray(urls)&&typeof urls[0]=="string"?{type:"fetch",url:urls[0]}:url.includes("/search")?{type:"api",query:"Parallel search"}:{type:"fetch",url}}function recencyToAfterDate(filter){let now=new Date,days={day:1,week:7,month:30,year:365}[filter]??0;return new Date(now.getTime()-days*864e5).toISOString().slice(0,10)}function normalizeDomain(value){let input=value.trim().toLowerCase();if(!input||(input.startsWith("-")&&(input=input.slice(1).trim()),!input))return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function mapDomainFilter(domainFilter){if(!domainFilter?.length)return{};let include_domains=[],exclude_domains=[];for(let raw of domainFilter){let domain=normalizeDomain(raw);if(!domain)continue;let target=raw.trim().startsWith("-")?exclude_domains:include_domains;target.includes(domain)||target.push(domain)}return{...include_domains.length?{include_domains}:{},...exclude_domains.length?{exclude_domains}:{}}}function buildSearchRequestBody(query,options={}){let numResults=Math.max(1,Math.min(Math.floor(options.numResults??5),20)),sourcePolicy={...mapDomainFilter(options.domainFilter),...options.recencyFilter?{after_date:recencyToAfterDate(options.recencyFilter)}:{}};return{objective:query,search_queries:[query],advanced_settings:{max_results:numResults,...Object.keys(sourcePolicy).length>0?{source_policy:sourcePolicy}:{}}}}function normalizeExcerpts(value){return Array.isArray(value)?value.filter(item=>typeof item=="string"&&item.trim().length>0):[]}function mapSearchResults(results){if(!Array.isArray(results))return[];let mapped=[];for(let i=0;i<results.length;i++){let item=results[i];if(!item?.url)continue;let excerpts2=normalizeExcerpts(item.excerpts);mapped.push({title:item.title||`Source ${i+1}`,url:item.url,snippet:excerpts2.length>0?excerpts2[0].replace(/\s+/g," ").trim().slice(0,200):""})}return mapped}function buildAnswerFromExcerpts(results){if(!Array.isArray(results))return"";let parts=[];for(let i=0;i<results.length;i++){let item=results[i];if(!item?.url)continue;let excerpts2=normalizeExcerpts(item.excerpts);excerpts2.length!==0&&parts.push(`${excerpts2.join(" ")}
35
+ Source: ${item.title||`Source ${i+1}`} (${item.url})`)}return parts.join(`
36
+
37
+ `)}function mapInlineContent(results){return Array.isArray(results)?results.flatMap(result=>{if(!result?.url)return[];let excerpts2=normalizeExcerpts(result.excerpts);return excerpts2.length===0?[]:[{url:result.url,title:result.title||"",content:excerpts2.join(`
38
+
39
+ `),error:null}]}):[]}function resolveExtractContent(result){let fullContent=typeof result.full_content=="string"?result.full_content.trim():"";return fullContent.length>0?fullContent:normalizeExcerpts(result.excerpts).join(`
40
+
41
+ `)}function mapExtractResult(result){if(!result?.url)return null;let content=resolveExtractContent(result);return content.length<MIN_USEFUL_CONTENT?null:{url:result.url,title:typeof result.title=="string"?result.title.trim():"",content,error:null}}function buildExtractRequestBody(url,options={},fullContent=!1){let body={urls:[url]},prompt=options.prompt?.trim();return prompt&&(body.objective=prompt),fullContent&&(body.advanced_settings={full_content:!0}),body}function findExtractResult(results,url){if(Array.isArray(results))return results.find(item=>item?.url===url)??results[0]}function hasExtractUrlError(errors,url){return Array.isArray(errors)?errors.some(entry=>typeof entry=="string"?entry===url:typeof entry=="object"&&entry!==null&&entry.url===url):!1}async function fetchAndMapExtractResult(url,body,signal){let data=await parallelFetch(PARALLEL_EXTRACT_URL,body,signal);if(hasExtractUrlError(data.errors,url))return{mapped:null,result:void 0};let result=findExtractResult(data.results,url);return{mapped:mapExtractResult(result),result}}async function searchWithParallel(query,options={}){let results=(await parallelFetch(PARALLEL_SEARCH_URL,buildSearchRequestBody(query,options),options.signal)).results,response={answer:buildAnswerFromExcerpts(results),results:mapSearchResults(results)};if(options.includeContent){let inlineContent=mapInlineContent(results);inlineContent.length>0&&(response.inlineContent=inlineContent)}return response}async function extractWithParallel(url,signal,options={}){let initial=await fetchAndMapExtractResult(url,buildExtractRequestBody(url,options),signal);return initial.mapped?initial.mapped:!initial.result||resolveExtractContent(initial.result).length>=MIN_USEFUL_CONTENT?null:(await fetchAndMapExtractResult(url,buildExtractRequestBody(url,options,!0),signal)).mapped}async function parallelFetch(url,body,signal){let apiKey=await getApiKey(signal),activityId=activityMonitor.logStart(activityContext(url,body)),response;try{response=await fetch(url,{method:"POST",headers:{"x-api-key":apiKey,"Content-Type":"application/json"},body:JSON.stringify(body),signal:requestSignal(signal)})}catch(err){let message=errorMessage(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Parallel API error ${response.status}: ${errorText.slice(0,300)}`)}try{let data=await response.json();return activityMonitor.logComplete(activityId,response.status),data}catch(err){throw activityMonitor.logComplete(activityId,response.status),new Error(`Parallel API returned invalid JSON: ${errorMessage(err)}`)}}var PARALLEL_MCP_URL="https://search.parallel.ai/mcp",CONFIG_PATH4=getWebSearchConfigPath(),REQUEST_TIMEOUT_MS=6e4;function requestSignal2(signal){let timeout=AbortSignal.timeout(REQUEST_TIMEOUT_MS);return signal?AbortSignal.any([signal,timeout]):timeout}function errorMessage2(err){return err instanceof Error?err.message:String(err)}function normalizeDomain2(value){let input=value.trim().toLowerCase();if(input.startsWith("-")&&(input=input.slice(1).trim()),!input)return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function domainMatches(hostname2,domain){return hostname2===domain||hostname2.endsWith(`.${domain}`)}function filterResults(results,domainFilter){if(!domainFilter?.length)return results;let included=domainFilter.filter(value=>!value.trim().startsWith("-")).map(normalizeDomain2).filter(value=>value!==null),excluded=domainFilter.filter(value=>value.trim().startsWith("-")).map(normalizeDomain2).filter(value=>value!==null);return results.filter(result=>{let hostname2;try{hostname2=new URL(result.url).hostname.toLowerCase()}catch{return!1}return(included.length===0||included.some(domain=>domainMatches(hostname2,domain)))&&!excluded.some(domain=>domainMatches(hostname2,domain))})}function buildSearchQuery(query,options){let parts=[query];for(let raw of options.domainFilter??[]){let domain=normalizeDomain2(raw);domain&&parts.push(raw.trim().startsWith("-")?`-site:${domain}`:`site:${domain}`)}if(options.recencyFilter){let labels={day:"past 24 hours",week:"past week",month:"past month",year:"past year"};parts.push(labels[options.recencyFilter])}return parts.join(" ")}async function callParallelMcp(toolName,args,signal){let apiKey=await resolveParallelApiKey(signal),headers={"Content-Type":"application/json",Accept:"application/json, text/event-stream"};apiKey&&(headers.Authorization=`Bearer ${apiKey}`);let response;try{response=await fetch(PARALLEL_MCP_URL,{method:"POST",headers,body:JSON.stringify({jsonrpc:"2.0",id:1,method:"tools/call",params:{name:toolName,arguments:args}}),signal:requestSignal2(signal)})}catch(err){let message=apiKey?redactCredential(errorMessage2(err),apiKey):errorMessage2(err);throw message===errorMessage2(err)?err:new Error(message)}let body=await response.text(),safeBody=apiKey?redactCredential(body,apiKey):body;if(!response.ok)throw response.status===429?new Error(`Parallel MCP rate limit reached (429). Add parallelApiKey to ${CONFIG_PATH4} or set PARALLEL_API_KEY for higher limits: ${safeBody.slice(0,200)}`):new Error(`Parallel MCP error ${response.status}: ${safeBody.slice(0,300)}`);let parsed=null;for(let candidateText of[...body.split(`
42
+ `).filter(line=>line.startsWith("data:")).map(line=>line.slice(5).trim()),body])if(candidateText)try{let candidate=JSON.parse(candidateText);if(candidate.result||candidate.error){parsed=candidate;break}}catch{}if(!parsed)throw new Error("Parallel MCP returned invalid JSON-RPC content");if(parsed.error){let code=typeof parsed.error.code=="number"?` ${parsed.error.code}`:"",message=apiKey?redactCredential(parsed.error.message||"Unknown error",apiKey):parsed.error.message||"Unknown error";throw new Error(`Parallel MCP error${code}: ${message}`)}if(parsed.result?.isError){let text2=parsed.result.content?.find(item=>item.type==="text"&&typeof item.text=="string")?.text?.trim()||"Parallel MCP returned an error";throw new Error(apiKey?redactCredential(text2,apiKey):text2)}if(parsed.result?.structuredContent&&typeof parsed.result.structuredContent=="object")return parsed.result.structuredContent;let text=parsed.result?.content?.find(item=>item.type==="text"&&typeof item.text=="string"&&item.text.trim())?.text;if(!text)throw new Error("Parallel MCP returned empty content");try{return JSON.parse(text)}catch{return text}}function parseTextResults(text){return text.split(/(?=^Title: )/m).flatMap(block=>{let url=block.match(/^URL: (.+)/m)?.[1]?.trim();if(!url)return[];let title=block.match(/^Title: (.+)/m)?.[1]?.trim()??"",textStart=block.indexOf(`
43
+ Text: `),excerpt=textStart>=0?block.slice(textStart+7).replace(/\n---\s*$/,"").trim():"";return[{url,title,excerpts:excerpt?[excerpt]:[]}]})}function getResults(payload){if(typeof payload=="string")return parseTextResults(payload);if(!payload||typeof payload!="object")return[];let results=payload.results;return Array.isArray(results)?results.filter(item=>!!item&&typeof item=="object"&&typeof item.url=="string"):[]}function excerpts(result){return Array.isArray(result.excerpts)?result.excerpts.filter(item=>typeof item=="string"&&item.trim()):[]}function isParallelMcpAvailable(){return!0}async function searchWithParallelMcp(query,options={}){let activityId=activityMonitor.logStart({type:"api",query});try{let searchQuery=buildSearchQuery(query,options),payload=await callParallelMcp("web_search",{objective:query,search_queries:[searchQuery]},options.signal),maxResults=Math.max(1,Math.min(Math.floor(options.numResults??5),20)),results=filterResults(getResults(payload),options.domainFilter).slice(0,maxResults);activityMonitor.logComplete(activityId,200);let response={answer:results.flatMap((result,index)=>{let content=excerpts(result).join(" ").trim();return content?[`${content}
44
+ Source: ${result.title||`Source ${index+1}`} (${result.url})`]:[]}).join(`
45
+
46
+ `),results:results.map((result,index)=>({title:result.title||`Source ${index+1}`,url:result.url,snippet:excerpts(result)[0]?.replace(/\s+/g," ").trim().slice(0,200)??""}))};if(options.includeContent){let inlineContent=results.flatMap(result=>{let content=excerpts(result).join(`
47
+
48
+ `);return content?[{url:result.url,title:result.title||"",content,error:null}]:[]});inlineContent.length&&(response.inlineContent=inlineContent)}return response}catch(err){let message=errorMessage2(err);throw message.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,message),err}}async function extractWithParallelMcp(url,signal,options={}){let activityId=activityMonitor.logStart({type:"fetch",url});try{let objective=options.prompt?.trim(),payload=await callParallelMcp("web_fetch",{urls:[url],...objective?{objective:objective.slice(0,200)}:{},full_content:!0},signal),result=getResults(payload).find(item=>item.url===url)??getResults(payload)[0];if(!result)return activityMonitor.logComplete(activityId,200),null;let content=(typeof result.full_content=="string"?result.full_content.trim():"")||excerpts(result).join(`
49
+
50
+ `);return activityMonitor.logComplete(activityId,200),content?{url:result.url,title:result.title||"",content,error:null}:null}catch(err){let message=errorMessage2(err);throw message.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,message),err}}import{existsSync as existsSync7,readFileSync as readFileSync7}from"node:fs";var TINYFISH_SEARCH_URL="https://api.search.tinyfish.ai",TINYFISH_FETCH_URL="https://api.fetch.tinyfish.ai",CONFIG_PATH5=getWebSearchConfigPath(),SEARCH_TIMEOUT_MS2=6e4,FETCH_TIMEOUT_MS=15e4,MAX_FETCH_URLS=10,MAX_FETCH_PER_URL_TIMEOUT_MS=11e4,cachedConfig4=null;function loadConfig3(){if(cachedConfig4)return cachedConfig4;if(!existsSync7(CONFIG_PATH5))return cachedConfig4={},cachedConfig4;let raw=readFileSync7(CONFIG_PATH5,"utf-8");try{return cachedConfig4=JSON.parse(raw),cachedConfig4}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH5}: ${message}`)}}async function getApiKey2(signal){let key=await resolveCredential({provider:"TinyFish",configuredValue:loadConfig3().tinyfishApiKey,environmentValue:process.env.TINYFISH_API_KEY,signal});if(!key)throw new Error(`TinyFish API key not found. Either:
51
+ 1. Create ${CONFIG_PATH5} with { "tinyfishApiKey": "your-key" }
52
+ 2. Set TINYFISH_API_KEY environment variable
53
+ Get a key at https://agent.tinyfish.ai/api-keys`);return key}function isTinyFishAvailable(){return hasCredentialSource({provider:"TinyFish",configuredValue:loadConfig3().tinyfishApiKey,environmentValue:process.env.TINYFISH_API_KEY})}function errorMessage3(err){return err instanceof Error?err.message:String(err)}function requestSignal3(signal,timeoutMs){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([signal,timeout]):timeout}function normalizeDomain3(value){let input=value.trim().toLowerCase();if(!input||(input.startsWith("-")&&(input=input.slice(1).trim()),!input))return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function mapDomainFilter2(domainFilter){let includeDomains=[],excludeDomains=[];for(let raw of domainFilter??[]){let domain=normalizeDomain3(raw);if(!domain)continue;let target=raw.trim().startsWith("-")?excludeDomains:includeDomains;target.includes(domain)||target.push(domain)}return{includeDomains,excludeDomains}}function recencyMinutes(filter){return filter?{day:1440,week:10080,month:43200,year:525600}[filter]:void 0}function normalizeNumResults(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),20))}function buildSearchUrl(query,options,page){let params=new URLSearchParams({query}),{includeDomains,excludeDomains}=mapDomainFilter2(options.domainFilter);includeDomains.length>0&&params.set("include_domains",includeDomains.join(",")),excludeDomains.length>0&&params.set("exclude_domains",excludeDomains.join(","));let recency=recencyMinutes(options.recencyFilter);return recency!==void 0&&params.set("recency_minutes",String(recency)),page>0&&params.set("page",String(page)),`${TINYFISH_SEARCH_URL}?${params.toString()}`}async function tinyFishJsonRequest(label,url,apiKey,init,timeoutMs,signal){let response;try{response=await fetch(url,{...init,headers:{"X-API-Key":apiKey,...init.body?{"Content-Type":"application/json"}:{},...init.headers},signal:requestSignal3(signal,timeoutMs)})}catch(err){let message=errorMessage3(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}let raw=await response.text();if(!response.ok)throw new Error(`TinyFish ${label} API error ${response.status}: ${redactCredential(raw,apiKey).slice(0,300)}`);try{return JSON.parse(raw)}catch(err){throw new Error(`TinyFish ${label} API returned invalid JSON: ${errorMessage3(err)}`)}}function mapSearchResults2(results){return Array.isArray(results)?results.flatMap(item=>{if(!item||typeof item.url!="string"||item.url.trim().length===0)return[];let url=item.url.trim();return[{title:typeof item.title=="string"&&item.title.trim()?item.title.trim():url,url,snippet:typeof item.snippet=="string"?item.snippet.replace(/\s+/g," ").trim():""}]}):[]}function deduplicateResults(results,limit){let seen=new Set,unique=[];for(let result of results)if(!seen.has(result.url)&&(seen.add(result.url),unique.push(result),unique.length>=limit))break;return unique}function buildAnswer(results){return results.map(result=>result.snippet?`${result.snippet}
54
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
55
+
56
+ `)}function fetchPerUrlTimeout(value){return typeof value!="number"||!Number.isFinite(value)?MAX_FETCH_PER_URL_TIMEOUT_MS:Math.max(1,Math.min(Math.floor(value),MAX_FETCH_PER_URL_TIMEOUT_MS))}function fetchBody(urls,options={}){let body={urls,format:"markdown",per_url_timeout_ms:fetchPerUrlTimeout(options.timeoutMs)},purpose=options.prompt?.trim();return purpose&&(body.purpose=purpose.slice(0,2e3)),body}function findFetchError(errors,url){if(Array.isArray(errors))return errors.find(item=>item?.url===url)??errors[0]}function fetchResultContent(result){return typeof result.text=="string"?result.text.trim():result.text&&typeof result.text=="object"?JSON.stringify(result.text,null,2):""}function mapFetchResult(result,requestedUrl){if(!result)return null;let content=fetchResultContent(result);return content?{url:requestedUrl,title:typeof result.title=="string"?result.title.trim():"",content,error:null}:null}async function fetchBatch(urls,apiKey,signal,options={}){return tinyFishJsonRequest("Fetch",TINYFISH_FETCH_URL,apiKey,{method:"POST",body:JSON.stringify(fetchBody(urls,options))},FETCH_TIMEOUT_MS,signal)}async function fetchInlineContent(urls,apiKey,signal){let content=[];for(let offset=0;offset<urls.length;offset+=MAX_FETCH_URLS){let batch=urls.slice(offset,offset+MAX_FETCH_URLS),data=await fetchBatch(batch,apiKey,signal);if(!Array.isArray(data.results)||!Array.isArray(data.errors))throw new Error("TinyFish Fetch API returned an unexpected response shape");for(let url of batch){let result=Array.isArray(data.results)?data.results.find(item=>item?.url===url||item?.final_url===url):void 0,mapped=mapFetchResult(result,url);mapped&&content.push(mapped)}}return content}async function searchWithTinyFish(query,options={}){let apiKey=await getApiKey2(options.signal),numResults=normalizeNumResults(options.numResults),activityId=activityMonitor.logStart({type:"api",query});try{let combined=[],pages=numResults>10?2:1;for(let page=0;page<pages;page++){let data=await tinyFishJsonRequest("Search",buildSearchUrl(query,options,page),apiKey,{method:"GET"},SEARCH_TIMEOUT_MS2,options.signal);if(!Array.isArray(data.results))throw new Error("TinyFish Search API returned an unexpected response shape");if(combined.push(...mapSearchResults2(data.results)),data.results.length<10)break}let results=deduplicateResults(combined,numResults),response={answer:buildAnswer(results),results};if(options.includeContent&&results.length>0){let inlineContent=await fetchInlineContent(results.map(result=>result.url),apiKey,options.signal);inlineContent.length>0&&(response.inlineContent=inlineContent)}return activityMonitor.logComplete(activityId,200),response}catch(err){let message=errorMessage3(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}async function extractWithTinyFish(url,signal,options={}){let apiKey=await getApiKey2(signal),activityId=activityMonitor.logStart({type:"fetch",url});try{let data=await fetchBatch([url],apiKey,signal,options);if(!Array.isArray(data.results)||!Array.isArray(data.errors))throw new Error("TinyFish Fetch API returned an unexpected response shape");let result=data.results.find(item=>item?.url===url||item?.final_url===url)??data.results[0],mapped=mapFetchResult(result,url);if(mapped)return activityMonitor.logComplete(activityId,200),mapped;let fetchError=findFetchError(data.errors,url);if(fetchError){let status=typeof fetchError.status=="number"?` (HTTP ${fetchError.status})`:"";throw new Error(`TinyFish Fetch failed for ${url}: ${fetchError.error||"unknown error"}${status}`)}return activityMonitor.logComplete(activityId,200),null}catch(err){let message=errorMessage3(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}import{existsSync as existsSync8,readFileSync as readFileSync8}from"node:fs";var SEARCH1API_SEARCH_URL="https://api.search1api.com/search",SEARCH1API_CRAWL_URL="https://api.search1api.com/crawl",CONFIG_PATH6=getWebSearchConfigPath(),SEARCH_TIMEOUT_MS3=6e4,CRAWL_TIMEOUT_MS=6e4,cachedConfig5=null;function loadConfig4(){if(cachedConfig5)return cachedConfig5;if(!existsSync8(CONFIG_PATH6))return cachedConfig5={},cachedConfig5;let raw=readFileSync8(CONFIG_PATH6,"utf-8"),parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH6}: ${message}`)}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error(`Invalid config in ${CONFIG_PATH6}: expected a JSON object`);return cachedConfig5=parsed,cachedConfig5}async function getApiKey3(signal){let key=await resolveCredential({provider:"Search1API",configuredValue:loadConfig4().search1apiApiKey,environmentValue:process.env.SEARCH1API_KEY,signal});if(!key)throw new Error(`Search1API key not found. Either:
57
+ 1. Create ${CONFIG_PATH6} with { "search1apiApiKey": "your-key" }
58
+ 2. Set SEARCH1API_KEY environment variable
59
+ Create a key at https://dashboard.search1api.com`);return key}function isSearch1APIAvailable(){return hasCredentialSource({provider:"Search1API",configuredValue:loadConfig4().search1apiApiKey,environmentValue:process.env.SEARCH1API_KEY})}function errorMessage4(err){return err instanceof Error?err.message:String(err)}function requestSignal4(signal,timeoutMs){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([signal,timeout]):timeout}function normalizeNumResults2(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),20))}function normalizeDomain4(value){let input=value.trim().toLowerCase();if(!input||(input.startsWith("-")&&(input=input.slice(1).trim()),!input))return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function mapDomainFilter3(domainFilter){let includeSites=[],excludeSites=[];for(let raw of domainFilter??[]){let domain=normalizeDomain4(raw);if(!domain)continue;let target=raw.trim().startsWith("-")?excludeSites:includeSites;target.includes(domain)||target.push(domain)}return{includeSites,excludeSites}}function buildSearchBody(query,options){let numResults=normalizeNumResults2(options.numResults),{includeSites,excludeSites}=mapDomainFilter3(options.domainFilter);return{query,max_results:numResults,crawl_results:options.includeContent?numResults:0,...includeSites.length>0?{include_sites:includeSites}:{},...excludeSites.length>0?{exclude_sites:excludeSites}:{},...options.recencyFilter?{time_range:options.recencyFilter}:{}}}async function search1APIJsonRequest(label,url,apiKey,body,timeoutMs,signal){let response;try{response=await fetch(url,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(body),signal:requestSignal4(signal,timeoutMs)})}catch(err){let message=errorMessage4(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}let raw=await response.text();if(!response.ok)throw new Error(`Search1API ${label} API error ${response.status}: ${redactCredential(raw,apiKey).slice(0,300)}`);try{return JSON.parse(raw)}catch(err){throw new Error(`Search1API ${label} API returned invalid JSON: ${errorMessage4(err)}`)}}function mapSearchResults3(results){if(!Array.isArray(results))throw new Error("Search1API Search API returned an unexpected response shape");return results.flatMap(item=>{if(!item||typeof item.link!="string"||item.link.trim().length===0)return[];let url=item.link.trim();return[{title:typeof item.title=="string"&&item.title.trim()?item.title.trim():url,url,snippet:typeof item.snippet=="string"?item.snippet.replace(/\s+/g," ").trim():""}]})}function mapInlineContent2(results){return Array.isArray(results)?results.flatMap(item=>!item||typeof item.link!="string"||item.link.trim().length===0?[]:typeof item.content!="string"||item.content.trim().length===0?[]:[{url:item.link.trim(),title:typeof item.title=="string"?item.title.trim():"",content:item.content,error:null}]):[]}function buildAnswer2(results){return results.map(result=>result.snippet?`${result.snippet}
60
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
61
+
62
+ `)}async function searchWithSearch1API(query,options={}){let apiKey=await getApiKey3(options.signal),activityId=activityMonitor.logStart({type:"api",query});try{let data=await search1APIJsonRequest("Search",SEARCH1API_SEARCH_URL,apiKey,buildSearchBody(query,options),SEARCH_TIMEOUT_MS3,options.signal),results=mapSearchResults3(data.results),response={answer:buildAnswer2(results),results};if(options.includeContent){let inlineContent=mapInlineContent2(data.results);inlineContent.length>0&&(response.inlineContent=inlineContent)}return activityMonitor.logComplete(activityId,200),response}catch(err){let message=errorMessage4(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}async function extractWithSearch1API(url,signal,options={}){let apiKey=await getApiKey3(signal),activityId=activityMonitor.logStart({type:"fetch",url});try{let result=(await search1APIJsonRequest("Crawl",SEARCH1API_CRAWL_URL,apiKey,{url},typeof options.timeoutMs=="number"&&Number.isFinite(options.timeoutMs)?Math.max(1,Math.floor(options.timeoutMs)):CRAWL_TIMEOUT_MS,signal)).results;if(!result||typeof result!="object")throw new Error("Search1API Crawl API returned an unexpected response shape");let content=typeof result.content=="string"?result.content.trim():"";return content?(activityMonitor.logComplete(activityId,200),{url,title:typeof result.title=="string"?result.title.trim():"",content,error:null}):(activityMonitor.logComplete(activityId,200),null)}catch(err){let message=errorMessage4(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}import{existsSync as existsSync9,readFileSync as readFileSync9}from"node:fs";var QUERIT_SEARCH_URL="https://api.querit.ai/v1/search",QUERIT_CONTENTS_URL="https://api.querit.ai/v1/contents",CONFIG_PATH7=getWebSearchConfigPath(),SEARCH_TIMEOUT_MS4=6e4,CONTENTS_TIMEOUT_MS=6e4,MAX_CONTENT_URLS=10,cachedConfig6=null;function loadConfig5(){if(cachedConfig6)return cachedConfig6;if(!existsSync9(CONFIG_PATH7))return cachedConfig6={},cachedConfig6;let raw=readFileSync9(CONFIG_PATH7,"utf-8"),parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH7}: ${message}`)}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error(`Invalid config in ${CONFIG_PATH7}: expected a JSON object`);return cachedConfig6=parsed,cachedConfig6}async function getApiKey4(signal){let key=await resolveCredential({provider:"Querit",configuredValue:loadConfig5().queritApiKey,environmentValue:process.env.QUERIT_API_KEY,signal});if(!key)throw new Error(`Querit API key not found. Either:
63
+ 1. Create ${CONFIG_PATH7} with { "queritApiKey": "your-key" }
64
+ 2. Set QUERIT_API_KEY environment variable
65
+ Create a key at https://www.querit.ai/en/dashboard/api-keys`);return key}function isQueritAvailable(){return hasCredentialSource({provider:"Querit",configuredValue:loadConfig5().queritApiKey,environmentValue:process.env.QUERIT_API_KEY})}function errorMessage5(err){return err instanceof Error?err.message:String(err)}function requestSignal5(signal,timeoutMs){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([signal,timeout]):timeout}function normalizeNumResults3(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),20))}function normalizeDomain5(value){let input=value.trim().toLowerCase();if(!input||(input.startsWith("-")&&(input=input.slice(1).trim()),!input))return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function mapDomainFilter4(domainFilter){let include=[],exclude=[];for(let raw of domainFilter??[]){let domain=normalizeDomain5(raw);if(!domain)continue;let target=raw.trim().startsWith("-")?exclude:include;target.includes(domain)||target.push(domain)}return{include,exclude}}function mapRecencyFilter(value){if(value==="day")return"d1";if(value==="week")return"w1";if(value==="month")return"m1";if(value==="year")return"y1"}function buildSearchBody2(query,options){let{include,exclude}=mapDomainFilter4(options.domainFilter),date=mapRecencyFilter(options.recencyFilter),filters={};return(include.length>0||exclude.length>0)&&(filters.sites={...include.length>0?{include}:{},...exclude.length>0?{exclude}:{}}),date&&(filters.timeRange={date}),{query,count:normalizeNumResults3(options.numResults),...Object.keys(filters).length>0?{filters}:{}}}function normalizeTimeoutMs(value){return typeof value!="number"||!Number.isFinite(value)?CONTENTS_TIMEOUT_MS:Math.max(1,Math.floor(value))}function crawlTimeoutSeconds(value){return typeof value!="number"||!Number.isFinite(value)?10:Math.max(1,Math.min(Math.ceil(value/1e3),60))}function buildContentsBody(urls,options={}){return{urls,format:"markdown",crawlTimeout:crawlTimeoutSeconds(options.timeoutMs),extrasMeta:!0}}async function queritJsonRequest(label,url,apiKey,body,timeoutMs,signal){let response;try{response=await fetch(url,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(body),signal:requestSignal5(signal,timeoutMs)})}catch(err){let message=errorMessage5(err),isRequestAbort=err instanceof Error?err.name==="AbortError"||err.name==="TimeoutError"||/abort|timeout/i.test(message):/abort|timeout/i.test(message);if(!signal?.aborted&&isRequestAbort){let timeoutError=new Error(`Querit ${label} API request timed out after ${Math.ceil(timeoutMs/1e3)} seconds`);throw timeoutError.name="TimeoutError",timeoutError}let redactedMessage=redactCredential(message,apiKey);if(redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}let raw=await response.text();if(!response.ok)throw new Error(`Querit ${label} API error ${response.status}: ${redactCredential(raw,apiKey).slice(0,300)}`);try{return JSON.parse(raw)}catch(err){throw new Error(`Querit ${label} API returned invalid JSON: ${errorMessage5(err)}`)}}function assertApiSuccess(label,data){let code=Number(data.error_code);if(!Number.isFinite(code)||code!==200){let renderedCode=data.error_code===void 0?"unknown":String(data.error_code),message=typeof data.error_msg=="string"&&data.error_msg.trim()?`: ${data.error_msg.trim()}`:"";throw new Error(`Querit ${label} API returned error ${renderedCode}${message}`)}}function mapSearchResults4(data){let items=data.results?.result;if(!Array.isArray(items))throw new Error("Querit Search API returned an unexpected response shape");return items.flatMap(item=>{if(!item||typeof item.url!="string"||item.url.trim().length===0)return[];let url=item.url.trim();return[{title:typeof item.title=="string"&&item.title.trim()?item.title.trim():url,url,snippet:typeof item.snippet=="string"?item.snippet.replace(/\s+/g," ").trim():""}]})}function buildAnswer3(results){return results.map(result=>result.snippet?`${result.snippet}
66
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
67
+
68
+ `)}function mapContentResult(result,requestedUrl){if(!result||typeof result.content!="string"||result.content.trim().length===0)return null;let metadata=result.extrasMeta;return{url:requestedUrl,title:metadata&&typeof metadata.title=="string"?metadata.title.trim():"",content:result.content.trim(),error:null}}function findContentResult(data,requestedUrl,index,requestedCount){if(!Array.isArray(data.results))return;let exact=data.results.find(item=>item?.url===requestedUrl||item?.extrasMeta?.url===requestedUrl);return exact||(requestedCount===1?data.results[0]:data.results.length===requestedCount?data.results[index]:void 0)}function failedContentStatus(data,result,index){return Array.isArray(data.statuses)?(result?.id?data.statuses.find(item=>item?.id===result.id):data.statuses[index])?.status==="failed":!1}async function fetchContentsBatch(urls,apiKey,signal,options={}){let data=await queritJsonRequest("Contents",QUERIT_CONTENTS_URL,apiKey,buildContentsBody(urls,options),normalizeTimeoutMs(options.timeoutMs),signal);if(assertApiSuccess("Contents",data),!Array.isArray(data.results)||!Array.isArray(data.statuses))throw new Error("Querit Contents API returned an unexpected response shape");return data}async function fetchInlineContent2(urls,apiKey,signal){let content=[];for(let offset=0;offset<urls.length;offset+=MAX_CONTENT_URLS){let batch=urls.slice(offset,offset+MAX_CONTENT_URLS),data=await fetchContentsBatch(batch,apiKey,signal);for(let index=0;index<batch.length;index++){let requestedUrl=batch[index],result=findContentResult(data,requestedUrl,index,batch.length),mapped=mapContentResult(result,requestedUrl);mapped&&content.push(mapped)}}return content}async function searchWithQuerit(query,options={}){let apiKey=await getApiKey4(options.signal),activityId=activityMonitor.logStart({type:"api",query});try{let data=await queritJsonRequest("Search",QUERIT_SEARCH_URL,apiKey,buildSearchBody2(query,options),SEARCH_TIMEOUT_MS4,options.signal);assertApiSuccess("Search",data);let results=mapSearchResults4(data),response={answer:buildAnswer3(results),results};if(options.includeContent&&results.length>0){let inlineContent=await fetchInlineContent2(results.map(result=>result.url),apiKey,options.signal);inlineContent.length>0&&(response.inlineContent=inlineContent)}return activityMonitor.logComplete(activityId,200),response}catch(err){let message=errorMessage5(err),redactedMessage=redactCredential(message,apiKey);if(options.signal?.aborted?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}async function extractWithQuerit(url,signal,options={}){let apiKey=await getApiKey4(signal),activityId=activityMonitor.logStart({type:"fetch",url});try{let data=await fetchContentsBatch([url],apiKey,signal,options),result=findContentResult(data,url,0,1),mapped=mapContentResult(result,url);if(mapped)return activityMonitor.logComplete(activityId,200),mapped;if(failedContentStatus(data,result,0))throw new Error(`Querit Contents API failed to crawl ${url}`);return activityMonitor.logComplete(activityId,200),null}catch(err){let message=errorMessage5(err),redactedMessage=redactCredential(message,apiKey);if(signal?.aborted?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}}import{lookup as dnsLookup}from"node:dns/promises";import{existsSync as existsSync10,readFileSync as readFileSync10,statSync as statSync2}from"node:fs";import net from"node:net";var DEFAULT_MAX_REDIRECTS=5,REDIRECT_STATUSES=new Set([301,302,303,307,308]),LOOPBACK_ALLOW_RANGES=["127.0.0.0/8","::1","::ffff:127.0.0.0/104"],WEB_SEARCH_CONFIG_PATH2=getWebSearchConfigPath(),cachedConfigRoot=null;function loadConfigRoot(){if(!existsSync10(WEB_SEARCH_CONFIG_PATH2))return null;let signature;try{let stat=statSync2(WEB_SEARCH_CONFIG_PATH2);signature=`${stat.mtimeMs}:${stat.size}`}catch{return null}if(cachedConfigRoot?.signature===signature)return cachedConfigRoot.value;let raw;try{raw=readFileSync10(WEB_SEARCH_CONFIG_PATH2,"utf-8")}catch{return null}let parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${WEB_SEARCH_CONFIG_PATH2}: ${message}`)}let value=parsed&&typeof parsed=="object"&&!Array.isArray(parsed)?parsed:null;return cachedConfigRoot={signature,value},value}var DEFAULT_DOMAIN_POLICY={allow:[],deny:[]};function loadFetchContentDomainPolicy(){let parsed=loadConfigRoot();if(!parsed)return{...DEFAULT_DOMAIN_POLICY};let fetchContent=parsed.fetchContent;if(fetchContent==null)return{...DEFAULT_DOMAIN_POLICY};if(typeof fetchContent!="object"||Array.isArray(fetchContent))throw new Error(`fetchContent in ${WEB_SEARCH_CONFIG_PATH2} must be an object`);let policy=fetchContent.domainPolicy;if(policy==null)return{...DEFAULT_DOMAIN_POLICY};if(typeof policy!="object"||Array.isArray(policy))throw new Error(`fetchContent.domainPolicy in ${WEB_SEARCH_CONFIG_PATH2} must be an object`);let config=policy;return{allow:parseDomainEntries(config.allow,"allow"),deny:parseDomainEntries(config.deny,"deny")}}function parseDomainEntries(value,field){if(value==null)return[];if(!Array.isArray(value))throw new Error(`fetchContent.domainPolicy.${field} in ${WEB_SEARCH_CONFIG_PATH2} must be an array of hostnames`);return value.map((entry,index)=>{if(typeof entry!="string")throw new Error(`fetchContent.domainPolicy.${field} in ${WEB_SEARCH_CONFIG_PATH2} must contain only hostnames; entry ${index+1} is ${typeof entry}`);let hostname2=normalizeDomainEntry(entry);if(!hostname2)throw new Error(`fetchContent.domainPolicy.${field} in ${WEB_SEARCH_CONFIG_PATH2} contains an invalid hostname: ${JSON.stringify(entry)}`);return hostname2})}function normalizeDomainEntry(entry){let hostname2=normalizeHostname2(entry.trim());return!hostname2||/\s|[\\/?:#@]/.test(hostname2)?null:net.isIP(hostname2)?hostname2:hostname2.length>253||!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(hostname2)?null:hostname2}function loadSsrfConfig(){let parsed=loadConfigRoot();if(!parsed)return{allowRanges:[],trustEnvProxy:!1};let ssrf=parsed.ssrf;if(ssrf==null)return{allowRanges:[],trustEnvProxy:!1};if(typeof ssrf!="object"||Array.isArray(ssrf))throw new Error(`ssrf in ${WEB_SEARCH_CONFIG_PATH2} must be an object`);let config=ssrf;if(config.allowRanges!==void 0&&config.allowRanges!==null&&!Array.isArray(config.allowRanges))throw new Error(`ssrf.allowRanges in ${WEB_SEARCH_CONFIG_PATH2} must be an array of CIDR strings`);if(config.trustEnvProxy!==void 0&&typeof config.trustEnvProxy!="boolean")throw new Error(`ssrf.trustEnvProxy in ${WEB_SEARCH_CONFIG_PATH2} must be a boolean`);let allowRanges=(Array.isArray(config.allowRanges)?config.allowRanges:[]).map((entry,index)=>{if(typeof entry!="string")throw new Error(`ssrf.allowRanges in ${WEB_SEARCH_CONFIG_PATH2} must contain only CIDR strings; entry ${index+1} is ${typeof entry}`);return entry.trim()}).filter(Boolean);return parseAllowRanges(allowRanges),{allowRanges,trustEnvProxy:config.trustEnvProxy===!0}}async function defaultLookup(hostname2){return dnsLookup(hostname2,{all:!0,verbatim:!0})}async function validateRemoteUrl(rawUrl,options={}){let url=rawUrl instanceof URL?rawUrl:new URL(rawUrl);if(url.protocol!=="http:"&&url.protocol!=="https:")throw new Error("Only HTTP and HTTPS URLs can be fetched remotely");let hostname2=normalizeHostname2(url.hostname);if(!hostname2)throw new Error("URL must include a hostname");if(hostname2==="localhost"){if(options.allowLoopback===!0)return url;throw new Error(`Blocked internal hostname: ${hostname2}`)}if(hostname2.endsWith(".localhost"))throw new Error(`Blocked internal hostname: ${hostname2}`);let allowRanges=parseAllowRanges(options.allowRanges);if(assertDomainPolicy(hostname2,options.domainPolicy),net.isIP(hostname2)){let addressAllowRanges=options.allowLoopback===!0?[...allowRanges,...parseAllowRanges(LOOPBACK_ALLOW_RANGES)]:allowRanges;return assertPublicAddress(hostname2,hostname2,addressAllowRanges),url}if(shouldTrustEnvProxy(url,options.trustEnvProxy===!0))return url;let addresses;try{addresses=await(options.lookup??defaultLookup)(hostname2)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to resolve ${hostname2}: ${message}`)}if(addresses.length===0)throw new Error(`Failed to resolve ${hostname2}: no addresses returned`);for(let{address}of addresses)assertPublicAddress(address,hostname2,allowRanges);return url}async function fetchRemoteUrl(url,init={},options={}){let fetchImpl=options.fetch??fetch,maxRedirects=options.maxRedirects??DEFAULT_MAX_REDIRECTS,current=await validateRemoteUrl(url,options),configuredOrigin=current.origin,requestInit=init;for(let redirects=0;redirects<=maxRedirects;redirects++){let response=await fetchImpl(current,{...requestInit,redirect:"manual"});if(!REDIRECT_STATUSES.has(response.status))return response;let location=response.headers.get("location");if(!location)return response;if(redirects===maxRedirects)throw new Error(`Too many redirects fetching ${current.toString()}`);let from=current,next=new URL(location,current);if(current=await validateRemoteUrl(next,next.origin===configuredOrigin?options:{...options,allowLoopback:!1}),response.status===303||(response.status===301||response.status===302)&&requestInit.method?.toUpperCase()==="POST"){let{body:_body,...nextInit}=requestInit;requestInit={...nextInit,method:"GET"}}options.onRedirect&&(requestInit=options.onRedirect({from,to:current,init:requestInit,response}))}throw new Error(`Too many redirects fetching ${current.toString()}`)}function normalizeHostname2(hostname2){return hostname2.toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"")}function assertDomainPolicy(hostname2,policy){if(policy){if(policy.deny.some(entry=>domainMatches2(hostname2,entry)))throw new Error(`Blocked hostname by fetch_content domain policy: ${hostname2}`);if(policy.allow.length>0&&!policy.allow.some(entry=>domainMatches2(hostname2,entry)))throw new Error(`Hostname not allowed by fetch_content domain policy: ${hostname2}`)}}function domainMatches2(hostname2,entry){return hostname2===entry||hostname2.endsWith(`.${entry}`)}function getProxyForProtocol(protocol){let candidates=protocol==="http:"?[process.env.HTTP_PROXY,process.env.http_proxy,process.env.ALL_PROXY,process.env.all_proxy]:protocol==="https:"?[process.env.HTTPS_PROXY,process.env.https_proxy,process.env.HTTP_PROXY,process.env.http_proxy,process.env.ALL_PROXY,process.env.all_proxy]:[];for(let candidate of candidates){let value=candidate?.trim();if(value)try{let proxyUrl=new URL(value);if((proxyUrl.protocol==="http:"||proxyUrl.protocol==="https:")&&proxyUrl.hostname)return value}catch{}}return""}function hostnameMatchesNoProxy(hostname2,port,entry){let trimmed=entry.trim();if(!trimmed)return!1;if(trimmed==="*")return!0;let hostEntry=trimmed,entryPort;if(hostEntry.startsWith("[")){let closingBracket=hostEntry.indexOf("]");if(closingBracket>=0){let suffix2=hostEntry.slice(closingBracket+1);/^:\\d+$/.test(suffix2)&&(entryPort=suffix2.slice(1)),hostEntry=hostEntry.slice(0,closingBracket+1)}}else{let colon=hostEntry.lastIndexOf(":");colon>-1&&/^\d+$/.test(hostEntry.slice(colon+1))&&(entryPort=hostEntry.slice(colon+1),hostEntry=hostEntry.slice(0,colon))}if(entryPort!==void 0&&entryPort!==port)return!1;let normalizedEntry=normalizeHostname2(hostEntry);if(!normalizedEntry)return!1;if(normalizedEntry===hostname2)return!0;let suffix=normalizedEntry.startsWith("*.")?normalizedEntry.slice(1):normalizedEntry.startsWith(".")?normalizedEntry:`.${normalizedEntry}`;return hostname2.endsWith(suffix)}function shouldTrustEnvProxy(url,enabled){if(!enabled||!getProxyForProtocol(url.protocol)||hasScopedProxyDecision()||getActiveProxy()&&!isProxyBypassedUrl(url))return!1;let hostname2=normalizeHostname2(url.hostname),port=url.port||(url.protocol==="https:"?"443":"80");return!(process.env.NO_PROXY||process.env.no_proxy||"").split(",").some(entry=>hostnameMatchesNoProxy(hostname2,port,entry))}function assertPublicAddress(address,hostname2,allowRanges=[]){let normalized=normalizeHostname2(address),ipVersion=net.isIP(normalized);if(ipVersion===0)throw new Error(`Resolved non-IP address for ${hostname2}: ${address}`);if(!isInAllowedRange(normalized,ipVersion,allowRanges)){if(ipVersion===4&&isBlockedIPv4(normalized)){let hint=isFakeIpProxyAddress(normalized)?'. This address is in 198.18.0.0/15, commonly used by TUN/fake-IP proxies. If that matches your setup, configure ssrf.allowRanges with ["198.18.0.0/15"] in web-search.json.':"";throw new Error(`Blocked internal address for ${hostname2}: ${normalized}${hint}`)}if(ipVersion===6&&isBlockedIPv6(normalized))throw new Error(`Blocked internal address for ${hostname2}: ${normalized}`)}}function isFakeIpProxyAddress(address){let[a,b]=address.split(".").map(part=>Number(part));return a===198&&(b===18||b===19)}function isBlockedIPv4(address){let parts=address.split(".").map(part=>Number(part));if(parts.length!==4||parts.some(part=>!Number.isInteger(part)||part<0||part>255))return!0;let[a,b]=parts;return a===0||a===10||a===127||a===100&&b>=64&&b<=127||a===169&&b===254||a===172&&b>=16&&b<=31||a===192&&b===168||isFakeIpProxyAddress(address)||a>=224}function isBlockedIPv6(address){let groups=parseIPv6(address);if(!groups)return!0;let first=groups[0];if(groups.every(group=>group===0)||groups.slice(0,7).every(group=>group===0)&&groups[7]===1||(first&65024)===64512||(first&65472)===65152)return!0;if(groups.slice(0,5).every(group=>group===0)&&groups[5]===65535){let ipv4=[groups[6]>>8,groups[6]&255,groups[7]>>8,groups[7]&255].join(".");return isBlockedIPv4(ipv4)}return!1}function parseIPv6(address){if(address.includes(".")){let lastColon=address.lastIndexOf(":"),ipv4=address.slice(lastColon+1);if(net.isIP(ipv4)!==4)return null;let octets=ipv4.split(".").map(part=>Number(part));address=`${address.slice(0,lastColon)}:${(octets[0]<<8|octets[1]).toString(16)}:${(octets[2]<<8|octets[3]).toString(16)}`}let pieces=address.split("::");if(pieces.length>2)return null;let left=pieces[0]?pieces[0].split(":"):[],right=pieces.length===2&&pieces[1]?pieces[1].split(":"):[],missing=8-left.length-right.length;if(pieces.length===1&&missing!==0||pieces.length===2&&missing<0)return null;let groups=[...left,...Array(missing).fill("0"),...right].map(part=>/^[0-9a-f]{1,4}$/i.test(part)?parseInt(part,16):-1);return groups.length===8&&groups.every(group=>group>=0&&group<=65535)?groups:null}function parseAllowRanges(input){if(input==null)return[];if(!Array.isArray(input))throw new Error("ssrf.allowRanges must be an array of CIDR strings");let rules=[];for(let entry of input){if(typeof entry!="string")throw new Error(`ssrf.allowRanges entries must be strings, got ${typeof entry}`);let rule=parseCidr(entry.trim());if(!rule)throw new Error(`Invalid CIDR notation in ssrf.allowRanges: "${entry}"`);rules.push(rule)}return rules}function parseCidr(raw){if(!raw)return null;let slash=raw.lastIndexOf("/"),addrPart=slash>=0?raw.slice(0,slash):raw,prefixPart=slash>=0?raw.slice(slash+1):null;if(prefixPart!==null&&!/^\d+$/.test(prefixPart))return null;let version=net.isIP(addrPart);if(version===4){let bytes=ipv4ToBytes(addrPart);if(!bytes)return null;let prefix=prefixPart===null?32:Number(prefixPart);return!Number.isInteger(prefix)||prefix<1||prefix>32?null:{bytes,prefix}}if(version===6){let groups=parseIPv6(addrPart);if(!groups)return null;let prefix=prefixPart===null?128:Number(prefixPart);return!Number.isInteger(prefix)||prefix<1||prefix>128?null:{bytes:ipv6GroupsToBytes(groups),prefix}}return null}function ipv4ToBytes(address){let parts=address.split(".");if(parts.length!==4)return null;let bytes=new Uint8Array(4);for(let i=0;i<4;i++){let octet=Number(parts[i]);if(!Number.isInteger(octet)||octet<0||octet>255)return null;bytes[i]=octet}return bytes}function ipv6GroupsToBytes(groups){let bytes=new Uint8Array(16);for(let i=0;i<8;i++)bytes[i*2]=groups[i]>>8,bytes[i*2+1]=groups[i]&255;return bytes}function ipToBytes(address,version){if(version===4)return ipv4ToBytes(address);if(version===6){let groups=parseIPv6(address);return groups?ipv6GroupsToBytes(groups):null}return null}function isInAllowedRange(address,ipVersion,allowRanges){if(allowRanges.length===0)return!1;let addrBytes=ipToBytes(address,ipVersion);if(!addrBytes)return!1;for(let rule of allowRanges)if(rule.bytes.length===addrBytes.length&&bytesMatchPrefix(addrBytes,rule.bytes,rule.prefix))return!0;return!1}function bytesMatchPrefix(addr,network,prefix){let fullBytes=prefix>>3,remBits=prefix&7;for(let i=0;i<fullBytes;i++)if(addr[i]!==network[i])return!1;if(remBits>0&&fullBytes<addr.length){let mask=255<<8-remBits&255;if((addr[fullBytes]&mask)!==(network[fullBytes]&mask))return!1}return!0}import{existsSync as existsSync11,readFileSync as readFileSync11}from"node:fs";import net2 from"node:net";var CONFIG_PATH8=getWebSearchConfigPath(),DEFAULT_API_VERSION="v2",EXTRACT_TIMEOUT_MS=6e4,SEARCH_TIMEOUT_MS5=6e4,DEFAULT_MAX_REDIRECTS2=5,REDIRECT_STATUSES2=new Set([301,302,303,307,308]),SUPPORTED_API_VERSIONS=["v1","v2"],cachedConfig7=null;function loadConfig6(){if(cachedConfig7)return cachedConfig7;if(!existsSync11(CONFIG_PATH8))return cachedConfig7={},cachedConfig7;let raw=readFileSync11(CONFIG_PATH8,"utf8"),parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH8}: ${message}`)}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error(`Invalid config in ${CONFIG_PATH8}: expected a JSON object`);return cachedConfig7=parsed,cachedConfig7}function normalizeBaseUrl(value){if(typeof value!="string")return null;let trimmed=value.trim();if(!trimmed)return null;let parsed;try{parsed=new URL(trimmed)}catch{throw new Error(`Invalid Firecrawl base URL in ${CONFIG_PATH8}: expected an HTTP or HTTPS URL`)}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:")throw new Error(`Invalid Firecrawl base URL in ${CONFIG_PATH8}: expected an HTTP or HTTPS URL`);if(parsed.username||parsed.password)throw new Error(`Invalid Firecrawl base URL in ${CONFIG_PATH8}: URL credentials are not allowed`);return parsed.pathname=parsed.pathname.replace(/\/+$/,""),parsed.search="",parsed.hash="",parsed.toString().replace(/\/+$/,"")}function getBaseUrl(){return normalizeBaseUrl(process.env.FIRECRAWL_BASE_URL)??normalizeBaseUrl(loadConfig6().firecrawlBaseUrl)}function requireBaseUrl(){let baseUrl=getBaseUrl();if(!baseUrl)throw new Error(`Firecrawl base URL not configured. Either:
69
+ 1. Set firecrawlBaseUrl in ${CONFIG_PATH8}
70
+ 2. Set FIRECRAWL_BASE_URL environment variable`);return baseUrl}function getApiVersion(){let raw=(typeof process.env.FIRECRAWL_API_VERSION=="string"?process.env.FIRECRAWL_API_VERSION.trim():"")||loadConfig6().firecrawlApiVersion;if(raw==null)return DEFAULT_API_VERSION;if(typeof raw!="string")throw new Error(`firecrawlApiVersion in ${CONFIG_PATH8} must be a string ("v1" or "v2")`);let normalized=raw.trim().toLowerCase();if(!normalized)return DEFAULT_API_VERSION;if(!SUPPORTED_API_VERSIONS.includes(normalized))throw new Error(`Unsupported Firecrawl API version "${raw}". Supported versions: ${SUPPORTED_API_VERSIONS.join(", ")}`);return normalized}function allowFreshScrape(){let environmentValue=process.env.FIRECRAWL_FRESH_SCRAPE;if(environmentValue!==void 0)return environmentValue==="1"||environmentValue.toLowerCase()==="true";let configured=loadConfig6().firecrawlFreshScrape;if(configured==null)return!1;if(typeof configured!="boolean")throw new Error(`firecrawlFreshScrape in ${CONFIG_PATH8} must be a boolean`);return configured}async function getApiKey5(signal){let configKey=loadConfig6().firecrawlApiKey;return resolveCredential({provider:"Firecrawl",configuredValue:configKey,environmentValue:process.env.FIRECRAWL_API_KEY,signal})}function requestSignal6(timeoutMs,signal){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([timeout,signal]):timeout}function errorMessage6(err){return err instanceof Error?err.message:String(err)}function isAbortError(err){return errorMessage6(err).toLowerCase().includes("abort")}function ssrfOptions(options){let config=loadSsrfConfig();return{allowRanges:options?.ssrf?.allowRanges??config.allowRanges,trustEnvProxy:options?.ssrf?.trustEnvProxy??config.trustEnvProxy,...options?.lookup?{lookup:options.lookup}:{}}}function isLoopbackApiUrl(url){let hostname2=url.hostname.toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"");return hostname2==="localhost"||hostname2==="::1"?!0:net2.isIP(hostname2)!==4?!1:hostname2.split(".")[0]==="127"}function firecrawlApiSsrfOptions(options,allowLoopback){return{...ssrfOptions(options),allowLoopback}}function withoutSensitiveHeaders(headers){let next={...headers};return delete next.Authorization,delete next.authorization,delete next.Cookie,delete next.cookie,delete next["X-API-Key"],delete next["x-api-key"],next}async function fetchFirecrawlApi(url,init,options){let allowLoopback=isLoopbackApiUrl(new URL(url)),current=await validateRemoteUrl(url,firecrawlApiSsrfOptions(options,allowLoopback)),headers=init.headers;for(let redirects=0;redirects<=DEFAULT_MAX_REDIRECTS2;redirects++){let response=await fetch(current,{...init,headers,redirect:"manual"});if(!REDIRECT_STATUSES2.has(response.status))return response;let location=response.headers.get("location");if(!location)return response;if(redirects===DEFAULT_MAX_REDIRECTS2)throw new Error(`Too many redirects fetching ${current.toString()}`);let next=await validateRemoteUrl(new URL(location,current),firecrawlApiSsrfOptions(options,allowLoopback));next.origin!==current.origin&&(headers=withoutSensitiveHeaders(headers)),current=next}throw new Error(`Too many redirects fetching ${current.toString()}`)}function scrapeBody(url){return{url,formats:["markdown"],onlyMainContent:!0,...allowFreshScrape()?{}:{lockdown:!0}}}function normalizeCount(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),20))}function normalizeDomain6(value){let input=value.trim().toLowerCase();if(!input||(input.startsWith("-")&&(input=input.slice(1).trim()),!input))return null;try{input=(input.includes("://")?new URL(input):new URL(`https://${input}`)).hostname}catch{input=input.split("/")[0]?.split(":")[0]??""}return input=input.replace(/^\.+|\.+$/g,""),/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input)?input:null}function parseDomainFilter(domainFilter){let filters={include:[],exclude:[]};for(let raw of domainFilter??[]){let domain=normalizeDomain6(raw);if(!domain)continue;let target=raw.trim().startsWith("-")?filters.exclude:filters.include;target.includes(domain)||target.push(domain)}return filters}function passesDomainFilters(url,filters){if(filters.include.length===0&&filters.exclude.length===0)return!0;let hostname2;try{hostname2=new URL(url).hostname.toLowerCase()}catch{return!1}let matches=domain=>hostname2===domain||hostname2.endsWith(`.${domain}`);return filters.exclude.some(matches)?!1:filters.include.length===0||filters.include.some(matches)}function mapRecencyFilter2(value){switch(value){case"day":return"qdr:d";case"week":return"qdr:w";case"month":return"qdr:m";case"year":return"qdr:y";default:return}}function searchBody(query,options,numResults,filters){return{query,limit:numResults,sources:["web"],...filters.include.length>0?{includeDomains:filters.include}:{},...filters.include.length===0&&filters.exclude.length>0?{excludeDomains:filters.exclude}:{},...mapRecencyFilter2(options.recencyFilter)?{tbs:mapRecencyFilter2(options.recencyFilter)}:{},...options.includeContent?{scrapeOptions:{formats:["markdown"],onlyMainContent:!0,...allowFreshScrape()?{}:{lockdown:!0}}}:{}}}function firstString(...values){for(let value of values)if(typeof value=="string"&&value.trim())return value.trim();return null}function buildAnswer4(results){return results.map(result=>result.snippet?`${result.snippet}
71
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
72
+
73
+ `)}function mapSearchResults5(data,numResults,filters){let web=Array.isArray(data)?data:data&&typeof data=="object"?data.web:void 0;if(!Array.isArray(web))throw new Error("Firecrawl search returned an unexpected web result shape");let results=[],inlineContent=[],seen=new Set;for(let rawItem of web){if(!rawItem||typeof rawItem!="object"||Array.isArray(rawItem))continue;let item=rawItem,url=firstString(item.url,item.metadata?.sourceURL,item.metadata?.url);if(!url||seen.has(url)||!passesDomainFilters(url,filters))continue;seen.add(url);let title=firstString(item.title,item.metadata?.title)??url,snippet=firstString(item.description,item.snippet,item.metadata?.description)??"";results.push({title,url,snippet});let markdown=firstString(item.markdown);if(markdown&&inlineContent.push({url,title,content:markdown,error:null}),results.length>=numResults)break}return{results,inlineContent}}async function firecrawlFetch(endpoint,body,signal,options,label=endpoint,activity=void 0){let baseUrl=requireBaseUrl(),version=getApiVersion(),apiKey=await getApiKey5(signal),headers={"Content-Type":"application/json"};apiKey&&(headers.Authorization=`Bearer ${apiKey}`);let requestUrl=`${baseUrl}/${version}/${endpoint}`,activityId=activityMonitor.logStart(activity??{type:"fetch",url:requestUrl});try{let response=await fetchFirecrawlApi(requestUrl,{method:"POST",headers,body:JSON.stringify(body),signal:requestSignal6(options?.timeoutMs??EXTRACT_TIMEOUT_MS,signal)},options);if(!response.ok){let text=await response.text().catch(()=>"");throw new Error(`Firecrawl ${label} error ${response.status}: ${redactCredential(text.slice(0,300),apiKey)}`)}let data;try{data=await response.json()}catch(err){throw new Error(`Firecrawl ${label} returned invalid JSON: ${errorMessage6(err)}`)}if(!data||typeof data!="object"||Array.isArray(data))throw new Error(`Firecrawl ${label} returned an unexpected response shape`);let envelope=data;if(envelope.success===!1){let reason=typeof envelope.error=="string"&&envelope.error.trim()?envelope.error:"unknown error";throw new Error(`Firecrawl ${label} unsuccessful: ${redactCredential(reason,apiKey)}`)}if(envelope.success!==!0)throw new Error(`Firecrawl ${label} returned an unexpected response shape`);return activityMonitor.logComplete(activityId,response.status),envelope}catch(err){throw isAbortError(err)?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,errorMessage6(err)),err}}function isFirecrawlAvailable(){return getBaseUrl()!==null}async function searchWithFirecrawl(query,options={}){requireBaseUrl();let numResults=normalizeCount(options.numResults),filters=parseDomainFilter(options.domainFilter),envelope=await firecrawlFetch("search",searchBody(query,options,numResults,filters),options.signal,{...options,timeoutMs:options.timeoutMs??SEARCH_TIMEOUT_MS5},"search",{type:"api",query}),mapped=mapSearchResults5(envelope.data,numResults,filters),response={answer:buildAnswer4(mapped.results),results:mapped.results};return options.includeContent&&mapped.inlineContent.length>0&&(response.inlineContent=mapped.inlineContent),response}async function extractWithFirecrawl(url,signal,options){requireBaseUrl(),await validateRemoteUrl(url,ssrfOptions(options));let data=(await firecrawlFetch("scrape",scrapeBody(url),signal,options)).data;if(!data||typeof data!="object"||Array.isArray(data))throw new Error("Firecrawl scrape returned an unexpected data shape");let scrape=data;if(typeof scrape.markdown!="string")throw new Error("Firecrawl scrape returned markdown in an unexpected shape");let content=scrape.markdown.trim();if(!content)return null;let metadataTitle=scrape.metadata?.title,title=typeof metadataTitle=="string"&&metadataTitle.trim()?metadataTitle.trim():typeof scrape.title=="string"?scrape.title.trim():"";return{url,title,content,error:null}}import{existsSync as existsSync12,readFileSync as readFileSync12}from"node:fs";var KAGI_SEARCH_URL="https://kagi.com/api/v1/search",KAGI_EXTRACT_URL="https://kagi.com/api/v1/extract",CONFIG_PATH9=getWebSearchConfigPath(),SEARCH_TIMEOUT_MS6=6e4,cachedConfig8=null;function loadConfig7(){if(cachedConfig8)return cachedConfig8;if(!existsSync12(CONFIG_PATH9))return cachedConfig8={},cachedConfig8;let raw=readFileSync12(CONFIG_PATH9,"utf-8"),parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH9}: ${message}`)}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error(`Invalid config in ${CONFIG_PATH9}: expected a JSON object`);return cachedConfig8=parsed,cachedConfig8}async function getApiKey6(signal){return resolveCredential({provider:"Kagi",configuredValue:loadConfig7().kagiApiKey,environmentValue:process.env.KAGI_API_KEY,signal})}async function requireApiKey(signal){let apiKey=await getApiKey6(signal);if(!apiKey)throw new Error(`Kagi API key not found. Either:
74
+ 1. Create ${CONFIG_PATH9} with { "kagiApiKey": "your-key" }
75
+ 2. Set KAGI_API_KEY environment variable
76
+ Create a key at https://kagi.com/settings?p=api`);return apiKey}function normalizeCount2(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),20))}function errorMessage7(err){return err instanceof Error?err.message:String(err)}function invalidResponse(message){return new Error(`Kagi API returned invalid response: ${message}`)}function firstString2(...values){for(let value of values)if(typeof value=="string"&&value.trim())return value.trim();return null}function appendSearchItems(value,results,inlineContent){if(Array.isArray(value)){for(let item2 of value)appendSearchItems(item2,results,inlineContent);return}if(!value||typeof value!="object")return;let item=value,url=firstString2(item.url,item.href,item.link);if(!url)return;let title=firstString2(item.title,item.name)??url,snippet=firstString2(item.snippet,item.description,item.summary,item.content,item.markdown,item.text)??"";results.push({title,url,snippet});let content=firstString2(item.markdown,item.content,item.text);content&&inlineContent.push({url,title,content,error:null})}function parseErrors(value){if(!value||typeof value!="object"||Array.isArray(value))return null;let envelope=value,rawErrors=envelope.errors??envelope.error;if(!Array.isArray(rawErrors))return null;let messages=rawErrors.map(entry=>{if(!entry||typeof entry!="object")return String(entry);let raw=entry;return firstString2(raw.message,raw.msg,raw.code)??JSON.stringify(raw)});return messages.length>0?messages.join("; "):null}function parseSearchResponse(value){if(!value||typeof value!="object"||Array.isArray(value))throw invalidResponse("expected an object envelope");let message=parseErrors(value);if(message)throw invalidResponse(message);let envelope=value,results=[],inlineContent=[],data=envelope.data,items=typeof data=="object"&&data!==null&&!Array.isArray(data)?data.search:data;return appendSearchItems(items,results,inlineContent),{results,inlineContent}}function parseExtractResponse(value,requestedUrl){if(!value||typeof value!="object"||Array.isArray(value))throw invalidResponse("expected extract object envelope");let message=parseErrors(value);if(message)throw invalidResponse(message);let envelope=value,candidates=Array.isArray(envelope.data)?envelope.data:[envelope.data??envelope];for(let candidate of candidates){if(!candidate||typeof candidate!="object"||Array.isArray(candidate))continue;let item=candidate,content=firstString2(item.markdown,item.content,item.text);if(content)return{url:firstString2(item.url,item.href,item.link)??requestedUrl,title:firstString2(item.title,item.name)??requestedUrl,content,error:null}}return null}function buildAnswer5(results){return results.map(result=>result.snippet?`${result.snippet}
77
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
78
+
79
+ `)}function isKagiAvailable(){return hasCredentialSource({provider:"Kagi",configuredValue:loadConfig7().kagiApiKey,environmentValue:process.env.KAGI_API_KEY})}async function searchWithKagi(query,options={}){let apiKey=await requireApiKey(options.signal),numResults=normalizeCount2(options.numResults),activityId=activityMonitor.logStart({type:"api",query}),response;try{response=await fetch(KAGI_SEARCH_URL,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({query,limit:numResults}),signal:options.signal?AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS6),options.signal]):AbortSignal.timeout(SEARCH_TIMEOUT_MS6)})}catch(err){let message=errorMessage7(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Kagi API error ${response.status}: ${errorText.slice(0,300)}`)}let rawData;try{rawData=await response.json()}catch(err){throw activityMonitor.logComplete(activityId,response.status),new Error(`Kagi API returned invalid JSON: ${errorMessage7(err)}`)}let parsed=parseSearchResponse(rawData);activityMonitor.logComplete(activityId,response.status);let results=parsed.results.slice(0,numResults),mapped={answer:buildAnswer5(results),results};if(options.includeContent){let urls=new Set(results.map(result=>result.url)),inlineContent=parsed.inlineContent.filter(content=>urls.has(content.url));inlineContent.length>0&&(mapped.inlineContent=inlineContent)}return mapped}function isKagiExtractAvailable(){return isKagiAvailable()}async function extractWithKagi(url,signal,options={}){let ssrf=options.ssrf??loadSsrfConfig(),domainPolicy=loadFetchContentDomainPolicy();await validateRemoteUrl(url,{allowRanges:ssrf.allowRanges,trustEnvProxy:ssrf.trustEnvProxy,domainPolicy,...options.lookup?{lookup:options.lookup}:{}});let apiKey=await requireApiKey(signal),activityId=activityMonitor.logStart({type:"api",query:`kagi extract: ${url}`}),response;try{response=await fetchRemoteUrl(KAGI_EXTRACT_URL,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({pages:[{url}]}),signal:signal?AbortSignal.any([AbortSignal.timeout(options.timeoutMs??SEARCH_TIMEOUT_MS6),signal]):AbortSignal.timeout(options.timeoutMs??SEARCH_TIMEOUT_MS6)},{allowRanges:ssrf.allowRanges,trustEnvProxy:ssrf.trustEnvProxy,onRedirect:({from,to,init})=>to.origin===from.origin?init:{...init,headers:{"Content-Type":"application/json",Accept:"application/json"}},...options.lookup?{lookup:options.lookup}:{}})}catch(err){let message=errorMessage7(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Kagi Extract API error ${response.status}: ${errorText.slice(0,300)}`)}let rawData;try{rawData=await response.json()}catch(err){throw activityMonitor.logComplete(activityId,response.status),new Error(`Kagi Extract API returned invalid JSON: ${errorMessage7(err)}`)}let parsed=parseExtractResponse(rawData,url);return activityMonitor.logComplete(activityId,response.status),parsed}import{existsSync as existsSync13,readFileSync as readFileSync13}from"node:fs";var OLLAMA_SEARCH_URL="https://ollama.com/api/web_search",OLLAMA_FETCH_URL="https://ollama.com/api/web_fetch",CONFIG_PATH10=getWebSearchConfigPath(),SEARCH_TIMEOUT_MS7=6e4,cachedConfig9=null;function loadConfig8(){if(cachedConfig9)return cachedConfig9;if(!existsSync13(CONFIG_PATH10))return cachedConfig9={},cachedConfig9;let raw=readFileSync13(CONFIG_PATH10,"utf-8"),parsed;try{parsed=JSON.parse(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH10}: ${message}`)}if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error(`Invalid config in ${CONFIG_PATH10}: expected a JSON object`);return cachedConfig9=parsed,cachedConfig9}async function getApiKey7(signal){return resolveCredential({provider:"Ollama",configuredValue:loadConfig8().ollamaApiKey,environmentValue:process.env.OLLAMA_API_KEY,signal})}async function requireApiKey2(signal){let apiKey=await getApiKey7(signal);if(!apiKey)throw new Error(`Ollama API key not found. Either:
80
+ 1. Create ${CONFIG_PATH10} with { "ollamaApiKey": "your-key" }
81
+ 2. Set OLLAMA_API_KEY environment variable
82
+ Create a key at https://ollama.com/settings/keys`);return apiKey}function normalizeCount3(value){return typeof value!="number"||!Number.isFinite(value)?5:Math.max(1,Math.min(Math.floor(value),10))}function errorMessage8(err){return err instanceof Error?err.message:String(err)}function invalidResponse2(message){return new Error(`Ollama API returned invalid response: ${message}`)}function parseSearchResponse2(value){if(!value||typeof value!="object"||Array.isArray(value))throw invalidResponse2("expected an object envelope");let envelope=value;if(!Array.isArray(envelope.results))throw invalidResponse2("expected results array");let results=[];for(let[index,value2]of envelope.results.entries()){if(!value2||typeof value2!="object"||Array.isArray(value2))throw invalidResponse2(`expected results[${index}] object`);let item=value2;if(typeof item.title!="string")throw invalidResponse2(`expected results[${index}].title string`);if(typeof item.url!="string"||!item.url)throw invalidResponse2(`expected results[${index}].url non-empty string`);if(typeof item.content!="string")throw invalidResponse2(`expected results[${index}].content string`);results.push({title:item.title,url:item.url,content:item.content})}return{results}}function parseFetchResponse(value){if(!value||typeof value!="object"||Array.isArray(value))throw invalidResponse2("expected fetch object envelope");let envelope=value;if(typeof envelope.title!="string")throw invalidResponse2("expected title string");if(typeof envelope.content!="string")throw invalidResponse2("expected content string");return{title:envelope.title,content:envelope.content,links:envelope.links}}function buildAnswer6(results){return results.map(result=>result.snippet?`${result.snippet}
83
+ Source: ${result.title} (${result.url})`:`Source: ${result.title} (${result.url})`).join(`
84
+
85
+ `)}function isOllamaAvailable(){return hasCredentialSource({provider:"Ollama",configuredValue:loadConfig8().ollamaApiKey,environmentValue:process.env.OLLAMA_API_KEY})}async function searchWithOllama(query,options={}){let apiKey=await requireApiKey2(options.signal),numResults=normalizeCount3(options.numResults),activityId=activityMonitor.logStart({type:"api",query}),response;try{response=await fetch(OLLAMA_SEARCH_URL,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({query,max_results:numResults}),signal:options.signal?AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS7),options.signal]):AbortSignal.timeout(SEARCH_TIMEOUT_MS7)})}catch(err){let message=errorMessage8(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Ollama API error ${response.status}: ${errorText.slice(0,300)}`)}let rawData;try{rawData=await response.json()}catch(err){throw activityMonitor.logComplete(activityId,response.status),new Error(`Ollama API returned invalid JSON: ${errorMessage8(err)}`)}let data=parseSearchResponse2(rawData);activityMonitor.logComplete(activityId,response.status);let results=data.results.slice(0,numResults).map(result=>({title:result.title,url:result.url,snippet:result.content})),mapped={answer:buildAnswer6(results),results};if(options.includeContent){let inlineContent=data.results.slice(0,numResults).filter(result=>result.content.trim().length>0).map(result=>({url:result.url,title:result.title,content:result.content,error:null}));inlineContent.length>0&&(mapped.inlineContent=inlineContent)}return mapped}function isOllamaFetchAvailable(){return isOllamaAvailable()}async function extractWithOllama(url,signal,options={}){let ssrf=options.ssrf??loadSsrfConfig(),domainPolicy=loadFetchContentDomainPolicy();await validateRemoteUrl(url,{allowRanges:ssrf.allowRanges,trustEnvProxy:ssrf.trustEnvProxy,domainPolicy,...options.lookup?{lookup:options.lookup}:{}});let apiKey=await requireApiKey2(signal),activityId=activityMonitor.logStart({type:"api",query:`ollama fetch: ${url}`}),response;try{response=await fetchRemoteUrl(OLLAMA_FETCH_URL,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({url}),signal:signal?AbortSignal.any([AbortSignal.timeout(options.timeoutMs??SEARCH_TIMEOUT_MS7),signal]):AbortSignal.timeout(options.timeoutMs??SEARCH_TIMEOUT_MS7)},{allowRanges:ssrf.allowRanges,trustEnvProxy:ssrf.trustEnvProxy,onRedirect:({from,to,init})=>to.origin===from.origin?init:{...init,headers:{"Content-Type":"application/json"}},...options.lookup?{lookup:options.lookup}:{}})}catch(err){let message=errorMessage8(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Ollama Web Fetch error ${response.status}: ${errorText.slice(0,300)}`)}let rawData;try{rawData=await response.json()}catch(err){throw activityMonitor.logComplete(activityId,response.status),new Error(`Ollama Web Fetch returned invalid JSON: ${errorMessage8(err)}`)}let data=parseFetchResponse(rawData);activityMonitor.logComplete(activityId,response.status);let content=data.content.trim();return content?{url,title:data.title,content,error:null}:null}import{existsSync as existsSync14,readFileSync as readFileSync14}from"node:fs";import{createSign}from"node:crypto";import{homedir as homedir2}from"node:os";import{join as join4}from"node:path";var CONFIG_PATH11=getWebSearchConfigPath(),DEFAULT_ADC_PATH=join4(homedir2(),".config","gcloud","application_default_credentials.json"),TOKEN_ENDPOINT="https://oauth2.googleapis.com/token",VERTEX_HOST="https://aiplatform.googleapis.com",VERTEX_API_VERSION="v1",REFRESH_SKEW_MS=6e4,cachedConfig10=null;function loadConfig9(){if(cachedConfig10)return cachedConfig10;if(!existsSync14(CONFIG_PATH11))return cachedConfig10={},cachedConfig10;let raw=readFileSync14(CONFIG_PATH11,"utf-8");try{let parsed=JSON.parse(raw);if(!parsed||typeof parsed!="object"||Array.isArray(parsed))throw new Error("config root must be an object");cachedConfig10=parsed}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH11}: ${message}`)}return cachedConfig10}function normalizeIdentifier(value,envName){if(typeof value=="string"){let trimmed=value.trim();if(trimmed)return trimmed}let fromEnv=process.env[envName]?.trim();return fromEnv||null}function isAdcAuthSelected(){return(loadConfig9().geminiAuth??"").toString().trim().toLowerCase()==="adc"}function getAdcProject(){return normalizeIdentifier(loadConfig9().geminiProject,"GOOGLE_CLOUD_PROJECT")??normalizeIdentifier(null,"GCLOUD_PROJECT")}function getAdcLocation(){return normalizeIdentifier(loadConfig9().geminiLocation,"GOOGLE_CLOUD_LOCATION")}function getAdcPath(){return process.env.GOOGLE_APPLICATION_CREDENTIALS?.trim()||DEFAULT_ADC_PATH}function getVertexApiBase(project,location){return`${VERTEX_HOST}/${VERTEX_API_VERSION}/projects/${encodeURIComponent(project)}/locations/${encodeURIComponent(location)}/publishers/google`}function isVertexHost(origin){return origin===VERTEX_HOST}function objectRecord(value){return value&&typeof value=="object"&&!Array.isArray(value)?value:null}function stringField(record,name){let value=record[name];return typeof value=="string"?value:void 0}function requiredString(record,name,context){let value=stringField(record,name)?.trim();if(!value)throw new Error(`${context} is missing ${name}`);return value}function parseAdcFile(raw){let parsed=objectRecord(JSON.parse(raw));if(!parsed)throw new Error("credential root must be an object");let type=stringField(parsed,"type")??"authorized_user";return type==="authorized_user"?{type,client_id:requiredString(parsed,"client_id","Gemini ADC authorized_user file"),client_secret:requiredString(parsed,"client_secret","Gemini ADC authorized_user file"),refresh_token:requiredString(parsed,"refresh_token","Gemini ADC authorized_user file"),universe_domain:stringField(parsed,"universe_domain")}:type==="service_account"?{type,client_email:requiredString(parsed,"client_email","Gemini ADC service_account file"),private_key:requiredString(parsed,"private_key","Gemini ADC service_account file"),private_key_id:stringField(parsed,"private_key_id"),token_uri:stringField(parsed,"token_uri"),universe_domain:stringField(parsed,"universe_domain")}:{type}}function parseTokenExchangeResponse(text,context){let raw;try{raw=JSON.parse(text)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`${context} returned invalid JSON: ${message}`)}let parsed=objectRecord(raw);if(!parsed)throw new Error(`${context} returned a non-object response`);let token=stringField(parsed,"access_token")?.trim();if(!token)throw new Error(`${context} returned no access_token`);let expiresIn=parsed.expires_in??3600;if(typeof expiresIn!="number"||!Number.isFinite(expiresIn))throw new Error(`${context} returned invalid expires_in`);return{token,expiresAt:Date.now()+Math.max(expiresIn*1e3-REFRESH_SKEW_MS,6e4)}}async function loadAdcFile(){let path=getAdcPath();if(!path||!existsSync14(path))throw new Error(`Google Application Default Credentials file not found at ${path}`);let raw=readFileSync14(path,"utf-8");try{return parseAdcFile(raw)}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse Google Application Default Credentials file at ${path}: ${message}`)}}var cachedToken=null;var OAUTH_CREDENTIAL_REJECTION_STATUSES=new Set([400,401,403]);function throwOnTokenExchangeFailure(res,detail,status){throw OAUTH_CREDENTIAL_REJECTION_STATUSES.has(status)?new CredentialResolutionError("Gemini ADC","oauth-credential-rejected"):new Error(`Gemini ADC token exchange failed (${status}): ${detail.slice(0,300)}`)}function redactValues(text,values){let redacted=text;for(let value of values)value&&(redacted=redactCredential(redacted,value));return redacted}async function exchangeRefreshToken(cfg,signal){let body=new URLSearchParams({client_id:cfg.client_id??"",client_secret:cfg.client_secret??"",refresh_token:cfg.refresh_token??"",grant_type:"refresh_token"}),res=await fetch(TOKEN_ENDPOINT,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body,signal}),text=await res.text();return res.ok||throwOnTokenExchangeFailure(res,redactValues(text,[cfg.client_secret,cfg.refresh_token]),res.status),parseTokenExchangeResponse(text,"Gemini ADC token exchange")}async function exchangeServiceAccountJwt(cfg,signal){if(!cfg.client_email||!cfg.private_key)throw new Error("Gemini ADC service_account file is missing client_email or private_key");let now=Math.floor(Date.now()/1e3),header={alg:"RS256",typ:"JWT"},claims={iss:cfg.client_email,scope:"https://www.googleapis.com/auth/cloud-platform",aud:TOKEN_ENDPOINT,iat:now,exp:now+3600},encodePart=obj=>Buffer.from(JSON.stringify(obj)).toString("base64url"),assertion=`${encodePart(header)}.${encodePart(claims)}`,signer=createSign("RSA-SHA256");signer.update(assertion),signer.end();let signature=signer.sign(cfg.private_key,"base64url"),jwt=`${assertion}.${signature}`,body=new URLSearchParams({grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:jwt}),res=await fetch(TOKEN_ENDPOINT,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body,signal}),text=await res.text();return res.ok||throwOnTokenExchangeFailure(res,redactValues(text,[jwt,cfg.private_key]),res.status),parseTokenExchangeResponse(text,"Gemini ADC service account token exchange")}async function getAdcAccessToken(signal){if(cachedToken&&cachedToken.expiresAt>Date.now())return cachedToken.token;let cfg=await loadAdcFile(),type=cfg.type??"authorized_user";if(type==="authorized_user")cachedToken=await exchangeRefreshToken(cfg,signal);else if(type==="service_account")cachedToken=await exchangeServiceAccountJwt(cfg,signal);else throw new Error(`Gemini ADC unsupported credential type "${type}" (expected authorized_user or service_account)`);return cachedToken.token}function isGeminiAdcAvailable(){return!isAdcAuthSelected()||hasGeminiApiKeySource()||hasExplicitApiBase()||!getAdcProject()||!getAdcLocation()?!1:existsSync14(getAdcPath())}function hasGeminiApiKeySource(){let configured=loadConfig9().geminiApiKey;return typeof configured=="string"&&configured.trim()?!0:!!process.env.GEMINI_API_KEY?.trim()}function hasExplicitApiBase(){if(process.env.GOOGLE_GEMINI_BASE_URL?.trim())return!0;let configured=loadConfig9().geminiBaseUrl;return typeof configured=="string"&&configured.trim().length>0}import{existsSync as existsSync15,readFileSync as readFileSync15}from"node:fs";var DEFAULT_API_HOST="https://generativelanguage.googleapis.com",API_VERSION="v1beta",API_BASE=`${DEFAULT_API_HOST}/${API_VERSION}`,CONFIG_PATH12=getWebSearchConfigPath(),DEFAULT_MODEL="gemini-3.6-flash",cachedConfig11=null;function loadConfig10(){if(cachedConfig11)return cachedConfig11;if(!existsSync15(CONFIG_PATH12))return cachedConfig11={},cachedConfig11;let raw=readFileSync15(CONFIG_PATH12,"utf-8");try{return cachedConfig11=JSON.parse(raw),cachedConfig11}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH12}: ${message}`)}}function withTimeout(signal,timeoutMs){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([signal,timeout]):timeout}function normalizeApiKey2(value){if(typeof value!="string")return null;let normalized=value.trim();return normalized.length>0?normalized:null}function normalizeBaseUrl2(value){if(typeof value!="string")return null;let normalized=value.trim().replace(/\/+$/,"");return normalized.length>0?normalized:null}function isCloudflareGateway(){return getApiHost().includes("gateway.ai.cloudflare.com")}async function getApiKey8(signal){return resolveCredential({provider:"Gemini",configuredValue:loadConfig10().geminiApiKey,environmentValue:process.env.GEMINI_API_KEY,signal})}function getApiHost(){return normalizeBaseUrl2(process.env.GOOGLE_GEMINI_BASE_URL)??normalizeBaseUrl2(loadConfig10().geminiBaseUrl)??DEFAULT_API_HOST}function getVersionedApiBase(){let project=getAdcProject(),location=getAdcLocation();return isGeminiAdcAvailable()&&project&&location?getVertexApiBase(project,location):`${getApiHost()}/${API_VERSION}`}function getUploadBase(){return`${getApiHost()}/upload/${API_VERSION}`}function getLegacyCloudflareApiKey(){return normalizeApiKey2(process.env.CLOUDFLARE_API_KEY)??normalizeApiKey2(loadConfig10().cloudflareApiKey)}async function resolveCloudflareApiKey(signal){return resolveCredential({provider:"Cloudflare",configuredValue:loadConfig10().cloudflareApiKey,environmentValue:process.env.CLOUDFLARE_API_KEY,signal})}function isGatewayConfigured(){return isCloudflareGateway()&&hasCredentialSource({provider:"Cloudflare",configuredValue:loadConfig10().cloudflareApiKey,environmentValue:process.env.CLOUDFLARE_API_KEY})}function buildAuthHeaders(apiKey=null,cloudflareApiKey=getLegacyCloudflareApiKey()){return isCloudflareGateway()?cloudflareApiKey?{"cf-aig-authorization":`Bearer ${cloudflareApiKey}`}:{}:apiKey?{"x-goog-api-key":apiKey}:{}}function redactGeminiCredentials(text,apiKey,cloudflareApiKey,adcToken){let out=redactCredential(redactCredential(text,apiKey),cloudflareApiKey);return adcToken&&(out=redactCredential(out,adcToken)),out}var responseCredentials=new WeakMap;function redactGeminiApiResponse(response,text,apiKey,adcToken){let credentials=responseCredentials.get(response);return redactGeminiCredentials(text,credentials?.apiKey??apiKey,credentials?.cloudflareApiKey,credentials?.adcToken??adcToken)}async function fetchGeminiApi(url,init={},apiKey){let parsedUrl=new URL(url);for(let name of parsedUrl.searchParams.keys())if(["key","api_key"].includes(name.toLowerCase()))throw new Error("Gemini API credential query parameters are not allowed");let project=getAdcProject(),location=getAdcLocation(),adcMode=isGeminiAdcAvailable()&&!!project&&!!location&&isVertexHost(parsedUrl.origin),adcToken=null;adcMode&&(adcToken=await getAdcAccessToken(init.signal??void 0));let resolvedApiKey=adcMode?null:apiKey===void 0?await getApiKey8(init.signal??void 0):apiKey,cloudflareApiKey=isCloudflareGateway()?await resolveCloudflareApiKey(init.signal??void 0):null,allowedOrigins=new Set([new URL(getApiHost()).origin,new URL(DEFAULT_API_HOST).origin,...adcMode?[parsedUrl.origin]:[]]);if((resolvedApiKey||isGatewayConfigured()||adcMode)&&!allowedOrigins.has(parsedUrl.origin))throw new Error("Gemini API request host is not allowed");let headers=new Headers(init.headers);if(headers.delete("x-goog-api-key"),headers.delete("cf-aig-authorization"),headers.delete("authorization"),adcMode&&adcToken)headers.set("Authorization",`Bearer ${adcToken}`);else for(let[name,value]of Object.entries(buildAuthHeaders(resolvedApiKey,cloudflareApiKey)))headers.set(name,value);try{let response=await fetch(parsedUrl,{...init,headers});return responseCredentials.set(response,{apiKey:resolvedApiKey,cloudflareApiKey,adcToken}),response}catch(error){let message=error instanceof Error?error.message:String(error),redactedMessage=redactGeminiCredentials(message,resolvedApiKey,cloudflareApiKey,adcToken);if(redactedMessage===message)throw error;let redactedError=new Error(redactedMessage);throw error instanceof Error&&(redactedError.name=error.name),redactedError}}function hasGeminiApiKeySource2(){return hasCredentialSource({provider:"Gemini",configuredValue:loadConfig10().geminiApiKey,environmentValue:process.env.GEMINI_API_KEY})}function isGeminiApiAvailable(){return isGeminiAdcAvailable()||hasGeminiApiKeySource2()||isGatewayConfigured()}function isGeminiApiAvailableWithVideo(){return hasGeminiApiKeySource2()||isGatewayConfigured()}async function queryGeminiApiWithInlineData(prompt,data,mimeType,options={}){let signal=withTimeout(options.signal,options.timeoutMs??12e4),apiKey=isGeminiAdcAvailable()?null:options.apiKey??await getApiKey8(signal);if(!apiKey&&!isGatewayConfigured()&&!isGeminiAdcAvailable())throw new Error(`Gemini API not configured. Either:
86
+ 1. Configure geminiApiKey in ${CONFIG_PATH12} or set GEMINI_API_KEY
87
+ 2. Set GOOGLE_GEMINI_BASE_URL + CLOUDFLARE_API_KEY for Cloudflare AI Gateway routing
88
+ 3. Set geminiAuth to "adc" with a Google Cloud ADC (GOOGLE_APPLICATION_CREDENTIALS) + project/location`);let model=options.model??DEFAULT_MODEL,url=`${getVersionedApiBase()}/models/${model}:generateContent`,res=await fetchGeminiApi(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contents:[{role:"user",parts:[{inlineData:{mimeType,data}},{text:prompt}]}]}),signal},apiKey);if(!res.ok){let errorText=redactGeminiApiResponse(res,await res.text(),apiKey);throw new Error(`Gemini API error ${res.status}: ${errorText.slice(0,300)}`)}let response=await res.json(),candidate=response.candidates?.[0];return{text:candidate?.content?.parts?.map(part=>part.text).filter(part=>typeof part=="string"&&part.length>0).join(`
89
+ `)??"",...candidate?.finishReason?{finishReason:candidate.finishReason}:{},...response.promptFeedback?.blockReason?{blockReason:response.promptFeedback.blockReason}:{}}}async function queryGeminiApiWithVideo(prompt,videoUri,options={}){let signal=withTimeout(options.signal,options.timeoutMs??12e4),apiKey=options.apiKey??await getApiKey8(signal);if(!apiKey&&!isGatewayConfigured())throw new Error(`Gemini API not configured. Either:
90
+ 1. Configure geminiApiKey in ${CONFIG_PATH12} or set GEMINI_API_KEY
91
+ 2. Set GOOGLE_GEMINI_BASE_URL + CLOUDFLARE_API_KEY for Cloudflare AI Gateway routing`);let model=options.model??DEFAULT_MODEL,url=`${getVersionedApiBase()}/models/${model}:generateContent`,fileData={fileUri:videoUri};options.mimeType&&(fileData.mimeType=options.mimeType);let res=await fetchGeminiApi(url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({contents:[{role:"user",parts:[{fileData},{text:prompt}]}]}),signal},apiKey);if(!res.ok){let errorText=redactGeminiApiResponse(res,await res.text(),apiKey);throw new Error(`Gemini API error ${res.status}: ${errorText.slice(0,300)}`)}let text=(await res.json()).candidates?.[0]?.content?.parts?.map(p=>p.text).filter(Boolean).join(`
92
+ `);if(!text)throw new Error("Gemini API returned empty response");return text}import{readFileSync as readFileSync16}from"node:fs";import{basename as basename2}from"node:path";var GEMINI_APP_URL="https://gemini.google.com/app",GEMINI_STREAM_GENERATE_URL="https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate",GEMINI_UPLOAD_URL="https://content-push.googleapis.com/upload",GEMINI_UPLOAD_PUSH_ID="feeds/mcudyrk2a4khkz",GOOGLE_LIST_ACCOUNTS_URL="https://accounts.google.com/ListAccounts?gpsia=1&source=ChromiumBrowser&laf=b64bin&json=standard",USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",MODEL_HEADER_NAME="x-goog-ext-525001261-jspb",DEFAULT_GEMINI_WEB_MODEL="gemini-3.1-pro",MODEL_HEADERS={[DEFAULT_GEMINI_WEB_MODEL]:'[1,null,null,null,"9d8ca3786ebdfbea",null,null,0,[4]]',"gemini-2.5-pro":'[1,null,null,null,"4af6c7f5da75d65d",null,null,0,[4]]',"gemini-2.5-flash":'[1,null,null,null,"9ec249fc9ad08861",null,null,0,[4]]'},REQUIRED_COOKIES=["__Secure-1PSID","__Secure-1PSIDTS"],geminiFetchImpl=null;var geminiFetchOverride=null,GEMINI_MAX_HEADER_SIZE=4*1024*1024;function createGeminiFetch(undiciImpl){let agent=new undiciImpl.EnvHttpProxyAgent({allowH2:!1,connectTimeout:3e4,maxHeaderSize:GEMINI_MAX_HEADER_SIZE,pipelining:1});return(input,init)=>undiciImpl.fetch(input,{...init,dispatcher:agent})}async function resolveGeminiFetch(){if(geminiFetchOverride)return geminiFetchOverride;if(geminiFetchImpl)return geminiFetchImpl;let undici;try{undici=await import("./undici-KA2LJNVT.js")}catch{return geminiFetchImpl=fetch,geminiFetchImpl}return geminiFetchImpl=createGeminiFetch(undici),geminiFetchImpl}async function isGeminiWebAvailable(chromeProfile){if(!isBrowserCookieAccessAllowed())return null;let configured=getBrowserCookieSelectionFromConfig(),result=await getGoogleCookies({browser:configured.browser,profile:normalizeChromeProfile(chromeProfile)??configured.profile,requiredCookies:REQUIRED_COOKIES});return result?result.cookies:null}function getGeminiWebAvailabilityDiagnostic(){return isBrowserCookieAccessAllowed()?getLastGoogleCookieDiagnostic():null}function getGeminiWebAvailabilityDiagnosticDetails(){return isBrowserCookieAccessAllowed()?getLastGoogleCookieDiagnosticDetails():null}async function getActiveGoogleEmail(cookies){let cookieHeader=buildCookieHeader2(cookies);if(!cookieHeader)return null;try{let html=await fetchWithCookieRedirects(GEMINI_APP_URL,cookieHeader,10,AbortSignal.timeout(1e4)),email=extractEmailFromGeminiHtml(html);if(email)return email}catch{}try{let response=await fetchWithCookieRedirects(GOOGLE_LIST_ACCOUNTS_URL,cookieHeader,10,AbortSignal.timeout(1e4));return extractEmailFromListAccounts(response)}catch{return null}}async function queryWithCookies(prompt,cookieMap,options={}){let model=options.model??DEFAULT_GEMINI_WEB_MODEL;if(!MODEL_HEADERS[model])throw new Error(`Gemini Web does not support model ${model}; configure Gemini API or choose a supported Gemini Web model.`);let timeoutMs=options.timeoutMs??12e4,fullPrompt=prompt;options.youtubeUrl&&(fullPrompt=`${fullPrompt}
93
+
94
+ YouTube video: ${options.youtubeUrl}`);let result=await runGeminiWebOnce(fullPrompt,cookieMap,model,options.files,timeoutMs,options.signal);if(result.errorMessage)throw new Error(result.errorMessage);if(!result.text)throw new Error("Gemini Web returned empty response");return result.text}async function runGeminiWebOnce(prompt,cookieMap,model,files,timeoutMs,signal){let effectiveSignal=withTimeout2(signal,timeoutMs),cookieHeader=buildCookieHeader2(cookieMap),accessToken=await fetchAccessToken(cookieHeader,effectiveSignal),uploaded=[];if(files)for(let filePath of files)uploaded.push(await uploadFile(filePath,cookieHeader,effectiveSignal));let fReq=buildFReqPayload(prompt,uploaded),params=new URLSearchParams;params.set("at",accessToken),params.set("f.req",fReq);let res=await(await resolveGeminiFetch())(GEMINI_STREAM_GENERATE_URL,{method:"POST",redirect:"error",headers:{"content-type":"application/x-www-form-urlencoded;charset=utf-8",host:"gemini.google.com",origin:"https://gemini.google.com",referer:"https://gemini.google.com/","x-same-domain":"1","user-agent":USER_AGENT,cookie:cookieHeader,[MODEL_HEADER_NAME]:MODEL_HEADERS[model]},body:params.toString(),signal:effectiveSignal}),rawText=await res.text();if(!res.ok)return{text:"",errorMessage:`Gemini request failed: ${res.status}`};try{return parseStreamGenerateResponse(rawText)}catch(err){let errorCode;try{let json=JSON.parse(trimJsonEnvelope(rawText));errorCode=extractErrorCode(json)}catch{}return{text:"",errorCode,errorMessage:err instanceof Error?err.message:String(err)}}}async function fetchAccessToken(cookieHeader,signal){let html=await fetchWithCookieRedirects(GEMINI_APP_URL,cookieHeader,10,signal);for(let key of["SNlM0e","thykhd"]){let match=html.match(new RegExp(`"${key}":"(.*?)"`));if(match?.[1])return match[1]}throw new Error("Unable to authenticate with Gemini. Make sure you're signed into gemini.google.com in a supported Chromium-based browser.")}async function fetchWithCookieRedirects(url,cookieHeader,maxRedirects,signal){let current=url,allowedOrigin=new URL(url).origin;for(let i=0;i<=maxRedirects;i++){let res=await(await resolveGeminiFetch())(current,{headers:{"user-agent":USER_AGENT,cookie:cookieHeader},redirect:"manual",signal});if(res.status>=300&&res.status<400){let location=res.headers.get("location");if(location){let next=new URL(location,current);if(next.origin!==allowedOrigin)throw new Error(`Refusing to send Google cookies across origins: ${allowedOrigin} -> ${next.origin}`);current=next.toString();continue}}return await res.text()}throw new Error(`Too many redirects (>${maxRedirects})`)}function extractEmailFromGeminiHtml(html){let patterns=[/"oPEP7c"\s*:\s*"([^"]+)"/,/aria-label="Google Account:[^"]*?\(([^)]+)\)"/,/"displayEmail"\s*:\s*"([^"]+)"/,/"defaultEmail"\s*:\s*"([^"]+)"/,/"email"\s*:\s*"([^"]+)"/,/"identifier"\s*:\s*"([^"]+)"/,/"gaiaIdentifier"\s*:\s*"([^"]+)"/];for(let pattern of patterns){let match=html.match(pattern),email=normalizeEmail(match?.[1]);if(email)return email}return findFirstEmail(html)}function extractEmailFromListAccounts(text){let trimmed=text.replace(/^\)\]\}'\s*/,"");try{return findEmailInValue(JSON.parse(trimmed))??findFirstEmail(trimmed)}catch{return findFirstEmail(trimmed)}}function findEmailInValue(value){if(typeof value=="string")return normalizeEmail(value);if(Array.isArray(value)){for(let item of value){let email=findEmailInValue(item);if(email)return email}return null}if(value&&typeof value=="object")for(let item of Object.values(value)){let email=findEmailInValue(item);if(email)return email}return null}function findFirstEmail(text){return decodeEmailEscapes(text).match(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i)?.[0]??null}function normalizeEmail(value){if(!value)return null;let normalized=decodeEmailEscapes(value.trim());return/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(normalized)?normalized:null}function decodeEmailEscapes(value){return value.replace(/\\u0040/gi,"@").replace(/\\x40/gi,"@").replace(/&#64;/gi,"@").replace(/&commat;/gi,"@").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}async function uploadFile(filePath,cookieHeader,signal){let data=readFileSync16(filePath),fileName=basename2(filePath),boundary="----FormBoundary"+Math.random().toString(36).slice(2),header=`--${boundary}\r
95
+ Content-Disposition: form-data; name="file"; filename="${fileName}"\r
96
+ Content-Type: application/octet-stream\r
97
+ \r
98
+ `,footer=`\r
99
+ --${boundary}--\r
100
+ `,body=Buffer.concat([Buffer.from(header,"utf-8"),data,Buffer.from(footer,"utf-8")]),res=await(await resolveGeminiFetch())(GEMINI_UPLOAD_URL,{method:"POST",redirect:"error",headers:{"content-type":`multipart/form-data; boundary=${boundary}`,"push-id":GEMINI_UPLOAD_PUSH_ID,"user-agent":USER_AGENT,cookie:cookieHeader},body,signal});if(!res.ok){let text=await res.text();throw new Error(`File upload failed: ${res.status} (${text.slice(0,200)})`)}return{id:await res.text(),name:fileName}}function buildFReqPayload(prompt,uploaded){let innerList=[uploaded.length>0?[prompt,0,null,uploaded.map(file=>[[file.id,1]])]:[prompt],null,null];return JSON.stringify([null,JSON.stringify(innerList)])}function withTimeout2(signal,timeoutMs){let timeout=AbortSignal.timeout(timeoutMs);return signal?AbortSignal.any([signal,timeout]):timeout}function buildCookieHeader2(cookieMap){return Object.entries(cookieMap).filter(([,value])=>typeof value=="string"&&value.length>0).map(([name,value])=>`${name}=${value}`).join("; ")}function getNestedValue(value,pathParts){let current=value;for(let part of pathParts){if(current==null||!Array.isArray(current))return;current=current[part]}return current}function trimJsonEnvelope(text){let start=text.indexOf("["),end=text.lastIndexOf("]");if(start===-1||end===-1||end<=start)throw new Error("Gemini response did not contain a JSON payload.");return text.slice(start,end+1)}function extractErrorCode(responseJson){let code=getNestedValue(responseJson,[0,5,2,0,1,0]);return typeof code=="number"&&code>=0?code:void 0}function extractCandidateText(candidate){let textRaw=getNestedValue(candidate,[1,0]),text=typeof textRaw=="string"?textRaw:"";if(/^http:\/\/googleusercontent\.com\/card_content\/\d+/.test(text)){let alt=getNestedValue(candidate,[22,0]);typeof alt=="string"&&alt.length>0&&(text=alt)}return text}function parseStreamGenerateResponse(rawText){let responseJson=JSON.parse(trimJsonEnvelope(rawText)),errorCode=extractErrorCode(responseJson),parts=Array.isArray(responseJson)?responseJson:[],firstCandidateSeen,latestNonEmptyText="";for(let i=0;i<parts.length;i++){let partBody=getNestedValue(parts[i],[2]);if(!(!partBody||typeof partBody!="string"))try{let parsed=JSON.parse(partBody),candidateList=getNestedValue(parsed,[4]);if(!Array.isArray(candidateList)||candidateList.length===0)continue;let firstCandidate=candidateList[0];firstCandidateSeen===void 0&&(firstCandidateSeen=firstCandidate);let text2=extractCandidateText(firstCandidate);text2.length>0&&(latestNonEmptyText=text2)}catch{}}return{text:latestNonEmptyText.length>0?latestNonEmptyText:extractCandidateText(firstCandidateSeen),errorCode}}import{existsSync as existsSync16,readFileSync as readFileSync17}from"node:fs";var PERPLEXITY_API_URL="https://api.perplexity.ai/chat/completions",CONFIG_PATH13=getWebSearchConfigPath(),RATE_LIMIT={maxRequests:10,windowMs:60*1e3},requestTimestamps=[],cachedConfig12=null;function loadConfig11(){if(cachedConfig12)return cachedConfig12;if(!existsSync16(CONFIG_PATH13))return cachedConfig12={},cachedConfig12;let content=readFileSync17(CONFIG_PATH13,"utf-8");try{return cachedConfig12=JSON.parse(content),cachedConfig12}catch(err){let message=err instanceof Error?err.message:String(err);throw new Error(`Failed to parse ${CONFIG_PATH13}: ${message}`)}}async function getApiKey9(signal){let key=await resolveCredential({provider:"Perplexity",configuredValue:loadConfig11().perplexityApiKey,environmentValue:process.env.PERPLEXITY_API_KEY,signal});if(!key)throw new Error(`Perplexity API key not found. Either:
101
+ 1. Create ${CONFIG_PATH13} with { "perplexityApiKey": "your-key" }
102
+ 2. Set PERPLEXITY_API_KEY environment variable
103
+ Get a key at https://perplexity.ai/settings/api`);return key}function checkRateLimit(){let now=Date.now(),windowStart=now-RATE_LIMIT.windowMs;for(;requestTimestamps.length>0&&requestTimestamps[0]<windowStart;)requestTimestamps.shift();if(requestTimestamps.length>=RATE_LIMIT.maxRequests){let waitMs=requestTimestamps[0]+RATE_LIMIT.windowMs-now;throw new Error(`Rate limited. Try again in ${Math.ceil(waitMs/1e3)}s`)}requestTimestamps.push(now)}function validateDomainFilter(domains){return domains.filter(d=>{let domain=d.startsWith("-")?d.slice(1):d;return/^[a-zA-Z0-9][a-zA-Z0-9-_.]*\.[a-zA-Z]{2,}$/.test(domain)})}function isPerplexityAvailable(){return hasCredentialSource({provider:"Perplexity",configuredValue:loadConfig11().perplexityApiKey,environmentValue:process.env.PERPLEXITY_API_KEY})}var MAX_CITATIONS=20;function citationsToKeep(answer,available,numResults){let highestCited=0;for(let match of answer.matchAll(/\[(\d{1,3})\]/g))highestCited=Math.max(highestCited,Number(match[1]));return Math.min(available,MAX_CITATIONS,Math.max(numResults,highestCited))}async function searchWithPerplexity(query,options={}){checkRateLimit();let activityId=activityMonitor.logStart({type:"api",query});activityMonitor.updateRateLimit({used:requestTimestamps.length,max:RATE_LIMIT.maxRequests,oldestTimestamp:requestTimestamps[0]??null,windowMs:RATE_LIMIT.windowMs});let apiKey=await getApiKey9(options.signal),numResults=typeof options.numResults=="number"&&Number.isFinite(options.numResults)?Math.max(1,Math.min(Math.floor(options.numResults),20)):5,requestBody={model:"sonar",messages:[{role:"user",content:query}],max_tokens:1024,return_related_questions:!1};if(options.recencyFilter&&(requestBody.search_recency_filter=options.recencyFilter),options.domainFilter&&options.domainFilter.length>0){let validated=validateDomainFilter(options.domainFilter);validated.length>0&&(requestBody.search_domain_filter=validated)}let response;try{response=await fetch(PERPLEXITY_API_URL,{method:"POST",headers:{Authorization:`Bearer ${apiKey}`,"Content-Type":"application/json"},body:JSON.stringify(requestBody),...options.signal?{signal:options.signal}:{}})}catch(err){let message=err instanceof Error?err.message:String(err),redactedMessage=redactCredential(message,apiKey);if(redactedMessage.toLowerCase().includes("abort")?activityMonitor.logComplete(activityId,0):activityMonitor.logError(activityId,redactedMessage),redactedMessage===message)throw err;let redactedError=new Error(redactedMessage);throw err instanceof Error&&(redactedError.name=err.name),redactedError}if(!response.ok){activityMonitor.logComplete(activityId,response.status);let errorText=redactCredential(await response.text(),apiKey);throw new Error(`Perplexity API error ${response.status}: ${errorText}`)}let data;try{data=await response.json()}catch(err){activityMonitor.logComplete(activityId,response.status);let message=err instanceof Error?err.message:String(err);throw new Error(`Perplexity API returned invalid JSON: ${message}`)}let answer=data.choices?.[0]?.message?.content||"",citations=Array.isArray(data.citations)?data.citations:[],results=[],citationCount=citationsToKeep(answer,citations.length,numResults);for(let i=0;i<citationCount;i++){let citation=citations[i];typeof citation=="string"?results.push({title:`Source ${i+1}`,url:citation,snippet:""}):citation&&typeof citation=="object"&&typeof citation.url=="string"&&results.push({title:citation.title||`Source ${i+1}`,url:citation.url,snippet:""})}return activityMonitor.logComplete(activityId,response.status),{answer,results}}export{pLimit,getWebSearchConfigDir,getWebSearchConfigPath,resolveApiBaseUrl,fetchWithCredentialRedirects,resolveCuratorNetworkConfig,formatSeconds,readExecError,isTimeoutError,trimErrorText,mapFfmpegError,normalizeProxyUrl,runWithProxy,installGlobalProxyFetch,resolveAuthFetchProfile,assertAuthFetchUrl,authFetchRedirectGuard,activityMonitor,checkGhAvailable,showGhHint,extractGitHub,clearCloneCache,CredentialResolutionError,redactCredential,hasCredentialSource,resolveCredential,isGeminiAdcAvailable,DEFAULT_MODEL,getApiKey8 as getApiKey,getVersionedApiBase,getUploadBase,isGatewayConfigured,redactGeminiApiResponse,fetchGeminiApi,isGeminiApiAvailable,isGeminiApiAvailableWithVideo,queryGeminiApiWithInlineData,queryGeminiApiWithVideo,isBrowserCookieAccessAllowed,getLastBrowserCookieDiagnostic,getBrowserCookiesForHosts,isGeminiWebAvailable,getGeminiWebAvailabilityDiagnostic,getGeminiWebAvailabilityDiagnosticDetails,getActiveGoogleEmail,queryWithCookies,isPerplexityAvailable,searchWithPerplexity,isParallelAvailable,searchWithParallel,extractWithParallel,isParallelMcpAvailable,searchWithParallelMcp,extractWithParallelMcp,isTinyFishAvailable,searchWithTinyFish,extractWithTinyFish,isSearch1APIAvailable,searchWithSearch1API,extractWithSearch1API,isQueritAvailable,searchWithQuerit,extractWithQuerit,loadFetchContentDomainPolicy,loadSsrfConfig,validateRemoteUrl,fetchRemoteUrl,isFirecrawlAvailable,searchWithFirecrawl,extractWithFirecrawl,isKagiAvailable,searchWithKagi,isKagiExtractAvailable,extractWithKagi,isOllamaAvailable,searchWithOllama,isOllamaFetchAvailable,extractWithOllama};