@herbertgao/pi-extensions 2026.10.2 → 2026.10.3

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 (359) hide show
  1. package/README.md +5 -12
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  4. package/node_modules/@herbertgao/pi-subagents/README.md +1 -1
  5. package/node_modules/@herbertgao/pi-subagents/package.json +4 -5
  6. package/node_modules/@herbertgao/pi-subagents/src/index.ts +1 -1
  7. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +1 -1
  8. package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +48 -72
  9. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +1 -1
  10. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +15 -6
  11. package/node_modules/@herbertgao/pi-subagents/src/workflow/collisions.ts +4 -1
  12. package/node_modules/@herbertgao/pi-subagents/src/workflow/json-schema.ts +9 -8
  13. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +6 -1
  14. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +2 -2
  15. package/node_modules/@narumitw/pi-caffeinate/package.json +1 -1
  16. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +13 -1
  17. package/node_modules/pi-lens/CHANGELOG.md +95 -0
  18. package/node_modules/pi-lens/README.md +1 -0
  19. package/node_modules/pi-lens/dist/chunk-2FQ62SPM.js +83 -0
  20. package/node_modules/pi-lens/dist/{chunk-6P62QVEA.js → chunk-2UMYMRI3.js} +2 -2
  21. package/node_modules/pi-lens/dist/{chunk-O6TQT6RI.js → chunk-34OCDWOS.js} +1 -1
  22. package/node_modules/pi-lens/dist/{chunk-XK4CIILI.js → chunk-3FERWMCH.js} +26 -26
  23. package/node_modules/pi-lens/dist/{chunk-ZAWW3AF6.js → chunk-3JL6IFD7.js} +8 -8
  24. package/node_modules/pi-lens/dist/{chunk-OAXNDZJ7.js → chunk-3JSEWUWI.js} +8 -4
  25. package/node_modules/pi-lens/dist/{chunk-RPD5K5NC.js → chunk-3MRXIJ6I.js} +2 -2
  26. package/node_modules/pi-lens/dist/{chunk-IVP5KAB7.js → chunk-3P4PF2BX.js} +14 -14
  27. package/node_modules/pi-lens/dist/{chunk-5THXD6X5.js → chunk-3PNFWVHT.js} +2 -2
  28. package/node_modules/pi-lens/dist/{chunk-VD4JQCQC.js → chunk-3TTPKMEF.js} +37 -37
  29. package/node_modules/pi-lens/dist/{chunk-7F72PXY2.js → chunk-5JHXUETW.js} +3 -3
  30. package/node_modules/pi-lens/dist/{chunk-5ZEJHV35.js → chunk-64LU2OVH.js} +2 -2
  31. package/node_modules/pi-lens/dist/{chunk-ODEEOXPH.js → chunk-6B5I6ICN.js} +11 -11
  32. package/node_modules/pi-lens/dist/{chunk-5RXBNSW2.js → chunk-6P54TMWL.js} +16 -8
  33. package/node_modules/pi-lens/dist/{chunk-K6VYLB2U.js → chunk-6UYA642J.js} +12 -12
  34. package/node_modules/pi-lens/dist/{chunk-V7R425XG.js → chunk-6XX5HCLK.js} +4 -4
  35. package/node_modules/pi-lens/dist/{chunk-D6QS3U6M.js → chunk-7AXO3ZDF.js} +15 -15
  36. package/node_modules/pi-lens/dist/{chunk-YGVYKNSN.js → chunk-7BX5DWSA.js} +59 -12
  37. package/node_modules/pi-lens/dist/{chunk-N3YQJI6O.js → chunk-7ELY2CSM.js} +7 -4
  38. package/node_modules/pi-lens/dist/{chunk-AWE5TMPO.js → chunk-7M4T5N3V.js} +13 -13
  39. package/node_modules/pi-lens/dist/{chunk-AJ3QXTRQ.js → chunk-AFZYMAIV.js} +33 -33
  40. package/node_modules/pi-lens/dist/{chunk-AJXODZY6.js → chunk-ALQRYH6O.js} +12 -12
  41. package/node_modules/pi-lens/dist/{chunk-AJVLWNFN.js → chunk-AXKPQ6ZI.js} +5 -5
  42. package/node_modules/pi-lens/dist/{chunk-HWBZIGMJ.js → chunk-BHWHXMQ2.js} +8 -8
  43. package/node_modules/pi-lens/dist/{chunk-IXEBJSUE.js → chunk-BJF25SUG.js} +10 -10
  44. package/node_modules/pi-lens/dist/{chunk-GVXA6CCE.js → chunk-BNKLYOOO.js} +1 -1
  45. package/node_modules/pi-lens/dist/{chunk-T4ERT73Y.js → chunk-CBD2B5CP.js} +20 -20
  46. package/node_modules/pi-lens/dist/{chunk-O5WILGMI.js → chunk-CFYISHUW.js} +5 -5
  47. package/node_modules/pi-lens/dist/{chunk-EOKRQ3SA.js → chunk-CMU4RMJB.js} +1 -1
  48. package/node_modules/pi-lens/dist/{chunk-YSNFMJKN.js → chunk-CULQYFLU.js} +2 -2
  49. package/node_modules/pi-lens/dist/{chunk-ORTMY4Q4.js → chunk-D65GOCJB.js} +21 -14
  50. package/node_modules/pi-lens/dist/{chunk-NTUJEGDZ.js → chunk-D6YF5HKX.js} +2 -2
  51. package/node_modules/pi-lens/dist/{chunk-BRJKOBZP.js → chunk-DMS52BEP.js} +17 -6
  52. package/node_modules/pi-lens/dist/{chunk-NL5GLMFI.js → chunk-ELVWJYRV.js} +11 -11
  53. package/node_modules/pi-lens/dist/{chunk-4W2PLC4J.js → chunk-EUT3B22Y.js} +12 -12
  54. package/node_modules/pi-lens/dist/{chunk-GUOGVTCQ.js → chunk-F5VLZHUW.js} +1 -1
  55. package/node_modules/pi-lens/dist/{chunk-I7SPGOWI.js → chunk-FGALODG3.js} +1 -1
  56. package/node_modules/pi-lens/dist/{chunk-Q5U6FMDI.js → chunk-G3RLJYA2.js} +12 -6
  57. package/node_modules/pi-lens/dist/{chunk-FJNKANOS.js → chunk-GAYGGICG.js} +9 -9
  58. package/node_modules/pi-lens/dist/{chunk-HVUZXSWK.js → chunk-H2W2AXD3.js} +38 -40
  59. package/node_modules/pi-lens/dist/{chunk-VHQLPIRJ.js → chunk-H5EV3VMF.js} +2 -2
  60. package/node_modules/pi-lens/dist/{chunk-27BBHSZC.js → chunk-HREZQCT3.js} +3 -3
  61. package/node_modules/pi-lens/dist/{chunk-TT22N74J.js → chunk-HSIRMK2D.js} +12 -12
  62. package/node_modules/pi-lens/dist/{chunk-3I5QFT3N.js → chunk-IMSQR4WO.js} +6 -3
  63. package/node_modules/pi-lens/dist/{chunk-B3I2UUT4.js → chunk-IQZXOZ7S.js} +156 -32
  64. package/node_modules/pi-lens/dist/{chunk-RIISMHKN.js → chunk-IR6XFA5P.js} +14 -13
  65. package/node_modules/pi-lens/dist/{chunk-LNAKEO63.js → chunk-IUKPRZER.js} +4 -4
  66. package/node_modules/pi-lens/dist/{chunk-RUOG5D2C.js → chunk-IUR76K6A.js} +5 -5
  67. package/node_modules/pi-lens/dist/{chunk-TO6WL3GM.js → chunk-J3FZR3YY.js} +12 -2
  68. package/node_modules/pi-lens/dist/{chunk-Y4T27COV.js → chunk-J6DFZDFA.js} +4 -4
  69. package/node_modules/pi-lens/dist/{chunk-E4MAEDPM.js → chunk-J7WJZ6W7.js} +11 -11
  70. package/node_modules/pi-lens/dist/{chunk-52H5B5TC.js → chunk-JONGANYH.js} +30 -30
  71. package/node_modules/pi-lens/dist/{chunk-TGPXLY2J.js → chunk-KJCWXUUS.js} +35 -1
  72. package/node_modules/pi-lens/dist/{chunk-I3R7GKDR.js → chunk-KJN4IOEJ.js} +1 -1
  73. package/node_modules/pi-lens/dist/{chunk-RPD4ZSB7.js → chunk-KMGPUKFD.js} +12 -12
  74. package/node_modules/pi-lens/dist/{chunk-OQGFCZJ4.js → chunk-LD7WFTRX.js} +13 -13
  75. package/node_modules/pi-lens/dist/{chunk-DIULIWKU.js → chunk-LNOMA3MP.js} +3 -3
  76. package/node_modules/pi-lens/dist/{chunk-HHYAELLJ.js → chunk-MGIWSROG.js} +5 -5
  77. package/node_modules/pi-lens/dist/{chunk-YLF3PPT5.js → chunk-MQA2YBAH.js} +3 -3
  78. package/node_modules/pi-lens/dist/{chunk-TVN5N6GY.js → chunk-MTDRLSI7.js} +690 -186
  79. package/node_modules/pi-lens/dist/{chunk-DQ2NZ7C4.js → chunk-N2IRDBZI.js} +44 -6
  80. package/node_modules/pi-lens/dist/{chunk-AHDW3GPE.js → chunk-N77WFUL7.js} +22 -22
  81. package/node_modules/pi-lens/dist/{chunk-NXPS2L6U.js → chunk-N7YNJE5R.js} +7 -7
  82. package/node_modules/pi-lens/dist/{chunk-7FBF7NPR.js → chunk-NFXP47RV.js} +13 -12
  83. package/node_modules/pi-lens/dist/{chunk-UY752QSN.js → chunk-NJF2X5XF.js} +17 -17
  84. package/node_modules/pi-lens/dist/{chunk-WONERJTP.js → chunk-O7HZX7CA.js} +1 -1
  85. package/node_modules/pi-lens/dist/{chunk-AS44CFQ4.js → chunk-OC7LYAU5.js} +7 -7
  86. package/node_modules/pi-lens/dist/{chunk-4RERDEXR.js → chunk-OEX24ECI.js} +30 -30
  87. package/node_modules/pi-lens/dist/{chunk-6VCD4VKZ.js → chunk-OYOB3ZFG.js} +2 -2
  88. package/node_modules/pi-lens/dist/{chunk-IIXOAGHR.js → chunk-OYTMZXRF.js} +18 -15
  89. package/node_modules/pi-lens/dist/{chunk-ARFCXG7S.js → chunk-OZJINN4O.js} +2 -2
  90. package/node_modules/pi-lens/dist/{chunk-34U7PLGE.js → chunk-PCHDGUKT.js} +11 -11
  91. package/node_modules/pi-lens/dist/{chunk-VCSRSYLF.js → chunk-RJFED73B.js} +34 -36
  92. package/node_modules/pi-lens/dist/chunk-RTQNRM5X.js +27 -0
  93. package/node_modules/pi-lens/dist/{chunk-PAK6IDME.js → chunk-S6AMWKPC.js} +2 -2
  94. package/node_modules/pi-lens/dist/{chunk-U3VGR4VU.js → chunk-T4QZ6FEH.js} +4 -4
  95. package/node_modules/pi-lens/dist/{chunk-VN2AXLEX.js → chunk-T54VJRAD.js} +54 -12
  96. package/node_modules/pi-lens/dist/{chunk-ZMOL6RQC.js → chunk-TA5L5KWQ.js} +2 -2
  97. package/node_modules/pi-lens/dist/{chunk-JOLITGCC.js → chunk-TQFBZVCG.js} +1 -1
  98. package/node_modules/pi-lens/dist/{chunk-VDBPVIKD.js → chunk-U52SAGRM.js} +1 -1
  99. package/node_modules/pi-lens/dist/{chunk-LW6XKDZQ.js → chunk-UEAHAMEI.js} +284 -35
  100. package/node_modules/pi-lens/dist/{chunk-NMABWBZN.js → chunk-UGSMCQ4D.js} +1 -1
  101. package/node_modules/pi-lens/dist/{chunk-6QIUX4EP.js → chunk-USHG4DLH.js} +7 -7
  102. package/node_modules/pi-lens/dist/{chunk-LSMJ6KBE.js → chunk-V5MEBST3.js} +16 -16
  103. package/node_modules/pi-lens/dist/chunk-VGEVL5EQ.js +29 -0
  104. package/node_modules/pi-lens/dist/{chunk-47D2BO4S.js → chunk-VPWKF3GN.js} +10 -10
  105. package/node_modules/pi-lens/dist/{chunk-UK3CMEAL.js → chunk-VSMJK3ZJ.js} +1 -1
  106. package/node_modules/pi-lens/dist/{chunk-22AVIGXS.js → chunk-VYKKMYVT.js} +7 -7
  107. package/node_modules/pi-lens/dist/{chunk-OS32RNR2.js → chunk-VZHJS6DR.js} +15 -15
  108. package/node_modules/pi-lens/dist/{chunk-E2WFBRHM.js → chunk-WATC3IQR.js} +3 -3
  109. package/node_modules/pi-lens/dist/chunk-WPE5FPGR.js +54 -0
  110. package/node_modules/pi-lens/dist/{chunk-V5PXFSZK.js → chunk-WSEWKCXU.js} +4 -4
  111. package/node_modules/pi-lens/dist/{chunk-NKOUFPQF.js → chunk-WW5BLB74.js} +2 -2
  112. package/node_modules/pi-lens/dist/{chunk-PWFHBTSF.js → chunk-XGUL4SLQ.js} +2 -2
  113. package/node_modules/pi-lens/dist/{chunk-F3P7VQ7H.js → chunk-XHSCVSOL.js} +3 -3
  114. package/node_modules/pi-lens/dist/{chunk-DFVMIKMQ.js → chunk-YLN4K6WD.js} +45 -9
  115. package/node_modules/pi-lens/dist/{chunk-VNMT7C64.js → chunk-Z6BB4JLQ.js} +2 -2
  116. package/node_modules/pi-lens/dist/{chunk-NTHH2J74.js → chunk-Z7QQA2KT.js} +12 -12
  117. package/node_modules/pi-lens/dist/{chunk-F3AU2TMM.js → chunk-ZETYB3XG.js} +15 -15
  118. package/node_modules/pi-lens/dist/{chunk-XECLWQZN.js → chunk-ZMOMPX2Z.js} +12 -10
  119. package/node_modules/pi-lens/dist/{chunk-C2AUYXQH.js → chunk-ZOEYVXSV.js} +4 -4
  120. package/node_modules/pi-lens/dist/{chunk-TLGFBM3F.js → chunk-ZZUFZUQZ.js} +68 -64
  121. package/node_modules/pi-lens/dist/index.js +30113 -28398
  122. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +8 -8
  123. package/node_modules/pi-lens/dist/mcp/cli.js +37 -37
  124. package/node_modules/pi-lens/dist/mcp/server.js +257 -158
  125. package/node_modules/pi-lens/dist/mcp/worker.js +55 -55
  126. package/node_modules/pi-lens/dist/probes/installer.js +19 -19
  127. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +2 -2
  128. package/node_modules/pi-lens/docs/configuration.md +9 -2
  129. package/node_modules/pi-lens/docs/custom-rules.md +25 -2
  130. package/node_modules/pi-lens/docs/environment-variables.md +34 -6
  131. package/node_modules/pi-lens/docs/features.md +37 -1
  132. package/node_modules/pi-lens/docs/globalconfig.md +1 -1
  133. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -1
  134. package/node_modules/pi-lens/docs/lsp-idle-eviction.md +1 -1
  135. package/node_modules/pi-lens/docs/pi-lens-fixer.md +9 -5
  136. package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +43 -1
  137. package/node_modules/pi-lens/docs/pi-lens-monitor.md +3 -1
  138. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +4 -3
  139. package/node_modules/pi-lens/docs/schema/pi-lens-config-v1.json +530 -0
  140. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  141. package/node_modules/pi-lens/docs/word-index.md +6 -0
  142. package/node_modules/pi-lens/package.json +1 -1
  143. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-identity-operator-on-literals-test.yml +12 -2
  144. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-js-test.yml +2 -0
  145. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/throw-new-error-test.yml +2 -0
  146. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-identity-operator-on-literals.yml +20 -12
  147. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error-js.yml +2 -2
  148. package/node_modules/pi-lens/rules/ast-grep-rules/rules/throw-new-error.yml +2 -2
  149. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  150. package/node_modules/pi-web-access/README.md +10 -6
  151. package/node_modules/pi-web-access/ceramic.ts +219 -0
  152. package/node_modules/pi-web-access/curator-page.ts +3 -1
  153. package/node_modules/pi-web-access/curator-server.ts +1 -0
  154. package/node_modules/pi-web-access/dist/index.js +846 -588
  155. package/node_modules/pi-web-access/dist/mcp-cli.js +725 -516
  156. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  157. package/node_modules/pi-web-access/github-extract.ts +34 -2
  158. package/node_modules/pi-web-access/index.ts +72 -30
  159. package/node_modules/pi-web-access/openai-search.ts +3 -3
  160. package/node_modules/pi-web-access/package.json +2 -2
  161. package/node_modules/pi-web-access/page-query.ts +6 -9
  162. package/node_modules/pi-web-access/parallel-mcp.ts +2 -0
  163. package/node_modules/pi-web-access/query-rewrite.ts +2 -2
  164. package/node_modules/pi-web-access/storage.ts +49 -0
  165. package/node_modules/pi-web-access/summary-review.ts +7 -6
  166. package/node_modules/pi-web-access/utils.ts +21 -6
  167. package/node_modules/pi-web-access/web-tool-core.ts +1 -0
  168. package/package.json +7 -12
  169. package/node_modules/pi-lens/dist/chunk-54B42YRX.js +0 -27
  170. package/node_modules/pi-lens/dist/chunk-CGGAIP7J.js +0 -29
  171. package/node_modules/pi-lens/dist/chunk-HMFXILPV.js +0 -83
  172. package/node_modules/pi-lens/dist/chunk-T6D4Q4AQ.js +0 -54
  173. package/node_modules/pi-web-access/opencode-session-headers.ts +0 -24
  174. package/node_modules/remote-pi/LICENSE +0 -21
  175. package/node_modules/remote-pi/README.md +0 -675
  176. package/node_modules/remote-pi/dist/actions/handlers.d.ts +0 -122
  177. package/node_modules/remote-pi/dist/actions/handlers.js +0 -160
  178. package/node_modules/remote-pi/dist/actions/handlers.js.map +0 -1
  179. package/node_modules/remote-pi/dist/actions/registry.d.ts +0 -39
  180. package/node_modules/remote-pi/dist/actions/registry.js +0 -58
  181. package/node_modules/remote-pi/dist/actions/registry.js.map +0 -1
  182. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +0 -2
  183. package/node_modules/remote-pi/dist/bin/supervisord.js +0 -86
  184. package/node_modules/remote-pi/dist/bin/supervisord.js.map +0 -1
  185. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +0 -58
  186. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +0 -71
  187. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +0 -1
  188. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +0 -60
  189. package/node_modules/remote-pi/dist/commands/list_commands.js +0 -73
  190. package/node_modules/remote-pi/dist/commands/list_commands.js.map +0 -1
  191. package/node_modules/remote-pi/dist/config.d.ts +0 -62
  192. package/node_modules/remote-pi/dist/config.js +0 -115
  193. package/node_modules/remote-pi/dist/config.js.map +0 -1
  194. package/node_modules/remote-pi/dist/daemon/client.d.ts +0 -20
  195. package/node_modules/remote-pi/dist/daemon/client.js +0 -131
  196. package/node_modules/remote-pi/dist/daemon/client.js.map +0 -1
  197. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +0 -176
  198. package/node_modules/remote-pi/dist/daemon/control_protocol.js +0 -63
  199. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +0 -1
  200. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +0 -45
  201. package/node_modules/remote-pi/dist/daemon/cron_log.js +0 -72
  202. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +0 -1
  203. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +0 -80
  204. package/node_modules/remote-pi/dist/daemon/cron_registry.js +0 -194
  205. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +0 -1
  206. package/node_modules/remote-pi/dist/daemon/id.d.ts +0 -24
  207. package/node_modules/remote-pi/dist/daemon/id.js +0 -36
  208. package/node_modules/remote-pi/dist/daemon/id.js.map +0 -1
  209. package/node_modules/remote-pi/dist/daemon/install.d.ts +0 -170
  210. package/node_modules/remote-pi/dist/daemon/install.js +0 -547
  211. package/node_modules/remote-pi/dist/daemon/install.js.map +0 -1
  212. package/node_modules/remote-pi/dist/daemon/registry.d.ts +0 -63
  213. package/node_modules/remote-pi/dist/daemon/registry.js +0 -153
  214. package/node_modules/remote-pi/dist/daemon/registry.js.map +0 -1
  215. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +0 -194
  216. package/node_modules/remote-pi/dist/daemon/rpc_child.js +0 -389
  217. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +0 -1
  218. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +0 -93
  219. package/node_modules/remote-pi/dist/daemon/supervisor.js +0 -596
  220. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +0 -1
  221. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +0 -26
  222. package/node_modules/remote-pi/dist/extension_ui_bridge.js +0 -341
  223. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +0 -1
  224. package/node_modules/remote-pi/dist/index.d.ts +0 -213
  225. package/node_modules/remote-pi/dist/index.js +0 -4996
  226. package/node_modules/remote-pi/dist/index.js.map +0 -1
  227. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +0 -10
  228. package/node_modules/remote-pi/dist/mcp/mesh_result.js +0 -42
  229. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +0 -1
  230. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +0 -16
  231. package/node_modules/remote-pi/dist/mcp/mesh_server.js +0 -327
  232. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +0 -1
  233. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +0 -30
  234. package/node_modules/remote-pi/dist/mesh/canonical.js +0 -61
  235. package/node_modules/remote-pi/dist/mesh/canonical.js.map +0 -1
  236. package/node_modules/remote-pi/dist/mesh/client.d.ts +0 -18
  237. package/node_modules/remote-pi/dist/mesh/client.js +0 -125
  238. package/node_modules/remote-pi/dist/mesh/client.js.map +0 -1
  239. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +0 -38
  240. package/node_modules/remote-pi/dist/mesh/encoding.js +0 -216
  241. package/node_modules/remote-pi/dist/mesh/encoding.js.map +0 -1
  242. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +0 -73
  243. package/node_modules/remote-pi/dist/mesh/self_revoke.js +0 -401
  244. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +0 -1
  245. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +0 -49
  246. package/node_modules/remote-pi/dist/mesh/siblings.js +0 -159
  247. package/node_modules/remote-pi/dist/mesh/siblings.js.map +0 -1
  248. package/node_modules/remote-pi/dist/mesh/types.d.ts +0 -34
  249. package/node_modules/remote-pi/dist/mesh/types.js +0 -11
  250. package/node_modules/remote-pi/dist/mesh/types.js.map +0 -1
  251. package/node_modules/remote-pi/dist/mesh/verify.d.ts +0 -17
  252. package/node_modules/remote-pi/dist/mesh/verify.js +0 -86
  253. package/node_modules/remote-pi/dist/mesh/verify.js.map +0 -1
  254. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +0 -8
  255. package/node_modules/remote-pi/dist/pairing/crypto.js +0 -22
  256. package/node_modules/remote-pi/dist/pairing/crypto.js.map +0 -1
  257. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +0 -28
  258. package/node_modules/remote-pi/dist/pairing/handshake.js +0 -113
  259. package/node_modules/remote-pi/dist/pairing/handshake.js.map +0 -1
  260. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +0 -16
  261. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +0 -103
  262. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +0 -1
  263. package/node_modules/remote-pi/dist/pairing/qr.d.ts +0 -59
  264. package/node_modules/remote-pi/dist/pairing/qr.js +0 -125
  265. package/node_modules/remote-pi/dist/pairing/qr.js.map +0 -1
  266. package/node_modules/remote-pi/dist/pairing/storage.d.ts +0 -120
  267. package/node_modules/remote-pi/dist/pairing/storage.js +0 -604
  268. package/node_modules/remote-pi/dist/pairing/storage.js.map +0 -1
  269. package/node_modules/remote-pi/dist/protocol/codec.d.ts +0 -7
  270. package/node_modules/remote-pi/dist/protocol/codec.js +0 -49
  271. package/node_modules/remote-pi/dist/protocol/codec.js.map +0 -1
  272. package/node_modules/remote-pi/dist/protocol/types.d.ts +0 -393
  273. package/node_modules/remote-pi/dist/protocol/types.js +0 -2
  274. package/node_modules/remote-pi/dist/protocol/types.js.map +0 -1
  275. package/node_modules/remote-pi/dist/rooms.d.ts +0 -29
  276. package/node_modules/remote-pi/dist/rooms.js +0 -57
  277. package/node_modules/remote-pi/dist/rooms.js.map +0 -1
  278. package/node_modules/remote-pi/dist/session/address.d.ts +0 -49
  279. package/node_modules/remote-pi/dist/session/address.js +0 -58
  280. package/node_modules/remote-pi/dist/session/address.js.map +0 -1
  281. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +0 -55
  282. package/node_modules/remote-pi/dist/session/agent_bridge.js +0 -146
  283. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +0 -1
  284. package/node_modules/remote-pi/dist/session/bridge.d.ts +0 -37
  285. package/node_modules/remote-pi/dist/session/bridge.js +0 -130
  286. package/node_modules/remote-pi/dist/session/bridge.js.map +0 -1
  287. package/node_modules/remote-pi/dist/session/broker.d.ts +0 -189
  288. package/node_modules/remote-pi/dist/session/broker.js +0 -507
  289. package/node_modules/remote-pi/dist/session/broker.js.map +0 -1
  290. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +0 -74
  291. package/node_modules/remote-pi/dist/session/broker_remote.js +0 -583
  292. package/node_modules/remote-pi/dist/session/broker_remote.js.map +0 -1
  293. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +0 -33
  294. package/node_modules/remote-pi/dist/session/cwd_lock.js +0 -126
  295. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +0 -1
  296. package/node_modules/remote-pi/dist/session/envelope.d.ts +0 -33
  297. package/node_modules/remote-pi/dist/session/envelope.js +0 -117
  298. package/node_modules/remote-pi/dist/session/envelope.js.map +0 -1
  299. package/node_modules/remote-pi/dist/session/global_config.d.ts +0 -33
  300. package/node_modules/remote-pi/dist/session/global_config.js +0 -73
  301. package/node_modules/remote-pi/dist/session/global_config.js.map +0 -1
  302. package/node_modules/remote-pi/dist/session/ipc.d.ts +0 -27
  303. package/node_modules/remote-pi/dist/session/ipc.js +0 -22
  304. package/node_modules/remote-pi/dist/session/ipc.js.map +0 -1
  305. package/node_modules/remote-pi/dist/session/leader_election.d.ts +0 -32
  306. package/node_modules/remote-pi/dist/session/leader_election.js +0 -106
  307. package/node_modules/remote-pi/dist/session/leader_election.js.map +0 -1
  308. package/node_modules/remote-pi/dist/session/local_config.d.ts +0 -55
  309. package/node_modules/remote-pi/dist/session/local_config.js +0 -157
  310. package/node_modules/remote-pi/dist/session/local_config.js.map +0 -1
  311. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +0 -20
  312. package/node_modules/remote-pi/dist/session/mesh_message.js +0 -28
  313. package/node_modules/remote-pi/dist/session/mesh_message.js.map +0 -1
  314. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +0 -116
  315. package/node_modules/remote-pi/dist/session/mesh_node.js +0 -573
  316. package/node_modules/remote-pi/dist/session/mesh_node.js.map +0 -1
  317. package/node_modules/remote-pi/dist/session/peer.d.ts +0 -139
  318. package/node_modules/remote-pi/dist/session/peer.js +0 -451
  319. package/node_modules/remote-pi/dist/session/peer.js.map +0 -1
  320. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +0 -13
  321. package/node_modules/remote-pi/dist/session/peer_inventory.js +0 -48
  322. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +0 -1
  323. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +0 -9
  324. package/node_modules/remote-pi/dist/session/peer_limits.js +0 -21
  325. package/node_modules/remote-pi/dist/session/peer_limits.js.map +0 -1
  326. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +0 -39
  327. package/node_modules/remote-pi/dist/session/setup_wizard.js +0 -63
  328. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +0 -1
  329. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +0 -5
  330. package/node_modules/remote-pi/dist/session/tool_gate.js +0 -11
  331. package/node_modules/remote-pi/dist/session/tool_gate.js.map +0 -1
  332. package/node_modules/remote-pi/dist/session/tools.d.ts +0 -24
  333. package/node_modules/remote-pi/dist/session/tools.js +0 -252
  334. package/node_modules/remote-pi/dist/session/tools.js.map +0 -1
  335. package/node_modules/remote-pi/dist/session/wizard.d.ts +0 -13
  336. package/node_modules/remote-pi/dist/session/wizard.js +0 -20
  337. package/node_modules/remote-pi/dist/session/wizard.js.map +0 -1
  338. package/node_modules/remote-pi/dist/settings.d.ts +0 -15
  339. package/node_modules/remote-pi/dist/settings.js +0 -52
  340. package/node_modules/remote-pi/dist/settings.js.map +0 -1
  341. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +0 -37
  342. package/node_modules/remote-pi/dist/transport/peer_channel.js +0 -98
  343. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +0 -1
  344. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +0 -29
  345. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +0 -62
  346. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +0 -1
  347. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +0 -91
  348. package/node_modules/remote-pi/dist/transport/relay_client.js +0 -206
  349. package/node_modules/remote-pi/dist/transport/relay_client.js.map +0 -1
  350. package/node_modules/remote-pi/dist/ui/footer.d.ts +0 -32
  351. package/node_modules/remote-pi/dist/ui/footer.js +0 -34
  352. package/node_modules/remote-pi/dist/ui/footer.js.map +0 -1
  353. package/node_modules/remote-pi/docs/daemon.md +0 -289
  354. package/node_modules/remote-pi/package.json +0 -92
  355. package/node_modules/remote-pi/service-templates/launchd.plist.template +0 -35
  356. package/node_modules/remote-pi/service-templates/systemd.service.template +0 -19
  357. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +0 -10
  358. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +0 -38
  359. package/node_modules/remote-pi/skills/agent-network/SKILL.md +0 -310
@@ -90,8 +90,8 @@ var init_activity = __esm({
90
90
  // credential-source.ts
91
91
  import { exec } from "node:child_process";
92
92
  import { promisify } from "node:util";
93
- function redactCredential(text3, credential) {
94
- return credential ? text3.split(credential).join("[redacted]") : text3;
93
+ function redactCredential(text4, credential) {
94
+ return credential ? text4.split(credential).join("[redacted]") : text4;
95
95
  }
96
96
  function normalize(value) {
97
97
  if (typeof value !== "string") return null;
@@ -346,8 +346,8 @@ function isTimeoutError(err) {
346
346
  const message = err.message ?? "";
347
347
  return name === "AbortError" || code === "ETIMEDOUT" || message.toLowerCase().includes("timed out");
348
348
  }
349
- function trimErrorText(text3) {
350
- return text3.replace(/\s+/g, " ").trim().slice(0, 200);
349
+ function trimErrorText(text4) {
350
+ return text4.replace(/\s+/g, " ").trim().slice(0, 200);
351
351
  }
352
352
  function mapFfmpegError(err) {
353
353
  const { code, stderr, message } = readExecError(err);
@@ -441,7 +441,7 @@ function installGlobalProxyFetch() {
441
441
  const current = globalThis.fetch;
442
442
  if (typeof current !== "function" || current.__piWebAccessProxyFetch === true) return;
443
443
  const nativeFetch = current;
444
- const wrapped = ((input, init) => {
444
+ const wrapped = (async (input, init) => {
445
445
  const proxy = init?.__proxy ?? getActiveProxy();
446
446
  if (!proxy) return nativeFetch(input, init);
447
447
  let url = null;
@@ -453,12 +453,20 @@ function installGlobalProxyFetch() {
453
453
  if (!url || url.protocol !== "http:" && url.protocol !== "https:" || isProxyBypassedUrl(url)) {
454
454
  return nativeFetch(input, init);
455
455
  }
456
+ if (input instanceof Request) {
457
+ const request = new Request(input, init);
458
+ request.signal.throwIfAborted();
459
+ const body = request.body === null ? null : new Uint8Array(await new Response(
460
+ request.body.pipeThrough(new TransformStream(), { signal: request.signal })
461
+ ).arrayBuffer());
462
+ init = { ...init, method: request.method, headers: request.headers, body, signal: request.signal, redirect: request.redirect };
463
+ }
456
464
  return fetchViaCurl(url, init ?? {}, proxy);
457
465
  });
458
466
  wrapped.__piWebAccessProxyFetch = true;
459
467
  globalThis.fetch = wrapped;
460
468
  }
461
- function parseHeaderDump(dump) {
469
+ function parseHeaderDump(dump, keepLengthHeaders) {
462
470
  const blocks = dump.split(/\r?\n\r?\n/).filter((block2) => /^HTTP\/[\d.]+\s+\d{3}/.test(block2.trim()));
463
471
  const block = (blocks.length > 0 ? blocks[blocks.length - 1] : "").trim();
464
472
  const lines = block.split(/\r?\n/);
@@ -476,7 +484,7 @@ function parseHeaderDump(dump) {
476
484
  const separator = line.indexOf(":");
477
485
  if (separator > 0) {
478
486
  const name = line.slice(0, separator).trim();
479
- if (name.toLowerCase() === "content-encoding" || name.toLowerCase() === "content-length") continue;
487
+ if (!keepLengthHeaders && (name.toLowerCase() === "content-encoding" || name.toLowerCase() === "content-length")) continue;
480
488
  headers.push([name, line.slice(separator + 1).trim()]);
481
489
  }
482
490
  }
@@ -537,7 +545,8 @@ async function fetchViaCurlOnce(url, init, proxyUrl) {
537
545
  "--write-out",
538
546
  "%{json}"
539
547
  ];
540
- if (method !== "GET" && method !== "HEAD") args.push("-X", method);
548
+ if (method === "HEAD") args.push("--head");
549
+ else if (method !== "GET") args.push("-X", method);
541
550
  for (const [name, value] of headers.entries()) {
542
551
  if (value === "") continue;
543
552
  args.push("-H", `${name}: ${value}`);
@@ -553,6 +562,8 @@ async function fetchViaCurlOnce(url, init, proxyUrl) {
553
562
  await writeFile(requestBodyFile, buffer);
554
563
  args.push("--data-binary", `@${requestBodyFile}`);
555
564
  if (method === "GET") args.unshift("-X", "GET");
565
+ } else if ((method === "POST" || method === "PUT") && !headers.has("content-length")) {
566
+ args.push("-H", "Content-Length: 0");
556
567
  }
557
568
  args.push(url.toString());
558
569
  const signal = init.signal ?? null;
@@ -609,7 +620,7 @@ async function fetchViaCurlOnce(url, init, proxyUrl) {
609
620
  await rm(dir, { recursive: true, force: true }).catch(() => {
610
621
  });
611
622
  }
612
- const { status, statusText, headers: responseHeaders } = parseHeaderDump(dump);
623
+ const { status, statusText, headers: responseHeaders } = parseHeaderDump(dump, method === "HEAD");
613
624
  if (status === 0) {
614
625
  throw new Error(`Proxy fetch to ${url.toString()} via ${redactProxyUrl(proxyUrl)} returned no HTTP status`);
615
626
  }
@@ -624,7 +635,7 @@ async function fetchViaCurlOnce(url, init, proxyUrl) {
624
635
  }
625
636
  } catch {
626
637
  }
627
- const nullBody = status === 204 || status === 205 || status === 304;
638
+ const nullBody = method === "HEAD" || status === 204 || status === 205 || status === 304;
628
639
  const response = new Response(nullBody ? null : new Uint8Array(bodyBuffer), {
629
640
  status,
630
641
  statusText: statusText || void 0,
@@ -733,10 +744,10 @@ function parseAdcFile(raw) {
733
744
  }
734
745
  return { type };
735
746
  }
736
- function parseTokenExchangeResponse(text3, context) {
747
+ function parseTokenExchangeResponse(text4, context) {
737
748
  let raw;
738
749
  try {
739
- raw = JSON.parse(text3);
750
+ raw = JSON.parse(text4);
740
751
  } catch (err) {
741
752
  const message = err instanceof Error ? err.message : String(err);
742
753
  throw new Error(`${context} returned invalid JSON: ${message}`);
@@ -783,11 +794,11 @@ async function exchangeRefreshToken(cfg, signal) {
783
794
  body,
784
795
  signal
785
796
  });
786
- const text3 = await res.text();
797
+ const text4 = await res.text();
787
798
  if (!res.ok) {
788
- throwOnTokenExchangeFailure(res, text3, res.status);
799
+ throwOnTokenExchangeFailure(res, text4, res.status);
789
800
  }
790
- return parseTokenExchangeResponse(text3, "Gemini ADC token exchange");
801
+ return parseTokenExchangeResponse(text4, "Gemini ADC token exchange");
791
802
  }
792
803
  async function exchangeServiceAccountJwt(cfg, signal) {
793
804
  if (!cfg.client_email || !cfg.private_key) {
@@ -819,11 +830,11 @@ async function exchangeServiceAccountJwt(cfg, signal) {
819
830
  body,
820
831
  signal
821
832
  });
822
- const text3 = await res.text();
833
+ const text4 = await res.text();
823
834
  if (!res.ok) {
824
- throwOnTokenExchangeFailure(res, text3, res.status);
835
+ throwOnTokenExchangeFailure(res, text4, res.status);
825
836
  }
826
- return parseTokenExchangeResponse(text3, "Gemini ADC service account token exchange");
837
+ return parseTokenExchangeResponse(text4, "Gemini ADC service account token exchange");
827
838
  }
828
839
  async function getAdcAccessToken(signal) {
829
840
  if (cachedToken && cachedToken.expiresAt > Date.now()) {
@@ -954,14 +965,14 @@ function buildAuthHeaders(apiKey = null, cloudflareApiKey = getLegacyCloudflareA
954
965
  if (!isCloudflareGateway()) return apiKey ? { "x-goog-api-key": apiKey } : {};
955
966
  return cloudflareApiKey ? { "cf-aig-authorization": `Bearer ${cloudflareApiKey}` } : {};
956
967
  }
957
- function redactGeminiCredentials(text3, apiKey, cloudflareApiKey, adcToken) {
958
- let out = redactCredential(redactCredential(text3, apiKey), cloudflareApiKey);
968
+ function redactGeminiCredentials(text4, apiKey, cloudflareApiKey, adcToken) {
969
+ let out = redactCredential(redactCredential(text4, apiKey), cloudflareApiKey);
959
970
  if (adcToken) out = redactCredential(out, adcToken);
960
971
  return out;
961
972
  }
962
- function redactGeminiApiResponse(response, text3, apiKey, adcToken) {
973
+ function redactGeminiApiResponse(response, text4, apiKey, adcToken) {
963
974
  const credentials = responseCredentials.get(response);
964
- return redactGeminiCredentials(text3, credentials?.apiKey ?? apiKey, credentials?.cloudflareApiKey, credentials?.adcToken ?? adcToken);
975
+ return redactGeminiCredentials(text4, credentials?.apiKey ?? apiKey, credentials?.cloudflareApiKey, credentials?.adcToken ?? adcToken);
965
976
  }
966
977
  async function fetchGeminiApi(url, init = {}, apiKey) {
967
978
  const parsedUrl = new URL(url);
@@ -1061,9 +1072,9 @@ async function queryGeminiApiWithInlineData(prompt, data, mimeType, options = {}
1061
1072
  }
1062
1073
  const response = await res.json();
1063
1074
  const candidate = response.candidates?.[0];
1064
- const text3 = candidate?.content?.parts?.map((part) => part.text).filter((part) => typeof part === "string" && part.length > 0).join("\n") ?? "";
1075
+ const text4 = candidate?.content?.parts?.map((part) => part.text).filter((part) => typeof part === "string" && part.length > 0).join("\n") ?? "";
1065
1076
  return {
1066
- text: text3,
1077
+ text: text4,
1067
1078
  ...candidate?.finishReason ? { finishReason: candidate.finishReason } : {},
1068
1079
  ...response.promptFeedback?.blockReason ? { blockReason: response.promptFeedback.blockReason } : {}
1069
1080
  };
@@ -1104,9 +1115,9 @@ async function queryGeminiApiWithVideo(prompt, videoUri, options = {}) {
1104
1115
  throw new Error(`Gemini API error ${res.status}: ${errorText.slice(0, 300)}`);
1105
1116
  }
1106
1117
  const data = await res.json();
1107
- const text3 = data.candidates?.[0]?.content?.parts?.map((p) => p.text).filter(Boolean).join("\n");
1108
- if (!text3) throw new Error("Gemini API returned empty response");
1109
- return text3;
1118
+ const text4 = data.candidates?.[0]?.content?.parts?.map((p) => p.text).filter(Boolean).join("\n");
1119
+ if (!text4) throw new Error("Gemini API returned empty response");
1120
+ return text4;
1110
1121
  }
1111
1122
  var DEFAULT_API_HOST, API_VERSION, API_BASE, CONFIG_PATH2, DEFAULT_MODEL, cachedConfig2, responseCredentials;
1112
1123
  var init_gemini_api = __esm({
@@ -1996,8 +2007,8 @@ Content-Type: ${file.mimeType}\r
1996
2007
  signal
1997
2008
  });
1998
2009
  if (!res.ok) {
1999
- const text3 = await res.text();
2000
- throw new Error(`File upload failed: ${res.status} (${text3.slice(0, 200)})`);
2010
+ const text4 = await res.text();
2011
+ throw new Error(`File upload failed: ${res.status} (${text4.slice(0, 200)})`);
2001
2012
  }
2002
2013
  return { id: await res.text(), name: fileName };
2003
2014
  }
@@ -2022,13 +2033,13 @@ function getNestedValue(value, pathParts) {
2022
2033
  }
2023
2034
  return current;
2024
2035
  }
2025
- function trimJsonEnvelope(text3) {
2026
- const start = text3.indexOf("[");
2027
- const end = text3.lastIndexOf("]");
2036
+ function trimJsonEnvelope(text4) {
2037
+ const start = text4.indexOf("[");
2038
+ const end = text4.lastIndexOf("]");
2028
2039
  if (start === -1 || end === -1 || end <= start) {
2029
2040
  throw new Error("Gemini response did not contain a JSON payload.");
2030
2041
  }
2031
- return text3.slice(start, end + 1);
2042
+ return text4.slice(start, end + 1);
2032
2043
  }
2033
2044
  function extractErrorCode(responseJson) {
2034
2045
  const code = getNestedValue(responseJson, [0, 5, 2, 0, 1, 0]);
@@ -2036,12 +2047,12 @@ function extractErrorCode(responseJson) {
2036
2047
  }
2037
2048
  function extractCandidateText(candidate) {
2038
2049
  const textRaw = getNestedValue(candidate, [1, 0]);
2039
- let text3 = typeof textRaw === "string" ? textRaw : "";
2040
- if (/^http:\/\/googleusercontent\.com\/card_content\/\d+/.test(text3)) {
2050
+ let text4 = typeof textRaw === "string" ? textRaw : "";
2051
+ if (/^http:\/\/googleusercontent\.com\/card_content\/\d+/.test(text4)) {
2041
2052
  const alt = getNestedValue(candidate, [22, 0]);
2042
- if (typeof alt === "string" && alt.length > 0) text3 = alt;
2053
+ if (typeof alt === "string" && alt.length > 0) text4 = alt;
2043
2054
  }
2044
- return text3;
2055
+ return text4;
2045
2056
  }
2046
2057
  function parseStreamGenerateResponse(rawText) {
2047
2058
  const responseJson = JSON.parse(trimJsonEnvelope(rawText));
@@ -2058,13 +2069,13 @@ function parseStreamGenerateResponse(rawText) {
2058
2069
  if (!Array.isArray(candidateList) || candidateList.length === 0) continue;
2059
2070
  const firstCandidate = candidateList[0];
2060
2071
  if (firstCandidateSeen === void 0) firstCandidateSeen = firstCandidate;
2061
- const text4 = extractCandidateText(firstCandidate);
2062
- if (text4.length > 0) latestNonEmptyText = text4;
2072
+ const text5 = extractCandidateText(firstCandidate);
2073
+ if (text5.length > 0) latestNonEmptyText = text5;
2063
2074
  } catch {
2064
2075
  }
2065
2076
  }
2066
- const text3 = latestNonEmptyText.length > 0 ? latestNonEmptyText : extractCandidateText(firstCandidateSeen);
2067
- return { text: text3, errorCode };
2077
+ const text4 = latestNonEmptyText.length > 0 ? latestNonEmptyText : extractCandidateText(firstCandidateSeen);
2078
+ return { text: text4, errorCode };
2068
2079
  }
2069
2080
  var GEMINI_APP_URL, GEMINI_STREAM_GENERATE_URL, GEMINI_UPLOAD_URL, GEMINI_UPLOAD_PUSH_ID, USER_AGENT, MODEL_HEADER_NAME, DEFAULT_GEMINI_WEB_MODEL, MODEL_HEADERS, REQUIRED_COOKIES, geminiFetchImpl, geminiFetchOverride, GEMINI_MAX_HEADER_SIZE;
2070
2081
  var init_gemini_web = __esm({
@@ -2645,7 +2656,9 @@ async function callParallelMcp(toolName, args, signal) {
2645
2656
  const apiKey = await resolveParallelApiKey(signal);
2646
2657
  const headers = {
2647
2658
  "Content-Type": "application/json",
2648
- "Accept": "application/json, text/event-stream"
2659
+ "Accept": "application/json, text/event-stream",
2660
+ // Parallel's free tier rate-limits the default "undici" User-Agent.
2661
+ "User-Agent": "pi-web-access"
2649
2662
  };
2650
2663
  if (apiKey) headers.Authorization = `Bearer ${apiKey}`;
2651
2664
  let response;
@@ -2688,20 +2701,20 @@ async function callParallelMcp(toolName, args, signal) {
2688
2701
  throw new Error(`Parallel MCP error${code}: ${message}`);
2689
2702
  }
2690
2703
  if (parsed.result?.isError) {
2691
- const text4 = parsed.result.content?.find((item) => item.type === "text" && typeof item.text === "string")?.text?.trim() || "Parallel MCP returned an error";
2692
- throw new Error(apiKey ? redactCredential(text4, apiKey) : text4);
2704
+ const text5 = parsed.result.content?.find((item) => item.type === "text" && typeof item.text === "string")?.text?.trim() || "Parallel MCP returned an error";
2705
+ throw new Error(apiKey ? redactCredential(text5, apiKey) : text5);
2693
2706
  }
2694
2707
  if (parsed.result?.structuredContent && typeof parsed.result.structuredContent === "object") return parsed.result.structuredContent;
2695
- const text3 = parsed.result?.content?.find((item) => item.type === "text" && typeof item.text === "string" && item.text.trim())?.text;
2696
- if (!text3) throw new Error("Parallel MCP returned empty content");
2708
+ const text4 = parsed.result?.content?.find((item) => item.type === "text" && typeof item.text === "string" && item.text.trim())?.text;
2709
+ if (!text4) throw new Error("Parallel MCP returned empty content");
2697
2710
  try {
2698
- return JSON.parse(text3);
2711
+ return JSON.parse(text4);
2699
2712
  } catch {
2700
- return text3;
2713
+ return text4;
2701
2714
  }
2702
2715
  }
2703
- function parseTextResults(text3) {
2704
- return text3.split(/(?=^Title: )/m).flatMap((block) => {
2716
+ function parseTextResults(text4) {
2717
+ return text4.split(/(?=^Title: )/m).flatMap((block) => {
2705
2718
  const url = block.match(/^URL: (.+)/m)?.[1]?.trim();
2706
2719
  if (!url) return [];
2707
2720
  const title = block.match(/^Title: (.+)/m)?.[1]?.trim() ?? "";
@@ -4248,8 +4261,8 @@ async function firecrawlFetch(endpoint, body, signal, options, label = endpoint,
4248
4261
  signal: requestSignal9(options?.timeoutMs ?? EXTRACT_TIMEOUT_MS, signal)
4249
4262
  }, options);
4250
4263
  if (!response.ok) {
4251
- const text3 = await response.text().catch(() => "");
4252
- throw new Error(`Firecrawl ${label} error ${response.status}: ${redactCredential(text3.slice(0, 300), apiKey)}`);
4264
+ const text4 = await response.text().catch(() => "");
4265
+ throw new Error(`Firecrawl ${label} error ${response.status}: ${redactCredential(text4.slice(0, 300), apiKey)}`);
4253
4266
  }
4254
4267
  let data;
4255
4268
  try {
@@ -4759,7 +4772,7 @@ var init_ollama = __esm({
4759
4772
  });
4760
4773
 
4761
4774
  // auth-fetch.ts
4762
- import { existsSync as existsSync40, readFileSync as readFileSync41 } from "node:fs";
4775
+ import { existsSync as existsSync41, readFileSync as readFileSync42 } from "node:fs";
4763
4776
  function resolveAuthFetchProfile(request) {
4764
4777
  const profiles = loadAuthFetchProfiles();
4765
4778
  if (profiles.length === 0) {
@@ -4797,8 +4810,8 @@ function authFetchRedirectGuard(profile, from, to) {
4797
4810
  }
4798
4811
  }
4799
4812
  function loadAuthFetchProfiles() {
4800
- if (!existsSync40(WEB_SEARCH_CONFIG_PATH2)) return [];
4801
- const raw = readFileSync41(WEB_SEARCH_CONFIG_PATH2, "utf-8");
4813
+ if (!existsSync41(WEB_SEARCH_CONFIG_PATH2)) return [];
4814
+ const raw = readFileSync42(WEB_SEARCH_CONFIG_PATH2, "utf-8");
4802
4815
  let parsed;
4803
4816
  try {
4804
4817
  const value = JSON.parse(raw);
@@ -5132,8 +5145,8 @@ function extractRSCContent(html) {
5132
5145
  if (!Array.isArray(node)) return;
5133
5146
  if (node[0] === "$" && (node[1] === "td" || node[1] === "th")) {
5134
5147
  const cellProps = node[3] || {};
5135
- const text3 = extractNode(cellProps.children, { inTable: true, inCode: false }).trim().replace(/\n/g, " ").replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
5136
- cells.push(text3);
5148
+ const text4 = extractNode(cellProps.children, { inTable: true, inCode: false }).trim().replace(/\n/g, " ").replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
5149
+ cells.push(text4);
5137
5150
  } else if (node[0] === "$" && typeof node[1] === "string" && node[1].startsWith("$L")) {
5138
5151
  const refId = node[1].slice(2);
5139
5152
  if (!visitedRefs.has(refId)) {
@@ -5173,9 +5186,9 @@ function extractRSCContent(html) {
5173
5186
  const parsed = getParsedChunk(id);
5174
5187
  if (!parsed) continue;
5175
5188
  visitedRefs.clear();
5176
- const text3 = extractNode(parsed);
5177
- if (text3.trim().length > 50 && !text3.includes("page was not found") && !text3.includes("404")) {
5178
- contentParts.push({ order: parseInt(id, 16), text: text3.trim() });
5189
+ const text4 = extractNode(parsed);
5190
+ if (text4.trim().length > 50 && !text4.includes("page was not found") && !text4.includes("404")) {
5191
+ contentParts.push({ order: parseInt(id, 16), text: text4.trim() });
5179
5192
  }
5180
5193
  }
5181
5194
  if (contentParts.length === 0) return null;
@@ -5198,20 +5211,20 @@ var init_rsc_extract = __esm({
5198
5211
  });
5199
5212
 
5200
5213
  // datalab-pdf-extract.ts
5201
- import { existsSync as existsSync41, readFileSync as readFileSync43 } from "node:fs";
5202
- function loadConfig35() {
5203
- if (cachedConfig34) return cachedConfig34;
5204
- if (!existsSync41(CONFIG_PATH38)) {
5205
- cachedConfig34 = {};
5206
- return cachedConfig34;
5214
+ import { existsSync as existsSync42, readFileSync as readFileSync44 } from "node:fs";
5215
+ function loadConfig36() {
5216
+ if (cachedConfig35) return cachedConfig35;
5217
+ if (!existsSync42(CONFIG_PATH39)) {
5218
+ cachedConfig35 = {};
5219
+ return cachedConfig35;
5207
5220
  }
5208
- const rawText = readFileSync43(CONFIG_PATH38, "utf-8");
5221
+ const rawText = readFileSync44(CONFIG_PATH39, "utf-8");
5209
5222
  try {
5210
- cachedConfig34 = JSON.parse(rawText);
5211
- return cachedConfig34;
5223
+ cachedConfig35 = JSON.parse(rawText);
5224
+ return cachedConfig35;
5212
5225
  } catch (err) {
5213
5226
  const message = err instanceof Error ? err.message : String(err);
5214
- throw new Error(`Failed to parse ${CONFIG_PATH38}: ${message}`);
5227
+ throw new Error(`Failed to parse ${CONFIG_PATH39}: ${message}`);
5215
5228
  }
5216
5229
  }
5217
5230
  function normalizeString(value) {
@@ -5226,14 +5239,14 @@ function normalizeFileId(value) {
5226
5239
  function isDatalabApiAvailable() {
5227
5240
  return hasCredentialSource({
5228
5241
  provider: "Datalab",
5229
- configuredValue: loadConfig35().datalabApiKey,
5242
+ configuredValue: loadConfig36().datalabApiKey,
5230
5243
  environmentValue: process.env.DATALAB_API_KEY
5231
5244
  });
5232
5245
  }
5233
5246
  async function getDatalabApiKey(signal) {
5234
5247
  return resolveCredential({
5235
5248
  provider: "Datalab",
5236
- configuredValue: loadConfig35().datalabApiKey,
5249
+ configuredValue: loadConfig36().datalabApiKey,
5237
5250
  environmentValue: process.env.DATALAB_API_KEY,
5238
5251
  signal
5239
5252
  });
@@ -5505,18 +5518,18 @@ async function fetchDatalab(url, init, apiKey) {
5505
5518
  }
5506
5519
  }
5507
5520
  async function readJsonResponse(response, apiKey) {
5508
- const text3 = await readResponseText(response);
5521
+ const text4 = await readResponseText(response);
5509
5522
  if (!response.ok) {
5510
- const detail = text3.trim().slice(0, MAX_ERROR_BODY_BYTES);
5523
+ const detail = text4.trim().slice(0, MAX_ERROR_BODY_BYTES);
5511
5524
  const message = detail ? `Datalab PDF conversion failed: HTTP ${response.status} ${response.statusText}: ${detail}` : `Datalab PDF conversion failed: HTTP ${response.status} ${response.statusText}`;
5512
5525
  throw new Error(redactCredential(message, apiKey));
5513
5526
  }
5514
- return parseJsonRecord(text3);
5527
+ return parseJsonRecord(text4);
5515
5528
  }
5516
- function parseJsonRecord(text3) {
5529
+ function parseJsonRecord(text4) {
5517
5530
  let parsed;
5518
5531
  try {
5519
- parsed = JSON.parse(text3);
5532
+ parsed = JSON.parse(text4);
5520
5533
  } catch (error) {
5521
5534
  throw new Error("Datalab PDF conversion returned invalid JSON", { cause: error });
5522
5535
  }
@@ -5558,7 +5571,7 @@ async function readResponseText(response) {
5558
5571
  function datalabFilename(title) {
5559
5572
  return title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 60) || "document";
5560
5573
  }
5561
- var DEFAULT_API_HOST2, API_PREFIX, DEFAULT_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, MAX_RESPONSE_BYTES, MAX_ERROR_BODY_BYTES, CLEANUP_TIMEOUT_MS, CONFIG_PATH38, DATALAB_MODE_VALUES, DATALAB_LOCATION_VALUES, DEFAULT_DATALAB_MODE, DEFAULT_PROCESSING_LOCATION, DEFAULT_DATALAB_TIMEOUT_MS, cachedConfig34;
5574
+ var DEFAULT_API_HOST2, API_PREFIX, DEFAULT_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, MAX_RESPONSE_BYTES, MAX_ERROR_BODY_BYTES, CLEANUP_TIMEOUT_MS, CONFIG_PATH39, DATALAB_MODE_VALUES, DATALAB_LOCATION_VALUES, DEFAULT_DATALAB_MODE, DEFAULT_PROCESSING_LOCATION, DEFAULT_DATALAB_TIMEOUT_MS, cachedConfig35;
5562
5575
  var init_datalab_pdf_extract = __esm({
5563
5576
  "datalab-pdf-extract.ts"() {
5564
5577
  init_credential_source();
@@ -5570,7 +5583,7 @@ var init_datalab_pdf_extract = __esm({
5570
5583
  MAX_RESPONSE_BYTES = 4 * 1024 * 1024;
5571
5584
  MAX_ERROR_BODY_BYTES = 300;
5572
5585
  CLEANUP_TIMEOUT_MS = 5e3;
5573
- CONFIG_PATH38 = getWebSearchConfigPath();
5586
+ CONFIG_PATH39 = getWebSearchConfigPath();
5574
5587
  DATALAB_MODE_VALUES = /* @__PURE__ */ new Set([
5575
5588
  "fast",
5576
5589
  "balanced",
@@ -5583,7 +5596,7 @@ var init_datalab_pdf_extract = __esm({
5583
5596
  DEFAULT_DATALAB_MODE = "balanced";
5584
5597
  DEFAULT_PROCESSING_LOCATION = "us";
5585
5598
  DEFAULT_DATALAB_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;
5586
- cachedConfig34 = null;
5599
+ cachedConfig35 = null;
5587
5600
  }
5588
5601
  });
5589
5602
 
@@ -5673,12 +5686,12 @@ var init_gemini_pdf_extract = __esm({
5673
5686
  });
5674
5687
 
5675
5688
  // pdf-extract.ts
5676
- import { existsSync as existsSync42, readFileSync as readFileSync44 } from "node:fs";
5689
+ import { existsSync as existsSync43, readFileSync as readFileSync45 } from "node:fs";
5677
5690
  import { writeFile as writeFile2, mkdir } from "node:fs/promises";
5678
5691
  import { join as join5, basename as basename2 } from "node:path";
5679
5692
  import { tmpdir as tmpdir3 } from "node:os";
5680
5693
  function loadPDFConfig() {
5681
- if (!existsSync42(CONFIG_PATH39)) {
5694
+ if (!existsSync43(CONFIG_PATH40)) {
5682
5695
  return {
5683
5696
  enabled: true,
5684
5697
  maxSizeMB: DEFAULT_PDF_MAX_SIZE_MB,
@@ -5688,13 +5701,13 @@ function loadPDFConfig() {
5688
5701
  datalabTimeoutMs: DEFAULT_DATALAB_TIMEOUT_MS
5689
5702
  };
5690
5703
  }
5691
- const rawText = readFileSync44(CONFIG_PATH39, "utf-8");
5704
+ const rawText = readFileSync45(CONFIG_PATH40, "utf-8");
5692
5705
  let raw;
5693
5706
  try {
5694
5707
  raw = JSON.parse(rawText);
5695
5708
  } catch (err) {
5696
5709
  const message = err instanceof Error ? err.message : String(err);
5697
- throw new Error(`Failed to parse ${CONFIG_PATH39}: ${message}`);
5710
+ throw new Error(`Failed to parse ${CONFIG_PATH40}: ${message}`);
5698
5711
  }
5699
5712
  const root = raw && typeof raw === "object" ? raw : {};
5700
5713
  const pdf = root.pdf && typeof root.pdf === "object" ? root.pdf : {};
@@ -5903,7 +5916,7 @@ function isPDF(url, contentType) {
5903
5916
  return false;
5904
5917
  }
5905
5918
  }
5906
- var PDF_PROVIDER_VALUES, DEFAULT_PDF_MAX_SIZE_MB, MAX_PDF_MAX_SIZE_MB, MAX_DATALAB_TIMEOUT_MS, DEFAULT_MAX_PAGES, DEFAULT_OUTPUT_DIR, CONFIG_PATH39, PAGE_MARKER_PATTERN2;
5919
+ var PDF_PROVIDER_VALUES, DEFAULT_PDF_MAX_SIZE_MB, MAX_PDF_MAX_SIZE_MB, MAX_DATALAB_TIMEOUT_MS, DEFAULT_MAX_PAGES, DEFAULT_OUTPUT_DIR, CONFIG_PATH40, PAGE_MARKER_PATTERN2;
5907
5920
  var init_pdf_extract = __esm({
5908
5921
  "pdf-extract.ts"() {
5909
5922
  init_credential_source();
@@ -5922,7 +5935,7 @@ var init_pdf_extract = __esm({
5922
5935
  MAX_DATALAB_TIMEOUT_MS = 3e5;
5923
5936
  DEFAULT_MAX_PAGES = 100;
5924
5937
  DEFAULT_OUTPUT_DIR = join5(tmpdir3(), "pi-web-pdf");
5925
- CONFIG_PATH39 = getWebSearchConfigPath();
5938
+ CONFIG_PATH40 = getWebSearchConfigPath();
5926
5939
  PAGE_MARKER_PATTERN2 = /^<!-- Page (\d+) -->$/gm;
5927
5940
  }
5928
5941
  });
@@ -6100,7 +6113,7 @@ var init_github_api = __esm({
6100
6113
  });
6101
6114
 
6102
6115
  // github-extract.ts
6103
- import { chmodSync, closeSync as closeSync2, constants as fsConstants, existsSync as existsSync43, lstatSync as lstatSync2, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, openSync as openSync2, readFileSync as readFileSync45, readSync, readdirSync as readdirSync3, realpathSync as realpathSync2, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
6116
+ import { chmodSync, closeSync as closeSync2, constants as fsConstants, existsSync as existsSync44, lstatSync as lstatSync2, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, openSync as openSync2, readFileSync as readFileSync46, readSync, readdirSync as readdirSync3, realpathSync as realpathSync2, rmSync as rmSync2, statSync as statSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
6104
6117
  import { lstat as lstatAsync, open as openAsync, opendir as opendirAsync, readFile as readFileAsync, realpath as realpathAsync, rm as rmAsync } from "node:fs/promises";
6105
6118
  import { execFile as execFile3, spawn as spawn2 } from "node:child_process";
6106
6119
  import { createHash as createHash2 } from "node:crypto";
@@ -6129,33 +6142,33 @@ function normalizeClonePath(value, fallback) {
6129
6142
  return expandPath(normalized);
6130
6143
  }
6131
6144
  function loadGitHubConfig() {
6132
- if (cachedConfig35) return cachedConfig35;
6145
+ if (cachedConfig36) return cachedConfig36;
6133
6146
  const defaults2 = {
6134
6147
  enabled: true,
6135
6148
  maxRepoSizeMB: 350,
6136
6149
  cloneTimeoutSeconds: 30,
6137
6150
  clonePath: "/tmp/pi-github-repos"
6138
6151
  };
6139
- if (!existsSync43(CONFIG_PATH40)) {
6140
- cachedConfig35 = defaults2;
6141
- return cachedConfig35;
6152
+ if (!existsSync44(CONFIG_PATH41)) {
6153
+ cachedConfig36 = defaults2;
6154
+ return cachedConfig36;
6142
6155
  }
6143
- const rawText = readFileSync45(CONFIG_PATH40, "utf-8");
6156
+ const rawText = readFileSync46(CONFIG_PATH41, "utf-8");
6144
6157
  let raw;
6145
6158
  try {
6146
6159
  raw = JSON.parse(rawText);
6147
6160
  } catch (err) {
6148
6161
  const message = err instanceof Error ? err.message : String(err);
6149
- throw new Error(`Failed to parse ${CONFIG_PATH40}: ${message}`);
6162
+ throw new Error(`Failed to parse ${CONFIG_PATH41}: ${message}`);
6150
6163
  }
6151
6164
  const gc = raw.githubClone ?? {};
6152
- cachedConfig35 = {
6165
+ cachedConfig36 = {
6153
6166
  enabled: normalizeEnabled(gc.enabled, defaults2.enabled),
6154
6167
  maxRepoSizeMB: normalizePositiveNumber(gc.maxRepoSizeMB, defaults2.maxRepoSizeMB),
6155
6168
  cloneTimeoutSeconds: normalizePositiveNumber(gc.cloneTimeoutSeconds, defaults2.cloneTimeoutSeconds),
6156
6169
  clonePath: normalizeClonePath(gc.clonePath, defaults2.clonePath)
6157
6170
  };
6158
- return cachedConfig35;
6171
+ return cachedConfig36;
6159
6172
  }
6160
6173
  function parseGitHubUrl(url) {
6161
6174
  let parsed;
@@ -6206,7 +6219,7 @@ function cacheKey(owner, repo, ref) {
6206
6219
  }
6207
6220
  function readLinuxBootId() {
6208
6221
  try {
6209
- const bootId = readFileSync45("/proc/sys/kernel/random/boot_id", "utf-8").trim();
6222
+ const bootId = readFileSync46("/proc/sys/kernel/random/boot_id", "utf-8").trim();
6210
6223
  return bootId.length > 0 ? bootId : null;
6211
6224
  } catch {
6212
6225
  return null;
@@ -6231,7 +6244,7 @@ function parseLinuxProcessInfo(stat) {
6231
6244
  }
6232
6245
  function readLinuxProcessInfo(pid) {
6233
6246
  try {
6234
- return parseLinuxProcessInfo(readFileSync45(`/proc/${pid}/stat`, "utf-8"));
6247
+ return parseLinuxProcessInfo(readFileSync46(`/proc/${pid}/stat`, "utf-8"));
6235
6248
  } catch (err) {
6236
6249
  if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
6237
6250
  return { state: "", startTime: null, dead: true };
@@ -6273,10 +6286,10 @@ function writeCloneRuntimeOwner(runtimePath) {
6273
6286
  mode: 384
6274
6287
  });
6275
6288
  }
6276
- function parseCloneRuntimeOwner(text3) {
6289
+ function parseCloneRuntimeOwner(text4) {
6277
6290
  let parsed;
6278
6291
  try {
6279
- parsed = JSON.parse(text3);
6292
+ parsed = JSON.parse(text4);
6280
6293
  } catch {
6281
6294
  return null;
6282
6295
  }
@@ -6569,7 +6582,7 @@ function resolveWithinRepo(rootPath, relativePath) {
6569
6582
  const rootPrefix = normalizedRoot.endsWith(pathSep) ? normalizedRoot : normalizedRoot + pathSep;
6570
6583
  if (!candidate.startsWith(rootPrefix)) return null;
6571
6584
  }
6572
- if (!existsSync43(candidate)) return candidate;
6585
+ if (!existsSync44(candidate)) return candidate;
6573
6586
  try {
6574
6587
  const realRoot = realpathSync2(normalizedRoot);
6575
6588
  const realCandidate = realpathSync2(candidate);
@@ -6582,7 +6595,7 @@ function resolveWithinRepo(rootPath, relativePath) {
6582
6595
  }
6583
6596
  function readTextFile(path) {
6584
6597
  try {
6585
- return readFileSync45(path, "utf-8");
6598
+ return readFileSync46(path, "utf-8");
6586
6599
  } catch {
6587
6600
  return null;
6588
6601
  }
@@ -6665,9 +6678,9 @@ function readReadme(localPath) {
6665
6678
  const candidates = ["README.md", "readme.md", "README", "README.txt", "README.rst"];
6666
6679
  for (const name of candidates) {
6667
6680
  const readmePath = join6(localPath, name);
6668
- if (existsSync43(readmePath)) {
6681
+ if (existsSync44(readmePath)) {
6669
6682
  try {
6670
- const content = readFileSync45(readmePath, "utf-8");
6683
+ const content = readFileSync46(readmePath, "utf-8");
6671
6684
  return content.length > 8192 ? content.slice(0, 8192) + "\n\n[README truncated at 8K chars]" : content;
6672
6685
  } catch {
6673
6686
  continue;
@@ -6696,7 +6709,7 @@ function generateContent(localPath, info) {
6696
6709
  if (info.type === "tree") {
6697
6710
  const dirPath = info.path || "";
6698
6711
  const fullDirPath = resolveWithinRepo(localPath, dirPath);
6699
- if (!fullDirPath || !existsSync43(fullDirPath)) {
6712
+ if (!fullDirPath || !existsSync44(fullDirPath)) {
6700
6713
  lines.push(`Path \`${dirPath}\` not found in clone. Showing repository root instead.`);
6701
6714
  lines.push("");
6702
6715
  lines.push("## Structure");
@@ -6712,7 +6725,7 @@ function generateContent(localPath, info) {
6712
6725
  if (info.type === "blob") {
6713
6726
  const filePath = info.path || "";
6714
6727
  const fullFilePath = resolveWithinRepo(localPath, filePath);
6715
- if (!fullFilePath || !existsSync43(fullFilePath)) {
6728
+ if (!fullFilePath || !existsSync44(fullFilePath)) {
6716
6729
  lines.push(`Path \`${filePath}\` not found in clone. Showing repository root instead.`);
6717
6730
  lines.push("");
6718
6731
  lines.push("## Structure");
@@ -6785,7 +6798,10 @@ async function extractGitHub(url, signal, forceClone) {
6785
6798
  const { owner, repo } = info;
6786
6799
  const key = cacheKey(owner, repo, info.ref);
6787
6800
  const cached = cloneCache.get(key);
6788
- if (cached) return awaitCachedClone(cached, url, owner, repo, info, signal);
6801
+ if (cached) {
6802
+ cached.lastUsedAt = Date.now();
6803
+ return awaitCachedClone(cached, url, owner, repo, info, signal);
6804
+ }
6789
6805
  if (info.refIsFullSha) {
6790
6806
  if (signal?.aborted) return null;
6791
6807
  const sizeNote = `Note: Commit SHA URLs use the GitHub API instead of cloning.`;
@@ -6822,6 +6838,7 @@ async function extractGitHub(url, signal, forceClone) {
6822
6838
  }
6823
6839
  const cachedAfterSizeCheck = cloneCache.get(key);
6824
6840
  if (cachedAfterSizeCheck) {
6841
+ cachedAfterSizeCheck.lastUsedAt = Date.now();
6825
6842
  const cachedResult = await awaitCachedClone(cachedAfterSizeCheck, url, owner, repo, info, signal);
6826
6843
  if (signal?.aborted) {
6827
6844
  activityMonitor.logComplete(activityId, 0);
@@ -6840,7 +6857,11 @@ async function extractGitHub(url, signal, forceClone) {
6840
6857
  return apiFallback;
6841
6858
  }
6842
6859
  const clonePromise = cloneRepo(owner, repo, info.ref, config, destination, signal);
6843
- cloneCache.set(key, { destination, clonePromise });
6860
+ const entry = { destination, clonePromise, lastUsedAt: Date.now(), settled: false };
6861
+ cloneCache.set(key, entry);
6862
+ void clonePromise.finally(() => {
6863
+ entry.settled = true;
6864
+ });
6844
6865
  const result = await clonePromise;
6845
6866
  if (signal?.aborted) {
6846
6867
  if (!result) cloneCache.delete(key);
@@ -6866,13 +6887,13 @@ async function extractGitHub(url, signal, forceClone) {
6866
6887
  const title = info.path ? `${owner}/${repo} - ${info.path}` : `${owner}/${repo}`;
6867
6888
  return { url, title, content, error: null };
6868
6889
  }
6869
- var CONFIG_PATH40, BINARY_EXTENSIONS, NOISE_DIRS, MAX_INLINE_FILE_CHARS2, MAX_TREE_ENTRIES2, CLONE_RUNTIME_OWNER_FILENAME, CLONE_RUNTIME_OWNER_VERSION, MAX_CLONE_RUNTIME_OWNER_BYTES, cloneCache, startedCloneRuntimeCleanups, cachedConfig35, cloneRuntime, NON_CODE_SEGMENTS, PROCESS_KILL_GRACE_MS;
6890
+ var CONFIG_PATH41, BINARY_EXTENSIONS, NOISE_DIRS, MAX_INLINE_FILE_CHARS2, MAX_TREE_ENTRIES2, CLONE_RUNTIME_OWNER_FILENAME, CLONE_RUNTIME_OWNER_VERSION, MAX_CLONE_RUNTIME_OWNER_BYTES, cloneCache, startedCloneRuntimeCleanups, cachedConfig36, cloneRuntime, NON_CODE_SEGMENTS, PROCESS_KILL_GRACE_MS;
6870
6891
  var init_github_extract = __esm({
6871
6892
  "github-extract.ts"() {
6872
6893
  init_activity();
6873
6894
  init_github_api();
6874
6895
  init_utils();
6875
- CONFIG_PATH40 = getWebSearchConfigPath();
6896
+ CONFIG_PATH41 = getWebSearchConfigPath();
6876
6897
  BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
6877
6898
  ".png",
6878
6899
  ".jpg",
@@ -6960,7 +6981,7 @@ var init_github_extract = __esm({
6960
6981
  MAX_CLONE_RUNTIME_OWNER_BYTES = 1024;
6961
6982
  cloneCache = /* @__PURE__ */ new Map();
6962
6983
  startedCloneRuntimeCleanups = /* @__PURE__ */ new Set();
6963
- cachedConfig35 = null;
6984
+ cachedConfig36 = null;
6964
6985
  cloneRuntime = null;
6965
6986
  NON_CODE_SEGMENTS = /* @__PURE__ */ new Set([
6966
6987
  "issues",
@@ -6999,29 +7020,29 @@ var init_github_extract = __esm({
6999
7020
 
7000
7021
  // github-issue-pr.ts
7001
7022
  import { execFile as execFile4 } from "node:child_process";
7002
- import { existsSync as existsSync44, readFileSync as readFileSync46 } from "node:fs";
7003
- function loadConfig36() {
7004
- if (cachedConfig36) return cachedConfig36;
7023
+ import { existsSync as existsSync45, readFileSync as readFileSync47 } from "node:fs";
7024
+ function loadConfig37() {
7025
+ if (cachedConfig37) return cachedConfig37;
7005
7026
  const defaults2 = { enabled: true };
7006
- if (!existsSync44(CONFIG_PATH41)) {
7007
- cachedConfig36 = defaults2;
7008
- return cachedConfig36;
7027
+ if (!existsSync45(CONFIG_PATH42)) {
7028
+ cachedConfig37 = defaults2;
7029
+ return cachedConfig37;
7009
7030
  }
7010
7031
  let parsed;
7011
7032
  try {
7012
- parsed = JSON.parse(readFileSync46(CONFIG_PATH41, "utf-8"));
7033
+ parsed = JSON.parse(readFileSync47(CONFIG_PATH42, "utf-8"));
7013
7034
  } catch (err) {
7014
7035
  const message = err instanceof Error ? err.message : String(err);
7015
- throw new Error(`Failed to parse ${CONFIG_PATH41}: ${message}`);
7036
+ throw new Error(`Failed to parse ${CONFIG_PATH42}: ${message}`);
7016
7037
  }
7017
7038
  const root = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7018
7039
  const value = root.githubPrIssue;
7019
7040
  if (value !== void 0 && (typeof value !== "object" || value === null || Array.isArray(value))) {
7020
- throw new Error(`githubPrIssue in ${CONFIG_PATH41} must be an object`);
7041
+ throw new Error(`githubPrIssue in ${CONFIG_PATH42} must be an object`);
7021
7042
  }
7022
7043
  const enabled = typeof value?.enabled === "boolean" ? value.enabled : true;
7023
- cachedConfig36 = { enabled };
7024
- return cachedConfig36;
7044
+ cachedConfig37 = { enabled };
7045
+ return cachedConfig37;
7025
7046
  }
7026
7047
  function validOwner(owner) {
7027
7048
  return /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/.test(owner) && !owner.includes("--");
@@ -7029,11 +7050,11 @@ function validOwner(owner) {
7029
7050
  function validRepo(repo) {
7030
7051
  return /^[A-Za-z0-9._-]{1,100}$/.test(repo) && repo !== "." && repo !== "..";
7031
7052
  }
7032
- function errorMessage27(err) {
7053
+ function errorMessage28(err) {
7033
7054
  return err instanceof Error ? err.message : String(err);
7034
7055
  }
7035
7056
  function isAbortError3(err) {
7036
- return errorMessage27(err).toLowerCase().includes("abort");
7057
+ return errorMessage28(err).toLowerCase().includes("abort");
7037
7058
  }
7038
7059
  function parseGitHubIssuePrUrl(url) {
7039
7060
  let parsed;
@@ -7269,7 +7290,7 @@ async function restFallback(url, info, options, signal) {
7269
7290
  return { data: { url, owner: info.owner, repo: info.repo, kind: info.kind, number: info.number, anchor: info.anchor, view, reviewThreads, fallbackNotes: notes } };
7270
7291
  } catch (err) {
7271
7292
  if (signal?.aborted || isAbortError3(err)) return { url, title: "", content: "", error: "Aborted" };
7272
- const message = errorMessage27(err);
7293
+ const message = errorMessage28(err);
7273
7294
  return { url, title: `${info.owner}/${info.repo}#${info.number}`, content: message, error: `GitHub REST fallback failed: ${message}` };
7274
7295
  }
7275
7296
  }
@@ -7327,12 +7348,12 @@ function milestoneTitle(value) {
7327
7348
  if (!value || typeof value !== "object" || Array.isArray(value)) return "none";
7328
7349
  return stringValue(value.title) || "none";
7329
7350
  }
7330
- function truncateText(text3, limit, label, appendix) {
7331
- if (text3.length <= limit) return text3;
7351
+ function truncateText(text4, limit, label, appendix) {
7352
+ if (text4.length <= limit) return text4;
7332
7353
  appendix.push(`## Full ${label}
7333
7354
 
7334
- ${text3}`);
7335
- return `${text3.slice(0, limit)}
7355
+ ${text4}`);
7356
+ return `${text4.slice(0, limit)}
7336
7357
 
7337
7358
  [${label} truncated; use get_search_content findText or offset for the full text]`;
7338
7359
  }
@@ -7562,7 +7583,7 @@ function renderGitHubPrIssue(data) {
7562
7583
  async function extractGitHubIssuePr(url, signal, options) {
7563
7584
  const info = parseGitHubIssuePrUrl(url);
7564
7585
  if (!info) return null;
7565
- if (!loadConfig36().enabled) return null;
7586
+ if (!loadConfig37().enabled) return null;
7566
7587
  if (signal?.aborted) return { url, title: "", content: "", error: "Aborted" };
7567
7588
  const ghAvailable2 = await checkGhAvailable(signal);
7568
7589
  if (signal?.aborted) return { url, title: "", content: "", error: "Aborted" };
@@ -7585,13 +7606,13 @@ async function extractGitHubIssuePr(url, signal, options) {
7585
7606
  if ("data" in fallback) return renderGitHubPrIssue(fallback.data);
7586
7607
  return fallback;
7587
7608
  }
7588
- var CONFIG_PATH41, GH_TIMEOUT_MS, GH_TOTAL_TIMEOUT_MS, MAX_DOC_CHARS, BODY_INLINE_CHARS, COMMENT_INLINE_CHARS, MAX_INLINE_COMMENTS, MAX_INLINE_REVIEWS, MAX_INLINE_CHECKS, MAX_INLINE_FILES, MAX_INLINE_COMMITS, MAX_INLINE_REVIEW_THREADS, REST_HEADERS, PR_SUBPATHS, PR_FIELDS, PR_CORE_FIELDS, ISSUE_FIELDS, ISSUE_CORE_FIELDS, cachedConfig36;
7609
+ var CONFIG_PATH42, GH_TIMEOUT_MS, GH_TOTAL_TIMEOUT_MS, MAX_DOC_CHARS, BODY_INLINE_CHARS, COMMENT_INLINE_CHARS, MAX_INLINE_COMMENTS, MAX_INLINE_REVIEWS, MAX_INLINE_CHECKS, MAX_INLINE_FILES, MAX_INLINE_COMMITS, MAX_INLINE_REVIEW_THREADS, REST_HEADERS, PR_SUBPATHS, PR_FIELDS, PR_CORE_FIELDS, ISSUE_FIELDS, ISSUE_CORE_FIELDS, cachedConfig37;
7589
7610
  var init_github_issue_pr = __esm({
7590
7611
  "github-issue-pr.ts"() {
7591
7612
  init_github_api();
7592
7613
  init_ssrf_protection();
7593
7614
  init_utils();
7594
- CONFIG_PATH41 = getWebSearchConfigPath();
7615
+ CONFIG_PATH42 = getWebSearchConfigPath();
7595
7616
  GH_TIMEOUT_MS = 1e4;
7596
7617
  GH_TOTAL_TIMEOUT_MS = 2e4;
7597
7618
  MAX_DOC_CHARS = 15e4;
@@ -7672,20 +7693,20 @@ var init_github_issue_pr = __esm({
7672
7693
  "url"
7673
7694
  ];
7674
7695
  ISSUE_CORE_FIELDS = ["title", "number", "state", "author", "createdAt", "closedAt", "labels", "assignees", "milestone", "comments", "body", "url"];
7675
- cachedConfig36 = null;
7696
+ cachedConfig37 = null;
7676
7697
  }
7677
7698
  });
7678
7699
 
7679
7700
  // feature-config.ts
7680
- import { existsSync as existsSync45, readFileSync as readFileSync47 } from "node:fs";
7701
+ import { existsSync as existsSync46, readFileSync as readFileSync48 } from "node:fs";
7681
7702
  function loadFeatureConfig() {
7682
- if (!existsSync45(CONFIG_PATH42)) return {};
7703
+ if (!existsSync46(CONFIG_PATH43)) return {};
7683
7704
  try {
7684
- const raw = JSON.parse(readFileSync47(CONFIG_PATH42, "utf-8"));
7705
+ const raw = JSON.parse(readFileSync48(CONFIG_PATH43, "utf-8"));
7685
7706
  return raw && typeof raw === "object" ? raw : {};
7686
7707
  } catch (err) {
7687
7708
  const message = err instanceof Error ? err.message : String(err);
7688
- throw new Error(`Failed to parse ${CONFIG_PATH42}: ${message}`);
7709
+ throw new Error(`Failed to parse ${CONFIG_PATH43}: ${message}`);
7689
7710
  }
7690
7711
  }
7691
7712
  function isImageEnabled() {
@@ -7698,25 +7719,25 @@ function canAttachImages() {
7698
7719
  return false;
7699
7720
  }
7700
7721
  }
7701
- var CONFIG_PATH42;
7722
+ var CONFIG_PATH43;
7702
7723
  var init_feature_config = __esm({
7703
7724
  "feature-config.ts"() {
7704
7725
  init_utils();
7705
- CONFIG_PATH42 = getWebSearchConfigPath();
7726
+ CONFIG_PATH43 = getWebSearchConfigPath();
7706
7727
  }
7707
7728
  });
7708
7729
 
7709
7730
  // youtube-extract.ts
7710
7731
  import { execFileSync } from "node:child_process";
7711
- import { existsSync as existsSync46, readFileSync as readFileSync48 } from "node:fs";
7712
- function errorMessage28(err) {
7732
+ import { existsSync as existsSync47, readFileSync as readFileSync49 } from "node:fs";
7733
+ function errorMessage29(err) {
7713
7734
  return err instanceof Error ? err.message : String(err);
7714
7735
  }
7715
7736
  function shouldRethrow(err) {
7716
- return errorMessage28(err).startsWith("Failed to parse ");
7737
+ return errorMessage29(err).startsWith("Failed to parse ");
7717
7738
  }
7718
7739
  function addAttemptError(errors, label, err) {
7719
- const message = errorMessage28(err).replace(/\s+/g, " ").trim();
7740
+ const message = errorMessage29(err).replace(/\s+/g, " ").trim();
7720
7741
  if (message) errors.push(`${label}: ${message}`);
7721
7742
  }
7722
7743
  function normalizePreferredModel(value, fallback) {
@@ -7728,25 +7749,25 @@ function normalizeEnabled2(value, fallback) {
7728
7749
  return typeof value === "boolean" ? value : fallback;
7729
7750
  }
7730
7751
  function loadYouTubeConfig() {
7731
- if (cachedConfig37) return cachedConfig37;
7732
- if (!existsSync46(CONFIG_PATH43)) {
7733
- cachedConfig37 = { ...defaults };
7734
- return cachedConfig37;
7752
+ if (cachedConfig38) return cachedConfig38;
7753
+ if (!existsSync47(CONFIG_PATH44)) {
7754
+ cachedConfig38 = { ...defaults };
7755
+ return cachedConfig38;
7735
7756
  }
7736
- const rawText = readFileSync48(CONFIG_PATH43, "utf-8");
7757
+ const rawText = readFileSync49(CONFIG_PATH44, "utf-8");
7737
7758
  let raw;
7738
7759
  try {
7739
7760
  raw = JSON.parse(rawText);
7740
7761
  } catch (err) {
7741
7762
  const message = err instanceof Error ? err.message : String(err);
7742
- throw new Error(`Failed to parse ${CONFIG_PATH43}: ${message}`);
7763
+ throw new Error(`Failed to parse ${CONFIG_PATH44}: ${message}`);
7743
7764
  }
7744
7765
  const yt = raw.youtube ?? {};
7745
- cachedConfig37 = {
7766
+ cachedConfig38 = {
7746
7767
  enabled: normalizeEnabled2(yt.enabled, defaults.enabled),
7747
7768
  preferredModel: normalizePreferredModel(yt.preferredModel, defaults.preferredModel)
7748
7769
  };
7749
- return cachedConfig37;
7770
+ return cachedConfig38;
7750
7771
  }
7751
7772
  function isYouTubeURL(url) {
7752
7773
  try {
@@ -7876,7 +7897,7 @@ async function tryGeminiWeb(url, prompt, model, signal, attemptErrors) {
7876
7897
  const cookies = await isGeminiWebAvailable();
7877
7898
  if (!cookies) return null;
7878
7899
  if (signal?.aborted) return null;
7879
- const text3 = await queryWithCookies(prompt, cookies, {
7900
+ const text4 = await queryWithCookies(prompt, cookies, {
7880
7901
  youtubeUrl: url,
7881
7902
  ...model !== "gemini-3.6-flash" ? { model } : {},
7882
7903
  signal,
@@ -7884,8 +7905,8 @@ async function tryGeminiWeb(url, prompt, model, signal, attemptErrors) {
7884
7905
  });
7885
7906
  return {
7886
7907
  url,
7887
- title: extractHeadingTitle(text3) ?? "YouTube Video",
7888
- content: text3,
7908
+ title: extractHeadingTitle(text4) ?? "YouTube Video",
7909
+ content: text4,
7889
7910
  error: null
7890
7911
  };
7891
7912
  } catch (err) {
@@ -7898,15 +7919,15 @@ async function tryGeminiApi(url, prompt, model, signal, attemptErrors) {
7898
7919
  try {
7899
7920
  if (!isGeminiApiAvailableWithVideo()) return null;
7900
7921
  if (signal?.aborted) return null;
7901
- const text3 = await queryGeminiApiWithVideo(prompt, url, {
7922
+ const text4 = await queryGeminiApiWithVideo(prompt, url, {
7902
7923
  model,
7903
7924
  signal,
7904
7925
  timeoutMs: 12e4
7905
7926
  });
7906
7927
  return {
7907
7928
  url,
7908
- title: extractHeadingTitle(text3) ?? "YouTube Video",
7909
- content: text3,
7929
+ title: extractHeadingTitle(text4) ?? "YouTube Video",
7930
+ content: text4,
7910
7931
  error: null
7911
7932
  };
7912
7933
  } catch (err) {
@@ -7938,7 +7959,7 @@ ${answer}
7938
7959
  return null;
7939
7960
  }
7940
7961
  }
7941
- var CONFIG_PATH43, YOUTUBE_PROMPT, YOUTUBE_REGEX, defaults, cachedConfig37;
7962
+ var CONFIG_PATH44, YOUTUBE_PROMPT, YOUTUBE_REGEX, defaults, cachedConfig38;
7942
7963
  var init_youtube_extract = __esm({
7943
7964
  "youtube-extract.ts"() {
7944
7965
  init_activity();
@@ -7948,7 +7969,7 @@ var init_youtube_extract = __esm({
7948
7969
  init_perplexity();
7949
7970
  init_extract();
7950
7971
  init_utils();
7951
- CONFIG_PATH43 = getWebSearchConfigPath();
7972
+ CONFIG_PATH44 = getWebSearchConfigPath();
7952
7973
  YOUTUBE_PROMPT = `Extract the complete content of this YouTube video. Include:
7953
7974
  1. Video title, channel name, and duration
7954
7975
  2. A brief summary (2-3 sentences)
@@ -7958,7 +7979,7 @@ var init_youtube_extract = __esm({
7958
7979
  Format as markdown.`;
7959
7980
  YOUTUBE_REGEX = /(?:(?:www\.|m\.)?youtube\.com\/(?:watch\?.*v=|shorts\/|live\/|embed\/|v\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/;
7960
7981
  defaults = { enabled: true, preferredModel: "gemini-3.6-flash" };
7961
- cachedConfig37 = null;
7982
+ cachedConfig38 = null;
7962
7983
  }
7963
7984
  });
7964
7985
 
@@ -8020,14 +8041,14 @@ async function extractWithGeminiWeb(url, signal) {
8020
8041
  if (!cookies) return null;
8021
8042
  const activityId = activityMonitor.logStart({ type: "api", query: `gemini_web: ${url}` });
8022
8043
  try {
8023
- const text3 = await queryWithCookies(EXTRACTION_PROMPT + url, cookies, {
8044
+ const text4 = await queryWithCookies(EXTRACTION_PROMPT + url, cookies, {
8024
8045
  signal,
8025
8046
  timeoutMs: 6e4
8026
8047
  });
8027
8048
  activityMonitor.logComplete(activityId, 200);
8028
- if (!text3 || text3.length < 50) return null;
8029
- const title = extractTitleFromContent(text3, url);
8030
- return { url, title, content: text3, error: null };
8049
+ if (!text4 || text4.length < 50) return null;
8050
+ const title = extractTitleFromContent(text4, url);
8051
+ return { url, title, content: text4, error: null };
8031
8052
  } catch (err) {
8032
8053
  if (shouldRethrow2(err)) throw err;
8033
8054
  const message = err instanceof Error ? err.message : String(err);
@@ -8039,8 +8060,8 @@ async function extractWithGeminiWeb(url, signal) {
8039
8060
  return null;
8040
8061
  }
8041
8062
  }
8042
- function extractTitleFromContent(text3, url) {
8043
- return extractHeadingTitle(text3) ?? (new URL(url).pathname.split("/").pop() || url);
8063
+ function extractTitleFromContent(text4, url) {
8064
+ return extractHeadingTitle(text4) ?? (new URL(url).pathname.split("/").pop() || url);
8044
8065
  }
8045
8066
  var EXTRACTION_PROMPT;
8046
8067
  var init_gemini_url_context = __esm({
@@ -8060,26 +8081,26 @@ URL: `;
8060
8081
  });
8061
8082
 
8062
8083
  // crawl4ai.ts
8063
- import { existsSync as existsSync47, readFileSync as readFileSync49 } from "node:fs";
8064
- function loadConfig37() {
8065
- if (cachedConfig38) return cachedConfig38;
8066
- if (!existsSync47(CONFIG_PATH44)) {
8067
- cachedConfig38 = {};
8068
- return cachedConfig38;
8084
+ import { existsSync as existsSync48, readFileSync as readFileSync50 } from "node:fs";
8085
+ function loadConfig38() {
8086
+ if (cachedConfig39) return cachedConfig39;
8087
+ if (!existsSync48(CONFIG_PATH45)) {
8088
+ cachedConfig39 = {};
8089
+ return cachedConfig39;
8069
8090
  }
8070
- const raw = readFileSync49(CONFIG_PATH44, "utf8");
8091
+ const raw = readFileSync50(CONFIG_PATH45, "utf8");
8071
8092
  let parsed;
8072
8093
  try {
8073
8094
  parsed = JSON.parse(raw);
8074
8095
  } catch (err) {
8075
8096
  const message = err instanceof Error ? err.message : String(err);
8076
- throw new Error(`Failed to parse ${CONFIG_PATH44}: ${message}`);
8097
+ throw new Error(`Failed to parse ${CONFIG_PATH45}: ${message}`);
8077
8098
  }
8078
8099
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8079
- throw new Error(`Invalid config in ${CONFIG_PATH44}: expected a JSON object`);
8100
+ throw new Error(`Invalid config in ${CONFIG_PATH45}: expected a JSON object`);
8080
8101
  }
8081
- cachedConfig38 = parsed;
8082
- return cachedConfig38;
8102
+ cachedConfig39 = parsed;
8103
+ return cachedConfig39;
8083
8104
  }
8084
8105
  function normalizeBaseUrl5(value) {
8085
8106
  if (typeof value !== "string") return null;
@@ -8089,13 +8110,13 @@ function normalizeBaseUrl5(value) {
8089
8110
  try {
8090
8111
  parsed = new URL(trimmed);
8091
8112
  } catch {
8092
- throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH44}: expected an HTTP or HTTPS URL`);
8113
+ throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH45}: expected an HTTP or HTTPS URL`);
8093
8114
  }
8094
8115
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
8095
- throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH44}: expected an HTTP or HTTPS URL`);
8116
+ throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH45}: expected an HTTP or HTTPS URL`);
8096
8117
  }
8097
8118
  if (parsed.username || parsed.password) {
8098
- throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH44}: URL credentials are not allowed`);
8119
+ throw new Error(`Invalid Crawl4AI base URL in ${CONFIG_PATH45}: URL credentials are not allowed`);
8099
8120
  }
8100
8121
  parsed.pathname = parsed.pathname.replace(/\/+$/, "");
8101
8122
  parsed.search = "";
@@ -8103,14 +8124,14 @@ function normalizeBaseUrl5(value) {
8103
8124
  return parsed.toString().replace(/\/+$/, "");
8104
8125
  }
8105
8126
  function getBaseUrl4() {
8106
- return normalizeBaseUrl5(process.env.CRAWL4AI_BASE_URL) ?? normalizeBaseUrl5(loadConfig37().crawl4aiBaseUrl);
8127
+ return normalizeBaseUrl5(process.env.CRAWL4AI_BASE_URL) ?? normalizeBaseUrl5(loadConfig38().crawl4aiBaseUrl);
8107
8128
  }
8108
8129
  function requireBaseUrl4() {
8109
8130
  const baseUrl = getBaseUrl4();
8110
8131
  if (!baseUrl) {
8111
8132
  throw new Error(
8112
8133
  `Crawl4AI base URL not configured. Either:
8113
- 1. Set crawl4aiBaseUrl in ${CONFIG_PATH44}
8134
+ 1. Set crawl4aiBaseUrl in ${CONFIG_PATH45}
8114
8135
  2. Set CRAWL4AI_BASE_URL environment variable`
8115
8136
  );
8116
8137
  }
@@ -8119,7 +8140,7 @@ function requireBaseUrl4() {
8119
8140
  async function getApiToken(signal) {
8120
8141
  return resolveCredential({
8121
8142
  provider: "Crawl4AI",
8122
- configuredValue: loadConfig37().crawl4aiApiToken,
8143
+ configuredValue: loadConfig38().crawl4aiApiToken,
8123
8144
  environmentValue: process.env.CRAWL4AI_API_TOKEN,
8124
8145
  signal
8125
8146
  });
@@ -8128,7 +8149,7 @@ function requestSignal13(timeoutMs, signal) {
8128
8149
  const timeout = AbortSignal.timeout(timeoutMs);
8129
8150
  return signal ? AbortSignal.any([timeout, signal]) : timeout;
8130
8151
  }
8131
- function errorMessage29(err) {
8152
+ function errorMessage30(err) {
8132
8153
  return err instanceof Error ? err.message : String(err);
8133
8154
  }
8134
8155
  function isAbortException(err) {
@@ -8176,8 +8197,8 @@ async function extractWithCrawl4ai(url, signal, options) {
8176
8197
  }
8177
8198
  });
8178
8199
  if (!response.ok) {
8179
- const text3 = await response.text().catch(() => "");
8180
- throw new Error(`Crawl4AI md error ${response.status}: ${redactCredential(text3, token).slice(0, 300)}`);
8200
+ const text4 = await response.text().catch(() => "");
8201
+ throw new Error(`Crawl4AI md error ${response.status}: ${redactCredential(text4, token).slice(0, 300)}`);
8181
8202
  }
8182
8203
  let data;
8183
8204
  try {
@@ -8205,49 +8226,49 @@ async function extractWithCrawl4ai(url, signal, options) {
8205
8226
  return { url, title: firstHeadingTitle(content), content, error: null };
8206
8227
  } catch (err) {
8207
8228
  if (signal?.aborted || isAbortException(err)) activityMonitor.logComplete(activityId, 0);
8208
- else activityMonitor.logError(activityId, errorMessage29(err));
8229
+ else activityMonitor.logError(activityId, errorMessage30(err));
8209
8230
  throw err;
8210
8231
  }
8211
8232
  }
8212
- var CONFIG_PATH44, EXTRACT_TIMEOUT_MS2, MARKDOWN_FILTER, cachedConfig38;
8233
+ var CONFIG_PATH45, EXTRACT_TIMEOUT_MS2, MARKDOWN_FILTER, cachedConfig39;
8213
8234
  var init_crawl4ai = __esm({
8214
8235
  "crawl4ai.ts"() {
8215
8236
  init_activity();
8216
8237
  init_credential_source();
8217
8238
  init_ssrf_protection();
8218
8239
  init_utils();
8219
- CONFIG_PATH44 = getWebSearchConfigPath();
8240
+ CONFIG_PATH45 = getWebSearchConfigPath();
8220
8241
  EXTRACT_TIMEOUT_MS2 = 6e4;
8221
8242
  MARKDOWN_FILTER = "fit";
8222
- cachedConfig38 = null;
8243
+ cachedConfig39 = null;
8223
8244
  }
8224
8245
  });
8225
8246
 
8226
8247
  // brightdata-unlocker.ts
8227
- import { existsSync as existsSync48, readFileSync as readFileSync50 } from "node:fs";
8248
+ import { existsSync as existsSync49, readFileSync as readFileSync51 } from "node:fs";
8228
8249
  function parseFailureDetail(err) {
8229
8250
  const message = err instanceof Error ? err.message : String(err);
8230
8251
  const position = message.match(/at position \d+(?: \(line \d+ column \d+\))?/);
8231
8252
  return position ? `invalid JSON ${position[0]}` : "invalid JSON";
8232
8253
  }
8233
- function loadConfig38() {
8234
- if (cachedConfig39) return cachedConfig39;
8235
- if (!existsSync48(CONFIG_PATH45)) {
8236
- cachedConfig39 = {};
8237
- return cachedConfig39;
8254
+ function loadConfig39() {
8255
+ if (cachedConfig40) return cachedConfig40;
8256
+ if (!existsSync49(CONFIG_PATH46)) {
8257
+ cachedConfig40 = {};
8258
+ return cachedConfig40;
8238
8259
  }
8239
- const raw = readFileSync50(CONFIG_PATH45, "utf8");
8260
+ const raw = readFileSync51(CONFIG_PATH46, "utf8");
8240
8261
  let parsed;
8241
8262
  try {
8242
8263
  parsed = JSON.parse(raw);
8243
8264
  } catch (err) {
8244
- throw new Error(`Failed to parse ${CONFIG_PATH45}: ${parseFailureDetail(err)}`);
8265
+ throw new Error(`Failed to parse ${CONFIG_PATH46}: ${parseFailureDetail(err)}`);
8245
8266
  }
8246
8267
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8247
- throw new Error(`Invalid config in ${CONFIG_PATH45}: expected a JSON object`);
8268
+ throw new Error(`Invalid config in ${CONFIG_PATH46}: expected a JSON object`);
8248
8269
  }
8249
- cachedConfig39 = parsed;
8250
- return cachedConfig39;
8270
+ cachedConfig40 = parsed;
8271
+ return cachedConfig40;
8251
8272
  }
8252
8273
  function normalizeZone2(value) {
8253
8274
  if (typeof value !== "string") return null;
@@ -8258,8 +8279,8 @@ function normalizeZone2(value) {
8258
8279
  function zoneSetting() {
8259
8280
  const fromEnv = process.env.BRIGHTDATA_UNLOCKER_ZONE;
8260
8281
  if (typeof fromEnv === "string" && fromEnv.trim()) return { raw: fromEnv.trim(), label: "BRIGHTDATA_UNLOCKER_ZONE" };
8261
- const configured = loadConfig38().brightdataUnlockerZone;
8262
- if (typeof configured === "string" && configured.trim()) return { raw: configured.trim(), label: `brightdataUnlockerZone in ${CONFIG_PATH45}` };
8282
+ const configured = loadConfig39().brightdataUnlockerZone;
8283
+ if (typeof configured === "string" && configured.trim()) return { raw: configured.trim(), label: `brightdataUnlockerZone in ${CONFIG_PATH46}` };
8263
8284
  return null;
8264
8285
  }
8265
8286
  function getZone() {
@@ -8277,7 +8298,7 @@ function requireZone() {
8277
8298
  }
8278
8299
  throw new Error(
8279
8300
  `Bright Data Web Unlocker zone not configured. Either:
8280
- 1. Set brightdataUnlockerZone in ${CONFIG_PATH45}
8301
+ 1. Set brightdataUnlockerZone in ${CONFIG_PATH46}
8281
8302
  2. Set BRIGHTDATA_UNLOCKER_ZONE environment variable
8282
8303
  The zone must be of type "unblocker"; a SERP zone will not serve Web Unlocker requests.`
8283
8304
  );
@@ -8285,14 +8306,14 @@ The zone must be of type "unblocker"; a SERP zone will not serve Web Unlocker re
8285
8306
  async function getApiKey27(signal) {
8286
8307
  const apiKey = await resolveCredential({
8287
8308
  provider: "Bright Data",
8288
- configuredValue: loadConfig38().brightdataApiKey,
8309
+ configuredValue: loadConfig39().brightdataApiKey,
8289
8310
  environmentValue: process.env.BRIGHTDATA_API_KEY,
8290
8311
  signal
8291
8312
  });
8292
8313
  if (!apiKey) {
8293
8314
  throw new Error(
8294
8315
  `Bright Data API key not found. Either:
8295
- 1. Create ${CONFIG_PATH45} with { "brightdataApiKey": "your-key" }
8316
+ 1. Create ${CONFIG_PATH46} with { "brightdataApiKey": "your-key" }
8296
8317
  2. Set BRIGHTDATA_API_KEY environment variable
8297
8318
  Get a key at https://brightdata.com/cp/setting/users`
8298
8319
  );
@@ -8303,11 +8324,11 @@ function requestSignal14(timeoutMs, signal) {
8303
8324
  const timeout = AbortSignal.timeout(timeoutMs);
8304
8325
  return signal ? AbortSignal.any([timeout, signal]) : timeout;
8305
8326
  }
8306
- function errorMessage30(err) {
8327
+ function errorMessage31(err) {
8307
8328
  return err instanceof Error ? err.message : String(err);
8308
8329
  }
8309
8330
  function isAbortError4(err) {
8310
- return errorMessage30(err).toLowerCase().includes("abort");
8331
+ return errorMessage31(err).toLowerCase().includes("abort");
8311
8332
  }
8312
8333
  function ssrfOptions3(options) {
8313
8334
  return {
@@ -8366,11 +8387,11 @@ async function brightDataRequest(url, zone, signal, options) {
8366
8387
  const errorText = await response.text().catch(() => "");
8367
8388
  throw new Error(`Bright Data Web Unlocker error ${response.status}: ${redactCredential(errorText, apiKey).slice(0, 300)}`);
8368
8389
  }
8369
- const text3 = await response.text();
8390
+ const text4 = await response.text();
8370
8391
  activityMonitor.logComplete(activityId, response.status);
8371
- return text3;
8392
+ return text4;
8372
8393
  } catch (err) {
8373
- const message = errorMessage30(err);
8394
+ const message = errorMessage31(err);
8374
8395
  const redactedMessage = redactCredential(message, apiKey);
8375
8396
  if (isAbortError4(err)) activityMonitor.logComplete(activityId, 0);
8376
8397
  else activityMonitor.logError(activityId, redactedMessage);
@@ -8380,8 +8401,8 @@ async function brightDataRequest(url, zone, signal, options) {
8380
8401
  throw redactedError;
8381
8402
  }
8382
8403
  }
8383
- function headingTitle(text3) {
8384
- const match = text3.match(/^#{1,2}\s+(.+)/m);
8404
+ function headingTitle(text4) {
8405
+ const match = text4.match(/^#{1,2}\s+(.+)/m);
8385
8406
  if (!match) return "";
8386
8407
  return match[1].replace(/\*+/g, "").trim();
8387
8408
  }
@@ -8389,7 +8410,7 @@ function isBrightDataUnlockerAvailable() {
8389
8410
  if (getZone() === null) return false;
8390
8411
  return hasCredentialSource({
8391
8412
  provider: "Bright Data",
8392
- configuredValue: loadConfig38().brightdataApiKey,
8413
+ configuredValue: loadConfig39().brightdataApiKey,
8393
8414
  environmentValue: process.env.BRIGHTDATA_API_KEY
8394
8415
  });
8395
8416
  }
@@ -8401,26 +8422,26 @@ async function extractWithBrightDataUnlocker(url, signal, options) {
8401
8422
  if (!content) return null;
8402
8423
  return { url, title: headingTitle(content), content, error: null };
8403
8424
  }
8404
- var CONFIG_PATH45, BRIGHTDATA_REQUEST_URL, EXTRACT_TIMEOUT_MS3, DEFAULT_MAX_REDIRECTS3, REDIRECT_STATUSES3, ZONE_PATTERN2, cachedConfig39;
8425
+ var CONFIG_PATH46, BRIGHTDATA_REQUEST_URL, EXTRACT_TIMEOUT_MS3, DEFAULT_MAX_REDIRECTS3, REDIRECT_STATUSES3, ZONE_PATTERN2, cachedConfig40;
8405
8426
  var init_brightdata_unlocker = __esm({
8406
8427
  "brightdata-unlocker.ts"() {
8407
8428
  init_activity();
8408
8429
  init_credential_source();
8409
8430
  init_ssrf_protection();
8410
8431
  init_utils();
8411
- CONFIG_PATH45 = getWebSearchConfigPath();
8432
+ CONFIG_PATH46 = getWebSearchConfigPath();
8412
8433
  BRIGHTDATA_REQUEST_URL = "https://api.brightdata.com/request";
8413
8434
  EXTRACT_TIMEOUT_MS3 = 6e4;
8414
8435
  DEFAULT_MAX_REDIRECTS3 = 5;
8415
8436
  REDIRECT_STATUSES3 = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
8416
8437
  ZONE_PATTERN2 = /^[a-z0-9_-]+$/i;
8417
- cachedConfig39 = null;
8438
+ cachedConfig40 = null;
8418
8439
  }
8419
8440
  });
8420
8441
 
8421
8442
  // video-extract.ts
8422
8443
  import { execFileSync as execFileSync2 } from "node:child_process";
8423
- import { existsSync as existsSync49, readFileSync as readFileSync51, readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
8444
+ import { existsSync as existsSync50, readFileSync as readFileSync52, readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
8424
8445
  import { readFile as readFile2 } from "node:fs/promises";
8425
8446
  import { resolve, extname as extname2, basename as basename4, join as join7, dirname as dirname2 } from "node:path";
8426
8447
  function shouldRethrow3(err) {
@@ -8441,17 +8462,17 @@ function normalizeMaxSizeMB(value, fallback) {
8441
8462
  }
8442
8463
  function loadVideoConfig() {
8443
8464
  if (cachedVideoConfig) return cachedVideoConfig;
8444
- if (!existsSync49(CONFIG_PATH46)) {
8465
+ if (!existsSync50(CONFIG_PATH47)) {
8445
8466
  cachedVideoConfig = { ...VIDEO_CONFIG_DEFAULTS };
8446
8467
  return cachedVideoConfig;
8447
8468
  }
8448
- const rawText = readFileSync51(CONFIG_PATH46, "utf-8");
8469
+ const rawText = readFileSync52(CONFIG_PATH47, "utf-8");
8449
8470
  let raw;
8450
8471
  try {
8451
8472
  raw = JSON.parse(rawText);
8452
8473
  } catch (err) {
8453
8474
  const message = err instanceof Error ? err.message : String(err);
8454
- throw new Error(`Failed to parse ${CONFIG_PATH46}: ${message}`);
8475
+ throw new Error(`Failed to parse ${CONFIG_PATH47}: ${message}`);
8455
8476
  }
8456
8477
  const v = raw.video ?? {};
8457
8478
  cachedVideoConfig = {
@@ -8497,10 +8518,10 @@ function isVideoFile(input) {
8497
8518
  }
8498
8519
  function resolveFilePath(filePath) {
8499
8520
  const absolutePath = resolve(filePath);
8500
- if (existsSync49(absolutePath)) return absolutePath;
8521
+ if (existsSync50(absolutePath)) return absolutePath;
8501
8522
  const dir = dirname2(absolutePath);
8502
8523
  const base = basename4(absolutePath);
8503
- if (!existsSync49(dir)) return null;
8524
+ if (!existsSync50(dir)) return null;
8504
8525
  try {
8505
8526
  const normalizedBase = normalizeSpaces(base);
8506
8527
  const match = readdirSync4(dir).find((f) => normalizeSpaces(f) === normalizedBase);
@@ -8592,7 +8613,7 @@ async function tryVideoGeminiWeb(info, prompt, model, signal) {
8592
8613
  const cookies = await isGeminiWebAvailable();
8593
8614
  if (!cookies) return null;
8594
8615
  if (signal?.aborted) return null;
8595
- const text3 = await queryWithCookies(prompt, cookies, {
8616
+ const text4 = await queryWithCookies(prompt, cookies, {
8596
8617
  files: [{ path: info.absolutePath, mimeType: info.mimeType }],
8597
8618
  ...model !== "gemini-3.6-flash" ? { model } : {},
8598
8619
  signal,
@@ -8600,8 +8621,8 @@ async function tryVideoGeminiWeb(info, prompt, model, signal) {
8600
8621
  });
8601
8622
  return {
8602
8623
  url: info.absolutePath,
8603
- title: extractVideoTitle(text3, info.absolutePath),
8604
- content: text3,
8624
+ title: extractVideoTitle(text4, info.absolutePath),
8625
+ content: text4,
8605
8626
  error: null
8606
8627
  };
8607
8628
  } catch (err) {
@@ -8618,7 +8639,7 @@ async function tryVideoGeminiApi(info, prompt, model, signal) {
8618
8639
  const uploaded = await uploadToFilesApi(info, apiKey, signal);
8619
8640
  fileName = uploaded.name;
8620
8641
  await pollFileState(fileName, apiKey, signal, 12e4);
8621
- const text3 = await queryGeminiApiWithVideo(prompt, uploaded.uri, {
8642
+ const text4 = await queryGeminiApiWithVideo(prompt, uploaded.uri, {
8622
8643
  apiKey,
8623
8644
  model,
8624
8645
  mimeType: info.mimeType,
@@ -8627,8 +8648,8 @@ async function tryVideoGeminiApi(info, prompt, model, signal) {
8627
8648
  });
8628
8649
  return {
8629
8650
  url: info.absolutePath,
8630
- title: extractVideoTitle(text3, info.absolutePath),
8631
- content: text3,
8651
+ title: extractVideoTitle(text4, info.absolutePath),
8652
+ content: text4,
8632
8653
  error: null
8633
8654
  };
8634
8655
  } catch (err) {
@@ -8653,8 +8674,8 @@ async function uploadToFilesApi(info, apiKey, signal) {
8653
8674
  signal
8654
8675
  }, apiKey);
8655
8676
  if (!initRes.ok) {
8656
- const text3 = redactGeminiApiResponse(initRes, await initRes.text(), apiKey);
8657
- throw new Error(`File upload init failed: ${initRes.status} (${text3.slice(0, 200)})`);
8677
+ const text4 = redactGeminiApiResponse(initRes, await initRes.text(), apiKey);
8678
+ throw new Error(`File upload init failed: ${initRes.status} (${text4.slice(0, 200)})`);
8658
8679
  }
8659
8680
  const uploadUrl = initRes.headers.get("x-goog-upload-url");
8660
8681
  if (!uploadUrl) throw new Error("No upload URL in response headers");
@@ -8670,8 +8691,8 @@ async function uploadToFilesApi(info, apiKey, signal) {
8670
8691
  signal
8671
8692
  }, apiKey);
8672
8693
  if (!uploadRes.ok) {
8673
- const text3 = redactGeminiApiResponse(uploadRes, await uploadRes.text(), apiKey);
8674
- throw new Error(`File upload failed: ${uploadRes.status} (${text3.slice(0, 200)})`);
8694
+ const text4 = redactGeminiApiResponse(uploadRes, await uploadRes.text(), apiKey);
8695
+ throw new Error(`File upload failed: ${uploadRes.status} (${text4.slice(0, 200)})`);
8675
8696
  }
8676
8697
  const result = await uploadRes.json();
8677
8698
  return result.file;
@@ -8695,10 +8716,10 @@ function deleteGeminiFile(fileName, apiKey) {
8695
8716
  console.error(`Failed to delete Gemini file ${fileName}: ${message}`);
8696
8717
  });
8697
8718
  }
8698
- function extractVideoTitle(text3, filePath) {
8699
- return extractHeadingTitle(text3) ?? basename4(filePath, extname2(filePath));
8719
+ function extractVideoTitle(text4, filePath) {
8720
+ return extractHeadingTitle(text4) ?? basename4(filePath, extname2(filePath));
8700
8721
  }
8701
- var CONFIG_PATH46, DEFAULT_VIDEO_PROMPT, VIDEO_EXTENSIONS, VIDEO_CONFIG_DEFAULTS, cachedVideoConfig;
8722
+ var CONFIG_PATH47, DEFAULT_VIDEO_PROMPT, VIDEO_EXTENSIONS, VIDEO_CONFIG_DEFAULTS, cachedVideoConfig;
8702
8723
  var init_video_extract = __esm({
8703
8724
  "video-extract.ts"() {
8704
8725
  init_activity();
@@ -8707,7 +8728,7 @@ var init_video_extract = __esm({
8707
8728
  init_gemini_api();
8708
8729
  init_extract();
8709
8730
  init_utils();
8710
- CONFIG_PATH46 = getWebSearchConfigPath();
8731
+ CONFIG_PATH47 = getWebSearchConfigPath();
8711
8732
  DEFAULT_VIDEO_PROMPT = `Extract the complete content of this video. Include:
8712
8733
  1. Video title (infer from content if not explicit), duration
8713
8734
  2. A brief summary (2-3 sentences)
@@ -8897,33 +8918,33 @@ function sha256Bytes(value) {
8897
8918
  function asciiLowerCode(code) {
8898
8919
  return code >= 65 && code <= 90 ? code + 32 : code;
8899
8920
  }
8900
- function matchesDataScheme(text3, index) {
8901
- return index + 5 <= text3.length && asciiLowerCode(text3.charCodeAt(index)) === 100 && asciiLowerCode(text3.charCodeAt(index + 1)) === 97 && asciiLowerCode(text3.charCodeAt(index + 2)) === 116 && asciiLowerCode(text3.charCodeAt(index + 3)) === 97 && text3.charCodeAt(index + 4) === 58;
8921
+ function matchesDataScheme(text4, index) {
8922
+ return index + 5 <= text4.length && asciiLowerCode(text4.charCodeAt(index)) === 100 && asciiLowerCode(text4.charCodeAt(index + 1)) === 97 && asciiLowerCode(text4.charCodeAt(index + 2)) === 116 && asciiLowerCode(text4.charCodeAt(index + 3)) === 97 && text4.charCodeAt(index + 4) === 58;
8902
8923
  }
8903
- function isSchemeBoundary(text3, index) {
8924
+ function isSchemeBoundary(text4, index) {
8904
8925
  if (index === 0) return true;
8905
- const code = text3.charCodeAt(index - 1);
8926
+ const code = text4.charCodeAt(index - 1);
8906
8927
  const alphaNumeric = code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
8907
8928
  return !alphaNumeric && code !== 43 && code !== 45 && code !== 46;
8908
8929
  }
8909
- function findNextDataScheme(text3, from) {
8910
- for (let i = from; i + 5 <= text3.length; i++) {
8911
- if (matchesDataScheme(text3, i) && isSchemeBoundary(text3, i)) return i;
8930
+ function findNextDataScheme(text4, from) {
8931
+ for (let i = from; i + 5 <= text4.length; i++) {
8932
+ if (matchesDataScheme(text4, i) && isSchemeBoundary(text4, i)) return i;
8912
8933
  }
8913
8934
  return -1;
8914
8935
  }
8915
- function dataUriEnclosure(text3, start) {
8936
+ function dataUriEnclosure(text4, start) {
8916
8937
  if (start === 0) return null;
8917
8938
  const immediateIndex = start - 1;
8918
- const immediate = text3[immediateIndex];
8939
+ const immediate = text4[immediateIndex];
8919
8940
  if (immediate === '"' || immediate === "'" || immediate === "`") {
8920
- const beforeQuote = immediateIndex > 0 ? text3[immediateIndex - 1] : "";
8941
+ const beforeQuote = immediateIndex > 0 ? text4[immediateIndex - 1] : "";
8921
8942
  const likelyOpeningQuote = immediateIndex === 0 || beforeQuote === "=" || beforeQuote === "(" || beforeQuote === "[" || beforeQuote === "{" || beforeQuote === ":" || beforeQuote === "," || /\s/.test(beforeQuote);
8922
8943
  if (likelyOpeningQuote) return { kind: "quote", close: immediate };
8923
8944
  }
8924
8945
  let openerIndex = immediateIndex;
8925
- while (openerIndex >= 0 && (text3[openerIndex] === " " || text3[openerIndex] === " ")) openerIndex--;
8926
- const opener = text3[openerIndex];
8946
+ while (openerIndex >= 0 && (text4[openerIndex] === " " || text4[openerIndex] === " ")) openerIndex--;
8947
+ const opener = text4[openerIndex];
8927
8948
  if (opener === "(") return { kind: "parentheses" };
8928
8949
  if (opener === "<") return { kind: "angle" };
8929
8950
  return null;
@@ -8932,13 +8953,13 @@ function isBareDataUriTerminator(ch) {
8932
8953
  const code = ch.charCodeAt(0);
8933
8954
  return code <= 32 || code === 127 || ch === '"' || ch === "`" || ch === "<" || ch === ">";
8934
8955
  }
8935
- function scanDataUriCandidate(text3, start) {
8936
- const enclosure = dataUriEnclosure(text3, start);
8956
+ function scanDataUriCandidate(text4, start) {
8957
+ const enclosure = dataUriEnclosure(text4, start);
8937
8958
  let comma = -1;
8938
8959
  let depth = enclosure?.kind === "parentheses" ? 1 : 0;
8939
8960
  let index = start + 5;
8940
- for (; index < text3.length; index++) {
8941
- const ch = text3[index];
8961
+ for (; index < text4.length; index++) {
8962
+ const ch = text4[index];
8942
8963
  if (enclosure?.kind === "quote") {
8943
8964
  if (ch === enclosure.close) break;
8944
8965
  } else if (enclosure?.kind === "parentheses") {
@@ -8957,16 +8978,16 @@ function scanDataUriCandidate(text3, start) {
8957
8978
  }
8958
8979
  return { end: index, comma, enclosure };
8959
8980
  }
8960
- function headerEndsWithBase64(text3, headerStart, comma) {
8981
+ function headerEndsWithBase64(text4, headerStart, comma) {
8961
8982
  let end = comma;
8962
- while (end > headerStart && (text3[end - 1] === " " || text3[end - 1] === " ")) end--;
8983
+ while (end > headerStart && (text4[end - 1] === " " || text4[end - 1] === " ")) end--;
8963
8984
  const token = "base64";
8964
8985
  if (end - headerStart < token.length + 1) return false;
8965
8986
  const tokenStart = end - token.length;
8966
8987
  for (let i = 0; i < token.length; i++) {
8967
- if (asciiLowerCode(text3.charCodeAt(tokenStart + i)) !== token.charCodeAt(i)) return false;
8988
+ if (asciiLowerCode(text4.charCodeAt(tokenStart + i)) !== token.charCodeAt(i)) return false;
8968
8989
  }
8969
- return tokenStart > headerStart && text3[tokenStart - 1] === ";";
8990
+ return tokenStart > headerStart && text4[tokenStart - 1] === ";";
8970
8991
  }
8971
8992
  function isMimeTokenChar(code) {
8972
8993
  if (code < 33 || code > 126) return false;
@@ -9005,14 +9026,14 @@ function isMimeTokenChar(code) {
9005
9026
  return true;
9006
9027
  }
9007
9028
  }
9008
- function normalizeMimeType(text3, headerStart, comma) {
9029
+ function normalizeMimeType(text4, headerStart, comma) {
9009
9030
  let end = headerStart;
9010
- while (end < comma && text3[end] !== ";") end++;
9031
+ while (end < comma && text4[end] !== ";") end++;
9011
9032
  if (end === headerStart) return "text/plain";
9012
9033
  if (end - headerStart > MAX_MIME_CHARS) return "application/octet-stream";
9013
9034
  let slashCount = 0;
9014
9035
  for (let i = headerStart; i < end; i++) {
9015
- const code = text3.charCodeAt(i);
9036
+ const code = text4.charCodeAt(i);
9016
9037
  if (code === 47) {
9017
9038
  slashCount++;
9018
9039
  if (i === headerStart || i === end - 1) return "application/octet-stream";
@@ -9021,7 +9042,7 @@ function normalizeMimeType(text3, headerStart, comma) {
9021
9042
  if (!isMimeTokenChar(code)) return "application/octet-stream";
9022
9043
  }
9023
9044
  if (slashCount !== 1) return "application/octet-stream";
9024
- return text3.slice(headerStart, end).toLowerCase();
9045
+ return text4.slice(headerStart, end).toLowerCase();
9025
9046
  }
9026
9047
  function hexValue(code) {
9027
9048
  if (code >= 48 && code <= 57) return code - 48;
@@ -9095,15 +9116,15 @@ function buildDataUriMarker(omission) {
9095
9116
  const decodeError = omission.decodeError ? `; decodeError=${omission.decodeError}` : "";
9096
9117
  return `[pi-web-access inline data URI omitted; ordinal=${omission.ordinal}; source=${omission.sourcePath}; mime=${omission.mimeType}; encoding=${omission.encoding}; encodedBytes=${omission.encodedBytes}; decodedBytes=${decoded}${decodeError}; sha256=${omission.sha256}; digestBasis=${omission.digestBasis}; retrieval=not-retained]`;
9097
9118
  }
9098
- function sanitizeTextInternal(text3, sourcePath, state) {
9119
+ function sanitizeTextInternal(text4, sourcePath, state) {
9099
9120
  let scanFrom = 0;
9100
9121
  let retainedFrom = 0;
9101
9122
  let outputLength = 0;
9102
9123
  const pieces = [];
9103
- while (scanFrom < text3.length) {
9104
- const start = findNextDataScheme(text3, scanFrom);
9124
+ while (scanFrom < text4.length) {
9125
+ const start = findNextDataScheme(text4, scanFrom);
9105
9126
  if (start < 0) break;
9106
- const candidate = scanDataUriCandidate(text3, start);
9127
+ const candidate = scanDataUriCandidate(text4, start);
9107
9128
  const end = candidate.end;
9108
9129
  const headerStart = start + 5;
9109
9130
  const missingComma = candidate.comma < 0;
@@ -9113,9 +9134,9 @@ function sanitizeTextInternal(text3, sourcePath, state) {
9113
9134
  }
9114
9135
  const headerEnd = missingComma ? end : candidate.comma;
9115
9136
  const headerLength = headerEnd - headerStart;
9116
- const encoding = headerEndsWithBase64(text3, headerStart, headerEnd) ? "base64" : "percent-encoded";
9117
- const mimeType = normalizeMimeType(text3, headerStart, headerEnd);
9118
- const payload = missingComma ? text3.slice(headerStart, end) : text3.slice(candidate.comma + 1, end);
9137
+ const encoding = headerEndsWithBase64(text4, headerStart, headerEnd) ? "base64" : "percent-encoded";
9138
+ const mimeType = normalizeMimeType(text4, headerStart, headerEnd);
9139
+ const payload = missingComma ? text4.slice(headerStart, end) : text4.slice(candidate.comma + 1, end);
9119
9140
  const encodedBytes = Buffer3.byteLength(payload, "utf8");
9120
9141
  let decodedBytes = null;
9121
9142
  let decodeError;
@@ -9151,7 +9172,7 @@ function sanitizeTextInternal(text3, sourcePath, state) {
9151
9172
  retrieval: "not-retained"
9152
9173
  };
9153
9174
  const marker = buildDataUriMarker(omission);
9154
- const prefix = text3.slice(retainedFrom, start);
9175
+ const prefix = text4.slice(retainedFrom, start);
9155
9176
  pieces.push(prefix, marker);
9156
9177
  outputLength += prefix.length;
9157
9178
  const markerStart = outputLength;
@@ -9160,13 +9181,13 @@ function sanitizeTextInternal(text3, sourcePath, state) {
9160
9181
  retainedFrom = end;
9161
9182
  scanFrom = end;
9162
9183
  }
9163
- if (state.omissions.length === 0 && retainedFrom === 0) return text3;
9164
- pieces.push(text3.slice(retainedFrom));
9184
+ if (state.omissions.length === 0 && retainedFrom === 0) return text4;
9185
+ pieces.push(text4.slice(retainedFrom));
9165
9186
  return pieces.join("");
9166
9187
  }
9167
- function sanitizeInlineDataUris(text3, sourcePath) {
9188
+ function sanitizeInlineDataUris(text4, sourcePath) {
9168
9189
  const state = { nextOrdinal: 1, omissions: [] };
9169
- const sanitized = sanitizeTextInternal(text3, sourcePath, state);
9190
+ const sanitized = sanitizeTextInternal(text4, sourcePath, state);
9170
9191
  return {
9171
9192
  text: sanitized,
9172
9193
  omissions: state.omissions.map(({ markerStart: _start, markerEnd: _end, ...omission }) => omission)
@@ -9192,13 +9213,13 @@ __export(extract_exports, {
9192
9213
  readPDFResponseBuffer: () => readPDFResponseBuffer,
9193
9214
  resolveFetchTimeoutMs: () => resolveFetchTimeoutMs
9194
9215
  });
9195
- import { existsSync as existsSync50, readFileSync as readFileSync52 } from "node:fs";
9216
+ import { existsSync as existsSync51, readFileSync as readFileSync53 } from "node:fs";
9196
9217
  import pLimit from "p-limit";
9197
9218
  function loadFetchTimeoutMs() {
9198
- if (!existsSync50(WEB_SEARCH_CONFIG_PATH3)) return DEFAULT_TIMEOUT_MS3;
9219
+ if (!existsSync51(WEB_SEARCH_CONFIG_PATH3)) return DEFAULT_TIMEOUT_MS3;
9199
9220
  let raw;
9200
9221
  try {
9201
- raw = JSON.parse(readFileSync52(WEB_SEARCH_CONFIG_PATH3, "utf-8"));
9222
+ raw = JSON.parse(readFileSync53(WEB_SEARCH_CONFIG_PATH3, "utf-8"));
9202
9223
  } catch (err) {
9203
9224
  const message = err instanceof Error ? err.message : String(err);
9204
9225
  throw new Error(`Failed to parse ${WEB_SEARCH_CONFIG_PATH3}: ${message}`);
@@ -9226,10 +9247,10 @@ function isDefuddleConsoleError(args) {
9226
9247
  const prefix = args[0];
9227
9248
  return prefix === "Defuddle" || typeof prefix === "string" && /^Defuddle(?:\s|:)/.test(prefix);
9228
9249
  }
9229
- async function extractWithDefuddle(text3, url) {
9250
+ async function extractWithDefuddle(text4, url) {
9230
9251
  const { Defuddle } = await import("defuddle/node");
9231
9252
  const { parseHTML } = await import("linkedom");
9232
- const { document } = parseHTML(text3);
9253
+ const { document } = parseHTML(text4);
9233
9254
  Object.defineProperty(document, "location", {
9234
9255
  value: new URL(url),
9235
9256
  configurable: true
@@ -9253,21 +9274,21 @@ async function extractWithDefuddle(text3, url) {
9253
9274
  }
9254
9275
  const result = await resultPromise;
9255
9276
  if (processingError !== void 0) {
9256
- throw new Error(`Defuddle failed to process document: ${errorMessage31(processingError)}`);
9277
+ throw new Error(`Defuddle failed to process document: ${errorMessage32(processingError)}`);
9257
9278
  }
9258
9279
  return typeof result.content === "string" ? { title: result.title, content: result.content } : null;
9259
9280
  }
9260
9281
  function loadSsrfAllowRanges() {
9261
9282
  return loadSsrfConfig().allowRanges;
9262
9283
  }
9263
- function errorMessage31(err) {
9284
+ function errorMessage32(err) {
9264
9285
  return err instanceof Error ? err.message : String(err);
9265
9286
  }
9266
9287
  function isConfigParseError(err) {
9267
- return errorMessage31(err).startsWith("Failed to parse ");
9288
+ return errorMessage32(err).startsWith("Failed to parse ");
9268
9289
  }
9269
9290
  function isAbortError5(err) {
9270
- return errorMessage31(err).toLowerCase().includes("abort");
9291
+ return errorMessage32(err).toLowerCase().includes("abort");
9271
9292
  }
9272
9293
  function isAbortException2(err) {
9273
9294
  return err instanceof DOMException && (err.name === "AbortError" || err.name === "TimeoutError");
@@ -9282,7 +9303,7 @@ function imageGateError() {
9282
9303
  try {
9283
9304
  return isImageEnabled() ? null : "Image fetching is disabled by image.enabled";
9284
9305
  } catch (err) {
9285
- return errorMessage31(err);
9306
+ return errorMessage32(err);
9286
9307
  }
9287
9308
  }
9288
9309
  async function resolveAuthCookieHeader(url, profile) {
@@ -9329,12 +9350,12 @@ async function fetchAuthenticatedRemoteUrl(url, init, validationOptions, profile
9329
9350
  throw new Error(`Too many redirects fetching ${current.toString()}`);
9330
9351
  }
9331
9352
  function loadFetchRouting() {
9332
- if (!existsSync50(WEB_SEARCH_CONFIG_PATH3)) {
9353
+ if (!existsSync51(WEB_SEARCH_CONFIG_PATH3)) {
9333
9354
  return { providers: DEFAULT_FETCH_PROVIDER_ORDER, allowRemoteHostedProviders: false };
9334
9355
  }
9335
9356
  let raw;
9336
9357
  try {
9337
- const parsed = JSON.parse(readFileSync52(WEB_SEARCH_CONFIG_PATH3, "utf-8"));
9358
+ const parsed = JSON.parse(readFileSync53(WEB_SEARCH_CONFIG_PATH3, "utf-8"));
9338
9359
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
9339
9360
  throw new Error("expected a JSON object");
9340
9361
  }
@@ -9525,7 +9546,7 @@ function safeVideoInfo(url) {
9525
9546
  const info = isVideoFile(url);
9526
9547
  return info ? { status: "video", info } : { status: "not-video" };
9527
9548
  } catch (err) {
9528
- return { status: "invalid", error: errorMessage31(err) };
9549
+ return { status: "invalid", error: errorMessage32(err) };
9529
9550
  }
9530
9551
  }
9531
9552
  async function extractContent(url, signal, options) {
@@ -9550,14 +9571,14 @@ async function extractContent(url, signal, options) {
9550
9571
  ...options?.lookup ? { lookup: options.lookup } : {}
9551
9572
  });
9552
9573
  } catch (err) {
9553
- return { url, title: "", content: "", error: errorMessage31(err) };
9574
+ return { url, title: "", content: "", error: errorMessage32(err) };
9554
9575
  }
9555
9576
  }
9556
9577
  if (options?.authFetchProfile || options?.mode === "raw") {
9557
9578
  try {
9558
9579
  return await extractViaHttp(url, resolveFetchTimeoutMs(options), signal, options);
9559
9580
  } catch (err) {
9560
- return { url, title: "", content: "", error: errorMessage31(err) };
9581
+ return { url, title: "", content: "", error: errorMessage32(err) };
9561
9582
  }
9562
9583
  }
9563
9584
  if (options?.frames || options?.timestamp) {
@@ -9695,20 +9716,20 @@ async function extractContent(url, signal, options) {
9695
9716
  2. Set GEMINI_API_KEY in ${WEB_SEARCH_CONFIG_PATH3}` };
9696
9717
  } catch (err) {
9697
9718
  if (isAbortError5(err)) return abortedResult(url);
9698
- return { url, title: "", content: "", error: errorMessage31(err) };
9719
+ return { url, title: "", content: "", error: errorMessage32(err) };
9699
9720
  }
9700
9721
  }
9701
9722
  try {
9702
9723
  if (!remoteUrl) new URL(url);
9703
9724
  } catch (err) {
9704
- return { url, title: "", content: "", error: errorMessage31(err) };
9725
+ return { url, title: "", content: "", error: errorMessage32(err) };
9705
9726
  }
9706
9727
  try {
9707
9728
  const ghIssuePrResult = await extractGitHubIssuePr(url, signal, options);
9708
9729
  if (ghIssuePrResult) return ghIssuePrResult;
9709
9730
  if (signal?.aborted) return abortedResult(url);
9710
9731
  } catch (err) {
9711
- const message = errorMessage31(err);
9732
+ const message = errorMessage32(err);
9712
9733
  if (isAbortError5(err)) return abortedResult(url);
9713
9734
  if (isConfigParseError(err)) {
9714
9735
  return { url, title: "", content: "", error: message };
@@ -9719,7 +9740,7 @@ async function extractContent(url, signal, options) {
9719
9740
  if (ghResult) return ghResult;
9720
9741
  if (signal?.aborted) return abortedResult(url);
9721
9742
  } catch (err) {
9722
- const message = errorMessage31(err);
9743
+ const message = errorMessage32(err);
9723
9744
  if (isAbortError5(err)) return abortedResult(url);
9724
9745
  if (isConfigParseError(err)) {
9725
9746
  return { url, title: "", content: "", error: message };
@@ -9730,7 +9751,7 @@ async function extractContent(url, signal, options) {
9730
9751
  try {
9731
9752
  youtubeEnabled = isYouTubeEnabled();
9732
9753
  } catch (err) {
9733
- return { url, title: "", content: "", error: errorMessage31(err) };
9754
+ return { url, title: "", content: "", error: errorMessage32(err) };
9734
9755
  }
9735
9756
  if (ytInfo.isYouTube && youtubeEnabled) {
9736
9757
  try {
@@ -9738,7 +9759,7 @@ async function extractContent(url, signal, options) {
9738
9759
  if (ytResult) return ytResult;
9739
9760
  if (signal?.aborted) return abortedResult(url);
9740
9761
  } catch (err) {
9741
- const message = errorMessage31(err);
9762
+ const message = errorMessage32(err);
9742
9763
  if (isAbortError5(err)) return abortedResult(url);
9743
9764
  return { url, title: "", content: "", error: message };
9744
9765
  }
@@ -9754,13 +9775,13 @@ async function extractContent(url, signal, options) {
9754
9775
  try {
9755
9776
  fetchTimeoutMs = resolveFetchTimeoutMs(options);
9756
9777
  } catch (err) {
9757
- return { url, title: "", content: "", error: errorMessage31(err) };
9778
+ return { url, title: "", content: "", error: errorMessage32(err) };
9758
9779
  }
9759
9780
  let fetchRouting;
9760
9781
  try {
9761
9782
  fetchRouting = loadFetchRouting();
9762
9783
  } catch (err) {
9763
- return { url, title: "", content: "", error: errorMessage31(err) };
9784
+ return { url, title: "", content: "", error: errorMessage32(err) };
9764
9785
  }
9765
9786
  const providerOrder = remoteUrl && !fetchRouting.allowRemoteHostedProviders ? fetchRouting.providers.filter((provider) => !REMOTE_HOSTED_FETCH_PROVIDERS.has(provider)) : fetchRouting.providers;
9766
9787
  if (providerOrder.length === 0) {
@@ -9823,7 +9844,7 @@ async function extractContent(url, signal, options) {
9823
9844
  }
9824
9845
  } catch (err) {
9825
9846
  if (isAbortError5(err)) return abortedResult(url);
9826
- firecrawlError = errorMessage31(err);
9847
+ firecrawlError = errorMessage32(err);
9827
9848
  if (isConfigParseError(err)) return parseErrorResult(firecrawlError);
9828
9849
  }
9829
9850
  continue;
@@ -9841,7 +9862,7 @@ async function extractContent(url, signal, options) {
9841
9862
  }
9842
9863
  } catch (err) {
9843
9864
  if (signal?.aborted || isAbortException2(err)) return abortedResult(url);
9844
- crawl4aiError = errorMessage31(err);
9865
+ crawl4aiError = errorMessage32(err);
9845
9866
  if (isConfigParseError(err)) return parseErrorResult(crawl4aiError);
9846
9867
  }
9847
9868
  continue;
@@ -9859,7 +9880,7 @@ async function extractContent(url, signal, options) {
9859
9880
  }
9860
9881
  } catch (err) {
9861
9882
  if (isAbortError5(err)) return abortedResult(url);
9862
- tinyfishError = errorMessage31(err);
9883
+ tinyfishError = errorMessage32(err);
9863
9884
  if (isConfigParseError(err)) return parseErrorResult(tinyfishError);
9864
9885
  }
9865
9886
  continue;
@@ -9872,7 +9893,7 @@ async function extractContent(url, signal, options) {
9872
9893
  }
9873
9894
  } catch (err) {
9874
9895
  if (isAbortError5(err)) return abortedResult(url);
9875
- search1apiError = errorMessage31(err);
9896
+ search1apiError = errorMessage32(err);
9876
9897
  if (isConfigParseError(err)) return parseErrorResult(search1apiError);
9877
9898
  }
9878
9899
  continue;
@@ -9885,7 +9906,7 @@ async function extractContent(url, signal, options) {
9885
9906
  }
9886
9907
  } catch (err) {
9887
9908
  if (isAbortError5(err)) return abortedResult(url);
9888
- queritError = errorMessage31(err);
9909
+ queritError = errorMessage32(err);
9889
9910
  if (isConfigParseError(err)) return parseErrorResult(queritError);
9890
9911
  }
9891
9912
  continue;
@@ -9903,7 +9924,7 @@ async function extractContent(url, signal, options) {
9903
9924
  }
9904
9925
  } catch (err) {
9905
9926
  if (isAbortError5(err)) return abortedResult(url);
9906
- kagiError = errorMessage31(err);
9927
+ kagiError = errorMessage32(err);
9907
9928
  if (isConfigParseError(err)) return parseErrorResult(kagiError);
9908
9929
  }
9909
9930
  continue;
@@ -9921,7 +9942,7 @@ async function extractContent(url, signal, options) {
9921
9942
  }
9922
9943
  } catch (err) {
9923
9944
  if (isAbortError5(err)) return abortedResult(url);
9924
- ollamaError = errorMessage31(err);
9945
+ ollamaError = errorMessage32(err);
9925
9946
  if (isConfigParseError(err)) return parseErrorResult(ollamaError);
9926
9947
  }
9927
9948
  continue;
@@ -9934,7 +9955,7 @@ async function extractContent(url, signal, options) {
9934
9955
  }
9935
9956
  } catch (err) {
9936
9957
  if (isAbortError5(err)) return abortedResult(url);
9937
- parallelError = errorMessage31(err);
9958
+ parallelError = errorMessage32(err);
9938
9959
  if (isConfigParseError(err)) return parseErrorResult(parallelError);
9939
9960
  }
9940
9961
  continue;
@@ -9945,7 +9966,7 @@ async function extractContent(url, signal, options) {
9945
9966
  if (parallelMcpResult) return withDeclaredLinks(parallelMcpResult);
9946
9967
  } catch (err) {
9947
9968
  if (isAbortError5(err)) return abortedResult(url);
9948
- parallelMcpError = errorMessage31(err);
9969
+ parallelMcpError = errorMessage32(err);
9949
9970
  if (isConfigParseError(err)) return parseErrorResult(parallelMcpError);
9950
9971
  }
9951
9972
  continue;
@@ -9963,7 +9984,7 @@ async function extractContent(url, signal, options) {
9963
9984
  }
9964
9985
  } catch (err) {
9965
9986
  if (isAbortError5(err)) return abortedResult(url);
9966
- brightdataError = errorMessage31(err);
9987
+ brightdataError = errorMessage32(err);
9967
9988
  if (isConfigParseError(err)) return parseErrorResult(brightdataError);
9968
9989
  }
9969
9990
  continue;
@@ -9975,7 +9996,7 @@ async function extractContent(url, signal, options) {
9975
9996
  } catch (err) {
9976
9997
  if (isAbortError5(err)) return abortedResult(url);
9977
9998
  if (err instanceof CredentialResolutionError || isConfigParseError(err)) {
9978
- return parseErrorResult(errorMessage31(err));
9999
+ return parseErrorResult(errorMessage32(err));
9979
10000
  }
9980
10001
  }
9981
10002
  if (geminiResult) return withDeclaredLinks(geminiResult);
@@ -10019,10 +10040,10 @@ async function extractContent(url, signal, options) {
10019
10040
  ].join("\n");
10020
10041
  return { ...finalHttpResult ?? { url, title: "", content: "", error: null }, error: guidance };
10021
10042
  }
10022
- function isCloudflareChallenge(response, text3, isHTML) {
10043
+ function isCloudflareChallenge(response, text4, isHTML) {
10023
10044
  if (response.status !== 200) return false;
10024
10045
  if (response.headers.get("cf-mitigated") === "challenge") return true;
10025
- return isHTML && /<title>\s*Just a moment\.\.\.\s*<\/title>/i.test(text3) && text3.includes("window._cf_chl_opt") && text3.includes("/cdn-cgi/challenge-platform/");
10046
+ return isHTML && /<title>\s*Just a moment\.\.\.\s*<\/title>/i.test(text4) && text4.includes("window._cf_chl_opt") && text4.includes("/cdn-cgi/challenge-platform/");
10026
10047
  }
10027
10048
  function isLikelyJSRendered(html) {
10028
10049
  const bodyMatch = html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
@@ -10161,9 +10182,9 @@ async function extractViaHttp(url, timeoutMs, signal, options, preferMarkdown =
10161
10182
  activityMonitor.logComplete(activityId, response.status);
10162
10183
  return { url, title: "", content: "", error: `Unsupported content type in raw mode: ${mimeType || "missing"}`, mimeType, status: response.status };
10163
10184
  }
10164
- const text4 = await readTextResponseWithLimit(response, maxResponseSize);
10185
+ const text5 = await readTextResponseWithLimit(response, maxResponseSize);
10165
10186
  activityMonitor.logComplete(activityId, response.status);
10166
- return { url, title: extractTextTitle(text4, url), content: text4, error: null, mimeType, status: response.status };
10187
+ return { url, title: extractTextTitle(text5, url), content: text5, error: null, mimeType, status: response.status };
10167
10188
  }
10168
10189
  if (SUPPORTED_IMAGE_TYPES.has(mimeType)) {
10169
10190
  const disabled = imageGateError();
@@ -10192,7 +10213,7 @@ async function extractViaHttp(url, timeoutMs, signal, options, preferMarkdown =
10192
10213
  status: response.status
10193
10214
  };
10194
10215
  } catch (err) {
10195
- const message = errorMessage31(err);
10216
+ const message = errorMessage32(err);
10196
10217
  activityMonitor.logError(activityId, message);
10197
10218
  return { url, title: "", content: "", error: message, mimeType, status: response.status };
10198
10219
  }
@@ -10233,19 +10254,19 @@ Characters: ${result.chars}`,
10233
10254
  error: `Unsupported content type: ${contentType.split(";")[0]}`
10234
10255
  };
10235
10256
  }
10236
- const text3 = await readTextResponseWithLimit(response, maxResponseSize);
10257
+ const text4 = await readTextResponseWithLimit(response, maxResponseSize);
10237
10258
  const isHTML = contentType.includes("text/html") || contentType.includes("application/xhtml+xml");
10238
- if (isCloudflareChallenge(response, text3, isHTML)) {
10259
+ if (isCloudflareChallenge(response, text4, isHTML)) {
10239
10260
  activityMonitor.logComplete(activityId, response.status);
10240
10261
  return { url, title: "", content: "", error: `HTTP ${response.status}: Blocked by Cloudflare challenge page`, status: response.status };
10241
10262
  }
10242
10263
  if (!isHTML) {
10243
10264
  activityMonitor.logComplete(activityId, response.status);
10244
- const title = extractTextTitle(text3, url);
10245
- if (mimeType !== "text/markdown" && mimeType !== "text/x-markdown") return { url, title, content: text3, error: null };
10265
+ const title = extractTextTitle(text4, url);
10266
+ if (mimeType !== "text/markdown" && mimeType !== "text/x-markdown") return { url, title, content: text4, error: null };
10246
10267
  const declaredLinks2 = discoverDeclaredWebLinks(null, response.headers.get("link"), response.url || url);
10247
- const markdown2 = { url, title, content: appendDeclaredWebLinks(text3, declaredLinks2), error: null, declaredLinks: declaredLinks2 };
10248
- if (!preferMarkdown || text3.trim().length >= MIN_USEFUL_CONTENT2) return markdown2;
10268
+ const markdown2 = { url, title, content: appendDeclaredWebLinks(text4, declaredLinks2), error: null, declaredLinks: declaredLinks2 };
10269
+ if (!preferMarkdown || text4.trim().length >= MIN_USEFUL_CONTENT2) return markdown2;
10249
10270
  const normal = await extractViaHttp(url, Math.max(1, timeoutMs - (Date.now() - startedAt)), signal, options, false);
10250
10271
  if (signal?.aborted || isNonRecoverableHttpError(normal.error) || normal.status === 404 || normal.status === 410 || isAbortError5(normal.error)) return normal;
10251
10272
  const normalHasBody = normal.content.trim() !== appendDeclaredWebLinks("", normal.declaredLinks ?? []).trim();
@@ -10258,7 +10279,7 @@ Browser retry failed: ${normal.error}` : "")
10258
10279
  };
10259
10280
  }
10260
10281
  const { parseHTML } = await import("linkedom");
10261
- const { document } = parseHTML(text3);
10282
+ const { document } = parseHTML(text4);
10262
10283
  const documentTitle = document.title?.trim() ?? "";
10263
10284
  const declaredLinks = discoverDeclaredWebLinks(
10264
10285
  document,
@@ -10269,7 +10290,7 @@ Browser retry failed: ${normal.error}` : "")
10269
10290
  const reader = new Readability(document);
10270
10291
  const article = reader.parse();
10271
10292
  if (!article) {
10272
- const rscResult = extractRSCContent(text3);
10293
+ const rscResult = extractRSCContent(text4);
10273
10294
  if (rscResult && rscResult.content.length >= MIN_USEFUL_CONTENT2) {
10274
10295
  activityMonitor.logComplete(activityId, response.status);
10275
10296
  return {
@@ -10281,7 +10302,7 @@ Browser retry failed: ${normal.error}` : "")
10281
10302
  };
10282
10303
  }
10283
10304
  controller.signal.throwIfAborted();
10284
- const defuddleResult = await extractWithDefuddle(text3, response.url || url);
10305
+ const defuddleResult = await extractWithDefuddle(text4, response.url || url);
10285
10306
  controller.signal.throwIfAborted();
10286
10307
  if (defuddleResult && defuddleResult.content.length >= MIN_USEFUL_CONTENT2) {
10287
10308
  activityMonitor.logComplete(activityId, response.status);
@@ -10294,7 +10315,7 @@ Browser retry failed: ${normal.error}` : "")
10294
10315
  };
10295
10316
  }
10296
10317
  activityMonitor.logComplete(activityId, response.status);
10297
- const jsRendered = isLikelyJSRendered(text3);
10318
+ const jsRendered = isLikelyJSRendered(text4);
10298
10319
  const errorMsg = jsRendered ? "Page appears to be JavaScript-rendered (content loads dynamically)" : "Could not extract readable content from HTML structure";
10299
10320
  return {
10300
10321
  url,
@@ -10310,7 +10331,7 @@ Browser retry failed: ${normal.error}` : "")
10310
10331
  const markdown = (await getTurndown()).turndown(article.content);
10311
10332
  activityMonitor.logComplete(activityId, response.status);
10312
10333
  if (markdown.length < MIN_USEFUL_CONTENT2) {
10313
- const rscResult = extractRSCContent(text3);
10334
+ const rscResult = extractRSCContent(text4);
10314
10335
  if (rscResult && rscResult.content.length >= MIN_USEFUL_CONTENT2) {
10315
10336
  return {
10316
10337
  url,
@@ -10321,7 +10342,7 @@ Browser retry failed: ${normal.error}` : "")
10321
10342
  };
10322
10343
  }
10323
10344
  controller.signal.throwIfAborted();
10324
- const defuddleResult = await extractWithDefuddle(text3, response.url || url);
10345
+ const defuddleResult = await extractWithDefuddle(text4, response.url || url);
10325
10346
  controller.signal.throwIfAborted();
10326
10347
  if (defuddleResult && defuddleResult.content.length >= MIN_USEFUL_CONTENT2) {
10327
10348
  return {
@@ -10336,7 +10357,7 @@ Browser retry failed: ${normal.error}` : "")
10336
10357
  url,
10337
10358
  title: article.title || documentTitle,
10338
10359
  content: appendDeclaredWebLinks(markdown, declaredLinks),
10339
- error: isLikelyJSRendered(text3) ? "Page appears to be JavaScript-rendered (content loads dynamically)" : "Extracted content appears incomplete",
10360
+ error: isLikelyJSRendered(text4) ? "Page appears to be JavaScript-rendered (content loads dynamically)" : "Extracted content appears incomplete",
10340
10361
  declaredLinks
10341
10362
  };
10342
10363
  }
@@ -10364,14 +10385,14 @@ Browser retry failed: ${normal.error}` : "")
10364
10385
  }
10365
10386
  }
10366
10387
  }
10367
- function extractHeadingTitle(text3) {
10368
- const match = text3.match(/^#{1,2}\s+(.+)/m);
10388
+ function extractHeadingTitle(text4) {
10389
+ const match = text4.match(/^#{1,2}\s+(.+)/m);
10369
10390
  if (!match) return null;
10370
10391
  const cleaned = match[1].replace(/\*+/g, "").trim();
10371
10392
  return cleaned || null;
10372
10393
  }
10373
- function extractTextTitle(text3, url) {
10374
- return extractHeadingTitle(text3) ?? (new URL(url).pathname.split("/").pop() || url);
10394
+ function extractTextTitle(text4, url) {
10395
+ return extractHeadingTitle(text4) ?? (new URL(url).pathname.split("/").pop() || url);
10375
10396
  }
10376
10397
  async function fetchAllContent(urls, signal, options) {
10377
10398
  const results = await Promise.all(urls.map((url) => fetchLimit(() => extractContent(url, signal, options))));
@@ -10438,7 +10459,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
10438
10459
  // package.json
10439
10460
  var package_default = {
10440
10461
  name: "pi-web-access",
10441
- version: "0.37.0",
10462
+ version: "0.38.0",
10442
10463
  description: "Web search, URL fetching, GitHub repo cloning, PDF extraction, YouTube video understanding, and local video analysis for Pi coding agent. Supports OpenAI, Brave, Parallel, TinyFish, Search1API, Searchinfinity, Querit, Tavily, Firecrawl, Crawl4AI, Jina, SERPdive, Kagi, Ollama, AnySearch, Bright Data SERP, SerpBase, SerpApi, Serply, You.com, SearXNG, degoog, Exa, Perplexity, Gemini, Kimi, and Mistral.",
10443
10464
  type: "module",
10444
10465
  bin: {
@@ -10499,7 +10520,7 @@ var package_default = {
10499
10520
  typescript: "^7.0.2"
10500
10521
  },
10501
10522
  dependencies: {
10502
- "@modelcontextprotocol/sdk": "1.27.1",
10523
+ "@modelcontextprotocol/sdk": "1.32.1",
10503
10524
  "@mozilla/readability": "^0.6.0",
10504
10525
  defuddle: "0.19.3",
10505
10526
  linkedom: "^0.16.0",
@@ -19015,7 +19036,7 @@ init_gemini_api();
19015
19036
  init_gemini_adc();
19016
19037
  init_gemini_web();
19017
19038
  init_perplexity();
19018
- import { existsSync as existsSync39, readFileSync as readFileSync40 } from "node:fs";
19039
+ import { existsSync as existsSync40, readFileSync as readFileSync41 } from "node:fs";
19019
19040
 
19020
19041
  // exa.ts
19021
19042
  init_activity();
@@ -19216,14 +19237,14 @@ async function callExaMcp(toolName, args, signal) {
19216
19237
  const message = parsed.result.content?.find((item) => item.type === "text" && typeof item.text === "string")?.text?.trim();
19217
19238
  throw new Error(message || "Exa MCP returned an error");
19218
19239
  }
19219
- const text3 = parsed.result?.content?.find((item) => item.type === "text" && typeof item.text === "string" && item.text.trim().length > 0)?.text;
19220
- if (!text3) {
19240
+ const text4 = parsed.result?.content?.find((item) => item.type === "text" && typeof item.text === "string" && item.text.trim().length > 0)?.text;
19241
+ if (!text4) {
19221
19242
  throw new Error("Exa MCP returned empty content");
19222
19243
  }
19223
- return text3;
19244
+ return text4;
19224
19245
  }
19225
- function parseMcpResults(text3) {
19226
- const blocks = text3.split(/(?=^Title: )/m).filter((block) => block.trim().length > 0);
19246
+ function parseMcpResults(text4) {
19247
+ const blocks = text4.split(/(?=^Title: )/m).filter((block) => block.trim().length > 0);
19227
19248
  const parsed = blocks.map((block) => {
19228
19249
  const title = block.match(/^Title: (.+)/m)?.[1]?.trim() ?? "";
19229
19250
  const url = block.match(/^URL: (.+)/m)?.[1]?.trim() ?? "";
@@ -19288,17 +19309,17 @@ function buildMcpQuery(query, options) {
19288
19309
  function isAbortMessage(message) {
19289
19310
  return message.toLowerCase().includes("abort");
19290
19311
  }
19291
- function parseJsonMcpResults(text3) {
19312
+ function parseJsonMcpResults(text4) {
19292
19313
  try {
19293
- const results = JSON.parse(text3).results;
19314
+ const results = JSON.parse(text4).results;
19294
19315
  return Array.isArray(results) && results.length > 0 ? results : null;
19295
19316
  } catch {
19296
19317
  return null;
19297
19318
  }
19298
19319
  }
19299
19320
  async function searchWithExaMcpTool(tool, args, options) {
19300
- const text3 = await callExaMcp(tool, args, options.signal);
19301
- const jsonResults = parseJsonMcpResults(text3);
19321
+ const text4 = await callExaMcp(tool, args, options.signal);
19322
+ const jsonResults = parseJsonMcpResults(text4);
19302
19323
  if (jsonResults) {
19303
19324
  return toSearchResponse(
19304
19325
  buildAnswerFromSearchResults(jsonResults),
@@ -19306,7 +19327,7 @@ async function searchWithExaMcpTool(tool, args, options) {
19306
19327
  options.includeContent ? mapInlineContent(jsonResults) : null
19307
19328
  );
19308
19329
  }
19309
- const textResults = parseMcpResults(text3);
19330
+ const textResults = parseMcpResults(text4);
19310
19331
  if (!textResults) return null;
19311
19332
  return toSearchResponse(
19312
19333
  buildAnswerFromMcpResults(textResults),
@@ -19725,7 +19746,7 @@ var CONFIG_PATH7 = getWebSearchConfigPath();
19725
19746
  var SEARCH_TIMEOUT_MS2 = 6e4;
19726
19747
  var EXCLUDED_MODEL_SEGMENTS = /* @__PURE__ */ new Set(["pro", "ultra"]);
19727
19748
  var MODEL_PREFERENCE = [
19728
- (id) => id.includes("terra"),
19749
+ (id) => id.includes("luna"),
19729
19750
  (id) => /^gpt-\d+(\.\d+)?$/.test(id),
19730
19751
  (id) => /^gpt-\d/.test(id)
19731
19752
  ];
@@ -19986,7 +20007,7 @@ async function resolveOpenAIAuth(ctx, signal) {
19986
20007
  environmentValue: process.env.OPENAI_API_KEY,
19987
20008
  signal
19988
20009
  });
19989
- return apiKey ? { provider: "openai", apiKey, model: modelOverride ?? "gpt-5.6-terra", headers: {}, responsesUrl } : void 0;
20010
+ return apiKey ? { provider: "openai", apiKey, model: modelOverride ?? "gpt-6-luna", headers: {}, responsesUrl } : void 0;
19990
20011
  }
19991
20012
  async function isOpenAISearchAvailable(ctx) {
19992
20013
  const config = loadConfig7();
@@ -20062,8 +20083,8 @@ function isWebSearchCall(item) {
20062
20083
  return !!item && typeof item === "object" && item.type === "web_search_call";
20063
20084
  }
20064
20085
  async function parseOpenAIResponse(response) {
20065
- const text3 = await response.text();
20066
- const trimmed = text3.trim();
20086
+ const text4 = await response.text();
20087
+ const trimmed = text4.trim();
20067
20088
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
20068
20089
  try {
20069
20090
  const parsed = JSON.parse(trimmed);
@@ -20079,7 +20100,7 @@ async function parseOpenAIResponse(response) {
20079
20100
  let completedResponse = null;
20080
20101
  let webSearchCallSeen = false;
20081
20102
  let streamError = null;
20082
- for (const line of text3.split("\n")) {
20103
+ for (const line of text4.split("\n")) {
20083
20104
  if (!line.startsWith("data: ")) continue;
20084
20105
  const data = line.slice(6).trim();
20085
20106
  if (!data || data === "[DONE]") continue;
@@ -20131,11 +20152,11 @@ function cleanSourceUrl(rawUrl) {
20131
20152
  return rawUrl.replace(/[?&]utm_source=openai$/, "");
20132
20153
  }
20133
20154
  }
20134
- function extractSnippetAround(text3, start, end) {
20135
- if (typeof start !== "number" || typeof end !== "number" || !text3) return "";
20155
+ function extractSnippetAround(text4, start, end) {
20156
+ if (typeof start !== "number" || typeof end !== "number" || !text4) return "";
20136
20157
  const before = Math.max(0, start - 100);
20137
- const after = Math.min(text3.length, end + 100);
20138
- const snippet = text3.slice(before, after).replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").trim();
20158
+ const after = Math.min(text4.length, end + 100);
20159
+ const snippet = text4.slice(before, after).replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").trim();
20139
20160
  return snippet.length > 300 ? `${snippet.slice(0, 297)}...` : snippet;
20140
20161
  }
20141
20162
  function addResult(results, seen, url, title, snippet = "") {
@@ -20158,7 +20179,7 @@ function extractSearchResults(output, numResults) {
20158
20179
  if (!Array.isArray(content)) continue;
20159
20180
  for (const part of content) {
20160
20181
  if (!part || typeof part !== "object") continue;
20161
- const text3 = typeof part.text === "string" ? part.text : "";
20182
+ const text4 = typeof part.text === "string" ? part.text : "";
20162
20183
  const annotations = part.annotations;
20163
20184
  if (!Array.isArray(annotations)) continue;
20164
20185
  for (const annotation of annotations) {
@@ -20168,7 +20189,7 @@ function extractSearchResults(output, numResults) {
20168
20189
  seenUrls,
20169
20190
  annotation.url,
20170
20191
  annotation.title,
20171
- extractSnippetAround(text3, annotation.start_index, annotation.end_index)
20192
+ extractSnippetAround(text4, annotation.start_index, annotation.end_index)
20172
20193
  );
20173
20194
  }
20174
20195
  }
@@ -20200,8 +20221,8 @@ function extractAnswer(output) {
20200
20221
  if (!Array.isArray(content)) continue;
20201
20222
  for (const part of content) {
20202
20223
  if (!part || typeof part !== "object") continue;
20203
- const text3 = part.text;
20204
- if (typeof text3 === "string" && text3.trim().length > 0) parts.push(text3);
20224
+ const text4 = part.text;
20225
+ if (typeof text4 === "string" && text4.trim().length > 0) parts.push(text4);
20205
20226
  }
20206
20227
  }
20207
20228
  return parts.join("\n").trim();
@@ -20253,10 +20274,10 @@ function buildAlphaSearchHeaders(headers, apiKey) {
20253
20274
  return result;
20254
20275
  }
20255
20276
  async function parseAlphaSearchResponse(response, numResults = 5) {
20256
- const text3 = await response.text();
20277
+ const text4 = await response.text();
20257
20278
  let payload;
20258
20279
  try {
20259
- payload = JSON.parse(text3);
20280
+ payload = JSON.parse(text4);
20260
20281
  } catch {
20261
20282
  throw new Error("OpenAI alpha/search returned invalid JSON");
20262
20283
  }
@@ -21874,8 +21895,8 @@ function parseResponse(value) {
21874
21895
  if (!Array.isArray(envelope.results)) throw invalidResponse4("expected a results array");
21875
21896
  return envelope.results;
21876
21897
  }
21877
- function redactSecrets(text3, secrets) {
21878
- let redacted = text3;
21898
+ function redactSecrets(text4, secrets) {
21899
+ let redacted = text4;
21879
21900
  for (const secret of secrets) redacted = redactCredential(redacted, secret);
21880
21901
  return redacted;
21881
21902
  }
@@ -22568,11 +22589,11 @@ function addSources(results, seen, sources) {
22568
22589
  if (!Array.isArray(sources)) return;
22569
22590
  for (const source of sources) addSource(results, seen, source);
22570
22591
  }
22571
- function extractSnippetAround2(text3, start, end) {
22572
- if (typeof start !== "number" || typeof end !== "number" || !text3) return "";
22592
+ function extractSnippetAround2(text4, start, end) {
22593
+ if (typeof start !== "number" || typeof end !== "number" || !text4) return "";
22573
22594
  const before = Math.max(0, start - 100);
22574
- const after = Math.min(text3.length, end + 100);
22575
- const snippet = text3.slice(before, after).replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").trim();
22595
+ const after = Math.min(text4.length, end + 100);
22596
+ const snippet = text4.slice(before, after).replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").trim();
22576
22597
  return snippet.length > 300 ? `${snippet.slice(0, 297)}...` : snippet;
22577
22598
  }
22578
22599
  function extractAnswer2(output) {
@@ -22583,8 +22604,8 @@ function extractAnswer2(output) {
22583
22604
  if (!Array.isArray(content)) continue;
22584
22605
  for (const part of content) {
22585
22606
  if (!part || typeof part !== "object") continue;
22586
- const text3 = part.text;
22587
- if (typeof text3 === "string" && text3.trim().length > 0) parts.push(text3);
22607
+ const text4 = part.text;
22608
+ if (typeof text4 === "string" && text4.trim().length > 0) parts.push(text4);
22588
22609
  }
22589
22610
  }
22590
22611
  return parts.join("\n").trim();
@@ -22598,7 +22619,7 @@ function extractSearchResults2(output, citations, numResults) {
22598
22619
  if (!Array.isArray(content)) continue;
22599
22620
  for (const part of content) {
22600
22621
  if (!part || typeof part !== "object") continue;
22601
- const text3 = typeof part.text === "string" ? part.text : "";
22622
+ const text4 = typeof part.text === "string" ? part.text : "";
22602
22623
  const annotations = part.annotations;
22603
22624
  if (!Array.isArray(annotations)) continue;
22604
22625
  for (const annotation of annotations) {
@@ -22609,7 +22630,7 @@ function extractSearchResults2(output, citations, numResults) {
22609
22630
  seenUrls,
22610
22631
  annotation.url,
22611
22632
  annotation.title,
22612
- extractSnippetAround2(text3, annotation.start_index, annotation.end_index)
22633
+ extractSnippetAround2(text4, annotation.start_index, annotation.end_index)
22613
22634
  );
22614
22635
  }
22615
22636
  }
@@ -22847,8 +22868,8 @@ function errorMessage18(err) {
22847
22868
  }
22848
22869
  var STATUS_SHAPED_PATTERN = /\b(?:error|status|http)[\s:=-]{1,4}(\d{3})\b/gi;
22849
22870
  var QUOTA_SHAPED_PATTERN = /rate limit|quota|too many requests/gi;
22850
- function untrustedText(text3, limit = 300) {
22851
- return text3.replace(/\s+/g, " ").trim().slice(0, limit).replace(STATUS_SHAPED_PATTERN, "upstream $1").replace(QUOTA_SHAPED_PATTERN, "upstream rate-limit notice");
22871
+ function untrustedText(text4, limit = 300) {
22872
+ return text4.replace(/\s+/g, " ").trim().slice(0, limit).replace(STATUS_SHAPED_PATTERN, "upstream $1").replace(QUOTA_SHAPED_PATTERN, "upstream rate-limit notice");
22852
22873
  }
22853
22874
  function invalidResponse7(zone, message) {
22854
22875
  return new Error(`Bright Data API returned invalid response for zone ${zone}: ${message}`);
@@ -23817,8 +23838,8 @@ function searchArguments2(query, options) {
23817
23838
  ...domain ? { search_domain_filter: domain } : {}
23818
23839
  };
23819
23840
  }
23820
- function parseResults(text3, limit, domain) {
23821
- let value = JSON.parse(text3);
23841
+ function parseResults(text4, limit, domain) {
23842
+ let value = JSON.parse(text4);
23822
23843
  if (typeof value === "string") value = JSON.parse(value);
23823
23844
  if (!Array.isArray(value)) throw new Error("Z.ai returned invalid response: expected a result list");
23824
23845
  const results = [];
@@ -23883,9 +23904,9 @@ async function searchWithZai(query, options = {}) {
23883
23904
  if (!toolName) throw new Error("Z.ai returned invalid response: web search tool not listed");
23884
23905
  const result = await client.callTool({ name: toolName, arguments: args }, void 0, { signal, timeout: SEARCH_TIMEOUT_MS28 });
23885
23906
  if (result.isError) throw new Error("Z.ai search tool returned an error");
23886
- const text3 = (Array.isArray(result.content) ? result.content : []).find((item) => item.type === "text" && typeof item.text === "string");
23887
- if (!text3) throw new Error("Z.ai returned invalid response: no search text");
23888
- const results = parseResults(text3.text, limit, args.search_domain_filter);
23907
+ const text4 = (Array.isArray(result.content) ? result.content : []).find((item) => item.type === "text" && typeof item.text === "string");
23908
+ if (!text4) throw new Error("Z.ai returned invalid response: no search text");
23909
+ const results = parseResults(text4.text, limit, args.search_domain_filter);
23889
23910
  activityMonitor.logComplete(activityId, 200);
23890
23911
  return { answer: formatSearchResultsAsAnswer(results), results };
23891
23912
  } catch (err) {
@@ -24241,6 +24262,189 @@ async function searchWithKeenable(query, options = {}) {
24241
24262
  return { answer: formatSearchResultsAsAnswer(results), results };
24242
24263
  }
24243
24264
 
24265
+ // ceramic.ts
24266
+ init_activity();
24267
+ init_domain_filter_normalization();
24268
+ init_search_answer_formatting();
24269
+ init_search_result_count_normalization();
24270
+ init_credential_source();
24271
+ init_utils();
24272
+ import { existsSync as existsSync38, readFileSync as readFileSync39 } from "node:fs";
24273
+ var CERAMIC_SEARCH_URL = "https://api.ceramic.ai/search";
24274
+ var CONFIG_PATH36 = getWebSearchConfigPath();
24275
+ var SEARCH_TIMEOUT_MS31 = 3e4;
24276
+ var MAX_REQUEST_RESULTS2 = 20;
24277
+ var REQUEST_DESCRIPTION_CHARS = 1e3;
24278
+ var MAX_SNIPPET_CHARS3 = 500;
24279
+ var cachedConfig33 = null;
24280
+ function loadConfig34() {
24281
+ if (cachedConfig33) return cachedConfig33;
24282
+ if (!existsSync38(CONFIG_PATH36)) {
24283
+ cachedConfig33 = {};
24284
+ return cachedConfig33;
24285
+ }
24286
+ const raw = readFileSync39(CONFIG_PATH36, "utf-8");
24287
+ let parsed;
24288
+ try {
24289
+ parsed = JSON.parse(raw);
24290
+ } catch (err) {
24291
+ const message = err instanceof Error ? err.message : String(err);
24292
+ throw new Error(`Failed to parse ${CONFIG_PATH36}: ${message}`);
24293
+ }
24294
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24295
+ throw new Error(`Invalid config in ${CONFIG_PATH36}: expected a JSON object`);
24296
+ }
24297
+ cachedConfig33 = parsed;
24298
+ return cachedConfig33;
24299
+ }
24300
+ async function requireApiKey14(signal) {
24301
+ const apiKey = await resolveCredential({
24302
+ provider: "Ceramic",
24303
+ configuredValue: loadConfig34().ceramicApiKey,
24304
+ environmentValue: process.env.CERAMIC_API_KEY,
24305
+ signal
24306
+ });
24307
+ if (!apiKey) {
24308
+ throw new Error(
24309
+ `Ceramic API key not found. Either:
24310
+ 1. Create ${CONFIG_PATH36} with { "ceramicApiKey": "your-key" }
24311
+ 2. Set CERAMIC_API_KEY environment variable
24312
+ Get a key at https://platform.ceramic.ai/keys`
24313
+ );
24314
+ }
24315
+ return apiKey;
24316
+ }
24317
+ function parseDomainFilter10(domainFilter) {
24318
+ const filters = { include: [], exclude: [] };
24319
+ for (const raw of domainFilter ?? []) {
24320
+ const domain = normalizeDomain(raw);
24321
+ if (!domain) continue;
24322
+ const target = raw.trim().startsWith("-") ? filters.exclude : filters.include;
24323
+ if (!target.includes(domain)) target.push(domain);
24324
+ }
24325
+ return filters;
24326
+ }
24327
+ function passesDomainFilters10(url, filters) {
24328
+ if (filters.include.length === 0 && filters.exclude.length === 0) return true;
24329
+ const hostname2 = url.hostname.toLowerCase();
24330
+ const matches = (domain) => hostname2 === domain || hostname2.endsWith(`.${domain}`);
24331
+ if (filters.exclude.some(matches)) return false;
24332
+ return filters.include.length === 0 || filters.include.some(matches);
24333
+ }
24334
+ function buildQuery7(query, filters) {
24335
+ if (filters.include.length === 0) return query;
24336
+ const sites = filters.include.map((domain) => `site:${domain}`);
24337
+ return `${query} ${sites.length === 1 ? sites[0] : `(${sites.join(" OR ")})`}`;
24338
+ }
24339
+ function text3(value) {
24340
+ return typeof value === "string" ? value.replace(/\s+/g, " ").trim() : "";
24341
+ }
24342
+ function errorMessage25(err) {
24343
+ return err instanceof Error ? err.message : String(err);
24344
+ }
24345
+ function invalidResponse14(message) {
24346
+ return new Error(`Ceramic returned invalid response: ${message}`);
24347
+ }
24348
+ function parseResponse10(value) {
24349
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidResponse14("expected an object envelope");
24350
+ const result = value.result;
24351
+ if (!result || typeof result !== "object" || Array.isArray(result)) throw invalidResponse14("expected result object");
24352
+ const results = result.results;
24353
+ if (!Array.isArray(results)) throw invalidResponse14("expected result.results array");
24354
+ return results;
24355
+ }
24356
+ function describeError(body) {
24357
+ try {
24358
+ const parsed = JSON.parse(body);
24359
+ const parts = [text3(parsed.title), text3(parsed.detail)].filter(Boolean);
24360
+ if (parts.length > 0) return parts.join(": ");
24361
+ } catch {
24362
+ }
24363
+ return body;
24364
+ }
24365
+ function isCeramicAvailable() {
24366
+ return hasCredentialSource({ provider: "Ceramic", configuredValue: loadConfig34().ceramicApiKey, environmentValue: process.env.CERAMIC_API_KEY });
24367
+ }
24368
+ async function searchWithCeramic(query, options = {}) {
24369
+ const apiKey = await requireApiKey14(options.signal);
24370
+ const numResults = normalizeSearchResultCount(options.numResults);
24371
+ const filters = parseDomainFilter10(options.domainFilter);
24372
+ const hasDomainFilters = filters.include.length > 0 || filters.exclude.length > 0;
24373
+ const body = {
24374
+ query: buildQuery7(query, filters),
24375
+ maxResults: hasDomainFilters ? Math.min(MAX_REQUEST_RESULTS2, numResults + 5) : numResults,
24376
+ maxDescriptionLength: REQUEST_DESCRIPTION_CHARS
24377
+ };
24378
+ const activityId = activityMonitor.logStart({ type: "api", query });
24379
+ const timeoutSignal = AbortSignal.timeout(SEARCH_TIMEOUT_MS31);
24380
+ let response;
24381
+ let entries;
24382
+ try {
24383
+ response = await fetchWithCredentialRedirects(CERAMIC_SEARCH_URL, {
24384
+ method: "POST",
24385
+ headers: {
24386
+ Accept: "application/json",
24387
+ "Content-Type": "application/json",
24388
+ Authorization: `Bearer ${apiKey}`
24389
+ },
24390
+ body: JSON.stringify(body),
24391
+ signal: options.signal ? AbortSignal.any([timeoutSignal, options.signal]) : timeoutSignal
24392
+ }, ["Authorization"]);
24393
+ if (!response.ok) {
24394
+ const errorText = redactCredential(describeError(await response.text()), apiKey).slice(0, 300);
24395
+ throw new Error(`Ceramic error ${response.status}: ${errorText}`);
24396
+ }
24397
+ let rawData;
24398
+ try {
24399
+ rawData = await response.json();
24400
+ } catch (err) {
24401
+ if (err instanceof Error && err.name === "TimeoutError") throw err;
24402
+ throw new Error(`Ceramic returned invalid JSON: ${errorMessage25(err)}`);
24403
+ }
24404
+ entries = parseResponse10(rawData);
24405
+ } catch (err) {
24406
+ if (options.signal?.aborted) {
24407
+ activityMonitor.logComplete(activityId, 0);
24408
+ throw new Error("Aborted");
24409
+ }
24410
+ const message = errorMessage25(err);
24411
+ const providerTimeout = timeoutSignal.aborted || err instanceof Error && err.name === "TimeoutError";
24412
+ const outgoing = providerTimeout ? new Error(`Ceramic request timed out after ${Math.round(SEARCH_TIMEOUT_MS31 / 1e3)}s`) : (() => {
24413
+ const redactedMessage = redactCredential(message, apiKey);
24414
+ if (redactedMessage === message && err instanceof Error) return err;
24415
+ const redactedError = new Error(redactedMessage);
24416
+ if (err instanceof Error) redactedError.name = err.name;
24417
+ return redactedError;
24418
+ })();
24419
+ activityMonitor.logError(activityId, redactCredential(errorMessage25(outgoing), apiKey));
24420
+ throw outgoing;
24421
+ }
24422
+ activityMonitor.logComplete(activityId, response.status);
24423
+ const results = [];
24424
+ const seen = /* @__PURE__ */ new Set();
24425
+ for (const entry of entries) {
24426
+ if (!entry || typeof entry !== "object") continue;
24427
+ if (typeof entry.url !== "string" || !entry.url) continue;
24428
+ let resultUrl;
24429
+ try {
24430
+ resultUrl = new URL(entry.url);
24431
+ } catch {
24432
+ continue;
24433
+ }
24434
+ if (resultUrl.protocol !== "http:" && resultUrl.protocol !== "https:") continue;
24435
+ if (!passesDomainFilters10(resultUrl, filters)) continue;
24436
+ if (seen.has(resultUrl.href)) continue;
24437
+ seen.add(resultUrl.href);
24438
+ results.push({
24439
+ title: text3(entry.title) || `Source ${results.length + 1}`,
24440
+ url: resultUrl.href,
24441
+ snippet: text3(entry.description).slice(0, MAX_SNIPPET_CHARS3)
24442
+ });
24443
+ if (results.length >= numResults) break;
24444
+ }
24445
+ return { answer: formatSearchResultsAsAnswer(results), results };
24446
+ }
24447
+
24244
24448
  // kimi-search.ts
24245
24449
  init_activity();
24246
24450
  init_domain_filter_normalization();
@@ -24250,7 +24454,7 @@ init_search_result_count_normalization();
24250
24454
  import { randomUUID as randomUUID2 } from "node:crypto";
24251
24455
  var KIMI_SEARCH_URL = "https://api.kimi.com/coding/v1/search";
24252
24456
  var KIMI_PROVIDERS = ["kimi-coding", "kimi-code"];
24253
- var SEARCH_TIMEOUT_MS31 = 3e4;
24457
+ var SEARCH_TIMEOUT_MS32 = 3e4;
24254
24458
  function buildRequestHeaders(auth) {
24255
24459
  const headers = new Headers();
24256
24460
  for (const [name, value] of Object.entries(auth.headers)) {
@@ -24365,7 +24569,7 @@ async function searchWithKimi(query, options = {}, ctx) {
24365
24569
  throw new Error("Kimi Code web search unavailable. Run /login kimi-coding to authenticate a Kimi Code Plan account.");
24366
24570
  }
24367
24571
  const activityId = activityMonitor.logStart({ type: "api", query });
24368
- const timeoutSignal = AbortSignal.timeout(SEARCH_TIMEOUT_MS31);
24572
+ const timeoutSignal = AbortSignal.timeout(SEARCH_TIMEOUT_MS32);
24369
24573
  const requestSignal15 = options.signal ? AbortSignal.any([timeoutSignal, options.signal]) : timeoutSignal;
24370
24574
  try {
24371
24575
  const response = await fetch(KIMI_SEARCH_URL, {
@@ -24417,45 +24621,45 @@ init_activity();
24417
24621
  init_domain_filter_normalization();
24418
24622
  init_credential_source();
24419
24623
  init_utils();
24420
- import { existsSync as existsSync38, readFileSync as readFileSync39 } from "node:fs";
24624
+ import { existsSync as existsSync39, readFileSync as readFileSync40 } from "node:fs";
24421
24625
  var MISTRAL_CONVERSATIONS_URL = "https://api.mistral.ai/v1/conversations";
24422
- var CONFIG_PATH36 = getWebSearchConfigPath();
24423
- var SEARCH_TIMEOUT_MS32 = 6e4;
24626
+ var CONFIG_PATH37 = getWebSearchConfigPath();
24627
+ var SEARCH_TIMEOUT_MS33 = 6e4;
24424
24628
  var DEFAULT_SEARCH_MODEL = "mistral-small-latest";
24425
24629
  var DEFAULT_SEARCH_TOOL = "web_search";
24426
24630
  var MAX_RESULTS = 20;
24427
- var cachedConfig33 = null;
24428
- function loadConfig34() {
24429
- if (cachedConfig33) return cachedConfig33;
24430
- if (!existsSync38(CONFIG_PATH36)) {
24431
- cachedConfig33 = {};
24432
- return cachedConfig33;
24631
+ var cachedConfig34 = null;
24632
+ function loadConfig35() {
24633
+ if (cachedConfig34) return cachedConfig34;
24634
+ if (!existsSync39(CONFIG_PATH37)) {
24635
+ cachedConfig34 = {};
24636
+ return cachedConfig34;
24433
24637
  }
24434
- const raw = readFileSync39(CONFIG_PATH36, "utf-8");
24638
+ const raw = readFileSync40(CONFIG_PATH37, "utf-8");
24435
24639
  let parsed;
24436
24640
  try {
24437
24641
  parsed = JSON.parse(raw);
24438
24642
  } catch (err) {
24439
24643
  const message = err instanceof Error ? err.message : String(err);
24440
- throw new Error(`Failed to parse ${CONFIG_PATH36}: ${message}`);
24644
+ throw new Error(`Failed to parse ${CONFIG_PATH37}: ${message}`);
24441
24645
  }
24442
24646
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
24443
- throw new Error(`Invalid config in ${CONFIG_PATH36}: expected a JSON object`);
24647
+ throw new Error(`Invalid config in ${CONFIG_PATH37}: expected a JSON object`);
24444
24648
  }
24445
- cachedConfig33 = parsed;
24446
- return cachedConfig33;
24649
+ cachedConfig34 = parsed;
24650
+ return cachedConfig34;
24447
24651
  }
24448
24652
  function resolveSearchModel(value) {
24449
24653
  if (value === void 0) return DEFAULT_SEARCH_MODEL;
24450
24654
  if (typeof value !== "string" || value.trim().length === 0) {
24451
- throw new Error(`mistralSearchModel in ${CONFIG_PATH36} must be a non-empty string`);
24655
+ throw new Error(`mistralSearchModel in ${CONFIG_PATH37} must be a non-empty string`);
24452
24656
  }
24453
24657
  return value.trim();
24454
24658
  }
24455
24659
  function resolveSearchTool(value) {
24456
24660
  if (value === void 0) return DEFAULT_SEARCH_TOOL;
24457
24661
  if (value !== "web_search" && value !== "web_search_premium") {
24458
- throw new Error(`mistralSearchTool in ${CONFIG_PATH36} must be either web_search or web_search_premium`);
24662
+ throw new Error(`mistralSearchTool in ${CONFIG_PATH37} must be either web_search or web_search_premium`);
24459
24663
  }
24460
24664
  return value;
24461
24665
  }
@@ -24473,7 +24677,7 @@ function parseDomainFilters(domainFilter) {
24473
24677
  }
24474
24678
  return filters;
24475
24679
  }
24476
- function passesDomainFilters10(url, filters) {
24680
+ function passesDomainFilters11(url, filters) {
24477
24681
  if (filters.include.length === 0 && filters.exclude.length === 0) return true;
24478
24682
  const hostname2 = new URL(url).hostname.toLowerCase();
24479
24683
  const matches = (domain) => hostname2 === domain || hostname2.endsWith(`.${domain}`);
@@ -24513,18 +24717,18 @@ function buildSearchPrompt(query, options, numResults) {
24513
24717
 
24514
24718
  ${query}` : query;
24515
24719
  }
24516
- function errorMessage25(err) {
24720
+ function errorMessage26(err) {
24517
24721
  return err instanceof Error ? err.message : String(err);
24518
24722
  }
24519
- function invalidResponse14(message) {
24723
+ function invalidResponse15(message) {
24520
24724
  return new Error(`Mistral API returned invalid response: ${message}`);
24521
24725
  }
24522
24726
  function parseConversationResponse(value, options, numResults) {
24523
24727
  if (!value || typeof value !== "object" || Array.isArray(value)) {
24524
- throw invalidResponse14("expected an object envelope");
24728
+ throw invalidResponse15("expected an object envelope");
24525
24729
  }
24526
24730
  const outputs = value.outputs;
24527
- if (!Array.isArray(outputs)) throw invalidResponse14("outputs must be an array");
24731
+ if (!Array.isArray(outputs)) throw invalidResponse15("outputs must be an array");
24528
24732
  const answerParts = [];
24529
24733
  const results = [];
24530
24734
  const seenUrls = /* @__PURE__ */ new Set();
@@ -24548,7 +24752,7 @@ function parseConversationResponse(value, options, numResults) {
24548
24752
  }
24549
24753
  if (part.type !== "tool_reference" || results.length >= numResults) continue;
24550
24754
  const url = normalizeResultUrl2(part.url);
24551
- if (!url || !passesDomainFilters10(url, domainFilters) || seenUrls.has(url)) continue;
24755
+ if (!url || !passesDomainFilters11(url, domainFilters) || seenUrls.has(url)) continue;
24552
24756
  seenUrls.add(url);
24553
24757
  const title = typeof part.title === "string" && part.title.trim() ? part.title.trim() : url;
24554
24758
  const snippet = typeof part.description === "string" ? part.description : "";
@@ -24556,20 +24760,20 @@ function parseConversationResponse(value, options, numResults) {
24556
24760
  }
24557
24761
  }
24558
24762
  const answer = answerParts.join("\n").trim();
24559
- if (!answer && results.length === 0) throw invalidResponse14("no answer or sources");
24763
+ if (!answer && results.length === 0) throw invalidResponse15("no answer or sources");
24560
24764
  return { answer, results };
24561
24765
  }
24562
24766
  async function getApiKey26(signal) {
24563
24767
  const apiKey = await resolveCredential({
24564
24768
  provider: "Mistral",
24565
- configuredValue: loadConfig34().mistralApiKey,
24769
+ configuredValue: loadConfig35().mistralApiKey,
24566
24770
  environmentValue: process.env.MISTRAL_API_KEY,
24567
24771
  signal
24568
24772
  });
24569
24773
  if (!apiKey) {
24570
24774
  throw new Error(
24571
24775
  `Mistral API key not found. Either:
24572
- 1. Create ${CONFIG_PATH36} with { "mistralApiKey": "your-key" }
24776
+ 1. Create ${CONFIG_PATH37} with { "mistralApiKey": "your-key" }
24573
24777
  2. Set MISTRAL_API_KEY environment variable
24574
24778
  Get a key at https://console.mistral.ai/api-keys`
24575
24779
  );
@@ -24578,7 +24782,7 @@ Get a key at https://console.mistral.ai/api-keys`
24578
24782
  }
24579
24783
  function isMistralAvailable() {
24580
24784
  try {
24581
- const config = loadConfig34();
24785
+ const config = loadConfig35();
24582
24786
  resolveSearchModel(config.mistralSearchModel);
24583
24787
  resolveSearchTool(config.mistralSearchTool);
24584
24788
  return hasCredentialSource({
@@ -24591,12 +24795,12 @@ function isMistralAvailable() {
24591
24795
  }
24592
24796
  }
24593
24797
  async function searchWithMistral(query, options = {}) {
24594
- const config = loadConfig34();
24798
+ const config = loadConfig35();
24595
24799
  const model = resolveSearchModel(config.mistralSearchModel);
24596
24800
  const tool = resolveSearchTool(config.mistralSearchTool);
24597
24801
  const numResults = normalizeCount4(options.numResults);
24598
24802
  const apiKey = await getApiKey26(options.signal);
24599
- const requestSignal15 = options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS32), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS32);
24803
+ const requestSignal15 = options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS33), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS33);
24600
24804
  const activityId = activityMonitor.logStart({ type: "api", query });
24601
24805
  try {
24602
24806
  const response = await fetch(MISTRAL_CONVERSATIONS_URL, {
@@ -24621,13 +24825,13 @@ async function searchWithMistral(query, options = {}) {
24621
24825
  try {
24622
24826
  parsed = await response.json();
24623
24827
  } catch (err) {
24624
- throw new Error(`Mistral API returned invalid JSON: ${errorMessage25(err)}`);
24828
+ throw new Error(`Mistral API returned invalid JSON: ${errorMessage26(err)}`);
24625
24829
  }
24626
24830
  const result = parseConversationResponse(parsed, options, numResults);
24627
24831
  activityMonitor.logComplete(activityId, response.status);
24628
24832
  return result;
24629
24833
  } catch (err) {
24630
- const message = errorMessage25(err);
24834
+ const message = errorMessage26(err);
24631
24835
  const redactedMessage = redactCredential(message, apiKey);
24632
24836
  if (redactedMessage.toLowerCase().includes("abort")) {
24633
24837
  activityMonitor.logComplete(activityId, 0);
@@ -24643,7 +24847,7 @@ async function searchWithMistral(query, options = {}) {
24643
24847
 
24644
24848
  // gemini-search.ts
24645
24849
  init_utils();
24646
- var RESOLVED_SEARCH_PROVIDERS = ["openai", "brave", "parallel", "parallel-mcp", "tinyfish", "search1api", "searchinfinity", "querit", "tavily", "you", "firecrawl", "jina", "searxng", "degoog", "duckduckgo", "perplexity", "gemini", "kimi", "exa", "serpdive", "kagi", "ollama", "anysearch", "xai", "mistral", "brightdata", "serpbase", "serpapi", "serper", "serply", "valyu", "bocha", "xcrawl", "baizhi", "zai", "keenable"];
24850
+ var RESOLVED_SEARCH_PROVIDERS = ["openai", "brave", "parallel", "parallel-mcp", "tinyfish", "search1api", "searchinfinity", "querit", "tavily", "you", "firecrawl", "jina", "searxng", "degoog", "duckduckgo", "perplexity", "gemini", "kimi", "exa", "serpdive", "kagi", "ollama", "anysearch", "xai", "mistral", "brightdata", "serpbase", "serpapi", "serper", "serply", "valyu", "bocha", "xcrawl", "baizhi", "zai", "keenable", "ceramic"];
24647
24851
  var SEARCH_PROVIDERS = ["auto", "all", ...RESOLVED_SEARCH_PROVIDERS];
24648
24852
  var SearchProviderError = class extends Error {
24649
24853
  provider;
@@ -24659,18 +24863,18 @@ var SearchProviderError = class extends Error {
24659
24863
  this.causeError = cause;
24660
24864
  }
24661
24865
  };
24662
- var CONFIG_PATH37 = getWebSearchConfigPath();
24866
+ var CONFIG_PATH38 = getWebSearchConfigPath();
24663
24867
  var DEFAULT_SEARCH_MODEL2 = "gemini-3.6-flash";
24664
24868
  var ALL_SEARCH_PROVIDERS = ["searxng", "openai", "exa", "brave", "parallel", "tinyfish", "search1api", "searchinfinity", "querit", "tavily", "firecrawl", "jina", "serpdive", "kagi", "ollama", "perplexity", "gemini", "bocha"];
24665
24869
  var VALID_ROUTING_KINDS = ["transient", "quota", "network", "invalid-response", "unsupported"];
24666
24870
  var cachedSearchConfig = null;
24667
24871
  function getSearchConfig() {
24668
24872
  if (cachedSearchConfig) return cachedSearchConfig;
24669
- if (!existsSync39(CONFIG_PATH37)) {
24873
+ if (!existsSync40(CONFIG_PATH38)) {
24670
24874
  cachedSearchConfig = { searchProvider: "auto", searchProviderConfigured: false };
24671
24875
  return cachedSearchConfig;
24672
24876
  }
24673
- const rawText = readFileSync40(CONFIG_PATH37, "utf-8");
24877
+ const rawText = readFileSync41(CONFIG_PATH38, "utf-8");
24674
24878
  let raw;
24675
24879
  try {
24676
24880
  const parsed = JSON.parse(rawText);
@@ -24680,25 +24884,25 @@ function getSearchConfig() {
24680
24884
  raw = parsed;
24681
24885
  } catch (err) {
24682
24886
  const message = err instanceof Error ? err.message : String(err);
24683
- throw new Error(`Failed to parse ${CONFIG_PATH37}: ${message}`);
24887
+ throw new Error(`Failed to parse ${CONFIG_PATH38}: ${message}`);
24684
24888
  }
24685
24889
  const searchModel = normalizeSearchModel(raw.searchModel);
24686
24890
  const webSearch = raw.webSearch;
24687
24891
  if (webSearch !== void 0 && (!webSearch || typeof webSearch !== "object" || Array.isArray(webSearch))) {
24688
- throw new Error(`webSearch in ${CONFIG_PATH37} must be an object`);
24892
+ throw new Error(`webSearch in ${CONFIG_PATH38} must be an object`);
24689
24893
  }
24690
- const allowedProviders = webSearch && Object.hasOwn(webSearch, "allowedProviders") ? normalizeResolvedProviderList(webSearch.allowedProviders, `webSearch.allowedProviders in ${CONFIG_PATH37}`) : void 0;
24894
+ const allowedProviders = webSearch && Object.hasOwn(webSearch, "allowedProviders") ? normalizeResolvedProviderList(webSearch.allowedProviders, `webSearch.allowedProviders in ${CONFIG_PATH38}`) : void 0;
24691
24895
  const searchProviderConfigured = Object.hasOwn(raw, "searchProvider") || Object.hasOwn(raw, "provider");
24692
- const searchProvider = normalizeSearchProviderSelection(raw.searchProvider ?? raw.provider, `provider in ${CONFIG_PATH37}`);
24896
+ const searchProvider = normalizeSearchProviderSelection(raw.searchProvider ?? raw.provider, `provider in ${CONFIG_PATH38}`);
24693
24897
  const searchRouting = Object.hasOwn(raw, "searchRouting") ? normalizeSearchRouting(raw.searchRouting) : void 0;
24694
24898
  if (allowedProviders) {
24695
24899
  if (Object.hasOwn(raw, "searchProvider")) {
24696
- assertSearchProviderSelectionAllowed(normalizeSearchProviderSelection(raw.searchProvider), `searchProvider in ${CONFIG_PATH37}`, allowedProviders);
24900
+ assertSearchProviderSelectionAllowed(normalizeSearchProviderSelection(raw.searchProvider), `searchProvider in ${CONFIG_PATH38}`, allowedProviders);
24697
24901
  }
24698
24902
  if (Object.hasOwn(raw, "provider")) {
24699
- assertSearchProviderSelectionAllowed(normalizeSearchProviderSelection(raw.provider), `provider in ${CONFIG_PATH37}`, allowedProviders);
24903
+ assertSearchProviderSelectionAllowed(normalizeSearchProviderSelection(raw.provider), `provider in ${CONFIG_PATH38}`, allowedProviders);
24700
24904
  }
24701
- if (searchRouting) assertSearchProviderSelectionAllowed(searchRouting.providers, `searchRouting.providers in ${CONFIG_PATH37}`, allowedProviders);
24905
+ if (searchRouting) assertSearchProviderSelectionAllowed(searchRouting.providers, `searchRouting.providers in ${CONFIG_PATH38}`, allowedProviders);
24702
24906
  }
24703
24907
  cachedSearchConfig = {
24704
24908
  searchProvider,
@@ -24711,21 +24915,21 @@ function getSearchConfig() {
24711
24915
  }
24712
24916
  function normalizeSearchRouting(value) {
24713
24917
  if (!value || typeof value !== "object" || Array.isArray(value)) {
24714
- throw new Error(`searchRouting in ${CONFIG_PATH37} must be an object`);
24918
+ throw new Error(`searchRouting in ${CONFIG_PATH38} must be an object`);
24715
24919
  }
24716
24920
  const raw = value;
24717
- const providers = normalizeResolvedProviderList(raw.providers, `searchRouting.providers in ${CONFIG_PATH37}`);
24921
+ const providers = normalizeResolvedProviderList(raw.providers, `searchRouting.providers in ${CONFIG_PATH38}`);
24718
24922
  const useCurrentModel = raw.useCurrentModel;
24719
24923
  if (useCurrentModel !== void 0 && typeof useCurrentModel !== "boolean") {
24720
- throw new Error(`searchRouting.useCurrentModel in ${CONFIG_PATH37} must be a boolean`);
24924
+ throw new Error(`searchRouting.useCurrentModel in ${CONFIG_PATH38} must be a boolean`);
24721
24925
  }
24722
24926
  if (!Array.isArray(raw.fallbackOn) || raw.fallbackOn.length === 0) {
24723
- throw new Error(`searchRouting.fallbackOn in ${CONFIG_PATH37} must be a non-empty array`);
24927
+ throw new Error(`searchRouting.fallbackOn in ${CONFIG_PATH38} must be a non-empty array`);
24724
24928
  }
24725
24929
  const fallbackOn = [];
24726
24930
  for (const kind of raw.fallbackOn) {
24727
24931
  if (typeof kind !== "string" || !VALID_ROUTING_KINDS.includes(kind)) {
24728
- throw new Error(`searchRouting.fallbackOn in ${CONFIG_PATH37} may only contain transient, quota, network, invalid-response, or unsupported`);
24932
+ throw new Error(`searchRouting.fallbackOn in ${CONFIG_PATH38} may only contain transient, quota, network, invalid-response, or unsupported`);
24729
24933
  }
24730
24934
  if (!fallbackOn.includes(kind)) {
24731
24935
  fallbackOn.push(kind);
@@ -24775,11 +24979,11 @@ function normalizeSearchProviderSelection(value, label = "provider") {
24775
24979
  const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
24776
24980
  return SEARCH_PROVIDERS.includes(normalized) ? normalized : "auto";
24777
24981
  }
24778
- function errorMessage26(err) {
24982
+ function errorMessage27(err) {
24779
24983
  return err instanceof Error ? err.message : String(err);
24780
24984
  }
24781
24985
  function isAbortError2(err) {
24782
- return errorMessage26(err).toLowerCase().includes("abort");
24986
+ return errorMessage27(err).toLowerCase().includes("abort");
24783
24987
  }
24784
24988
  async function tryOpenAIInAuto(query, options, fallbackErrors) {
24785
24989
  try {
@@ -24789,7 +24993,7 @@ async function tryOpenAIInAuto(query, options, fallbackErrors) {
24789
24993
  }
24790
24994
  } catch (err) {
24791
24995
  if (isAbortError2(err)) throw err;
24792
- fallbackErrors.push(`OpenAI: ${errorMessage26(err)}`);
24996
+ fallbackErrors.push(`OpenAI: ${errorMessage27(err)}`);
24793
24997
  }
24794
24998
  return null;
24795
24999
  }
@@ -24800,7 +25004,7 @@ async function searchWithGemini(query, options, strictErrors) {
24800
25004
  if (apiResult) return apiResult;
24801
25005
  } catch (err) {
24802
25006
  if (err instanceof CredentialResolutionError || isAbortError2(err)) throw err;
24803
- errors.push(`Gemini API: ${errorMessage26(err)}`);
25007
+ errors.push(`Gemini API: ${errorMessage27(err)}`);
24804
25008
  }
24805
25009
  try {
24806
25010
  const webResult = await searchWithGeminiWeb(query, options);
@@ -24809,7 +25013,7 @@ async function searchWithGemini(query, options, strictErrors) {
24809
25013
  if (diagnostic) errors.push(`Gemini Web: ${diagnostic}`);
24810
25014
  } catch (err) {
24811
25015
  if (isAbortError2(err)) throw err;
24812
- errors.push(`Gemini Web: ${errorMessage26(err)}`);
25016
+ errors.push(`Gemini Web: ${errorMessage27(err)}`);
24813
25017
  }
24814
25018
  if (strictErrors && errors.length > 0) {
24815
25019
  throw new Error(`Gemini search failed:
@@ -24824,11 +25028,11 @@ function providerErrorStatus(message) {
24824
25028
  }
24825
25029
  function classifyProviderError(provider, err) {
24826
25030
  if (err instanceof SearchProviderError) return err;
24827
- const message = errorMessage26(err);
25031
+ const message = errorMessage27(err);
24828
25032
  const lower = message.toLowerCase();
24829
25033
  const status = providerErrorStatus(message);
24830
25034
  const openAIStreamError = provider === "openai" && lower.includes("openai api stream error");
24831
- const text3 = openAIStreamError ? lower.replace(/_/g, " ") : lower;
25035
+ const text4 = openAIStreamError ? lower.replace(/_/g, " ") : lower;
24832
25036
  let kind = "unknown";
24833
25037
  const mentionsUnsupportedWebSearch = /(?:web[_ -]?search|web[_ -]?search_preview|(?:the )?tool)\b.*\b(?:unsupported|not supported|does not support|doesn't support|unknown|unrecognized|unavailable|not found)|\b(?:unsupported|not supported|does not support|doesn't support|unknown|unrecognized|unavailable|not found)\b.*\b(?:web[_ -]?search|web[_ -]?search_preview|(?:the )?tool)/i.test(lower);
24834
25038
  if (err instanceof CredentialResolutionError || /(?:api )?key (?:not found|missing)|credential resolution/.test(lower)) {
@@ -24849,19 +25053,19 @@ function classifyProviderError(provider, err) {
24849
25053
  kind = "quota";
24850
25054
  } else if (status !== void 0 && (status === 408 || status === 425 || status >= 500)) {
24851
25055
  kind = "transient";
24852
- } else if (/rate limit|quota|too many requests/.test(text3) || openAIStreamError && /usage limit/.test(text3)) {
25056
+ } else if (/rate limit|quota|too many requests/.test(text4) || openAIStreamError && /usage limit/.test(text4)) {
24853
25057
  kind = "quota";
24854
- } else if (/unauthorized|forbidden|permission denied/.test(text3) || openAIStreamError && /authentication error|permission error|invalid api key/.test(text3)) {
25058
+ } else if (/unauthorized|forbidden|permission denied/.test(text4) || openAIStreamError && /authentication error|permission error|invalid api key/.test(text4)) {
24855
25059
  kind = "auth";
24856
- } else if (/bad request|invalid request/.test(text3)) {
25060
+ } else if (/bad request|invalid request/.test(text4)) {
24857
25061
  kind = "invalid-request";
24858
- } else if (/invalid json|no parseable response|no parseable results|invalid response|returned empty response|no web_search_call/.test(text3)) {
25062
+ } else if (/invalid json|no parseable response|no parseable results|invalid response|returned empty response|no web_search_call/.test(text4)) {
24859
25063
  kind = "invalid-response";
24860
- } else if (/temporar|service unavailable|server error/.test(text3) || openAIStreamError && /internal error|\bapi error|overloaded/.test(text3)) {
25064
+ } else if (/temporar|service unavailable|server error/.test(text4) || openAIStreamError && /internal error|\bapi error|overloaded/.test(text4)) {
24861
25065
  kind = "transient";
24862
- } else if (err instanceof TypeError || /fetch failed|network|econnreset|econnrefused|enotfound|etimedout|timed out|socket/.test(text3)) {
25066
+ } else if (err instanceof TypeError || /fetch failed|network|econnreset|econnrefused|enotfound|etimedout|timed out|socket/.test(text4)) {
24863
25067
  kind = "network";
24864
- } else if (/invalid or missing|invalid config|failed to parse|must be an? |configuration/.test(text3)) {
25068
+ } else if (/invalid or missing|invalid config|failed to parse|must be an? |configuration/.test(text4)) {
24865
25069
  kind = "config";
24866
25070
  } else if (openAIStreamError) {
24867
25071
  kind = "invalid-response";
@@ -24900,6 +25104,7 @@ async function searchWithResolvedProvider(provider, query, options, useCurrentMo
24900
25104
  if (provider === "zai") return { ...await searchWithZai(query, options), provider };
24901
25105
  if (provider === "valyu") return { ...await searchWithValyu(query, options), provider };
24902
25106
  if (provider === "keenable") return { ...await searchWithKeenable(query, options), provider };
25107
+ if (provider === "ceramic") return { ...await searchWithCeramic(query, options), provider };
24903
25108
  if (provider === "xcrawl") return { ...await searchWithXCrawl(query, options), provider };
24904
25109
  if (provider === "perplexity") return { ...await searchWithPerplexity(query, options), provider };
24905
25110
  if (provider === "searxng") return { ...await searchWithSearXNG(query, options), provider };
@@ -24911,7 +25116,7 @@ async function searchWithResolvedProvider(provider, query, options, useCurrentMo
24911
25116
  if (result2) return { ...result2, provider };
24912
25117
  throw new Error(
24913
25118
  `Gemini search unavailable. Either:
24914
- 1. Configure geminiApiKey in ${CONFIG_PATH37} or set GEMINI_API_KEY
25119
+ 1. Configure geminiApiKey in ${CONFIG_PATH38} or set GEMINI_API_KEY
24915
25120
  2. Set GOOGLE_GEMINI_BASE_URL + CLOUDFLARE_API_KEY for Cloudflare AI Gateway routing
24916
25121
  3. Set geminiAuth to "adc" in web-search.json with a Google Cloud ADC + project/location
24917
25122
  4. Sign into gemini.google.com in a supported Chromium-based browser`
@@ -24952,6 +25157,7 @@ async function isResolvedProviderAvailable(provider, options, useCurrentModel =
24952
25157
  if (provider === "zai") return isZaiAvailable();
24953
25158
  if (provider === "valyu") return isValyuAvailable();
24954
25159
  if (provider === "keenable") return isKeenableAvailable();
25160
+ if (provider === "ceramic") return isCeramicAvailable();
24955
25161
  if (provider === "xcrawl") return isXcrawlAvailable();
24956
25162
  if (provider === "perplexity") return isPerplexityAvailable();
24957
25163
  if (provider === "searxng") return isSearXNGAvailable();
@@ -24997,6 +25203,7 @@ function providerLabel(provider) {
24997
25203
  if (provider === "zai") return "Z.ai";
24998
25204
  if (provider === "valyu") return "Valyu";
24999
25205
  if (provider === "keenable") return "Keenable";
25206
+ if (provider === "ceramic") return "Ceramic";
25000
25207
  return provider.charAt(0).toUpperCase() + provider.slice(1);
25001
25208
  }
25002
25209
  async function searchWithAllProvider(provider, query, options) {
@@ -25012,7 +25219,7 @@ async function searchWithProviders(query, options, selectedProviders) {
25012
25219
  available: provider === "gemini" ? isGeminiApiAvailable() : await isResolvedProviderAvailable(provider, options)
25013
25220
  })))).filter((entry) => entry.available).map((entry) => entry.provider);
25014
25221
  if (providers.length === 0) {
25015
- throw new Error('No configured search provider available for provider "all". Parallel MCP, degoog, DuckDuckGo, Kimi, AnySearch, xAI, Mistral, Bright Data, SerpBase, SerpApi, Serper, Serply, You.com, Valyu, Baizhi, Z.ai, XCrawl, and Keenable are excluded.');
25222
+ throw new Error('No configured search provider available for provider "all". Parallel MCP, degoog, DuckDuckGo, Kimi, AnySearch, xAI, Mistral, Bright Data, SerpBase, SerpApi, Serper, Serply, You.com, Valyu, Baizhi, Z.ai, XCrawl, Keenable, and Ceramic are excluded.');
25016
25223
  }
25017
25224
  const settled = await Promise.allSettled(
25018
25225
  providers.map((provider) => selectedProviders ? searchWithResolvedProvider(provider, query, options) : searchWithAllProvider(provider, query, options))
@@ -25025,7 +25232,7 @@ async function searchWithProviders(query, options, selectedProviders) {
25025
25232
  if (outcome.status === "fulfilled") {
25026
25233
  successes.push(outcome.value);
25027
25234
  } else {
25028
- failures.push({ provider: providers[index], error: errorMessage26(outcome.reason) });
25235
+ failures.push({ provider: providers[index], error: errorMessage27(outcome.reason) });
25029
25236
  }
25030
25237
  }
25031
25238
  if (successes.length === 0) {
@@ -25082,7 +25289,7 @@ async function searchWithConfiguredRouting(query, options, routing) {
25082
25289
  return await searchWithResolvedProvider(provider, query, options, useCurrentModel);
25083
25290
  } catch (err) {
25084
25291
  const classified = classifyProviderError(provider, err);
25085
- diagnostics.push(`${provider} [${classified.kind}]: ${errorMessage26(err)}`);
25292
+ diagnostics.push(`${provider} [${classified.kind}]: ${errorMessage27(err)}`);
25086
25293
  if (!routing.fallbackOn.includes(classified.kind)) {
25087
25294
  throw classified;
25088
25295
  }
@@ -25111,7 +25318,7 @@ async function search(query, options = {}) {
25111
25318
  return { ...result, provider: "searxng" };
25112
25319
  } catch (err) {
25113
25320
  if (isAbortError2(err)) throw err;
25114
- fallbackErrors.push(`SearXNG: ${errorMessage26(err)}`);
25321
+ fallbackErrors.push(`SearXNG: ${errorMessage27(err)}`);
25115
25322
  }
25116
25323
  }
25117
25324
  let triedOpenAI = false;
@@ -25126,7 +25333,7 @@ async function search(query, options = {}) {
25126
25333
  if (result) return { ...result, provider: "exa" };
25127
25334
  } catch (err) {
25128
25335
  if (err instanceof CredentialResolutionError || isAbortError2(err)) throw err;
25129
- fallbackErrors.push(`Exa: ${errorMessage26(err)}`);
25336
+ fallbackErrors.push(`Exa: ${errorMessage27(err)}`);
25130
25337
  }
25131
25338
  }
25132
25339
  if (allowed.has("openai") && !triedOpenAI) {
@@ -25139,7 +25346,7 @@ async function search(query, options = {}) {
25139
25346
  return { ...result, provider: "brave" };
25140
25347
  } catch (err) {
25141
25348
  if (isAbortError2(err)) throw err;
25142
- fallbackErrors.push(`Brave: ${errorMessage26(err)}`);
25349
+ fallbackErrors.push(`Brave: ${errorMessage27(err)}`);
25143
25350
  }
25144
25351
  }
25145
25352
  if (allowed.has("parallel") && isParallelAvailable()) {
@@ -25148,7 +25355,7 @@ async function search(query, options = {}) {
25148
25355
  return { ...result, provider: "parallel" };
25149
25356
  } catch (err) {
25150
25357
  if (isAbortError2(err)) throw err;
25151
- fallbackErrors.push(`Parallel: ${errorMessage26(err)}`);
25358
+ fallbackErrors.push(`Parallel: ${errorMessage27(err)}`);
25152
25359
  }
25153
25360
  }
25154
25361
  if (allowed.has("tinyfish") && isTinyFishAvailable()) {
@@ -25157,7 +25364,7 @@ async function search(query, options = {}) {
25157
25364
  return { ...result, provider: "tinyfish" };
25158
25365
  } catch (err) {
25159
25366
  if (isAbortError2(err)) throw err;
25160
- fallbackErrors.push(`TinyFish: ${errorMessage26(err)}`);
25367
+ fallbackErrors.push(`TinyFish: ${errorMessage27(err)}`);
25161
25368
  }
25162
25369
  }
25163
25370
  if (allowed.has("search1api") && isSearch1APIAvailable()) {
@@ -25166,7 +25373,7 @@ async function search(query, options = {}) {
25166
25373
  return { ...result, provider: "search1api" };
25167
25374
  } catch (err) {
25168
25375
  if (isAbortError2(err)) throw err;
25169
- fallbackErrors.push(`Search1API: ${errorMessage26(err)}`);
25376
+ fallbackErrors.push(`Search1API: ${errorMessage27(err)}`);
25170
25377
  }
25171
25378
  }
25172
25379
  if (allowed.has("searchinfinity") && isSearchinfinityAvailable()) {
@@ -25175,7 +25382,7 @@ async function search(query, options = {}) {
25175
25382
  return { ...result, provider: "searchinfinity" };
25176
25383
  } catch (err) {
25177
25384
  if (isAbortError2(err)) throw err;
25178
- fallbackErrors.push(`Searchinfinity: ${errorMessage26(err)}`);
25385
+ fallbackErrors.push(`Searchinfinity: ${errorMessage27(err)}`);
25179
25386
  }
25180
25387
  }
25181
25388
  if (allowed.has("querit") && isQueritAvailable()) {
@@ -25184,7 +25391,7 @@ async function search(query, options = {}) {
25184
25391
  return { ...result, provider: "querit" };
25185
25392
  } catch (err) {
25186
25393
  if (isAbortError2(err)) throw err;
25187
- fallbackErrors.push(`Querit: ${errorMessage26(err)}`);
25394
+ fallbackErrors.push(`Querit: ${errorMessage27(err)}`);
25188
25395
  }
25189
25396
  }
25190
25397
  if (allowed.has("tavily") && isTavilyAvailable()) {
@@ -25193,7 +25400,7 @@ async function search(query, options = {}) {
25193
25400
  return { ...result, provider: "tavily" };
25194
25401
  } catch (err) {
25195
25402
  if (isAbortError2(err)) throw err;
25196
- fallbackErrors.push(`Tavily: ${errorMessage26(err)}`);
25403
+ fallbackErrors.push(`Tavily: ${errorMessage27(err)}`);
25197
25404
  }
25198
25405
  }
25199
25406
  if (allowed.has("firecrawl") && isFirecrawlAvailable()) {
@@ -25202,7 +25409,7 @@ async function search(query, options = {}) {
25202
25409
  return { ...result, provider: "firecrawl" };
25203
25410
  } catch (err) {
25204
25411
  if (isAbortError2(err)) throw err;
25205
- fallbackErrors.push(`Firecrawl: ${errorMessage26(err)}`);
25412
+ fallbackErrors.push(`Firecrawl: ${errorMessage27(err)}`);
25206
25413
  }
25207
25414
  }
25208
25415
  if (allowed.has("jina") && isJinaSearchAvailable()) {
@@ -25211,7 +25418,7 @@ async function search(query, options = {}) {
25211
25418
  return { ...result, provider: "jina" };
25212
25419
  } catch (err) {
25213
25420
  if (isAbortError2(err)) throw err;
25214
- fallbackErrors.push(`Jina: ${errorMessage26(err)}`);
25421
+ fallbackErrors.push(`Jina: ${errorMessage27(err)}`);
25215
25422
  }
25216
25423
  }
25217
25424
  if (allowed.has("serpdive") && isSerpdiveAvailable()) {
@@ -25220,7 +25427,7 @@ async function search(query, options = {}) {
25220
25427
  return { ...result, provider: "serpdive" };
25221
25428
  } catch (err) {
25222
25429
  if (isAbortError2(err)) throw err;
25223
- fallbackErrors.push(`SERPdive: ${errorMessage26(err)}`);
25430
+ fallbackErrors.push(`SERPdive: ${errorMessage27(err)}`);
25224
25431
  }
25225
25432
  }
25226
25433
  if (allowed.has("kagi") && isKagiAvailable()) {
@@ -25229,7 +25436,7 @@ async function search(query, options = {}) {
25229
25436
  return { ...result, provider: "kagi" };
25230
25437
  } catch (err) {
25231
25438
  if (isAbortError2(err)) throw err;
25232
- fallbackErrors.push(`Kagi: ${errorMessage26(err)}`);
25439
+ fallbackErrors.push(`Kagi: ${errorMessage27(err)}`);
25233
25440
  }
25234
25441
  }
25235
25442
  if (allowed.has("bocha") && isBochaAvailable()) {
@@ -25238,7 +25445,7 @@ async function search(query, options = {}) {
25238
25445
  return { ...result, provider: "bocha" };
25239
25446
  } catch (err) {
25240
25447
  if (isAbortError2(err)) throw err;
25241
- fallbackErrors.push(`Bocha: ${errorMessage26(err)}`);
25448
+ fallbackErrors.push(`Bocha: ${errorMessage27(err)}`);
25242
25449
  }
25243
25450
  }
25244
25451
  if (allowed.has("ollama") && isOllamaAvailable()) {
@@ -25247,7 +25454,7 @@ async function search(query, options = {}) {
25247
25454
  return { ...result, provider: "ollama" };
25248
25455
  } catch (err) {
25249
25456
  if (isAbortError2(err)) throw err;
25250
- fallbackErrors.push(`Ollama: ${errorMessage26(err)}`);
25457
+ fallbackErrors.push(`Ollama: ${errorMessage27(err)}`);
25251
25458
  }
25252
25459
  }
25253
25460
  if (allowed.has("perplexity") && isPerplexityAvailable()) {
@@ -25256,7 +25463,7 @@ async function search(query, options = {}) {
25256
25463
  return { ...result, provider: "perplexity" };
25257
25464
  } catch (err) {
25258
25465
  if (isAbortError2(err)) throw err;
25259
- fallbackErrors.push(`Perplexity: ${errorMessage26(err)}`);
25466
+ fallbackErrors.push(`Perplexity: ${errorMessage27(err)}`);
25260
25467
  }
25261
25468
  }
25262
25469
  if (allowed.has("gemini")) try {
@@ -25264,7 +25471,7 @@ async function search(query, options = {}) {
25264
25471
  if (geminiResult) return { ...geminiResult, provider: "gemini" };
25265
25472
  } catch (err) {
25266
25473
  if (isAbortError2(err)) throw err;
25267
- fallbackErrors.push(`Gemini: ${errorMessage26(err)}`);
25474
+ fallbackErrors.push(`Gemini: ${errorMessage27(err)}`);
25268
25475
  }
25269
25476
  if (fallbackErrors.length > 0) {
25270
25477
  throw new Error(`Auto provider search failed:
@@ -25273,11 +25480,11 @@ async function search(query, options = {}) {
25273
25480
  throw new Error(
25274
25481
  `No search provider available. Either:
25275
25482
  1. Use /login to sign in with a Codex subscription for OpenAI web search
25276
- 2. Set openaiApiKey, braveApiKey, parallelApiKey, tinyfishApiKey, search1apiApiKey, searchinfinityApiKey, queritApiKey, tavilyApiKey, firecrawlBaseUrl, jinaApiKey, serpdiveApiKey, kagiApiKey, ollamaApiKey, searxngBaseUrl, perplexityApiKey, exaApiKey, geminiApiKey, bochaApiKey, or cloudflareApiKey in ${CONFIG_PATH37}
25483
+ 2. Set openaiApiKey, braveApiKey, parallelApiKey, tinyfishApiKey, search1apiApiKey, searchinfinityApiKey, queritApiKey, tavilyApiKey, firecrawlBaseUrl, jinaApiKey, serpdiveApiKey, kagiApiKey, ollamaApiKey, searxngBaseUrl, perplexityApiKey, exaApiKey, geminiApiKey, bochaApiKey, or cloudflareApiKey in ${CONFIG_PATH38}
25277
25484
  3. Set OPENAI_API_KEY, BRAVE_API_KEY, PARALLEL_API_KEY, TINYFISH_API_KEY, SEARCH1API_KEY, SEARCHINFINITY_API_KEY, QUERIT_API_KEY, TAVILY_API_KEY, FIRECRAWL_BASE_URL, JINA_API_KEY, SERPDIVE_API_KEY, KAGI_API_KEY, BOCHA_API_KEY, OLLAMA_API_KEY, SEARXNG_BASE_URL, EXA_API_KEY, PERPLEXITY_API_KEY, GEMINI_API_KEY, or CLOUDFLARE_API_KEY env vars
25278
25485
  4. Set GOOGLE_GEMINI_BASE_URL with CLOUDFLARE_API_KEY for Cloudflare AI Gateway routing
25279
25486
  5. Sign into gemini.google.com in a supported Chromium-based browser
25280
- 6. Explicitly select provider: "anysearch" for anonymous AnySearch, "xcrawl" for XCrawl, "xai" for Grok, "mistral" for Mistral Conversations web search, "brightdata" with brightdataSerpZone for paid Bright Data SERP, "serpbase", "serpapi", "serper", or "serply" for Google SERP, "you" for You.com, "zai" for Z.ai GLM Coding Plan search, "valyu" for research search, or "keenable" for keyless Keenable search`
25487
+ 6. Explicitly select provider: "anysearch" for anonymous AnySearch, "xcrawl" for XCrawl, "xai" for Grok, "mistral" for Mistral Conversations web search, "brightdata" with brightdataSerpZone for paid Bright Data SERP, "serpbase", "serpapi", "serper", or "serply" for Google SERP, "you" for You.com, "zai" for Z.ai GLM Coding Plan search, "valyu" for research search, "keenable" for keyless Keenable search, or "ceramic" for Ceramic search`
25281
25488
  );
25282
25489
  }
25283
25490
  async function searchWithGeminiApi(query, options = {}) {
@@ -25327,13 +25534,13 @@ async function searchWithGeminiWeb(query, options = {}) {
25327
25534
  const prompt = buildSearchPrompt2(query, options);
25328
25535
  const activityId = activityMonitor.logStart({ type: "api", query });
25329
25536
  try {
25330
- const text3 = await queryWithCookies(prompt, cookies, {
25537
+ const text4 = await queryWithCookies(prompt, cookies, {
25331
25538
  signal: options.signal,
25332
25539
  timeoutMs: 12e4
25333
25540
  });
25334
25541
  activityMonitor.logComplete(activityId, 200);
25335
- const results = extractSourceUrls(text3);
25336
- return { answer: text3, results };
25542
+ const results = extractSourceUrls(text4);
25543
+ return { answer: text4, results };
25337
25544
  } catch (err) {
25338
25545
  const message = err instanceof Error ? err.message : String(err);
25339
25546
  if (message.toLowerCase().includes("abort")) {
@@ -25514,8 +25721,8 @@ var TOOL_RUNNERS = {
25514
25721
  get_search_content: (core2, args, signal) => core2.getSearchContent(args, signal),
25515
25722
  source_check: (core2, args, signal) => core2.sourceCheck(args, signal)
25516
25723
  };
25517
- function errorResult(text3) {
25518
- return { content: [{ type: "text", text: text3 }], isError: true };
25724
+ function errorResult(text4) {
25725
+ return { content: [{ type: "text", text: text4 }], isError: true };
25519
25726
  }
25520
25727
  function toCallToolResult(result) {
25521
25728
  return { content: result.content, ...result.isError && { isError: true } };
@@ -25550,7 +25757,7 @@ function createMcpServer(core2, info, enabledTools) {
25550
25757
  }
25551
25758
 
25552
25759
  // web-tool-core.ts
25553
- import { existsSync as existsSync51, readFileSync as readFileSync53 } from "node:fs";
25760
+ import { existsSync as existsSync52, readFileSync as readFileSync54 } from "node:fs";
25554
25761
  import pLimit2 from "p-limit";
25555
25762
 
25556
25763
  // fetch-params.ts
@@ -25654,8 +25861,8 @@ function editDistanceWithin(left, right, maximum) {
25654
25861
  }
25655
25862
  return previous[right.length] <= maximum;
25656
25863
  }
25657
- function literalMatches(text3, query, caseInsensitive) {
25658
- const haystack = caseInsensitive ? text3.toLocaleLowerCase() : text3;
25864
+ function literalMatches(text4, query, caseInsensitive) {
25865
+ const haystack = caseInsensitive ? text4.toLocaleLowerCase() : text4;
25659
25866
  const needle = caseInsensitive ? query.toLocaleLowerCase() : query;
25660
25867
  const matches = [];
25661
25868
  for (let start = haystack.indexOf(needle); start >= 0; start = haystack.indexOf(needle, start + Math.max(needle.length, 1))) {
@@ -25663,12 +25870,12 @@ function literalMatches(text3, query, caseInsensitive) {
25663
25870
  }
25664
25871
  return matches;
25665
25872
  }
25666
- function fuzzyMatches(text3, query) {
25873
+ function fuzzyMatches(text4, query) {
25667
25874
  const queryTokens = normalize2(query).match(/[\p{L}\p{N}]+/gu) ?? [];
25668
25875
  if (queryTokens.length === 0) return [];
25669
25876
  const matches = [];
25670
25877
  const paragraphs = /[^\n]+(?:\n(?!\n)[^\n]+)*/g;
25671
- for (const paragraph of text3.matchAll(paragraphs)) {
25878
+ for (const paragraph of text4.matchAll(paragraphs)) {
25672
25879
  const paragraphText = paragraph[0];
25673
25880
  if (paragraphText.trim().length === 0 || paragraph.index === void 0) continue;
25674
25881
  const tokens = [...paragraphText.matchAll(/[\p{L}\p{N}]+/gu)];
@@ -25727,10 +25934,10 @@ function upperBound(values, target) {
25727
25934
  }
25728
25935
  return low;
25729
25936
  }
25730
- function findContent(text3, queries, mode) {
25937
+ function findContent(text4, queries, mode) {
25731
25938
  const normalizedQueries = [...new Set(queries.map((query) => query.trim()).filter(Boolean))];
25732
25939
  const occurrences = normalizedQueries.map((query) => {
25733
- const matches2 = mode === "fuzzy" ? fuzzyMatches(text3, query) : literalMatches(text3, query, mode === "case-insensitive");
25940
+ const matches2 = mode === "fuzzy" ? fuzzyMatches(text4, query) : literalMatches(text4, query, mode === "case-insensitive");
25734
25941
  return { query, matches: matches2, starts: matches2.map((match) => match.start), ends: matches2.map((match) => match.end) };
25735
25942
  });
25736
25943
  const matches = occurrences.flatMap((result) => result.matches);
@@ -25742,7 +25949,7 @@ function findContent(text3, queries, mode) {
25742
25949
  id: `Q${index + 1}`,
25743
25950
  order: index
25744
25951
  }));
25745
- const whitespaceRuns = [...text3.matchAll(/\s+/g)].map((run) => ({ start: run.index, end: run.index + run[0].length }));
25952
+ const whitespaceRuns = [...text4.matchAll(/\s+/g)].map((run) => ({ start: run.index, end: run.index + run[0].length }));
25746
25953
  const whitespaceStarts = whitespaceRuns.map((run) => run.start);
25747
25954
  const whitespaceEnds = whitespaceRuns.map((run) => run.end);
25748
25955
  const whitespaceSavings = [0];
@@ -25775,7 +25982,7 @@ function findContent(text3, queries, mode) {
25775
25982
  const counts = rangeCounts(range);
25776
25983
  if (counts.length === 0) continue;
25777
25984
  const labelsLength = counts.reduce((total, result) => total + (overflow ? result.id.length : result.query.length + 2) + 2 + String(result.count).length, 2 * (counts.length - 1));
25778
- const snippetLength = normalizedLength(range.start, range.end) + (range.start > 0 ? 1 : 0) + (range.end < text3.length ? 1 : 0);
25985
+ const snippetLength = normalizedLength(range.start, range.end) + (range.start > 0 ? 1 : 0) + (range.end < text4.length ? 1 : 0);
25779
25986
  length += 2 + String(index + 1).length + 2 + labelsLength + 1 + snippetLength;
25780
25987
  returnedMatches += counts.reduce((total, result) => total + result.count, 0);
25781
25988
  }
@@ -25792,8 +25999,8 @@ function findContent(text3, queries, mode) {
25792
25999
  const contained = rangeCounts(range);
25793
26000
  if (contained.length === 0) continue;
25794
26001
  const prefix = range.start > 0 ? "\u2026" : "";
25795
- const suffix = range.end < text3.length ? "\u2026" : "";
25796
- const snippet = `${prefix}${text3.slice(range.start, range.end).replace(/\s+/g, " ").trim()}${suffix}`;
26002
+ const suffix = range.end < text4.length ? "\u2026" : "";
26003
+ const snippet = `${prefix}${text4.slice(range.start, range.end).replace(/\s+/g, " ").trim()}${suffix}`;
25797
26004
  const counts = contained.map((result) => `${overflow ? result.id : `"${result.query}"`} \xD7${result.count}`).join(", ");
25798
26005
  sections.push(`${index + 1}. ${counts}
25799
26006
  ${snippet}`);
@@ -25804,18 +26011,18 @@ ${snippet}`);
25804
26011
  if (returnedMatches < matches.length) sections.push(`Showing ${returnedMatches} of ${matches.length} matches.`);
25805
26012
  return { text: sections.join("\n\n"), matchCount: matches.length, returnedMatches, queryResults };
25806
26013
  }
25807
- const fullRanges = contextRanges(text3.length, matches);
26014
+ const fullRanges = contextRanges(text4.length, matches);
25808
26015
  const full = measure(fullRanges);
25809
26016
  if (full.returnedMatches === matches.length && full.length <= MAX_OUTPUT_CHARS) return formatRanges(fullRanges);
25810
26017
  let ranges = [];
25811
26018
  let omitted = matchingQueries.map((result) => result.id);
25812
26019
  if (measure(ranges, true, omitted).length > MAX_OUTPUT_CHARS) {
25813
- const text4 = `${heading}
26020
+ const text5 = `${heading}
25814
26021
 
25815
26022
  Unable to format bounded excerpts: query metadata exceeds ${MAX_OUTPUT_CHARS} characters.
25816
26023
 
25817
26024
  Showing 0 of ${matches.length} matches.`;
25818
- return { text: text4, matchCount: matches.length, returnedMatches: 0, queryResults };
26025
+ return { text: text5, matchCount: matches.length, returnedMatches: 0, queryResults };
25819
26026
  }
25820
26027
  const witnesses = [];
25821
26028
  for (const { id, matches: queryMatches } of matchingQueries) {
@@ -25841,7 +26048,7 @@ Showing 0 of ${matches.length} matches.`;
25841
26048
  for (const witness of witnesses) {
25842
26049
  const proposed = mergeRanges([...ranges, {
25843
26050
  start: Math.max(0, witness.start - CONTEXT_CHARS),
25844
- end: Math.min(text3.length, witness.end + CONTEXT_CHARS)
26051
+ end: Math.min(text4.length, witness.end + CONTEXT_CHARS)
25845
26052
  }]);
25846
26053
  if (measure(proposed, true, omitted).length <= MAX_OUTPUT_CHARS) ranges = proposed;
25847
26054
  }
@@ -25854,7 +26061,7 @@ Showing 0 of ${matches.length} matches.`;
25854
26061
  init_utils();
25855
26062
 
25856
26063
  // storage.ts
25857
- import { closeSync, constants, fchmodSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync as readFileSync42, readdirSync as readdirSync2, renameSync, unlinkSync, writeFileSync } from "node:fs";
26064
+ import { closeSync, constants, fchmodSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync as readFileSync43, readdirSync as readdirSync2, renameSync, unlinkSync, writeFileSync } from "node:fs";
25858
26065
  init_utils();
25859
26066
  import { join as join4 } from "node:path";
25860
26067
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -25866,6 +26073,7 @@ var DEFAULT_CACHE_LIMITS = { maxEntries: 128, maxBytes: 128 * 1024 * 1024 };
25866
26073
  var O_DIRECTORY = process.platform === "win32" ? 0 : constants.O_DIRECTORY ?? 0;
25867
26074
  var O_NOFOLLOW = process.platform === "win32" ? 0 : constants.O_NOFOLLOW ?? 0;
25868
26075
  var storedResults = /* @__PURE__ */ new Map();
26076
+ var resultHolders = /* @__PURE__ */ new Map();
25869
26077
  function generateId() {
25870
26078
  return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
25871
26079
  }
@@ -26014,7 +26222,7 @@ function readCachedFetchData(data) {
26014
26222
  const opened = openRegularFile(path);
26015
26223
  fd = opened.fd;
26016
26224
  enforceMode(fd, 384);
26017
- const parsed = JSON.parse(readFileSync42(fd, "utf8"));
26225
+ const parsed = JSON.parse(readFileSync43(fd, "utf8"));
26018
26226
  if (!isValidStoredData(parsed) || parsed.type !== "fetch" || parsed.id !== data.id || !isInlineFetchData(parsed)) {
26019
26227
  return unavailableFetchData(data, "Cached fetched content is invalid");
26020
26228
  }
@@ -26057,6 +26265,7 @@ function deleteResult(id) {
26057
26265
  } catch {
26058
26266
  }
26059
26267
  }
26268
+ resultHolders.delete(id);
26060
26269
  return storedResults.delete(id);
26061
26270
  }
26062
26271
  function isValidStoredData(data) {
@@ -26105,8 +26314,8 @@ function classifySource(url) {
26105
26314
  if (BLOG_HOSTS.test(host) || BLOG_PATHS.test(path)) return "blog";
26106
26315
  return "unknown";
26107
26316
  }
26108
- function hashContent(text3) {
26109
- return `sha256:${createHash("sha256").update(text3, "utf8").digest("hex")}`;
26317
+ function hashContent(text4) {
26318
+ return `sha256:${createHash("sha256").update(text4, "utf8").digest("hex")}`;
26110
26319
  }
26111
26320
  function tokenize(value) {
26112
26321
  return [...new Set(value.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 3))];
@@ -26116,10 +26325,10 @@ function extractRelevantSpans(content, hint) {
26116
26325
  const sentencePattern = /[^.!?]+(?:[.!?]+(?=\s|$)|$)/g;
26117
26326
  for (const match of content.matchAll(sentencePattern)) {
26118
26327
  const raw = match[0];
26119
- const text3 = raw.trim();
26120
- if (text3.length > 0 && text3.length <= 400) {
26121
- const start = (match.index ?? 0) + raw.indexOf(text3);
26122
- sentences.push({ text: text3, start, end: start + text3.length });
26328
+ const text4 = raw.trim();
26329
+ if (text4.length > 0 && text4.length <= 400) {
26330
+ const start = (match.index ?? 0) + raw.indexOf(text4);
26331
+ sentences.push({ text: text4, start, end: start + text4.length });
26123
26332
  }
26124
26333
  }
26125
26334
  const terms = tokenize(hint);
@@ -26242,9 +26451,9 @@ function parseConfigRoot(raw) {
26242
26451
  }
26243
26452
  return parsed;
26244
26453
  }
26245
- function loadConfig39() {
26246
- if (!existsSync51(WEB_SEARCH_CONFIG_PATH4)) return {};
26247
- return parseConfigRoot(readFileSync53(WEB_SEARCH_CONFIG_PATH4, "utf-8"));
26454
+ function loadConfig40() {
26455
+ if (!existsSync52(WEB_SEARCH_CONFIG_PATH4)) return {};
26456
+ return parseConfigRoot(readFileSync54(WEB_SEARCH_CONFIG_PATH4, "utf-8"));
26248
26457
  }
26249
26458
  var DEFAULT_TOOL_NAMES = {
26250
26459
  webSearch: "web_search",
@@ -26295,7 +26504,7 @@ function resolveRequestedProvider(requested) {
26295
26504
  assertSearchProviderSelectionAllowed(normalizedRequested, "Requested provider");
26296
26505
  return normalizedRequested;
26297
26506
  }
26298
- const config = loadConfig39();
26507
+ const config = loadConfig40();
26299
26508
  const provider = normalizeProviderInput(config.searchProvider ?? config.provider, `provider in ${WEB_SEARCH_CONFIG_PATH4}`) ?? "auto";
26300
26509
  assertSearchProviderSelectionAllowed(provider, `configured provider in ${WEB_SEARCH_CONFIG_PATH4}`);
26301
26510
  return provider;
@@ -26358,7 +26567,7 @@ function isAbortError6(err) {
26358
26567
  var DEFAULT_MAX_INLINE_CONTENT_CHARS = 3e4;
26359
26568
  var MIN_INLINE_CONTENT_CHARS = 1e3;
26360
26569
  var MAX_INLINE_CONTENT_CHARS = 2e5;
26361
- function getMaxInlineContentChars(config = loadConfig39()) {
26570
+ function getMaxInlineContentChars(config = loadConfig40()) {
26362
26571
  const value = config.maxInlineContentChars;
26363
26572
  if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < MIN_INLINE_CONTENT_CHARS) {
26364
26573
  return DEFAULT_MAX_INLINE_CONTENT_CHARS;
@@ -26394,14 +26603,14 @@ function initialContentSlice(content, maxChars) {
26394
26603
  const lineBreak = content.lastIndexOf("\n", endOffset);
26395
26604
  if (lineBreak >= Math.floor(maxChars * 0.8)) endOffset = lineBreak + 1;
26396
26605
  }
26397
- const text3 = content.slice(0, endOffset);
26606
+ const text4 = content.slice(0, endOffset);
26398
26607
  return {
26399
- text: text3,
26608
+ text: text4,
26400
26609
  endOffset,
26401
26610
  totalBytes: Buffer.byteLength(content),
26402
26611
  totalLines: content.length === 0 ? 0 : content.split("\n").length,
26403
- shownBytes: Buffer.byteLength(text3),
26404
- shownLines: text3.length === 0 ? 0 : text3.split("\n").length
26612
+ shownBytes: Buffer.byteLength(text4),
26613
+ shownLines: text4.length === 0 ? 0 : text4.split("\n").length
26405
26614
  };
26406
26615
  }
26407
26616
  function normalizeFindQueries(value) {
@@ -26520,23 +26729,23 @@ ${r.snippet}` : ""}
26520
26729
  }
26521
26730
  return output;
26522
26731
  }
26523
- function boundSearchPresentation(text3, guidance, truncationGuidance, maxChars) {
26524
- const fullText = `${text3}${guidance}`;
26732
+ function boundSearchPresentation(text4, guidance, truncationGuidance, maxChars) {
26733
+ const fullText = `${text4}${guidance}`;
26525
26734
  if (fullText.length <= maxChars) {
26526
- return { text: fullText, truncated: false, originalChars: text3.length, returnedChars: text3.length, omittedChars: 0 };
26735
+ return { text: fullText, truncated: false, originalChars: text4.length, returnedChars: text4.length, omittedChars: 0 };
26527
26736
  }
26528
26737
  const marker = `
26529
26738
 
26530
26739
  ---
26531
26740
  [Output truncated.]${truncationGuidance}`;
26532
26741
  const prefixLength = maxChars - marker.length;
26533
- const bounded = `${text3.slice(0, prefixLength)}${marker}`;
26742
+ const bounded = `${text4.slice(0, prefixLength)}${marker}`;
26534
26743
  return {
26535
26744
  text: bounded,
26536
26745
  truncated: true,
26537
- originalChars: text3.length,
26746
+ originalChars: text4.length,
26538
26747
  returnedChars: prefixLength,
26539
- omittedChars: text3.length - prefixLength
26748
+ omittedChars: text4.length - prefixLength
26540
26749
  };
26541
26750
  }
26542
26751
  function registeredFetchToolNames(settings2) {
@@ -27064,9 +27273,9 @@ Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 })
27064
27273
  if (params.findText !== void 0) {
27065
27274
  try {
27066
27275
  const found = findContent(serialized, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
27067
- const { text: text4, ...findDetails } = found;
27276
+ const { text: text5, ...findDetails } = found;
27068
27277
  return {
27069
- content: [{ type: "text", text: text4 }],
27278
+ content: [{ type: "text", text: text5 }],
27070
27279
  details: { responseId: artifact.id, type: "research", contentLength: serialized.length, findMode: params.findMode ?? "case-insensitive", ...findDetails }
27071
27280
  };
27072
27281
  } catch (err) {
@@ -27097,13 +27306,13 @@ Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 })
27097
27306
  details: { error: "Offset out of range", offset, contentLength: serialized.length }
27098
27307
  };
27099
27308
  }
27100
- const { endOffset, text: text3 } = sliceWithContinuation(serialized, offset, limit, maxInlineContentChars, (end) => `
27309
+ const { endOffset, text: text4 } = sliceWithContinuation(serialized, offset, limit, maxInlineContentChars, (end) => `
27101
27310
 
27102
27311
  ---
27103
27312
  Showing chars ${offset}-${end} of ${serialized.length}. Use ${toolNames.getSearchContent}({ responseId: "${artifact.id}", offset: ${end}, limit: ${limit} }) for the next slice.`);
27104
27313
  const hasMore = endOffset < serialized.length;
27105
27314
  return {
27106
- content: [{ type: "text", text: text3 }],
27315
+ content: [{ type: "text", text: text4 }],
27107
27316
  details: { responseId: artifact.id, type: "research", contentLength: serialized.length, offset, limit, returnedChars: endOffset - offset, nextOffset: hasMore ? endOffset : null, truncated: hasMore }
27108
27317
  };
27109
27318
  }
@@ -27144,9 +27353,9 @@ Showing chars ${offset}-${end} of ${serialized.length}. Use ${toolNames.getSearc
27144
27353
  if (params.findText !== void 0) {
27145
27354
  try {
27146
27355
  const found = findContent(fullResults, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
27147
- const { text: text4, ...findDetails } = found;
27356
+ const { text: text5, ...findDetails } = found;
27148
27357
  return {
27149
- content: [{ type: "text", text: text4 }],
27358
+ content: [{ type: "text", text: text5 }],
27150
27359
  details: { responseId: params.responseId, query: queryData.query, resultCount: queryData.results.length, contentLength: fullResults.length, findMode: params.findMode ?? "case-insensitive", ...findDetails }
27151
27360
  };
27152
27361
  } catch (err) {
@@ -27178,14 +27387,14 @@ Showing chars ${offset}-${end} of ${serialized.length}. Use ${toolNames.getSearc
27178
27387
  };
27179
27388
  }
27180
27389
  const queryIndex = data.queries.indexOf(queryData);
27181
- const { endOffset, text: text3 } = sliceWithContinuation(fullResults, offset, limit, maxInlineContentChars, (end) => `
27390
+ const { endOffset, text: text4 } = sliceWithContinuation(fullResults, offset, limit, maxInlineContentChars, (end) => `
27182
27391
 
27183
27392
  ---
27184
27393
  Showing chars ${offset}-${end} of ${fullResults.length}. Use ${toolNames.getSearchContent}({ responseId: "${params.responseId}", queryIndex: ${queryIndex}, offset: ${end}, limit: ${limit} }) for the next slice.`);
27185
27394
  const returnedChars = endOffset - offset;
27186
27395
  const hasMore = endOffset < fullResults.length;
27187
27396
  return {
27188
- content: [{ type: "text", text: text3 }],
27397
+ content: [{ type: "text", text: text4 }],
27189
27398
  details: {
27190
27399
  responseId: params.responseId,
27191
27400
  query: queryData.query,
@@ -27246,11 +27455,11 @@ Use one of the available indexes.` }],
27246
27455
  if (params.findText !== void 0) {
27247
27456
  try {
27248
27457
  const found = findContent(urlData.content, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
27249
- const { text: text4, ...findDetails } = found;
27458
+ const { text: text5, ...findDetails } = found;
27250
27459
  return {
27251
27460
  content: [{ type: "text", text: `# ${urlData.title || urlData.url}
27252
27461
 
27253
- ${text4}` }],
27462
+ ${text5}` }],
27254
27463
  details: { url: urlData.url, title: urlData.title, contentLength: urlData.content.length, findMode: params.findMode ?? "case-insensitive", ...findDetails }
27255
27464
  };
27256
27465
  } catch (err) {
@@ -27284,20 +27493,20 @@ ${text4}` }],
27284
27493
  const endOffset = Math.min(offset + limit, urlData.content.length);
27285
27494
  const contentSlice = urlData.content.slice(offset, endOffset);
27286
27495
  const hasMore = endOffset < urlData.content.length;
27287
- let text3 = `# ${urlData.title || urlData.url}
27496
+ let text4 = `# ${urlData.title || urlData.url}
27288
27497
 
27289
27498
  ${contentSlice}`;
27290
27499
  if (hasMore || offset > 0) {
27291
- text3 += `
27500
+ text4 += `
27292
27501
 
27293
27502
  ---
27294
27503
  Showing chars ${offset}-${endOffset} of ${urlData.content.length}.`;
27295
27504
  if (hasMore) {
27296
- text3 += ` Use ${toolNames.getSearchContent}({ responseId: "${params.responseId}", urlIndex: ${selectedUrlIndex}, offset: ${endOffset}, limit: ${limit} }) for the next slice.`;
27505
+ text4 += ` Use ${toolNames.getSearchContent}({ responseId: "${params.responseId}", urlIndex: ${selectedUrlIndex}, offset: ${endOffset}, limit: ${limit} }) for the next slice.`;
27297
27506
  }
27298
27507
  }
27299
27508
  return {
27300
- content: [{ type: "text", text: text3 }],
27509
+ content: [{ type: "text", text: text4 }],
27301
27510
  details: {
27302
27511
  url: urlData.url,
27303
27512
  title: urlData.title,
@@ -27367,7 +27576,7 @@ function standaloneFetchRejection(params, fetchModes) {
27367
27576
  return void 0;
27368
27577
  }
27369
27578
  function createStandaloneWebToolCore() {
27370
- const config = loadConfig39();
27579
+ const config = loadConfig40();
27371
27580
  const settings2 = {
27372
27581
  toolNames: { ...DEFAULT_TOOL_NAMES },
27373
27582
  enabledTools: {