@herbertgao/pi-extensions 2026.10.0 → 2026.10.2

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 (769) hide show
  1. package/README.md +16 -12
  2. package/THIRD_PARTY_NOTICES.md +3 -3
  3. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +2 -2
  4. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +2 -2
  5. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
  6. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +1 -1
  7. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +2 -2
  8. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
  9. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/index.js +4 -0
  10. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +43 -3
  11. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +142 -59
  12. package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +21 -21
  13. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
  14. package/node_modules/@dietrichgebert/ponytail/AGENTS.md +21 -21
  15. package/node_modules/@dietrichgebert/ponytail/README.md +52 -242
  16. package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +3 -3
  17. package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +4 -4
  18. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +70 -16
  19. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +8 -7
  20. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +30 -30
  21. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-map.js +103 -0
  22. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +46 -23
  23. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +39 -7
  24. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +20 -3
  25. package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +3 -3
  26. package/node_modules/@dietrichgebert/ponytail/package.json +3 -3
  27. package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +47 -17
  28. package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +21 -7
  29. package/node_modules/@dietrichgebert/ponytail/skills/plugin.json +5 -0
  30. package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +33 -101
  31. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +89 -27
  32. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +13 -12
  33. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +21 -18
  34. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +12 -13
  35. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +96 -52
  36. package/node_modules/@herbertgao/pi-agency/LICENSE +21 -0
  37. package/node_modules/@herbertgao/pi-agency/README.md +40 -0
  38. package/node_modules/@herbertgao/pi-agency/package.json +53 -0
  39. package/node_modules/@herbertgao/pi-agency/src/index.ts +441 -0
  40. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +12 -12
  41. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +30 -6
  42. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +15 -9
  43. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +27 -9
  44. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +4 -1
  45. package/node_modules/@herbertgao/pi-cc-extensions/package.json +2 -2
  46. package/node_modules/@narumitw/pi-caffeinate/package.json +4 -4
  47. package/node_modules/@tifan/pi-mermaid-open/package.json +5 -1
  48. package/node_modules/@tifan/pi-mermaid-open/src/index.ts +26 -9
  49. package/node_modules/@tifan/pi-recap/package.json +1 -1
  50. package/node_modules/@tifan/pi-recap/src/index.ts +104 -20
  51. package/node_modules/@tifan/pi-recap/src/models.ts +46 -4
  52. package/node_modules/pi-antigravity/README.md +23 -2
  53. package/node_modules/pi-antigravity/package.json +5 -3
  54. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +3 -2
  55. package/node_modules/pi-antigravity/src/features/generate-image.ts +72 -0
  56. package/node_modules/pi-antigravity/src/features/google-search.ts +71 -0
  57. package/node_modules/pi-antigravity/src/image/image.ts +86 -47
  58. package/node_modules/pi-antigravity/src/image/native.ts +69 -0
  59. package/node_modules/pi-antigravity/src/index.ts +52 -137
  60. package/node_modules/pi-antigravity/src/search/search.ts +130 -31
  61. package/node_modules/pi-antigravity/src/stream/stream.ts +162 -113
  62. package/node_modules/pi-antigravity/src/types/enums.ts +1 -0
  63. package/node_modules/pi-antigravity/src/types/types.ts +1 -1
  64. package/node_modules/pi-antigravity/src/utils/security.ts +47 -1
  65. package/node_modules/pi-antigravity/src/utils/util.ts +38 -6
  66. package/node_modules/pi-lens/CHANGELOG.md +1064 -0
  67. package/node_modules/pi-lens/README.md +115 -25
  68. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +6 -2
  69. package/node_modules/pi-lens/dist/chunk-22AVIGXS.js +560 -0
  70. package/node_modules/pi-lens/dist/chunk-27BBHSZC.js +106 -0
  71. package/node_modules/pi-lens/dist/chunk-2BEMIWEW.js +51 -0
  72. package/node_modules/pi-lens/dist/chunk-2EECBNC5.js +89 -0
  73. package/node_modules/pi-lens/dist/chunk-34U7PLGE.js +23 -0
  74. package/node_modules/pi-lens/dist/chunk-3I5QFT3N.js +181 -0
  75. package/node_modules/pi-lens/dist/chunk-3MED75HT.js +37 -0
  76. package/node_modules/pi-lens/dist/chunk-47D2BO4S.js +87 -0
  77. package/node_modules/pi-lens/dist/chunk-4RERDEXR.js +348 -0
  78. package/node_modules/pi-lens/dist/chunk-4W2PLC4J.js +27 -0
  79. package/node_modules/pi-lens/dist/chunk-52H5B5TC.js +202 -0
  80. package/node_modules/pi-lens/dist/chunk-54B42YRX.js +27 -0
  81. package/node_modules/pi-lens/dist/chunk-5RXBNSW2.js +266 -0
  82. package/node_modules/pi-lens/dist/chunk-5THXD6X5.js +201 -0
  83. package/node_modules/pi-lens/dist/chunk-5W3R6LFT.js +24 -0
  84. package/node_modules/pi-lens/dist/chunk-5ZEJHV35.js +341 -0
  85. package/node_modules/pi-lens/dist/chunk-6P62QVEA.js +118 -0
  86. package/node_modules/pi-lens/dist/chunk-6QIUX4EP.js +459 -0
  87. package/node_modules/pi-lens/dist/chunk-6VCD4VKZ.js +78 -0
  88. package/node_modules/pi-lens/dist/chunk-7F72PXY2.js +326 -0
  89. package/node_modules/pi-lens/dist/chunk-7FBF7NPR.js +998 -0
  90. package/node_modules/pi-lens/dist/chunk-7U2IDNXN.js +37 -0
  91. package/node_modules/pi-lens/dist/chunk-ABBOA7UD.js +157 -0
  92. package/node_modules/pi-lens/dist/chunk-AHDW3GPE.js +50 -0
  93. package/node_modules/pi-lens/dist/chunk-AJ3QXTRQ.js +756 -0
  94. package/node_modules/pi-lens/dist/chunk-AJVLWNFN.js +1610 -0
  95. package/node_modules/pi-lens/dist/chunk-AJXODZY6.js +112 -0
  96. package/node_modules/pi-lens/dist/chunk-ARFCXG7S.js +84 -0
  97. package/node_modules/pi-lens/dist/chunk-AS44CFQ4.js +708 -0
  98. package/node_modules/pi-lens/dist/chunk-AWE5TMPO.js +38 -0
  99. package/node_modules/pi-lens/dist/chunk-B3I2UUT4.js +4692 -0
  100. package/node_modules/pi-lens/dist/chunk-BRJKOBZP.js +331 -0
  101. package/node_modules/pi-lens/dist/chunk-BW5KFIQC.js +59 -0
  102. package/node_modules/pi-lens/dist/chunk-C2AUYXQH.js +149 -0
  103. package/node_modules/pi-lens/dist/chunk-CGGAIP7J.js +29 -0
  104. package/node_modules/pi-lens/dist/chunk-D6QS3U6M.js +30 -0
  105. package/node_modules/pi-lens/dist/chunk-DFVMIKMQ.js +349 -0
  106. package/node_modules/pi-lens/dist/chunk-DIULIWKU.js +169 -0
  107. package/node_modules/pi-lens/dist/chunk-DQ2NZ7C4.js +2317 -0
  108. package/node_modules/pi-lens/dist/chunk-E2WFBRHM.js +213 -0
  109. package/node_modules/pi-lens/dist/chunk-E4MAEDPM.js +50 -0
  110. package/node_modules/pi-lens/dist/chunk-EOKRQ3SA.js +30 -0
  111. package/node_modules/pi-lens/dist/chunk-F3AU2TMM.js +2626 -0
  112. package/node_modules/pi-lens/dist/chunk-F3P7VQ7H.js +170 -0
  113. package/node_modules/pi-lens/dist/chunk-FC4RP4I2.js +12 -0
  114. package/node_modules/pi-lens/dist/chunk-FJNKANOS.js +32 -0
  115. package/node_modules/pi-lens/dist/chunk-GUOGVTCQ.js +146 -0
  116. package/node_modules/pi-lens/dist/chunk-GVXA6CCE.js +18 -0
  117. package/node_modules/pi-lens/dist/chunk-HHYAELLJ.js +2334 -0
  118. package/node_modules/pi-lens/dist/chunk-HMFXILPV.js +83 -0
  119. package/node_modules/pi-lens/dist/chunk-HVUZXSWK.js +421 -0
  120. package/node_modules/pi-lens/dist/chunk-HWBZIGMJ.js +62 -0
  121. package/node_modules/pi-lens/dist/chunk-I3R7GKDR.js +17 -0
  122. package/node_modules/pi-lens/dist/chunk-I7SPGOWI.js +55 -0
  123. package/node_modules/pi-lens/dist/chunk-IIXOAGHR.js +38 -0
  124. package/node_modules/pi-lens/dist/chunk-IVP5KAB7.js +2250 -0
  125. package/node_modules/pi-lens/dist/chunk-IXEBJSUE.js +22 -0
  126. package/node_modules/pi-lens/dist/chunk-JOLITGCC.js +27 -0
  127. package/node_modules/pi-lens/dist/chunk-K6VYLB2U.js +145 -0
  128. package/node_modules/pi-lens/dist/chunk-LJDODBBZ.js +78 -0
  129. package/node_modules/pi-lens/dist/chunk-LNAKEO63.js +78 -0
  130. package/node_modules/pi-lens/dist/chunk-LSMJ6KBE.js +4139 -0
  131. package/node_modules/pi-lens/dist/chunk-LW6XKDZQ.js +5565 -0
  132. package/node_modules/pi-lens/dist/chunk-N3YQJI6O.js +899 -0
  133. package/node_modules/pi-lens/dist/chunk-NABLC7W3.js +148 -0
  134. package/node_modules/pi-lens/dist/chunk-NKOUFPQF.js +659 -0
  135. package/node_modules/pi-lens/dist/chunk-NL5GLMFI.js +211 -0
  136. package/node_modules/pi-lens/dist/chunk-NMABWBZN.js +327 -0
  137. package/node_modules/pi-lens/dist/chunk-NTHH2J74.js +27 -0
  138. package/node_modules/pi-lens/dist/chunk-NTUJEGDZ.js +59 -0
  139. package/node_modules/pi-lens/dist/chunk-NXL4FFQQ.js +47 -0
  140. package/node_modules/pi-lens/dist/chunk-NXPS2L6U.js +466 -0
  141. package/node_modules/pi-lens/dist/chunk-O5WILGMI.js +42 -0
  142. package/node_modules/pi-lens/dist/chunk-O6TQT6RI.js +48 -0
  143. package/node_modules/pi-lens/dist/chunk-OAXNDZJ7.js +323 -0
  144. package/node_modules/pi-lens/dist/chunk-ODEEOXPH.js +44 -0
  145. package/node_modules/pi-lens/dist/chunk-OQGFCZJ4.js +4533 -0
  146. package/node_modules/pi-lens/dist/chunk-ORTMY4Q4.js +282 -0
  147. package/node_modules/pi-lens/dist/chunk-OS32RNR2.js +442 -0
  148. package/node_modules/pi-lens/dist/chunk-PAK6IDME.js +189 -0
  149. package/node_modules/pi-lens/dist/chunk-PWFHBTSF.js +406 -0
  150. package/node_modules/pi-lens/dist/chunk-Q5U6FMDI.js +2352 -0
  151. package/node_modules/pi-lens/dist/chunk-QOZXJ4NA.js +3364 -0
  152. package/node_modules/pi-lens/dist/chunk-QYF5S6P6.js +45 -0
  153. package/node_modules/pi-lens/dist/chunk-RIISMHKN.js +36 -0
  154. package/node_modules/pi-lens/dist/chunk-RPD4ZSB7.js +25 -0
  155. package/node_modules/pi-lens/dist/chunk-RPD5K5NC.js +79 -0
  156. package/node_modules/pi-lens/dist/chunk-RUOG5D2C.js +262 -0
  157. package/node_modules/pi-lens/dist/chunk-T4ERT73Y.js +599 -0
  158. package/node_modules/pi-lens/dist/chunk-T6D4Q4AQ.js +54 -0
  159. package/node_modules/pi-lens/dist/chunk-TGPXLY2J.js +391 -0
  160. package/node_modules/pi-lens/dist/chunk-TLGFBM3F.js +12116 -0
  161. package/node_modules/pi-lens/dist/chunk-TO6WL3GM.js +88 -0
  162. package/node_modules/pi-lens/dist/chunk-TT22N74J.js +517 -0
  163. package/node_modules/pi-lens/dist/chunk-TVN5N6GY.js +21216 -0
  164. package/node_modules/pi-lens/dist/chunk-U3VGR4VU.js +308 -0
  165. package/node_modules/pi-lens/dist/chunk-UK3CMEAL.js +1250 -0
  166. package/node_modules/pi-lens/dist/chunk-UOPVJQ4N.js +103 -0
  167. package/node_modules/pi-lens/dist/chunk-UXVNL3D7.js +23 -0
  168. package/node_modules/pi-lens/dist/chunk-UY752QSN.js +45 -0
  169. package/node_modules/pi-lens/dist/chunk-V5PXFSZK.js +188 -0
  170. package/node_modules/pi-lens/dist/chunk-V7R425XG.js +398 -0
  171. package/node_modules/pi-lens/dist/chunk-VCSRSYLF.js +81 -0
  172. package/node_modules/pi-lens/dist/chunk-VD4JQCQC.js +162 -0
  173. package/node_modules/pi-lens/dist/chunk-VDBPVIKD.js +62 -0
  174. package/node_modules/pi-lens/dist/chunk-VHQLPIRJ.js +114 -0
  175. package/node_modules/pi-lens/dist/chunk-VN2AXLEX.js +5414 -0
  176. package/node_modules/pi-lens/dist/chunk-VNMT7C64.js +478 -0
  177. package/node_modules/pi-lens/dist/chunk-WONERJTP.js +309 -0
  178. package/node_modules/pi-lens/dist/chunk-XECLWQZN.js +85 -0
  179. package/node_modules/pi-lens/dist/chunk-XIMYZ3JA.js +27 -0
  180. package/node_modules/pi-lens/dist/chunk-XK4CIILI.js +144 -0
  181. package/node_modules/pi-lens/dist/chunk-Y4T27COV.js +562 -0
  182. package/node_modules/pi-lens/dist/chunk-YGVYKNSN.js +1860 -0
  183. package/node_modules/pi-lens/dist/chunk-YLF3PPT5.js +308 -0
  184. package/node_modules/pi-lens/dist/chunk-YSNFMJKN.js +14 -0
  185. package/node_modules/pi-lens/dist/chunk-Z3CCVDUB.js +76 -0
  186. package/node_modules/pi-lens/dist/chunk-Z54ZSOBZ.js +61 -0
  187. package/node_modules/pi-lens/dist/chunk-ZAWW3AF6.js +97 -0
  188. package/node_modules/pi-lens/dist/chunk-ZMOL6RQC.js +167 -0
  189. package/node_modules/pi-lens/dist/index.js +16456 -8335
  190. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +186 -232
  191. package/node_modules/pi-lens/dist/mcp/cli.js +137 -98
  192. package/node_modules/pi-lens/dist/mcp/server.js +22589 -1573
  193. package/node_modules/pi-lens/dist/mcp/worker.js +97 -38
  194. package/node_modules/pi-lens/dist/probes/installer.js +135 -0
  195. package/node_modules/pi-lens/dist/workers/project-snapshot-persist-worker.js +22 -0
  196. package/node_modules/pi-lens/dist/workers/review-graph-persist-worker.js +15 -0
  197. package/node_modules/pi-lens/docs/agent-guide.md +13 -4
  198. package/node_modules/pi-lens/docs/agent-tools.md +42 -0
  199. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +3 -2
  200. package/node_modules/pi-lens/docs/configuration.md +20 -1
  201. package/node_modules/pi-lens/docs/environment-variables.md +52 -2
  202. package/node_modules/pi-lens/docs/features.md +8 -4
  203. package/node_modules/pi-lens/docs/globalconfig.md +1 -0
  204. package/node_modules/pi-lens/docs/io-bridge-v2-migration.md +94 -0
  205. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +36 -4
  206. package/node_modules/pi-lens/docs/lsp-idle-eviction.md +124 -0
  207. package/node_modules/pi-lens/docs/mcp.md +21 -5
  208. package/node_modules/pi-lens/docs/merge-queue-rollout.md +77 -0
  209. package/node_modules/pi-lens/docs/pi-lens-fixer.md +156 -88
  210. package/node_modules/pi-lens/docs/pi-lens-investigator.md +74 -26
  211. package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +694 -0
  212. package/node_modules/pi-lens/docs/pi-lens-monitor.md +73 -7
  213. package/node_modules/pi-lens/docs/pi-lens-retro.md +6 -4
  214. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +188 -48
  215. package/node_modules/pi-lens/docs/pi-lens-subagent.md +246 -45
  216. package/node_modules/pi-lens/docs/pi-lens-warden.md +18 -7
  217. package/node_modules/pi-lens/docs/public-api-stability.md +55 -0
  218. package/node_modules/pi-lens/docs/release-qa-baseline.md +84 -17
  219. package/node_modules/pi-lens/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  220. package/node_modules/pi-lens/docs/servercapabilities.md +53 -49
  221. package/node_modules/pi-lens/docs/settings.md +1 -0
  222. package/node_modules/pi-lens/docs/usage.md +5 -1
  223. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm +0 -0
  224. package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm.json +3 -3
  225. package/node_modules/pi-lens/package.json +18 -6
  226. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  227. package/node_modules/pi-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  228. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +1275 -62
  229. package/node_modules/pi-lens/scripts/download-grammars.js +5 -0
  230. package/node_modules/pi-lens/scripts/grammars.lock.json +6 -1
  231. package/node_modules/pi-lens/scripts/install-selftest.mjs +33 -34
  232. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +13 -4
  233. package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +18 -0
  234. package/node_modules/pi-typesafe/README.md +1 -1
  235. package/node_modules/pi-typesafe/dist/backends.d.ts +15 -5
  236. package/node_modules/pi-typesafe/dist/backends.js +18 -0
  237. package/node_modules/pi-typesafe/dist/client.d.ts +4 -3
  238. package/node_modules/pi-typesafe/dist/client.js +22 -7
  239. package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
  240. package/node_modules/pi-typesafe/dist/index.js +1 -1
  241. package/node_modules/pi-typesafe/dist/usage.d.ts +14 -4
  242. package/node_modules/pi-typesafe/dist/usage.js +147 -42
  243. package/node_modules/pi-typesafe/package.json +1 -1
  244. package/node_modules/pi-web-access/CHANGELOG.md +48 -0
  245. package/node_modules/pi-web-access/README.md +57 -11
  246. package/node_modules/pi-web-access/brave-rate-limit.ts +8 -2
  247. package/node_modules/pi-web-access/curator-page.ts +5 -1
  248. package/node_modules/pi-web-access/curator-server.ts +2 -0
  249. package/node_modules/pi-web-access/declared-web-links.ts +2 -2
  250. package/node_modules/pi-web-access/degoog.ts +323 -0
  251. package/node_modules/pi-web-access/dist/index.js +3483 -2745
  252. package/node_modules/pi-web-access/dist/mcp-cli.js +27443 -0
  253. package/node_modules/pi-web-access/exa.ts +5 -1
  254. package/node_modules/pi-web-access/extract.ts +41 -3
  255. package/node_modules/pi-web-access/firecrawl.ts +35 -4
  256. package/node_modules/pi-web-access/gemini-search.ts +34 -11
  257. package/node_modules/pi-web-access/gemini-web.ts +14 -9
  258. package/node_modules/pi-web-access/index.ts +153 -1202
  259. package/node_modules/pi-web-access/keenable.ts +221 -0
  260. package/node_modules/pi-web-access/mcp-cli.ts +40 -0
  261. package/node_modules/pi-web-access/mcp-server.ts +81 -0
  262. package/node_modules/pi-web-access/mcp-tool-definitions.ts +117 -0
  263. package/node_modules/pi-web-access/openai-search.ts +34 -1
  264. package/node_modules/pi-web-access/package.json +23 -5
  265. package/node_modules/pi-web-access/perplexity.ts +64 -56
  266. package/node_modules/pi-web-access/tool-arguments.ts +20 -0
  267. package/node_modules/pi-web-access/video-extract.ts +1 -1
  268. package/node_modules/pi-web-access/web-tool-contract.ts +86 -0
  269. package/node_modules/pi-web-access/web-tool-core.ts +1502 -0
  270. package/node_modules/pi-web-access/youtube-extract.ts +2 -5
  271. package/package.json +17 -12
  272. package/node_modules/@dietrichgebert/ponytail/README.es.md +0 -329
  273. package/node_modules/@dietrichgebert/ponytail/README.ko.md +0 -346
  274. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +0 -21
  275. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +0 -62
  276. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
  277. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +0 -115
  278. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +0 -27
  279. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +0 -27
  280. package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
  281. package/node_modules/@dietrichgebert/ponytail/assets/retriever-icon.png +0 -0
  282. package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-dark.svg +0 -4
  283. package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-light.svg +0 -4
  284. package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
  285. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
  286. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
  287. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
  288. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -35
  289. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +0 -1610
  290. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +0 -593
  291. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +0 -147
  292. package/node_modules/pi-lens/dist/clients/agent-nudge.js +0 -325
  293. package/node_modules/pi-lens/dist/clients/analysed-root.js +0 -1
  294. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +0 -731
  295. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +0 -146
  296. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -118
  297. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -10
  298. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +0 -154
  299. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +0 -75
  300. package/node_modules/pi-lens/dist/clients/atomic-write.js +0 -189
  301. package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +0 -12
  302. package/node_modules/pi-lens/dist/clients/bash-file-access.js +0 -1056
  303. package/node_modules/pi-lens/dist/clients/biome-client.js +0 -357
  304. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -837
  305. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +0 -129
  306. package/node_modules/pi-lens/dist/clients/bootstrap.js +0 -569
  307. package/node_modules/pi-lens/dist/clients/bounded-cache.js +0 -190
  308. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +0 -202
  309. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -295
  310. package/node_modules/pi-lens/dist/clients/build-identity.js +0 -95
  311. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +0 -113
  312. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +0 -105
  313. package/node_modules/pi-lens/dist/clients/bus-publish.js +0 -171
  314. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +0 -190
  315. package/node_modules/pi-lens/dist/clients/cache-manager.js +0 -524
  316. package/node_modules/pi-lens/dist/clients/cache-observability.js +0 -1313
  317. package/node_modules/pi-lens/dist/clients/call-graph.js +0 -852
  318. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +0 -422
  319. package/node_modules/pi-lens/dist/clients/cascade-budget.js +0 -196
  320. package/node_modules/pi-lens/dist/clients/cascade-format.js +0 -315
  321. package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -31
  322. package/node_modules/pi-lens/dist/clients/cascade-types.js +0 -9
  323. package/node_modules/pi-lens/dist/clients/child-unref.js +0 -124
  324. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +0 -286
  325. package/node_modules/pi-lens/dist/clients/codebase-model.js +0 -173
  326. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +0 -40
  327. package/node_modules/pi-lens/dist/clients/complexity-client.js +0 -462
  328. package/node_modules/pi-lens/dist/clients/config-core/deny.js +0 -221
  329. package/node_modules/pi-lens/dist/clients/config-core/index.js +0 -50
  330. package/node_modules/pi-lens/dist/clients/config-core/merge.js +0 -357
  331. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +0 -340
  332. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +0 -248
  333. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +0 -164
  334. package/node_modules/pi-lens/dist/clients/config-core/records.js +0 -218
  335. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +0 -125
  336. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +0 -78
  337. package/node_modules/pi-lens/dist/clients/config-core/schema.js +0 -165
  338. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +0 -285
  339. package/node_modules/pi-lens/dist/clients/config-locations.js +0 -388
  340. package/node_modules/pi-lens/dist/clients/config-resolve.js +0 -798
  341. package/node_modules/pi-lens/dist/clients/config-schema.js +0 -251
  342. package/node_modules/pi-lens/dist/clients/config-warn.js +0 -407
  343. package/node_modules/pi-lens/dist/clients/console-guard-install.js +0 -26
  344. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +0 -42
  345. package/node_modules/pi-lens/dist/clients/dead-code-client.js +0 -510
  346. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -30
  347. package/node_modules/pi-lens/dist/clients/deadline-utils.js +0 -280
  348. package/node_modules/pi-lens/dist/clients/debug-handles.js +0 -211
  349. package/node_modules/pi-lens/dist/clients/debug-heap.js +0 -174
  350. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +0 -106
  351. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +0 -426
  352. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +0 -169
  353. package/node_modules/pi-lens/dist/clients/dependency-checker.js +0 -885
  354. package/node_modules/pi-lens/dist/clients/deps/ast-grep-napi.js +0 -22
  355. package/node_modules/pi-lens/dist/clients/deps/js-yaml.js +0 -9
  356. package/node_modules/pi-lens/dist/clients/deps/minimatch.js +0 -4
  357. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +0 -14
  358. package/node_modules/pi-lens/dist/clients/deps/typebox.js +0 -14
  359. package/node_modules/pi-lens/dist/clients/deps/vscode-jsonrpc.js +0 -1
  360. package/node_modules/pi-lens/dist/clients/deps/web-tree-sitter.js +0 -24
  361. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +0 -630
  362. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +0 -305
  363. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +0 -73
  364. package/node_modules/pi-lens/dist/clients/diagnostic-tracker.js +0 -105
  365. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +0 -230
  366. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  367. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  368. package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -35
  369. package/node_modules/pi-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  370. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -1269
  371. package/node_modules/pi-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  372. package/node_modules/pi-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  373. package/node_modules/pi-lens/dist/clients/dispatch/fact-runner.js +0 -30
  374. package/node_modules/pi-lens/dist/clients/dispatch/fact-scheduler.js +0 -68
  375. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +0 -377
  376. package/node_modules/pi-lens/dist/clients/dispatch/facts/comment-facts.js +0 -22
  377. package/node_modules/pi-lens/dist/clients/dispatch/facts/file-content.js +0 -19
  378. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +0 -348
  379. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +0 -204
  380. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  381. package/node_modules/pi-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  382. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +0 -339
  383. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +0 -417
  384. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +0 -89
  385. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +0 -2377
  386. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -11
  387. package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +0 -87
  388. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -278
  389. package/node_modules/pi-lens/dist/clients/dispatch/priorities.js +0 -20
  390. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +0 -50
  391. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +0 -69
  392. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +0 -135
  393. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-noise.js +0 -40
  394. package/node_modules/pi-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  395. package/node_modules/pi-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  396. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  397. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  398. package/node_modules/pi-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  399. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +0 -72
  400. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  401. package/node_modules/pi-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  402. package/node_modules/pi-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  403. package/node_modules/pi-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  404. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  405. package/node_modules/pi-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  406. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  407. package/node_modules/pi-lens/dist/clients/dispatch/runner-context.js +0 -52
  408. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -111
  409. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  410. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -296
  411. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -219
  412. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -82
  413. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -416
  414. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -183
  415. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -176
  416. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -164
  417. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -195
  418. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -137
  419. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -29
  420. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -69
  421. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -167
  422. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +0 -104
  423. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -135
  424. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -91
  425. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -171
  426. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -940
  427. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -117
  428. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +0 -108
  429. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -99
  430. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -110
  431. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -379
  432. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -167
  433. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -102
  434. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +0 -414
  435. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -85
  436. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -120
  437. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  438. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  439. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +0 -169
  440. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -99
  441. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -88
  442. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -256
  443. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -173
  444. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -102
  445. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -128
  446. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -259
  447. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -183
  448. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -166
  449. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -163
  450. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -174
  451. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -168
  452. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -125
  453. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -643
  454. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -253
  455. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  456. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  457. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
  458. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  459. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  460. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  461. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  462. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  463. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -15
  464. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -128
  465. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  466. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -95
  467. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -79
  468. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +0 -79
  469. package/node_modules/pi-lens/dist/clients/dispatch/tool-profile.js +0 -30
  470. package/node_modules/pi-lens/dist/clients/dispatch/types.js +0 -21
  471. package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  472. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  473. package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -32
  474. package/node_modules/pi-lens/dist/clients/disposition-publish.js +0 -124
  475. package/node_modules/pi-lens/dist/clients/durable-store.js +0 -97
  476. package/node_modules/pi-lens/dist/clients/effective-config.js +0 -415
  477. package/node_modules/pi-lens/dist/clients/env-utils.js +0 -83
  478. package/node_modules/pi-lens/dist/clients/error-class.js +0 -23
  479. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +0 -17
  480. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +0 -274
  481. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +0 -250
  482. package/node_modules/pi-lens/dist/clients/extension-log.js +0 -504
  483. package/node_modules/pi-lens/dist/clients/extension-mode.js +0 -73
  484. package/node_modules/pi-lens/dist/clients/feature-hints.js +0 -103
  485. package/node_modules/pi-lens/dist/clients/file-kinds.js +0 -412
  486. package/node_modules/pi-lens/dist/clients/file-role.js +0 -134
  487. package/node_modules/pi-lens/dist/clients/file-time.js +0 -160
  488. package/node_modules/pi-lens/dist/clients/file-utils.js +0 -1032
  489. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +0 -494
  490. package/node_modules/pi-lens/dist/clients/finding-identity.js +0 -88
  491. package/node_modules/pi-lens/dist/clients/fix-worklog.js +0 -103
  492. package/node_modules/pi-lens/dist/clients/format-events-publish.js +0 -343
  493. package/node_modules/pi-lens/dist/clients/format-service.js +0 -222
  494. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +0 -9
  495. package/node_modules/pi-lens/dist/clients/formatters.js +0 -2032
  496. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +0 -17
  497. package/node_modules/pi-lens/dist/clients/freshness.js +0 -38
  498. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +0 -394
  499. package/node_modules/pi-lens/dist/clients/generation-guard.js +0 -215
  500. package/node_modules/pi-lens/dist/clients/git-guard.js +0 -1136
  501. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +0 -243
  502. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +0 -509
  503. package/node_modules/pi-lens/dist/clients/go-client.js +0 -104
  504. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +0 -605
  505. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +0 -348
  506. package/node_modules/pi-lens/dist/clients/grammar-source.js +0 -465
  507. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +0 -135
  508. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +0 -424
  509. package/node_modules/pi-lens/dist/clients/hook-budgets.js +0 -76
  510. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +0 -140
  511. package/node_modules/pi-lens/dist/clients/host-ports.js +0 -39
  512. package/node_modules/pi-lens/dist/clients/indent-retarget.js +0 -154
  513. package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +0 -186
  514. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +0 -156
  515. package/node_modules/pi-lens/dist/clients/installer/index.js +0 -5416
  516. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  517. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +0 -783
  518. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +0 -7
  519. package/node_modules/pi-lens/dist/clients/instance-reaper.js +0 -1137
  520. package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +0 -145
  521. package/node_modules/pi-lens/dist/clients/instance-registry.js +0 -773
  522. package/node_modules/pi-lens/dist/clients/jscpd-client.js +0 -378
  523. package/node_modules/pi-lens/dist/clients/json-cache-read.js +0 -65
  524. package/node_modules/pi-lens/dist/clients/knip-client.js +0 -788
  525. package/node_modules/pi-lens/dist/clients/language-policy.js +0 -252
  526. package/node_modules/pi-lens/dist/clients/language-profile.js +0 -361
  527. package/node_modules/pi-lens/dist/clients/language-registry.js +0 -603
  528. package/node_modules/pi-lens/dist/clients/latency-logger.js +0 -727
  529. package/node_modules/pi-lens/dist/clients/lazy-import.js +0 -21
  530. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +0 -54
  531. package/node_modules/pi-lens/dist/clients/lens-config.js +0 -404
  532. package/node_modules/pi-lens/dist/clients/lens-engine.js +0 -358
  533. package/node_modules/pi-lens/dist/clients/lens-events.js +0 -125
  534. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +0 -467
  535. package/node_modules/pi-lens/dist/clients/lens-map.js +0 -1156
  536. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +0 -74
  537. package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -222
  538. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +0 -178
  539. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +0 -421
  540. package/node_modules/pi-lens/dist/clients/lsp/client.js +0 -4593
  541. package/node_modules/pi-lens/dist/clients/lsp/config.js +0 -691
  542. package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +0 -41
  543. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +0 -225
  544. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +0 -467
  545. package/node_modules/pi-lens/dist/clients/lsp/edits.js +0 -1219
  546. package/node_modules/pi-lens/dist/clients/lsp/index.js +0 -8305
  547. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +0 -216
  548. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +0 -298
  549. package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -63
  550. package/node_modules/pi-lens/dist/clients/lsp/launch.js +0 -746
  551. package/node_modules/pi-lens/dist/clients/lsp/lombok.js +0 -158
  552. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +0 -5
  553. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -251
  554. package/node_modules/pi-lens/dist/clients/lsp/position-encoding.js +0 -61
  555. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  556. package/node_modules/pi-lens/dist/clients/lsp/server.js +0 -3290
  557. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +0 -192
  558. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +0 -17
  559. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -56
  560. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +0 -332
  561. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  562. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +0 -85
  563. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/index.js +0 -10
  564. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +0 -392
  565. package/node_modules/pi-lens/dist/clients/lsp/watch-queue.js +0 -61
  566. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  567. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  568. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  569. package/node_modules/pi-lens/dist/clients/lsp-budget.js +0 -186
  570. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +0 -110
  571. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +0 -9
  572. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +0 -396
  573. package/node_modules/pi-lens/dist/clients/lsp-status.js +0 -59
  574. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +0 -40
  575. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +0 -420
  576. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +0 -31
  577. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +0 -523
  578. package/node_modules/pi-lens/dist/clients/mcp/review.js +0 -197
  579. package/node_modules/pi-lens/dist/clients/mcp/session.js +0 -412
  580. package/node_modules/pi-lens/dist/clients/memory-sampler.js +0 -208
  581. package/node_modules/pi-lens/dist/clients/message-end-attribution.js +0 -30
  582. package/node_modules/pi-lens/dist/clients/metrics-client.js +0 -107
  583. package/node_modules/pi-lens/dist/clients/metrics-history.js +0 -327
  584. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +0 -263
  585. package/node_modules/pi-lens/dist/clients/model-provider.js +0 -53
  586. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +0 -189
  587. package/node_modules/pi-lens/dist/clients/module-report.js +0 -2150
  588. package/node_modules/pi-lens/dist/clients/mutating-tool.js +0 -651
  589. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +0 -368
  590. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +0 -240
  591. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -734
  592. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +0 -101
  593. package/node_modules/pi-lens/dist/clients/observed-mutation.js +0 -1253
  594. package/node_modules/pi-lens/dist/clients/oldtext-autopatch.js +0 -128
  595. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +0 -496
  596. package/node_modules/pi-lens/dist/clients/opengrep-client.js +0 -333
  597. package/node_modules/pi-lens/dist/clients/opengrep-config.js +0 -76
  598. package/node_modules/pi-lens/dist/clients/package-manager.js +0 -607
  599. package/node_modules/pi-lens/dist/clients/package-root.js +0 -38
  600. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +0 -439
  601. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +0 -43
  602. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +0 -108
  603. package/node_modules/pi-lens/dist/clients/path-utils.js +0 -1244
  604. package/node_modules/pi-lens/dist/clients/performance-report.js +0 -331
  605. package/node_modules/pi-lens/dist/clients/persist-debounce.js +0 -70
  606. package/node_modules/pi-lens/dist/clients/persistent-reverify.js +0 -271
  607. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +0 -119
  608. package/node_modules/pi-lens/dist/clients/pipeline.js +0 -1480
  609. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +0 -37
  610. package/node_modules/pi-lens/dist/clients/print-mode.js +0 -21
  611. package/node_modules/pi-lens/dist/clients/probe-home-state.js +0 -228
  612. package/node_modules/pi-lens/dist/clients/process-bridge.js +0 -66
  613. package/node_modules/pi-lens/dist/clients/process-singletons.js +0 -210
  614. package/node_modules/pi-lens/dist/clients/process-snapshot.js +0 -68
  615. package/node_modules/pi-lens/dist/clients/project-changes.js +0 -181
  616. package/node_modules/pi-lens/dist/clients/project-conventions.js +0 -171
  617. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +0 -137
  618. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +0 -109
  619. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
  620. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  621. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  622. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  623. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  624. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  625. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  626. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  627. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  628. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  629. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  630. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +0 -520
  631. package/node_modules/pi-lens/dist/clients/project-diagnostics/types.js +0 -1
  632. package/node_modules/pi-lens/dist/clients/project-lens-config.js +0 -807
  633. package/node_modules/pi-lens/dist/clients/project-report.js +0 -701
  634. package/node_modules/pi-lens/dist/clients/project-scale.js +0 -237
  635. package/node_modules/pi-lens/dist/clients/project-scan-policy.js +0 -11
  636. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +0 -48
  637. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +0 -20
  638. package/node_modules/pi-lens/dist/clients/project-snapshot.js +0 -1653
  639. package/node_modules/pi-lens/dist/clients/project-trust.js +0 -181
  640. package/node_modules/pi-lens/dist/clients/python-environment.js +0 -217
  641. package/node_modules/pi-lens/dist/clients/python-provenance.js +0 -639
  642. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +0 -47
  643. package/node_modules/pi-lens/dist/clients/quiet-window.js +0 -236
  644. package/node_modules/pi-lens/dist/clients/read-bridge.js +0 -139
  645. package/node_modules/pi-lens/dist/clients/read-expansion.js +0 -266
  646. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +0 -251
  647. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +0 -1306
  648. package/node_modules/pi-lens/dist/clients/read-guard.js +0 -1561
  649. package/node_modules/pi-lens/dist/clients/recent-touches.js +0 -240
  650. package/node_modules/pi-lens/dist/clients/redact/secrets.js +0 -449
  651. package/node_modules/pi-lens/dist/clients/resource-sampler.js +0 -628
  652. package/node_modules/pi-lens/dist/clients/reverse-deps.js +0 -270
  653. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +0 -5126
  654. package/node_modules/pi-lens/dist/clients/review-graph/format.js +0 -33
  655. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +0 -163
  656. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +0 -481
  657. package/node_modules/pi-lens/dist/clients/review-graph/persist-worker.js +0 -10
  658. package/node_modules/pi-lens/dist/clients/review-graph/query.js +0 -244
  659. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +0 -21
  660. package/node_modules/pi-lens/dist/clients/review-graph/service.js +0 -96
  661. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  662. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +0 -103
  663. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +0 -299
  664. package/node_modules/pi-lens/dist/clients/review-graph/types.js +0 -1
  665. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +0 -449
  666. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +0 -81
  667. package/node_modules/pi-lens/dist/clients/ruff-client.js +0 -179
  668. package/node_modules/pi-lens/dist/clients/rules-scanner.js +0 -131
  669. package/node_modules/pi-lens/dist/clients/run-duration.js +0 -55
  670. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +0 -746
  671. package/node_modules/pi-lens/dist/clients/runtime-config.js +0 -77
  672. package/node_modules/pi-lens/dist/clients/runtime-context.js +0 -211
  673. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +0 -1324
  674. package/node_modules/pi-lens/dist/clients/runtime-session.js +0 -2485
  675. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +0 -1295
  676. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +0 -2049
  677. package/node_modules/pi-lens/dist/clients/runtime-turn.js +0 -3767
  678. package/node_modules/pi-lens/dist/clients/rust-client.js +0 -97
  679. package/node_modules/pi-lens/dist/clients/safe-spawn.js +0 -2357
  680. package/node_modules/pi-lens/dist/clients/sanitize.js +0 -286
  681. package/node_modules/pi-lens/dist/clients/scan-utils.js +0 -25
  682. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +0 -165
  683. package/node_modules/pi-lens/dist/clients/search-read-registration.js +0 -94
  684. package/node_modules/pi-lens/dist/clients/secret-findings.js +0 -114
  685. package/node_modules/pi-lens/dist/clients/security-scan-client.js +0 -352
  686. package/node_modules/pi-lens/dist/clients/session-event-guard.js +0 -297
  687. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +0 -484
  688. package/node_modules/pi-lens/dist/clients/session-start-observability.js +0 -94
  689. package/node_modules/pi-lens/dist/clients/session-state-store.js +0 -101
  690. package/node_modules/pi-lens/dist/clients/session-summary.js +0 -15
  691. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +0 -27
  692. package/node_modules/pi-lens/dist/clients/sg-runner.js +0 -876
  693. package/node_modules/pi-lens/dist/clients/sgconfig.js +0 -347
  694. package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +0 -338
  695. package/node_modules/pi-lens/dist/clients/single-flight.js +0 -158
  696. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +0 -108
  697. package/node_modules/pi-lens/dist/clients/skills-resolver.js +0 -141
  698. package/node_modules/pi-lens/dist/clients/slow-fs.js +0 -138
  699. package/node_modules/pi-lens/dist/clients/smells-rollup.js +0 -231
  700. package/node_modules/pi-lens/dist/clients/source-filter.js +0 -596
  701. package/node_modules/pi-lens/dist/clients/source-walker.js +0 -211
  702. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +0 -120
  703. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +0 -110
  704. package/node_modules/pi-lens/dist/clients/stale-marker.js +0 -17
  705. package/node_modules/pi-lens/dist/clients/startup-scan.js +0 -400
  706. package/node_modules/pi-lens/dist/clients/startup-timing.js +0 -130
  707. package/node_modules/pi-lens/dist/clients/string-utils.js +0 -33
  708. package/node_modules/pi-lens/dist/clients/subagent-mode.js +0 -111
  709. package/node_modules/pi-lens/dist/clients/symbol-containment.js +0 -24
  710. package/node_modules/pi-lens/dist/clients/symbol-types.js +0 -5
  711. package/node_modules/pi-lens/dist/clients/test-runner-client.js +0 -2507
  712. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +0 -287
  713. package/node_modules/pi-lens/dist/clients/todo-scanner.js +0 -229
  714. package/node_modules/pi-lens/dist/clients/tool-agreement.js +0 -423
  715. package/node_modules/pi-lens/dist/clients/tool-config.js +0 -249
  716. package/node_modules/pi-lens/dist/clients/tool-cwd.js +0 -270
  717. package/node_modules/pi-lens/dist/clients/tool-definition.js +0 -47
  718. package/node_modules/pi-lens/dist/clients/tool-event.js +0 -105
  719. package/node_modules/pi-lens/dist/clients/tool-policy.js +0 -2755
  720. package/node_modules/pi-lens/dist/clients/tool-probe.js +0 -53
  721. package/node_modules/pi-lens/dist/clients/tool-render.js +0 -156
  722. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +0 -118
  723. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +0 -364
  724. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +0 -4195
  725. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +0 -100
  726. package/node_modules/pi-lens/dist/clients/tree-sitter-navigator.js +0 -269
  727. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +0 -569
  728. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +0 -158
  729. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  730. package/node_modules/pi-lens/dist/clients/trivy-client.js +0 -467
  731. package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -50
  732. package/node_modules/pi-lens/dist/clients/turn-context.js +0 -52
  733. package/node_modules/pi-lens/dist/clients/turn-end/lane.js +0 -51
  734. package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -112
  735. package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +0 -204
  736. package/node_modules/pi-lens/dist/clients/turn-summary-render.js +0 -72
  737. package/node_modules/pi-lens/dist/clients/turn-summary.js +0 -132
  738. package/node_modules/pi-lens/dist/clients/typos-config.js +0 -29
  739. package/node_modules/pi-lens/dist/clients/user-notify.js +0 -51
  740. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +0 -57
  741. package/node_modules/pi-lens/dist/clients/warm-attach.js +0 -305
  742. package/node_modules/pi-lens/dist/clients/widget-state.js +0 -1808
  743. package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -49
  744. package/node_modules/pi-lens/dist/clients/word-index-store.js +0 -459
  745. package/node_modules/pi-lens/dist/clients/word-index.js +0 -2080
  746. package/node_modules/pi-lens/dist/clients/workspace-topology.js +0 -443
  747. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +0 -65
  748. package/node_modules/pi-lens/dist/clients/zizmor-config.js +0 -340
  749. package/node_modules/pi-lens/dist/i18n.js +0 -69
  750. package/node_modules/pi-lens/dist/mcp/build-staleness.js +0 -124
  751. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +0 -583
  752. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +0 -129
  753. package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
  754. package/node_modules/pi-lens/dist/tools/activate-tools.js +0 -87
  755. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +0 -137
  756. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +0 -244
  757. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +0 -762
  758. package/node_modules/pi-lens/dist/tools/effective-config.js +0 -90
  759. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +0 -375
  760. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +0 -2571
  761. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +0 -1745
  762. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +0 -1367
  763. package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +0 -294
  764. package/node_modules/pi-lens/dist/tools/module-report.js +0 -382
  765. package/node_modules/pi-lens/dist/tools/project-report.js +0 -86
  766. package/node_modules/pi-lens/dist/tools/render-compact.js +0 -374
  767. package/node_modules/pi-lens/dist/tools/scan-progress.js +0 -53
  768. package/node_modules/pi-lens/dist/tools/shared.js +0 -29
  769. package/node_modules/pi-lens/dist/tools/symbol-search.js +0 -155
@@ -0,0 +1,1502 @@
1
+ // Host-neutral execution core for web_search (non-curator path), fetch_content,
2
+ // get_search_content, and source_check. The Pi extension (index.ts) and the MCP
3
+ // server both run tools through createWebToolCore; everything that differs per
4
+ // host (session persistence, background notifications, Pi model access) is a
5
+ // WebToolCoreHost hook. This module must stay free of runtime imports from
6
+ // index.ts, curator/summary/activation modules, and @earendil-works/* packages.
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
9
+ import type { KeyId } from "@earendil-works/pi-tui";
10
+ import pLimit from "p-limit";
11
+ import type { ExtractedContent, ExtractOptions } from "./extract.ts";
12
+ import { normalizeFetchContentParams, type FetchContentParams } from "./fetch-params.ts";
13
+ import { resolveAuthFetchProfile, type AuthFetchProfile } from "./auth-fetch.ts";
14
+ import { findContent, type FindMode } from "./content-find.ts";
15
+ import {
16
+ assertSearchProviderSelectionAllowed,
17
+ normalizeSearchProviderSelection,
18
+ search,
19
+ type SearchProvider,
20
+ type SearchProviderSelection,
21
+ } from "./gemini-search.ts";
22
+ import { isOpenAISearchAvailable } from "./openai-search.ts";
23
+ import type { SearchResult } from "./perplexity.ts";
24
+ import { getWebSearchConfigPath, runWithProxy } from "./utils.ts";
25
+ import { deleteResult, generateId, getResult, storeResult, type QueryResultData, type StoredSearchData } from "./storage.ts";
26
+ import {
27
+ buildResearchArtifact,
28
+ getResearchArtifact,
29
+ storeResearchArtifact,
30
+ withClaimAssessment,
31
+ type RecencyFilter,
32
+ type ResearchArtifact,
33
+ } from "./source-check.ts";
34
+ import type { SummaryMeta } from "./summary-review.ts";
35
+ import type {
36
+ FetchContentCallParams,
37
+ FetchContentStructuredContent,
38
+ GetSearchContentCallParams,
39
+ SourceCheckCallParams,
40
+ WebSearchCallParams,
41
+ WebSearchStructuredContent,
42
+ WebToolContent,
43
+ WebToolCore,
44
+ WebToolResult,
45
+ } from "./web-tool-contract.ts";
46
+
47
+ export const WEB_SEARCH_CONFIG_PATH = getWebSearchConfigPath();
48
+
49
+ export interface WebSearchConfig {
50
+ anysearchApiKey?: unknown;
51
+ xcrawlApiKey?: unknown;
52
+ brightdataApiKey?: unknown;
53
+ brightdataSerpZone?: unknown;
54
+ kagiApiKey?: unknown;
55
+ ollamaApiKey?: unknown;
56
+ serpbaseApiKey?: unknown;
57
+ serpapiApiKey?: unknown;
58
+ serperApiKey?: unknown;
59
+ serplyApiKey?: unknown;
60
+ youApiKey?: unknown;
61
+ baizhiApiKey?: unknown;
62
+ zaiApiKey?: unknown;
63
+ tinyfishApiKey?: unknown;
64
+ valyuApiKey?: unknown;
65
+ keenableApiKey?: unknown;
66
+ degoogBaseUrl?: unknown;
67
+ degoogApiKey?: unknown;
68
+ degoogEngines?: unknown;
69
+ degoogHeaders?: unknown;
70
+ xaiApiKey?: unknown;
71
+ provider?: unknown;
72
+ searchProvider?: unknown;
73
+ workflow?: string;
74
+ curatorTimeoutSeconds?: unknown;
75
+ autoOpenBrowser?: unknown;
76
+ curatorRemote?: unknown;
77
+ summaryModel?: string;
78
+ summaryGenerationDeadlineMs?: unknown;
79
+ summaryInstructions?: unknown;
80
+ maxInlineContentChars?: unknown;
81
+ fetch?: {
82
+ defaultMode?: unknown;
83
+ allowedModes?: unknown;
84
+ };
85
+ webSearch?: {
86
+ enabled?: boolean;
87
+ allowedProviders?: unknown;
88
+ };
89
+ tools?: Partial<Record<keyof ToolNames, { enabled?: boolean }>>;
90
+ toolActivation?: unknown;
91
+ commands?: Partial<Record<"websearch" | "curator" | "search" | "google-account", { enabled?: boolean }>>;
92
+ toolNames?: Partial<ToolNames>;
93
+ shortcuts?: {
94
+ curate?: KeyId;
95
+ activity?: KeyId;
96
+ };
97
+ ssrf?: {
98
+ /** CIDR ranges exempted from the SSRF guard (e.g. fake-IP proxy ranges). */
99
+ allowRanges?: string[];
100
+ /** Skip local hostname DNS preflight when an HTTP(S)_PROXY env var applies. */
101
+ trustEnvProxy?: boolean;
102
+ };
103
+ }
104
+
105
+ export function parseConfigRoot(raw: string): Record<string, unknown> {
106
+ let parsed: unknown;
107
+ try {
108
+ parsed = JSON.parse(raw);
109
+ } catch (err) {
110
+ const message = err instanceof Error ? err.message : String(err);
111
+ throw new Error(`Failed to parse ${WEB_SEARCH_CONFIG_PATH}: ${message}`);
112
+ }
113
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
114
+ throw new Error(`Invalid config in ${WEB_SEARCH_CONFIG_PATH}: expected a JSON object`);
115
+ }
116
+ return parsed as Record<string, unknown>;
117
+ }
118
+
119
+ export function loadConfig(): WebSearchConfig {
120
+ if (!existsSync(WEB_SEARCH_CONFIG_PATH)) return {};
121
+ return parseConfigRoot(readFileSync(WEB_SEARCH_CONFIG_PATH, "utf-8")) as WebSearchConfig;
122
+ }
123
+
124
+ export type ToolNames = {
125
+ webSearch: string;
126
+ sourceCheck: string;
127
+ fetchContent: string;
128
+ getSearchContent: string;
129
+ };
130
+
131
+ export const DEFAULT_TOOL_NAMES: ToolNames = {
132
+ webSearch: "web_search",
133
+ sourceCheck: "source_check",
134
+ fetchContent: "fetch_content",
135
+ getSearchContent: "get_search_content",
136
+ };
137
+ const SEARCH_QUERY_CONCURRENCY = 3;
138
+ const FETCH_MODES = ["readable", "raw", "answer"] as const;
139
+ export type FetchMode = typeof FETCH_MODES[number];
140
+ export type FetchModeConfig = { defaultMode: FetchMode; allowedModes: FetchMode[] };
141
+
142
+ export function resolveFetchModeConfig(config: WebSearchConfig): FetchModeConfig {
143
+ const configuredModes = config.fetch?.allowedModes ?? FETCH_MODES;
144
+ if (!Array.isArray(configuredModes) || configuredModes.length === 0 || configuredModes.some(mode => !FETCH_MODES.includes(mode as FetchMode))) {
145
+ throw new Error(`fetch.allowedModes in ${WEB_SEARCH_CONFIG_PATH} must be a non-empty array containing only "readable", "raw", or "answer"`);
146
+ }
147
+ const allowedModes = configuredModes as FetchMode[];
148
+ const duplicateMode = allowedModes.find((mode, index) => allowedModes.indexOf(mode) !== index);
149
+ if (duplicateMode) {
150
+ throw new Error(`fetch.allowedModes in ${WEB_SEARCH_CONFIG_PATH} must not contain duplicates: "${duplicateMode}"`);
151
+ }
152
+ const defaultMode = config.fetch?.defaultMode ?? "readable";
153
+ if (!allowedModes.includes(defaultMode as FetchMode)) {
154
+ throw new Error(`fetch.defaultMode in ${WEB_SEARCH_CONFIG_PATH} must be one of fetch.allowedModes`);
155
+ }
156
+ return { defaultMode: defaultMode as FetchMode, allowedModes };
157
+ }
158
+
159
+ // Limit each batch independently so separate Pi tool calls can still run in parallel.
160
+ export function runSearchQueries<T>(queries: string[], run: (query: string, index: number) => Promise<T>): Promise<T[]> {
161
+ const limit = pLimit(SEARCH_QUERY_CONCURRENCY);
162
+ return Promise.all(queries.map((query, index) => limit(() => run(query, index))));
163
+ }
164
+
165
+ export function isToolEnabled(config: WebSearchConfig, key: keyof ToolNames): boolean {
166
+ const override = config.tools?.[key]?.enabled;
167
+ if (typeof override === "boolean") return override;
168
+ return key !== "webSearch" && key !== "sourceCheck" || config.webSearch?.enabled !== false;
169
+ }
170
+
171
+ function joinToolNames(names: string[]): string {
172
+ if (names.length === 0) return "stored content";
173
+ if (names.length === 1) return names[0];
174
+ if (names.length === 2) return `${names[0]} or ${names[1]}`;
175
+ return `${names.slice(0, -1).join(", ")}, or ${names[names.length - 1]}`;
176
+ }
177
+
178
+ export function normalizeProviderInput(value: unknown, label = "provider"): SearchProviderSelection | undefined {
179
+ if (value === undefined) return undefined;
180
+ return normalizeSearchProviderSelection(value, label);
181
+ }
182
+
183
+ export function resolveRequestedProvider(requested: unknown): SearchProviderSelection {
184
+ const normalizedRequested = normalizeProviderInput(requested);
185
+ if (normalizedRequested && normalizedRequested !== "auto") {
186
+ assertSearchProviderSelectionAllowed(normalizedRequested, "Requested provider");
187
+ return normalizedRequested;
188
+ }
189
+ const config = loadConfig();
190
+ const provider = normalizeProviderInput(config.searchProvider ?? config.provider, `provider in ${WEB_SEARCH_CONFIG_PATH}`) ?? "auto";
191
+ assertSearchProviderSelectionAllowed(provider, `configured provider in ${WEB_SEARCH_CONFIG_PATH}`);
192
+ return provider;
193
+ }
194
+
195
+ export function toCuratorProvider(provider: SearchProviderSelection): SearchProvider | undefined {
196
+ if (Array.isArray(provider)) return "all";
197
+ return provider === "auto" ? undefined : provider;
198
+ }
199
+
200
+ export function normalizeRecencyFilter(value: unknown): RecencyFilter | undefined {
201
+ return value === "day" || value === "week" || value === "month" || value === "year"
202
+ ? value
203
+ : undefined;
204
+ }
205
+
206
+ export function normalizeQueryList(queryList: unknown[]): string[] {
207
+ const normalized: string[] = [];
208
+ for (const query of queryList) {
209
+ if (typeof query !== "string") continue;
210
+ const trimmed = query.trim();
211
+ if (trimmed.length > 0) normalized.push(trimmed);
212
+ }
213
+ return normalized;
214
+ }
215
+
216
+ // Some local models serialize a multi-query list into the single-string `query`
217
+ // field as a JSON array (query: "[\"a\", \"b\"]") instead of using the
218
+ // `queries` parameter. Forwarding that raw string verbatim makes every backend
219
+ // search for the literal array text and return zero results, with no signal to
220
+ // the model that its argument shape was wrong. Expand a string that parses as a
221
+ // JSON array of strings so each element is searched independently.
222
+ export function expandQueryString(query: unknown): string[] {
223
+ if (typeof query !== "string") return [];
224
+ const trimmed = query.trim();
225
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
226
+ try {
227
+ const parsed: unknown = JSON.parse(trimmed);
228
+ // Only expand an unambiguously string-only array. Mixed or non-string
229
+ // arrays are kept as the literal query so we never silently drop
230
+ // members or collapse them into an empty search.
231
+ if (Array.isArray(parsed) && parsed.every((entry): entry is string => typeof entry === "string")) {
232
+ return parsed
233
+ .map((entry) => entry.trim())
234
+ .filter((entry) => entry.length > 0);
235
+ }
236
+ } catch {
237
+ // Not JSON — treat as a literal query string.
238
+ }
239
+ }
240
+ return [query];
241
+ }
242
+
243
+ let extractModulePromise: Promise<typeof import("./extract.ts")> | undefined;
244
+ export async function fetchAllContent(
245
+ urls: string[],
246
+ signal?: AbortSignal,
247
+ options?: ExtractOptions,
248
+ ): Promise<ExtractedContent[]> {
249
+ const extractModule = await (extractModulePromise ??= import("./extract.ts"));
250
+ return extractModule.fetchAllContent(urls, signal, options);
251
+ }
252
+
253
+ /** Returns content for every URL in order: the provider's content where it supplied some,
254
+ * and a page fetch only for the URLs it did not cover. */
255
+ export async function fetchUncoveredContent(
256
+ urls: string[],
257
+ provided: ExtractedContent[] | undefined,
258
+ fetchPages: (urls: string[]) => Promise<ExtractedContent[]>,
259
+ ): Promise<ExtractedContent[]> {
260
+ const providedByUrl = new Map<string, ExtractedContent>();
261
+ for (const content of provided ?? []) {
262
+ if (!providedByUrl.has(content.url)) providedByUrl.set(content.url, content);
263
+ }
264
+ const missing = urls.filter(url => !providedByUrl.has(url));
265
+ const fetched = missing.length > 0 ? await fetchPages(missing) : [];
266
+ let next = 0;
267
+ return urls.map(url => providedByUrl.get(url) ?? fetched[next++]);
268
+ }
269
+
270
+ export function withRegisteredFetchOptions(
271
+ options: ExtractOptions | undefined,
272
+ toolNames: ExtractOptions["toolNames"],
273
+ proxy?: string,
274
+ ): ExtractOptions {
275
+ return {
276
+ ...(options ?? {}),
277
+ toolNames,
278
+ ...(proxy !== undefined ? { proxy } : {}),
279
+ };
280
+ }
281
+
282
+ function isAbortError(err: unknown): boolean {
283
+ return (err instanceof Error ? err.message : String(err)).toLowerCase().includes("abort");
284
+ }
285
+
286
+ const DEFAULT_MAX_INLINE_CONTENT_CHARS = 30_000;
287
+ const MIN_INLINE_CONTENT_CHARS = 1_000;
288
+ const MAX_INLINE_CONTENT_CHARS = 200_000;
289
+
290
+ export function getMaxInlineContentChars(config = loadConfig()): number {
291
+ const value = config.maxInlineContentChars;
292
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < MIN_INLINE_CONTENT_CHARS) {
293
+ return DEFAULT_MAX_INLINE_CONTENT_CHARS;
294
+ }
295
+ return Math.min(value, MAX_INLINE_CONTENT_CHARS);
296
+ }
297
+
298
+ export function stripThumbnails(results: ExtractedContent[]): ExtractedContent[] {
299
+ return results.map(({ thumbnail, frames, ...rest }) => rest);
300
+ }
301
+
302
+ function searchStructuredContent(responseId: string, fetchId: string | null, results: QueryResultData[]): WebSearchStructuredContent {
303
+ return {
304
+ responseId,
305
+ fetchId,
306
+ queries: results.map(({ query, answer, error, provider, providers, results }) => ({
307
+ query, answer, error, provider, providers,
308
+ results: results.map(({ title, url, snippet }) => ({ title, url, snippet })),
309
+ })),
310
+ };
311
+ }
312
+
313
+ // Full content per URL, without thumbnails or frames.
314
+ function fetchStructuredContent(responseId: string | null, results: ExtractedContent[]): FetchContentStructuredContent {
315
+ return {
316
+ responseId,
317
+ urls: results.map(({ url, title, content, error, mimeType, status, duration }) => ({ url, title, content, error, mimeType, status, duration })),
318
+ };
319
+ }
320
+
321
+ function initialContentSlice(content: string, maxChars: number): {
322
+ text: string;
323
+ endOffset: number;
324
+ totalBytes: number;
325
+ totalLines: number;
326
+ shownBytes: number;
327
+ shownLines: number;
328
+ } {
329
+ let endOffset = Math.min(content.length, maxChars);
330
+ if (endOffset < content.length) {
331
+ const lineBreak = content.lastIndexOf("\n", endOffset);
332
+ if (lineBreak >= Math.floor(maxChars * 0.8)) endOffset = lineBreak + 1;
333
+ }
334
+ const text = content.slice(0, endOffset);
335
+ return {
336
+ text,
337
+ endOffset,
338
+ totalBytes: Buffer.byteLength(content),
339
+ totalLines: content.length === 0 ? 0 : content.split("\n").length,
340
+ shownBytes: Buffer.byteLength(text),
341
+ shownLines: text.length === 0 ? 0 : text.split("\n").length,
342
+ };
343
+ }
344
+
345
+ function normalizeFindQueries(value: string | string[]): string[] {
346
+ const queries = (Array.isArray(value) ? value : [value]).map(query => query.trim()).filter(Boolean);
347
+ if (queries.length === 0) throw new Error("findText must contain at least one non-empty string");
348
+ return queries;
349
+ }
350
+
351
+ type GetSearchContentParams = GetSearchContentCallParams;
352
+
353
+ export type RawGetSearchContentParams = Omit<GetSearchContentParams, "findMode"> & { findMode?: unknown };
354
+
355
+ function normalizeFindMode(value: unknown): FindMode | undefined {
356
+ if (value === undefined) return undefined;
357
+ if (value === "exact" || value === "case-insensitive" || value === "fuzzy") return value;
358
+ throw new Error('findMode must be "exact", "case-insensitive", or "fuzzy"');
359
+ }
360
+
361
+ function normalizeGetSearchContentParams(params: RawGetSearchContentParams): GetSearchContentParams {
362
+ const normalized: GetSearchContentParams = { ...params, findMode: normalizeFindMode(params.findMode) };
363
+
364
+ if (normalized.query?.trim() === "") delete normalized.query;
365
+ if (normalized.url?.trim() === "") delete normalized.url;
366
+
367
+ if (normalized.findText !== undefined) {
368
+ delete normalized.offset;
369
+ delete normalized.limit;
370
+ }
371
+
372
+ return normalized;
373
+ }
374
+
375
+ function formatInputValue(value: unknown): string {
376
+ if (typeof value === "string") return JSON.stringify(value);
377
+ if (typeof value === "number") return Number.isNaN(value) ? "NaN" : String(value);
378
+ try {
379
+ const serialized = JSON.stringify(value);
380
+ return serialized === undefined ? String(value) : serialized;
381
+ } catch {
382
+ return String(value);
383
+ }
384
+ }
385
+
386
+ function formatSearchSummary(results: SearchResult[], answer: string): string {
387
+ if (results.length === 0) {
388
+ return answer ? `${answer}\n\n---\n\n**Sources:**\nNo sources returned.` : "No results found.";
389
+ }
390
+ let output = answer ? `${answer}\n\n---\n\n**Sources:**\n` : "";
391
+ output += results.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}`).join("\n\n");
392
+ return output;
393
+ }
394
+
395
+ function formatSourceCheckResult(artifact: ResearchArtifact, getSearchContentTool: string | null = DEFAULT_TOOL_NAMES.getSearchContent): string {
396
+ const assessment = artifact.claims?.[0];
397
+ const lines = [`# Source check: ${artifact.query}`, ""];
398
+ if (assessment) {
399
+ lines.push(`**Status:** ${assessment.status} (confidence ${assessment.confidence.toFixed(2)})`);
400
+ lines.push(`**Rationale:** ${assessment.rationale}`);
401
+ if (assessment.supporting_passages.length > 0) lines.push(`**Supporting passages:** ${assessment.supporting_passages.join(", ")}`);
402
+ if (assessment.contradicting_passages.length > 0) lines.push(`**Contradicting passages:** ${assessment.contradicting_passages.join(", ")}`);
403
+ lines.push("");
404
+ }
405
+ if (artifact.sources.length > 0) {
406
+ lines.push("## Sources");
407
+ for (const source of artifact.sources) lines.push(`${source.rank}. [${source.quality}] ${source.title}\n ${source.url}`);
408
+ lines.push("");
409
+ }
410
+ if (artifact.errors?.length) lines.push(`Search errors: ${artifact.errors.map((entry) => `${entry.query}: ${entry.error}`).join("; ")}`);
411
+ lines.push(getSearchContentTool
412
+ ? `Artifact responseId: ${artifact.id} (retrievable via ${getSearchContentTool}).`
413
+ : `Artifact responseId: ${artifact.id}. Content retrieval is not registered.`);
414
+ return lines.join("\n");
415
+ }
416
+
417
+ function duplicateQuerySet(results: QueryResultData[]): Set<string> {
418
+ const counts = new Map<string, number>();
419
+ for (const result of results) {
420
+ counts.set(result.query, (counts.get(result.query) ?? 0) + 1);
421
+ }
422
+ const duplicates = new Set<string>();
423
+ for (const [query, count] of counts) {
424
+ if (count > 1) duplicates.add(query);
425
+ }
426
+ return duplicates;
427
+ }
428
+
429
+ function formatQueryHeader(query: string, provider: string | undefined, duplicateQueries: Set<string>): string {
430
+ const suffix = duplicateQueries.has(query) && provider ? ` (${provider})` : "";
431
+ return `## Query: "${query}"${suffix}\n\n`;
432
+ }
433
+
434
+ function hasFullInlineCoverage(urls: string[], inlineContent: ExtractedContent[] | undefined): boolean {
435
+ if (!inlineContent || inlineContent.length === 0) return false;
436
+ const coveredUrls = new Set(inlineContent.map(c => c.url));
437
+ return urls.every(url => coveredUrls.has(url));
438
+ }
439
+
440
+ function formatFullResults(queryData: QueryResultData): string {
441
+ let output = `## Results for: "${queryData.query}"\n\n`;
442
+ const providers = queryData.providers ?? (queryData.provider ? [queryData.provider] : []);
443
+ if (providers.length > 0) output += `**Provider${providers.length === 1 ? "" : "s"}:** ${providers.join(", ")}\n\n`;
444
+ if (queryData.answer) {
445
+ output += `${queryData.answer}\n\n---\n\n`;
446
+ }
447
+ for (const r of queryData.results) {
448
+ output += `### ${r.title}\n${r.url}${r.snippet ? `\n\n${r.snippet}` : ""}\n\n`;
449
+ }
450
+ return output;
451
+ }
452
+
453
+ function boundSearchPresentation(
454
+ text: string,
455
+ guidance: string,
456
+ truncationGuidance: string,
457
+ maxChars: number,
458
+ ): { text: string; truncated: boolean; originalChars: number; returnedChars: number; omittedChars: number } {
459
+ const fullText = `${text}${guidance}`;
460
+ if (fullText.length <= maxChars) {
461
+ return { text: fullText, truncated: false, originalChars: text.length, returnedChars: text.length, omittedChars: 0 };
462
+ }
463
+ const marker = `\n\n---\n[Output truncated.]${truncationGuidance}`;
464
+ // Reserve marker space so the complete model-visible response never exceeds the configured ceiling.
465
+ const prefixLength = maxChars - marker.length;
466
+ const bounded = `${text.slice(0, prefixLength)}${marker}`;
467
+ return {
468
+ text: bounded,
469
+ truncated: true,
470
+ originalChars: text.length,
471
+ returnedChars: prefixLength,
472
+ omittedChars: text.length - prefixLength,
473
+ };
474
+ }
475
+
476
+ export type SummaryWorkflow = "summary-review" | "auto-summary";
477
+ export type FetchedContentData = StoredSearchData & { type: "fetch"; urls: ExtractedContent[] };
478
+
479
+ export interface SearchReturnOptions {
480
+ queryList: string[];
481
+ results: QueryResultData[];
482
+ urls: string[];
483
+ includeContent: boolean;
484
+ inlineContent?: ExtractedContent[];
485
+ curated?: boolean;
486
+ curatedFrom?: number;
487
+ workflow?: SummaryWorkflow;
488
+ approvedSummary?: string;
489
+ summaryMeta?: SummaryMeta;
490
+ proxy?: string;
491
+ }
492
+
493
+ /** Tool names and limits a host resolved once at startup. */
494
+ export interface WebToolCoreSettings {
495
+ toolNames: ToolNames;
496
+ enabledTools: Record<keyof ToolNames, boolean>;
497
+ /** Output ceiling for search results and stored-content pages. fetch_content rereads config per call. */
498
+ maxInlineContentChars: number;
499
+ fetchModes: FetchModeConfig;
500
+ }
501
+
502
+ export interface PageAnswerRequest {
503
+ question: string;
504
+ pageText: string;
505
+ sourceUrl: string;
506
+ model?: string;
507
+ }
508
+
509
+ /** Everything that differs between hosts. Pi supplies session persistence, background
510
+ * notifications, and page answers; the standalone host keeps results in memory only. */
511
+ export interface WebToolCoreHost {
512
+ settings: WebToolCoreSettings;
513
+ /** Store fetched page content under id so the retrieval tool can page through it. */
514
+ storeFetchedContent(id: string, data: FetchedContentData): void;
515
+ /** Called after search or research results are stored in memory. */
516
+ publishResult?(data: StoredSearchData): void;
517
+ /** Fetch includeContent pages the provider did not cover in the background and return
518
+ * their responseId. When omitted, web_search awaits the same fetch before returning. */
519
+ startBackgroundFetch?(urls: string[], proxy?: string, provided?: ExtractedContent[]): string | null;
520
+ /** Answers fetch_content mode "answer"; requires the host's model access. */
521
+ answerFromPage?(request: PageAnswerRequest, extensionContext: ExtensionContext | undefined, signal?: AbortSignal): Promise<{ text: string }>;
522
+ /** Extraction options every fetch in this host adds (for example direct-image policy). */
523
+ extractOptions?: Pick<ExtractOptions, "rejectDirectImages">;
524
+ }
525
+
526
+ export type WebToolUpdate = (update: { content: Array<{ type: "text"; text: string }>; details: Record<string, unknown> }) => void;
527
+
528
+ /** Per-call inputs only Pi has: its live ExtensionContext and partial-result callback. */
529
+ export interface WebToolCallOptions {
530
+ extensionContext?: ExtensionContext;
531
+ onUpdate?: WebToolUpdate;
532
+ }
533
+
534
+ export interface WebSearchCallOptions extends WebToolCallOptions {
535
+ /** Generates an auto-summary after searches complete; returning a tool result ends the call. */
536
+ summarize?(results: QueryResultData[]): Promise<WebToolResult | { approvedSummary: string; summaryMeta: SummaryMeta }>;
537
+ /** Wait for includeContent pages and store them with the result instead of fetching in the background. */
538
+ awaitContent?: boolean;
539
+ }
540
+
541
+ // Pi's TypeBox schemas type enums as plain strings; the core normalizes them.
542
+ export type WebSearchParams = Omit<WebSearchCallParams, "recencyFilter"> & { recencyFilter?: string; workflow?: string };
543
+ export type FetchContentToolParams = FetchContentCallParams & FetchContentParams;
544
+ export type SourceCheckParams = Omit<SourceCheckCallParams, "recencyFilter"> & { recencyFilter?: string };
545
+
546
+ export interface WebToolCoreInstance extends WebToolCore {
547
+ webSearch(params: WebSearchParams, signal?: AbortSignal, call?: WebSearchCallOptions): Promise<WebToolResult>;
548
+ fetchContent(params: FetchContentToolParams, signal?: AbortSignal, call?: WebToolCallOptions): Promise<WebToolResult>;
549
+ getSearchContent(params: RawGetSearchContentParams, signal?: AbortSignal): Promise<WebToolResult>;
550
+ sourceCheck(params: SourceCheckParams, signal?: AbortSignal, call?: WebToolCallOptions): Promise<WebToolResult>;
551
+ /** Formats and stores search results; the Pi curator reuses it for curated returns. */
552
+ buildSearchReturn(opts: SearchReturnOptions): WebToolResult;
553
+ }
554
+
555
+ /** Names fetch failure guidance may point at: only tools registered this session. */
556
+ export function registeredFetchToolNames(settings: WebToolCoreSettings): NonNullable<ExtractOptions["toolNames"]> {
557
+ return {
558
+ ...(settings.enabledTools.webSearch ? { webSearch: settings.toolNames.webSearch } : {}),
559
+ ...(settings.enabledTools.fetchContent ? { fetchContent: settings.toolNames.fetchContent } : {}),
560
+ };
561
+ }
562
+
563
+ export function storedContentSourceNames(settings: WebToolCoreSettings): string {
564
+ return joinToolNames([
565
+ ...(settings.enabledTools.webSearch ? [settings.toolNames.webSearch] : []),
566
+ ...(settings.enabledTools.sourceCheck ? [settings.toolNames.sourceCheck] : []),
567
+ ...(settings.enabledTools.fetchContent ? [settings.toolNames.fetchContent] : []),
568
+ ]);
569
+ }
570
+
571
+ /** Slices content from offset and appends the next-slice instructions, shrinking
572
+ * the slice so the whole page, instructions included, stays within maxChars. */
573
+ function sliceWithContinuation(content: string, offset: number, limit: number, maxChars: number, continuationAt: (endOffset: number) => string): { endOffset: number; text: string } {
574
+ let endOffset = offset + Math.min(limit, content.length - offset);
575
+ let continuation = "";
576
+ while (endOffset < content.length) {
577
+ continuation = continuationAt(endOffset);
578
+ const overflow = endOffset - offset + continuation.length - maxChars;
579
+ if (overflow <= 0) break;
580
+ endOffset -= overflow;
581
+ }
582
+ return { endOffset, text: content.slice(offset, endOffset) + (endOffset < content.length ? continuation : "") };
583
+ }
584
+
585
+ export function createWebToolCore(host: WebToolCoreHost): WebToolCoreInstance {
586
+ const { settings } = host;
587
+ const toolNames = settings.toolNames;
588
+ const getSearchContentEnabled = settings.enabledTools.getSearchContent;
589
+ const fetchModeConfig = settings.fetchModes;
590
+ const registeredToolNames = registeredFetchToolNames(settings);
591
+ const storedContentSources = storedContentSourceNames(settings);
592
+
593
+ function fetchOptions(options: ExtractOptions | undefined, proxy?: string): ExtractOptions {
594
+ const merged = host.extractOptions ? { ...(options ?? {}), ...host.extractOptions } : options;
595
+ return withRegisteredFetchOptions(merged, registeredToolNames, proxy);
596
+ }
597
+
598
+ function storeFetchResult(responseId: string, data: FetchedContentData, authProfile?: AuthFetchProfile): boolean {
599
+ if (authProfile?.cache === "off") return false;
600
+ host.storeFetchedContent(responseId, data);
601
+ return true;
602
+ }
603
+
604
+ function storeAndPublishSearch(results: QueryResultData[]): string {
605
+ const id = generateId();
606
+ const data: StoredSearchData = {
607
+ id, type: "search", timestamp: Date.now(), queries: results,
608
+ };
609
+ storeResult(id, data);
610
+ host.publishResult?.(data);
611
+ return id;
612
+ }
613
+
614
+ function buildSearchReturn(opts: SearchReturnOptions): WebToolResult {
615
+ const sc = opts.results.filter(r => !r.error).length;
616
+ const tr = opts.results.reduce((sum, r) => sum + r.results.length, 0);
617
+
618
+ const hasApprovedSummary = typeof opts.approvedSummary === "string" && opts.approvedSummary.trim().length > 0;
619
+ const maxInlineContentChars = settings.maxInlineContentChars;
620
+ let output = "";
621
+ if (hasApprovedSummary) {
622
+ output = opts.approvedSummary!.trim();
623
+ } else {
624
+ if (opts.curated) {
625
+ output += "[These results were manually curated by the user in the browser. Use them as-is — do not re-search or discard.]\n\n";
626
+ }
627
+ const providerNames = opts.results.map(result => {
628
+ const providers = result.providers ?? (result.provider ? [result.provider] : []);
629
+ return providers.join(", ") || "unknown";
630
+ });
631
+ output += opts.results.length === 1
632
+ ? `**Provider:** ${providerNames[0]}\n\n`
633
+ : `**Providers used:** ${providerNames.map((name, index) => `Query ${index + 1}: ${name}`).join("; ")}\n\n`;
634
+ const duplicateQueries = opts.curated ? duplicateQuerySet(opts.results) : new Set<string>();
635
+ for (const { query, answer, results, error, provider } of opts.results) {
636
+ if (opts.queryList.length > 1) {
637
+ output += opts.curated
638
+ ? formatQueryHeader(query, provider, duplicateQueries)
639
+ : `## Query: "${query}"\n\n`;
640
+ }
641
+ if (error) output += `Error: ${error}\n\n`;
642
+ else output += formatSearchSummary(results, answer) + "\n\n";
643
+ }
644
+ }
645
+
646
+ const hasInlineReady = hasFullInlineCoverage(opts.urls, opts.inlineContent);
647
+ let fetchId: string | null = null;
648
+ if (hasInlineReady && opts.inlineContent) {
649
+ fetchId = generateId();
650
+ const data = {
651
+ id: fetchId,
652
+ type: "fetch",
653
+ timestamp: Date.now(),
654
+ urls: opts.inlineContent,
655
+ } satisfies FetchedContentData;
656
+ host.storeFetchedContent(fetchId, data);
657
+ } else if (opts.includeContent) {
658
+ fetchId = host.startBackgroundFetch?.(opts.urls, opts.proxy, opts.inlineContent) ?? null;
659
+ }
660
+
661
+ const searchId = storeAndPublishSearch(opts.results);
662
+ const isBackgroundFetch = fetchId !== null && !hasInlineReady;
663
+ const unboundedPresentation = output.trim();
664
+ const buildGuidance = (forTruncation: boolean): string => {
665
+ let value = "";
666
+ if (hasInlineReady && opts.inlineContent && fetchId) {
667
+ value += `\n---\nFull content for ${opts.inlineContent.length} sources is ready as responseId "${fetchId}". `;
668
+ value += getSearchContentEnabled
669
+ ? `Use ${toolNames.getSearchContent}({ responseId: "${fetchId}", urlIndex: 0, offset: 0, limit: ${maxInlineContentChars} }) to retrieve the first bounded page.`
670
+ : forTruncation ? `Enable ${toolNames.getSearchContent} to retrieve the full stored content.` : "";
671
+ } else if (isBackgroundFetch && fetchId) {
672
+ value += `\n---\nContent fetching in background as responseId "${fetchId}". Will notify when ready.`;
673
+ }
674
+ if (getSearchContentEnabled || forTruncation) {
675
+ value += `\n---\nFull search results are stored as responseId "${searchId}". `;
676
+ value += getSearchContentEnabled
677
+ ? `Use ${toolNames.getSearchContent}({ responseId: "${searchId}", queryIndex: 0, offset: 0, limit: ${maxInlineContentChars} }) to retrieve the first bounded page${opts.results.length > 1 ? `; repeat with queryIndex 1 through ${opts.results.length - 1}` : ""}.`
678
+ : `Enable ${toolNames.getSearchContent} to retrieve the full stored results.`;
679
+ }
680
+ return value;
681
+ };
682
+ const presentation = hasApprovedSummary
683
+ ? { text: unboundedPresentation, truncated: false, originalChars: unboundedPresentation.length, returnedChars: unboundedPresentation.length, omittedChars: 0 }
684
+ : boundSearchPresentation(unboundedPresentation, buildGuidance(false), buildGuidance(true), maxInlineContentChars);
685
+
686
+ return {
687
+ content: [{ type: "text", text: presentation.text }],
688
+ structuredContent: searchStructuredContent(searchId, fetchId, opts.results),
689
+ details: {
690
+ queries: opts.queryList,
691
+ queryCount: opts.queryList.length,
692
+ successfulQueries: sc,
693
+ totalResults: tr,
694
+ includeContent: opts.includeContent,
695
+ fetchId,
696
+ fetchUrls: isBackgroundFetch ? opts.urls : undefined,
697
+ searchId,
698
+ queryProviders: opts.results.map(result => ({
699
+ query: result.query,
700
+ providers: result.providers ?? (result.provider ? [result.provider] : []),
701
+ })),
702
+ truncated: presentation.truncated,
703
+ originalChars: presentation.originalChars,
704
+ returnedChars: presentation.returnedChars,
705
+ omittedChars: presentation.omittedChars,
706
+ ...(opts.curated ? {
707
+ curated: true,
708
+ curatedFrom: opts.curatedFrom,
709
+ curatedQueries: opts.results.map(r => ({
710
+ query: r.query,
711
+ provider: r.provider || null,
712
+ answer: r.answer || null,
713
+ sources: r.results.map(s => ({ title: s.title, url: s.url })),
714
+ error: r.error,
715
+ })),
716
+ } : {}),
717
+ ...((opts.workflow && hasApprovedSummary)
718
+ ? {
719
+ summary: {
720
+ text: opts.approvedSummary!.trim(),
721
+ workflow: opts.workflow,
722
+ model: opts.summaryMeta?.model ?? null,
723
+ durationMs: opts.summaryMeta?.durationMs ?? 0,
724
+ tokenEstimate: opts.summaryMeta?.tokenEstimate ?? 0,
725
+ fallbackUsed: opts.summaryMeta?.fallbackUsed === true,
726
+ fallbackReason: opts.summaryMeta?.fallbackReason,
727
+ phase: opts.summaryMeta?.phase,
728
+ edited: opts.summaryMeta?.edited === true,
729
+ },
730
+ }
731
+ : {}),
732
+ },
733
+ };
734
+ }
735
+
736
+ async function webSearch(params: WebSearchParams, signal?: AbortSignal, call: WebSearchCallOptions = {}): Promise<WebToolResult> {
737
+ const { extensionContext: ctx, onUpdate } = call;
738
+ return runWithProxy(typeof params.proxy === "string" ? params.proxy : undefined, async () => {
739
+ const rawQueryList: unknown[] = Array.isArray(params.queries)
740
+ ? params.queries
741
+ : (params.query !== undefined ? expandQueryString(params.query) : []);
742
+ const queryList = normalizeQueryList(rawQueryList);
743
+ const recencyFilter = normalizeRecencyFilter(params.recencyFilter);
744
+
745
+ if (queryList.length === 0) {
746
+ return {
747
+ content: [{ type: "text", text: "Error: No query provided. Use 'query' or 'queries' parameter." }],
748
+ details: { error: "No query provided" },
749
+ };
750
+ }
751
+
752
+ let completedSearches = 0;
753
+ const allUrls: string[] = [];
754
+ const allInlineContent: ExtractedContent[] = [];
755
+ const resolvedProvider = resolveRequestedProvider(params.provider);
756
+
757
+ const queryResponses = await runSearchQueries(queryList, async (query) => {
758
+ signal?.throwIfAborted();
759
+ onUpdate?.({
760
+ content: [{ type: "text", text: `Searching "${query}" (${completedSearches}/${queryList.length} complete)...` }],
761
+ details: { phase: "search", progress: completedSearches / queryList.length, currentQuery: query },
762
+ });
763
+
764
+ try {
765
+ const { answer, results, inlineContent, provider, providerResponses } = await search(query, {
766
+ provider: resolvedProvider,
767
+ numResults: params.numResults,
768
+ recencyFilter,
769
+ domainFilter: params.domainFilter,
770
+ includeContent: params.includeContent,
771
+ category: params.category,
772
+ signal,
773
+ extensionContext: ctx,
774
+ });
775
+
776
+ const providers = providerResponses?.map(response => response.provider) ?? [provider];
777
+ return { result: { query, answer, results, error: null, provider, providers } satisfies QueryResultData, inlineContent };
778
+ } catch (err) {
779
+ if (signal?.aborted || isAbortError(err)) throw err;
780
+ const message = err instanceof Error ? err.message : String(err);
781
+ const requestedProvider = toCuratorProvider(resolvedProvider);
782
+ return {
783
+ result: { query, answer: "", results: [], error: message, provider: requestedProvider } satisfies QueryResultData,
784
+ inlineContent: undefined,
785
+ };
786
+ } finally {
787
+ completedSearches++;
788
+ if (!signal?.aborted) {
789
+ onUpdate?.({
790
+ content: [{ type: "text", text: `Completed ${completedSearches}/${queryList.length} searches.` }],
791
+ details: { phase: "search", progress: completedSearches / queryList.length, currentQuery: query },
792
+ });
793
+ }
794
+ }
795
+ });
796
+ const searchResults = queryResponses.map(response => response.result);
797
+ for (const response of queryResponses) {
798
+ for (const result of response.result.results) {
799
+ if (!allUrls.includes(result.url)) allUrls.push(result.url);
800
+ }
801
+ if (response.inlineContent) allInlineContent.push(...response.inlineContent);
802
+ }
803
+
804
+ let approvedSummary: string | undefined;
805
+ let summaryMeta: SummaryMeta | undefined;
806
+ if (call.summarize) {
807
+ const summary = await call.summarize(searchResults);
808
+ if ("content" in summary) return summary;
809
+ approvedSummary = summary.approvedSummary;
810
+ summaryMeta = summary.summaryMeta;
811
+ }
812
+
813
+ let inlineContent = allInlineContent.length > 0 ? allInlineContent : undefined;
814
+ if (params.includeContent && (call.awaitContent || !host.startBackgroundFetch) && allUrls.length > 0 && !hasFullInlineCoverage(allUrls, inlineContent)) {
815
+ // Hosts without background notifications, and calls that ask to, wait for the same page fetch instead.
816
+ const proxy = typeof params.proxy === "string" ? params.proxy : undefined;
817
+ const fetched = await fetchUncoveredContent(allUrls, inlineContent, urls => fetchAllContent(urls, signal, fetchOptions(undefined, proxy)));
818
+ signal?.throwIfAborted();
819
+ inlineContent = stripThumbnails(fetched);
820
+ }
821
+
822
+ return buildSearchReturn({
823
+ queryList,
824
+ results: searchResults,
825
+ urls: allUrls,
826
+ includeContent: params.includeContent ?? false,
827
+ inlineContent,
828
+ workflow: call.summarize ? "auto-summary" : undefined,
829
+ approvedSummary,
830
+ summaryMeta,
831
+ proxy: typeof params.proxy === "string" ? params.proxy : undefined,
832
+ });
833
+ });
834
+ }
835
+
836
+ async function sourceCheck(params: SourceCheckParams, signal?: AbortSignal, call: WebToolCallOptions = {}): Promise<WebToolResult> {
837
+ const ctx = call.extensionContext;
838
+ return runWithProxy(typeof params.proxy === "string" ? params.proxy : undefined, async () => {
839
+ const claim = typeof params.claim === "string" ? params.claim.trim() : "";
840
+ if (!claim) {
841
+ return { content: [{ type: "text", text: "Error: 'claim' is required." }], details: { error: "Missing claim" } };
842
+ }
843
+
844
+ const requestedQueries = Array.isArray(params.queries)
845
+ ? params.queries.filter((query): query is string => typeof query === "string").map((query) => query.trim()).filter(Boolean)
846
+ : [];
847
+ const queries = (requestedQueries.length > 0 ? requestedQueries : [claim]).slice(0, 8);
848
+ const numResults = typeof params.numResults === "number" && Number.isFinite(params.numResults)
849
+ ? Math.min(20, Math.max(1, Math.floor(params.numResults)))
850
+ : 5;
851
+ const domainFilter = Array.isArray(params.domainFilter)
852
+ ? params.domainFilter.filter((domain): domain is string => typeof domain === "string")
853
+ : undefined;
854
+ const recencyFilter = normalizeRecencyFilter(params.recencyFilter);
855
+ const resultsByUrl = new Map<string, SearchResult>();
856
+ const summaries: string[] = [];
857
+ const errors: Array<{ query: string; error: string }> = [];
858
+ let provider: string | undefined;
859
+
860
+ for (const query of queries) {
861
+ if (signal?.aborted) break;
862
+ try {
863
+ const response = await search(query, {
864
+ provider: resolveRequestedProvider(params.provider),
865
+ numResults,
866
+ recencyFilter,
867
+ domainFilter,
868
+ signal,
869
+ extensionContext: ctx,
870
+ });
871
+ if (signal?.aborted) break;
872
+ provider ??= response.provider;
873
+ if (response.answer) summaries.push(`${query}: ${response.answer}`);
874
+ for (const result of response.results) {
875
+ if (!resultsByUrl.has(result.url)) resultsByUrl.set(result.url, result);
876
+ }
877
+ } catch (err) {
878
+ if (signal?.aborted || isAbortError(err)) break;
879
+ errors.push({ query, error: err instanceof Error ? err.message : String(err) });
880
+ }
881
+ }
882
+
883
+ const results = [...resultsByUrl.values()].slice(0, 20).map((result, index) => ({ ...result, rank: index + 1 }));
884
+ let fetched: ExtractedContent[] = [];
885
+ if (params.fetchContent && results.length > 0) {
886
+ const urls = results.slice(0, 5).map((result) => result.url);
887
+ try {
888
+ fetched = await fetchAllContent(urls, signal, fetchOptions(undefined, typeof params.proxy === "string" ? params.proxy : undefined));
889
+ } catch (err) {
890
+ if (signal?.aborted || isAbortError(err)) throw err;
891
+ fetched = urls.map((url) => ({ url, title: "", content: "", error: err instanceof Error ? err.message : String(err) }));
892
+ }
893
+ }
894
+ const artifact = withClaimAssessment(buildResearchArtifact({
895
+ query: claim,
896
+ provider,
897
+ summary: summaries.length > 0 ? summaries.join("\n\n") : undefined,
898
+ results,
899
+ fetched,
900
+ recency: recencyFilter,
901
+ domainFilter,
902
+ }), [claim]);
903
+ if (errors.length > 0) artifact.errors = errors;
904
+ storeResearchArtifact(artifact);
905
+ host.publishResult?.({
906
+ id: artifact.id,
907
+ type: "research",
908
+ timestamp: artifact.timestamp,
909
+ artifact,
910
+ });
911
+ return {
912
+ content: [{ type: "text", text: formatSourceCheckResult(artifact, getSearchContentEnabled ? toolNames.getSearchContent : null) }],
913
+ details: { responseId: artifact.id, artifact, sourceCount: artifact.sources.length, passageCount: artifact.passages.length, searchCount: queries.length },
914
+ };
915
+ });
916
+ }
917
+
918
+ async function fetchContent(params: FetchContentToolParams, signal?: AbortSignal, call: WebToolCallOptions = {}): Promise<WebToolResult> {
919
+ const { extensionContext: ctx, onUpdate } = call;
920
+ let normalized: ReturnType<typeof normalizeFetchContentParams>;
921
+ try {
922
+ normalized = normalizeFetchContentParams(params);
923
+ } catch (err) {
924
+ const error = err instanceof Error ? err.message : String(err);
925
+ return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
926
+ }
927
+ const { urlList, options } = normalized;
928
+ const mode = options.mode ?? fetchModeConfig.defaultMode;
929
+ if (!fetchModeConfig.allowedModes.includes(mode)) {
930
+ const error = `Fetch mode "${mode}" is disabled by fetch.allowedModes.`;
931
+ return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
932
+ }
933
+ return runWithProxy(options.proxy, async () => {
934
+ if (mode === "answer" && !options.prompt) {
935
+ return { content: [{ type: "text", text: "Error: mode answer requires prompt." }], details: { error: "mode answer requires prompt" } };
936
+ }
937
+ if (mode === "raw" && (options.forceClone === true || options.timestamp || options.frames || options.prompt || options.model || options.answerModel)) {
938
+ return { content: [{ type: "text", text: "Error: mode raw cannot be combined with forceClone, prompt, timestamp, frames, model, or answerModel." }], details: { error: "Incompatible raw mode options" } };
939
+ }
940
+ if (mode !== "answer" && options.answerModel) {
941
+ return { content: [{ type: "text", text: "Error: answerModel requires mode answer." }], details: { error: "answerModel requires mode answer" } };
942
+ }
943
+ if (mode === "answer" && options.model) {
944
+ return { content: [{ type: "text", text: "Error: use answerModel, not model, with mode answer." }], details: { error: "model is incompatible with mode answer" } };
945
+ }
946
+ if (mode === "answer" && options.auth !== undefined) {
947
+ return { content: [{ type: "text", text: "Error: auth cannot be combined with mode answer." }], details: { error: "auth cannot be combined with mode answer" } };
948
+ }
949
+ let authFetchProfile: AuthFetchProfile | undefined;
950
+ if (options.auth !== undefined) {
951
+ try {
952
+ authFetchProfile = resolveAuthFetchProfile(options.auth);
953
+ } catch (err) {
954
+ const error = err instanceof Error ? err.message : String(err);
955
+ return { content: [{ type: "text", text: `Error: ${error}` }], details: { error } };
956
+ }
957
+ }
958
+ if (urlList.length === 0) {
959
+ return {
960
+ content: [{ type: "text", text: "Error: No URL provided. Use the 'url' parameter, or 'urls' for parallel fetches." }],
961
+ details: { error: "No URL provided" },
962
+ };
963
+ }
964
+
965
+ onUpdate?.({
966
+ content: [{ type: "text", text: `Fetching ${urlList.length} URL(s)...` }],
967
+ details: { phase: "fetch", progress: 0 },
968
+ });
969
+
970
+ const { answerModel: _answerModel, auth: _auth, ...extractionOptions } = { ...options, mode };
971
+ const { prompt: _prompt, ...answerExtractionOptions } = extractionOptions;
972
+ const requestOptions = {
973
+ ...(mode === "answer" ? answerExtractionOptions : extractionOptions),
974
+ ...(authFetchProfile ? { authFetchProfile } : {}),
975
+ };
976
+ const fetchResults = await fetchAllContent(urlList, signal, fetchOptions(requestOptions, options.proxy));
977
+ const presentedResults = mode === "answer"
978
+ ? await Promise.all(fetchResults.map(async result => {
979
+ if (result.error) return result;
980
+ if (result.thumbnail || result.mimeType?.startsWith("image/")) {
981
+ return { ...result, error: "Page answer requires textual fetched content" };
982
+ }
983
+ try {
984
+ if (!host.answerFromPage) throw new Error("this host cannot answer from fetched pages");
985
+ const answer = await host.answerFromPage({
986
+ question: options.prompt!,
987
+ pageText: result.content,
988
+ sourceUrl: result.url,
989
+ ...(options.answerModel ? { model: options.answerModel } : {}),
990
+ }, ctx, signal);
991
+ return { ...result, content: answer.text };
992
+ } catch (err) {
993
+ return { ...result, error: `Page answer failed: ${err instanceof Error ? err.message : String(err)}` };
994
+ }
995
+ }))
996
+ : fetchResults;
997
+ const successful = presentedResults.filter((r) => !r.error).length;
998
+ const totalChars = presentedResults.reduce((sum, r) => sum + r.content.length, 0);
999
+
1000
+ const responseId = generateId();
1001
+ const data = {
1002
+ id: responseId,
1003
+ type: "fetch",
1004
+ timestamp: Date.now(),
1005
+ urls: stripThumbnails(fetchResults),
1006
+ } satisfies FetchedContentData;
1007
+ const storedContent = storeFetchResult(responseId, data, authFetchProfile);
1008
+ const structuredContent = fetchStructuredContent(storedContent ? responseId : null, presentedResults);
1009
+
1010
+ if (urlList.length === 1) {
1011
+ const result = presentedResults[0];
1012
+ if (result.error) {
1013
+ return {
1014
+ isError: true,
1015
+ content: [{ type: "text", text: `Error: ${result.error}` }],
1016
+ structuredContent,
1017
+ details: { urls: urlList, urlCount: 1, successful: 0, error: result.error, ...(storedContent ? { responseId } : {}), prompt: params.prompt, timestamp: params.timestamp, frames: params.frames },
1018
+ };
1019
+ }
1020
+
1021
+ const fullLength = result.content.length;
1022
+ const slice = initialContentSlice(result.content, getMaxInlineContentChars());
1023
+ const truncated = slice.endOffset < fullLength;
1024
+ let output = slice.text;
1025
+
1026
+ if (truncated) {
1027
+ output += `\n\n---\nShowing ${slice.endOffset} of ${fullLength} chars, ${slice.shownBytes} of ${slice.totalBytes} bytes, and ${slice.shownLines} of ${slice.totalLines} lines. `;
1028
+ output += storedContent
1029
+ ? getSearchContentEnabled
1030
+ ? `Use ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0, offset: ${slice.endOffset} }) for the next slice.`
1031
+ : "Content retrieval is not registered."
1032
+ : "Authenticated fetch cache is off; repeat the fetch to read more.";
1033
+ }
1034
+
1035
+ const content: WebToolContent[] = [];
1036
+ if (result.frames?.length) {
1037
+ for (const frame of result.frames) {
1038
+ content.push({ type: "image", data: frame.data, mimeType: frame.mimeType });
1039
+ content.push({ type: "text", text: `Frame at ${frame.timestamp}` });
1040
+ }
1041
+ } else if (result.thumbnail) {
1042
+ content.push({ type: "image", data: result.thumbnail.data, mimeType: result.thumbnail.mimeType });
1043
+ }
1044
+ content.push({ type: "text", text: output });
1045
+
1046
+ const imageCount = (result.frames?.length ?? 0) + (result.thumbnail ? 1 : 0);
1047
+ return {
1048
+ content,
1049
+ structuredContent,
1050
+ details: {
1051
+ urls: urlList,
1052
+ urlCount: 1,
1053
+ successful: 1,
1054
+ totalChars: fullLength,
1055
+ title: result.title,
1056
+ ...(storedContent ? { responseId } : {}),
1057
+ truncated,
1058
+ hasImage: imageCount > 0,
1059
+ imageCount,
1060
+ prompt: params.prompt,
1061
+ timestamp: params.timestamp,
1062
+ frames: params.frames,
1063
+ duration: result.duration,
1064
+ mode,
1065
+ mimeType: result.mimeType,
1066
+ status: result.status,
1067
+ totalBytes: slice.totalBytes,
1068
+ totalLines: slice.totalLines,
1069
+ shownBytes: slice.shownBytes,
1070
+ shownLines: slice.shownLines,
1071
+ },
1072
+ };
1073
+ }
1074
+
1075
+ let output = "## Fetched URLs\n\n";
1076
+ for (const { url, title, content, error } of presentedResults) {
1077
+ if (error) {
1078
+ output += `- ${url}: Error - ${error}\n`;
1079
+ } else {
1080
+ output += `- ${title || url} (${content.length} chars)\n`;
1081
+ }
1082
+ }
1083
+ output += storedContent
1084
+ ? getSearchContentEnabled
1085
+ ? `\n---\nUse ${toolNames.getSearchContent}({ responseId: "${responseId}", urlIndex: 0 }) to retrieve bounded content slices.`
1086
+ : "\n---\nContent retrieval is not registered."
1087
+ : "\n---\nAuthenticated fetch cache is off; repeat the fetch to read content.";
1088
+
1089
+ return {
1090
+ ...(successful === 0 ? { isError: true } : {}),
1091
+ content: [{ type: "text", text: output }],
1092
+ structuredContent,
1093
+ details: { urls: urlList, urlCount: urlList.length, successful, totalChars, ...(storedContent ? { responseId } : {}) },
1094
+ };
1095
+ });
1096
+ }
1097
+
1098
+ async function getSearchContent(rawParams: RawGetSearchContentParams): Promise<WebToolResult> {
1099
+ const maxInlineContentChars = settings.maxInlineContentChars;
1100
+ const params = normalizeGetSearchContentParams(rawParams);
1101
+ if (params.findMode !== undefined && params.findText === undefined) {
1102
+ return {
1103
+ content: [{ type: "text", text: `findMode ${formatInputValue(params.findMode)} requires findText; provide findText or omit findMode.` }],
1104
+ details: { error: "findMode requires findText" },
1105
+ };
1106
+ }
1107
+ const data = getResult(params.responseId);
1108
+ if (!data) {
1109
+ return {
1110
+ content: [{ type: "text", text: `Error: No stored results for responseId ${formatInputValue(params.responseId)}. Use a responseId returned by ${storedContentSources}.` }],
1111
+ details: { error: "Not found", responseId: params.responseId },
1112
+ };
1113
+ }
1114
+
1115
+ if (data.type === "research") {
1116
+ const artifact = getResearchArtifact(params.responseId);
1117
+ if (!artifact) {
1118
+ return {
1119
+ content: [{ type: "text", text: `Error: stored research artifact for responseId ${formatInputValue(params.responseId)} was not found. Use a responseId returned by ${storedContentSources}.` }],
1120
+ details: { error: "Artifact not found", responseId: params.responseId },
1121
+ };
1122
+ }
1123
+ const serialized = JSON.stringify(artifact, null, 2);
1124
+ if (params.findText !== undefined) {
1125
+ try {
1126
+ const found = findContent(serialized, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
1127
+ const { text, ...findDetails } = found;
1128
+ return {
1129
+ content: [{ type: "text", text }],
1130
+ details: { responseId: artifact.id, type: "research", contentLength: serialized.length, findMode: params.findMode ?? "case-insensitive", ...findDetails },
1131
+ };
1132
+ } catch (err) {
1133
+ const error = err instanceof Error ? err.message : String(err);
1134
+ return {
1135
+ content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in research artifact for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
1136
+ details: { error, responseId: params.responseId, type: "research" },
1137
+ };
1138
+ }
1139
+ }
1140
+ const offset = params.offset ?? 0;
1141
+ const limit = params.limit ?? maxInlineContentChars;
1142
+ if (!Number.isInteger(offset) || offset < 0) {
1143
+ return {
1144
+ content: [{ type: "text", text: `Invalid offset: received ${formatInputValue(offset)} for responseId ${formatInputValue(params.responseId)}; offset must be a non-negative integer. Use 0 or a larger integer.` }],
1145
+ details: { error: "Invalid offset", offset },
1146
+ };
1147
+ }
1148
+ if (!Number.isInteger(limit) || limit <= 0 || limit > maxInlineContentChars) {
1149
+ return {
1150
+ content: [{ type: "text", text: `Invalid limit: received ${formatInputValue(limit)} for responseId ${formatInputValue(params.responseId)}; limit must be an integer from 1 to ${maxInlineContentChars}. Use a value in that range.` }],
1151
+ details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars },
1152
+ };
1153
+ }
1154
+ if (offset > serialized.length) {
1155
+ return {
1156
+ content: [{ type: "text", text: `Offset ${offset} is out of range for responseId ${formatInputValue(params.responseId)}. Received offset ${offset}; valid range is 0-${serialized.length}. Use an offset within that range.` }],
1157
+ details: { error: "Offset out of range", offset, contentLength: serialized.length },
1158
+ };
1159
+ }
1160
+ const { endOffset, text } = sliceWithContinuation(serialized, offset, limit, maxInlineContentChars, (end) =>
1161
+ `\n\n---\nShowing chars ${offset}-${end} of ${serialized.length}. Use ${toolNames.getSearchContent}({ responseId: "${artifact.id}", offset: ${end}, limit: ${limit} }) for the next slice.`);
1162
+ const hasMore = endOffset < serialized.length;
1163
+ return {
1164
+ content: [{ type: "text", text }],
1165
+ details: { responseId: artifact.id, type: "research", contentLength: serialized.length, offset, limit, returnedChars: endOffset - offset, nextOffset: hasMore ? endOffset : null, truncated: hasMore },
1166
+ };
1167
+ }
1168
+
1169
+ if (data.type === "search" && data.queries) {
1170
+ let queryData: QueryResultData | undefined;
1171
+
1172
+ if (params.query !== undefined) {
1173
+ queryData = data.queries.find((q) => q.query === params.query);
1174
+ if (!queryData) {
1175
+ const available = data.queries.map((q) => `"${q.query}"`).join(", ");
1176
+ return {
1177
+ content: [{ type: "text", text: `Query ${formatInputValue(params.query)} was not found for responseId ${formatInputValue(params.responseId)}. Received query=${formatInputValue(params.query)}. Available queries: ${available || "none"}. Use one of the available queries or queryIndex.` }],
1178
+ details: { error: "Query not found" },
1179
+ };
1180
+ }
1181
+ } else if (params.queryIndex !== undefined) {
1182
+ queryData = data.queries[params.queryIndex];
1183
+ if (!queryData) {
1184
+ const available = data.queries.map((q, i) => `${i}: "${q.query}"`).join(", ");
1185
+ return {
1186
+ content: [{ type: "text", text: `Query index ${formatInputValue(params.queryIndex)} is out of range for responseId ${formatInputValue(params.responseId)}. Received queryIndex=${formatInputValue(params.queryIndex)}; valid indexes are 0-${data.queries.length - 1}. Available queries: ${available || "none"}. Use one of the available indexes.` }],
1187
+ details: { error: "Index out of range" },
1188
+ };
1189
+ }
1190
+ } else {
1191
+ const available = data.queries.map((q, i) => `${i}: "${q.query}"`).join(", ");
1192
+ return {
1193
+ content: [{ type: "text", text: `Specify query or queryIndex for responseId ${formatInputValue(params.responseId)}. Available queries: ${available || "none"}.` }],
1194
+ details: { error: "No query specified" },
1195
+ };
1196
+ }
1197
+
1198
+ if (queryData.error) {
1199
+ return {
1200
+ content: [{ type: "text", text: `Error retrieving query ${formatInputValue(queryData.query)} from responseId ${formatInputValue(params.responseId)}: ${queryData.error}. Check the stored search result and retry with another query or queryIndex if needed.` }],
1201
+ details: { error: queryData.error, query: queryData.query },
1202
+ };
1203
+ }
1204
+
1205
+ const fullResults = formatFullResults(queryData);
1206
+ if (params.findText !== undefined) {
1207
+ try {
1208
+ const found = findContent(fullResults, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
1209
+ const { text, ...findDetails } = found;
1210
+ return {
1211
+ content: [{ type: "text", text }],
1212
+ details: { responseId: params.responseId, query: queryData.query, resultCount: queryData.results.length, contentLength: fullResults.length, findMode: params.findMode ?? "case-insensitive", ...findDetails },
1213
+ };
1214
+ } catch (err) {
1215
+ const error = err instanceof Error ? err.message : String(err);
1216
+ return {
1217
+ content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in query ${formatInputValue(queryData.query)} for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
1218
+ details: { error, query: queryData.query },
1219
+ };
1220
+ }
1221
+ }
1222
+
1223
+ const offset = params.offset ?? 0;
1224
+ const limit = params.limit ?? maxInlineContentChars;
1225
+ if (!Number.isInteger(offset) || offset < 0) {
1226
+ return {
1227
+ content: [{ type: "text", text: `Invalid offset: received ${formatInputValue(offset)} for query ${formatInputValue(queryData.query)}; offset must be a non-negative integer. Use 0 or a larger integer.` }],
1228
+ details: { error: "Invalid offset", offset },
1229
+ };
1230
+ }
1231
+ if (!Number.isInteger(limit) || limit <= 0 || limit > maxInlineContentChars) {
1232
+ return {
1233
+ content: [{ type: "text", text: `Invalid limit: received ${formatInputValue(limit)} for query ${formatInputValue(queryData.query)}; limit must be an integer from 1 to ${maxInlineContentChars}. Use a value in that range.` }],
1234
+ details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars },
1235
+ };
1236
+ }
1237
+ if (offset > fullResults.length) {
1238
+ return {
1239
+ content: [{ type: "text", text: `Offset ${offset} is out of range for query ${formatInputValue(queryData.query)} in responseId ${formatInputValue(params.responseId)}. Received offset ${offset}; valid range is 0-${fullResults.length}. Use an offset within that range.` }],
1240
+ details: { error: "Offset out of range", offset, contentLength: fullResults.length },
1241
+ };
1242
+ }
1243
+ const queryIndex = data.queries.indexOf(queryData);
1244
+ const { endOffset, text } = sliceWithContinuation(fullResults, offset, limit, maxInlineContentChars, (end) =>
1245
+ `\n\n---\nShowing chars ${offset}-${end} of ${fullResults.length}. Use ${toolNames.getSearchContent}({ responseId: "${params.responseId}", queryIndex: ${queryIndex}, offset: ${end}, limit: ${limit} }) for the next slice.`);
1246
+ const returnedChars = endOffset - offset;
1247
+ const hasMore = endOffset < fullResults.length;
1248
+ return {
1249
+ content: [{ type: "text", text }],
1250
+ details: {
1251
+ responseId: params.responseId,
1252
+ query: queryData.query,
1253
+ resultCount: queryData.results.length,
1254
+ contentLength: fullResults.length,
1255
+ offset,
1256
+ limit,
1257
+ returnedChars,
1258
+ nextOffset: hasMore ? endOffset : null,
1259
+ truncated: hasMore,
1260
+ },
1261
+ };
1262
+ }
1263
+
1264
+ if (data.type === "fetch" && data.urls) {
1265
+ let urlData: ExtractedContent | undefined;
1266
+ let selectedUrlIndex = -1;
1267
+
1268
+ if (params.url !== undefined) {
1269
+ selectedUrlIndex = data.urls.findIndex((u) => u.url === params.url);
1270
+ urlData = data.urls[selectedUrlIndex];
1271
+ if (!urlData) {
1272
+ const available = data.urls.map((u) => u.url).join("\n ");
1273
+ return {
1274
+ content: [{ type: "text", text: `URL ${formatInputValue(params.url)} was not found for responseId ${formatInputValue(params.responseId)}. Received url=${formatInputValue(params.url)}. Available URLs:\n ${available || " none"}\nUse one of the available URLs or urlIndex.` }],
1275
+ details: { error: "URL not found" },
1276
+ };
1277
+ }
1278
+ } else if (params.urlIndex !== undefined) {
1279
+ selectedUrlIndex = params.urlIndex;
1280
+ urlData = data.urls[selectedUrlIndex];
1281
+ if (!urlData) {
1282
+ const available = data.urls.map((u, i) => `${i}: ${u.url}`).join("\n ");
1283
+ return {
1284
+ content: [{ type: "text", text: `URL index ${formatInputValue(params.urlIndex)} is out of range for responseId ${formatInputValue(params.responseId)}. Received urlIndex=${formatInputValue(params.urlIndex)}; valid indexes are 0-${data.urls.length - 1}. Available URLs:\n ${available || " none"}\nUse one of the available indexes.` }],
1285
+ details: { error: "Index out of range" },
1286
+ };
1287
+ }
1288
+ } else if (data.urls.length === 1) {
1289
+ // Single stored URL: default to it so calls that omit url and urlIndex
1290
+ // (common with findText on single-URL fetches) succeed without a retry.
1291
+ selectedUrlIndex = 0;
1292
+ urlData = data.urls[0];
1293
+ } else {
1294
+ const available = data.urls.map((u, i) => `${i}: ${u.url}`).join("\n ");
1295
+ return {
1296
+ content: [{ type: "text", text: `Specify url or urlIndex for responseId ${formatInputValue(params.responseId)}. Available URLs:\n ${available || " none"}` }],
1297
+ details: { error: "No URL specified" },
1298
+ };
1299
+ }
1300
+
1301
+ if (urlData.error) {
1302
+ return {
1303
+ content: [{ type: "text", text: `Error retrieving URL ${formatInputValue(urlData.url)} from responseId ${formatInputValue(params.responseId)}: ${urlData.error}. Check the stored fetch result and retry with another URL or urlIndex if needed.` }],
1304
+ details: { error: urlData.error, url: urlData.url },
1305
+ };
1306
+ }
1307
+
1308
+ if (params.findText !== undefined) {
1309
+ try {
1310
+ const found = findContent(urlData.content, normalizeFindQueries(params.findText), params.findMode ?? "case-insensitive");
1311
+ const { text, ...findDetails } = found;
1312
+ return {
1313
+ content: [{ type: "text", text: `# ${urlData.title || urlData.url}\n\n${text}` }],
1314
+ details: { url: urlData.url, title: urlData.title, contentLength: urlData.content.length, findMode: params.findMode ?? "case-insensitive", ...findDetails },
1315
+ };
1316
+ } catch (err) {
1317
+ const error = err instanceof Error ? err.message : String(err);
1318
+ return {
1319
+ content: [{ type: "text", text: `Unable to find ${formatInputValue(params.findText)} in URL ${formatInputValue(urlData.url)} for responseId ${formatInputValue(params.responseId)}: ${error}. Check findText and use a supported findMode.` }],
1320
+ details: { error, url: urlData.url },
1321
+ };
1322
+ }
1323
+ }
1324
+
1325
+ const offset = params.offset ?? 0;
1326
+ const limit = params.limit ?? maxInlineContentChars;
1327
+ if (!Number.isInteger(offset) || offset < 0) {
1328
+ return {
1329
+ content: [{ type: "text", text: `Invalid offset: received ${formatInputValue(offset)} for URL ${formatInputValue(urlData.url)}; offset must be a non-negative integer. Use 0 or a larger integer.` }],
1330
+ details: { error: "Invalid offset", offset },
1331
+ };
1332
+ }
1333
+ if (!Number.isInteger(limit) || limit <= 0 || limit > maxInlineContentChars) {
1334
+ return {
1335
+ content: [{ type: "text", text: `Invalid limit: received ${formatInputValue(limit)} for URL ${formatInputValue(urlData.url)}; limit must be an integer from 1 to ${maxInlineContentChars}. Use a value in that range.` }],
1336
+ details: { error: "Invalid limit", limit, maxLimit: maxInlineContentChars },
1337
+ };
1338
+ }
1339
+ if (offset > urlData.content.length) {
1340
+ return {
1341
+ content: [{ type: "text", text: `Offset ${offset} is out of range for URL ${formatInputValue(urlData.url)} in responseId ${formatInputValue(params.responseId)}. Received offset ${offset}; valid range is 0-${urlData.content.length}. Use an offset within that range.` }],
1342
+ details: { error: "Offset out of range", offset, contentLength: urlData.content.length },
1343
+ };
1344
+ }
1345
+
1346
+ const endOffset = Math.min(offset + limit, urlData.content.length);
1347
+ const contentSlice = urlData.content.slice(offset, endOffset);
1348
+ const hasMore = endOffset < urlData.content.length;
1349
+ let text = `# ${urlData.title || urlData.url}\n\n${contentSlice}`;
1350
+ if (hasMore || offset > 0) {
1351
+ text += `\n\n---\nShowing chars ${offset}-${endOffset} of ${urlData.content.length}.`;
1352
+ if (hasMore) {
1353
+ text += ` Use ${toolNames.getSearchContent}({ responseId: "${params.responseId}", urlIndex: ${selectedUrlIndex}, offset: ${endOffset}, limit: ${limit} }) for the next slice.`;
1354
+ }
1355
+ }
1356
+
1357
+ return {
1358
+ content: [{ type: "text", text }],
1359
+ details: {
1360
+ url: urlData.url,
1361
+ title: urlData.title,
1362
+ contentLength: urlData.content.length,
1363
+ offset,
1364
+ limit,
1365
+ returnedChars: contentSlice.length,
1366
+ nextOffset: hasMore ? endOffset : null,
1367
+ truncated: hasMore,
1368
+ },
1369
+ };
1370
+ }
1371
+
1372
+ return {
1373
+ content: [{ type: "text", text: `Invalid stored data for responseId ${formatInputValue(params.responseId)}: received type ${formatInputValue(data.type)}. Use a responseId returned by ${storedContentSources}.` }],
1374
+ details: { error: "Invalid data" },
1375
+ };
1376
+ }
1377
+
1378
+ return {
1379
+ webSearch,
1380
+ fetchContent,
1381
+ getSearchContent,
1382
+ sourceCheck,
1383
+ buildSearchReturn,
1384
+ };
1385
+ }
1386
+
1387
+ const MAX_STORED_RESULTS = 50;
1388
+ const STANDALONE_DIRECT_IMAGE_ERROR = "Direct image fetch is not supported over MCP; fetch_content returns text there. Fetch images from the Pi extension instead.";
1389
+
1390
+ export interface StandaloneWebToolCore extends WebToolCore {
1391
+ /** Default names of the tools web-search.json enables; hosts list only these. */
1392
+ enabledToolNames: string[];
1393
+ }
1394
+
1395
+ function standaloneError(error: string): WebToolResult {
1396
+ return { content: [{ type: "text", text: `Error: ${error}` }], details: { error }, isError: true };
1397
+ }
1398
+
1399
+ // Marks a final tool result as failed (`isError: true`) for both the Pi tools
1400
+ // and the MCP server. A result with details.error is an error, and so is a call
1401
+ // where nothing requested succeeded: every web_search query, every fetch_content
1402
+ // URL, or every source_check search failed. A working search with zero matches
1403
+ // is not.
1404
+ export function markToolError<T extends Omit<WebToolResult, "structuredContent">>(result: T): T {
1405
+ const { error, queryCount, successfulQueries, urlCount, successful, searchCount, artifact } = result.details;
1406
+ const nothingSucceeded = (typeof queryCount === "number" && queryCount > 0 && successfulQueries === 0)
1407
+ || (typeof urlCount === "number" && urlCount > 0 && successful === 0)
1408
+ || (typeof searchCount === "number" && searchCount > 0 && (artifact as ResearchArtifact).errors?.length === searchCount);
1409
+ return error !== undefined || nothingSucceeded ? { ...result, isError: true } : result;
1410
+ }
1411
+
1412
+ // Explicit requests for providers that need Pi's model registry or login state
1413
+ // fail here instead of silently falling back. Automatic selection already skips
1414
+ // them without a Pi context and picks among the providers usable here.
1415
+ async function standaloneProviderRejection(requested: unknown): Promise<string | undefined> {
1416
+ let selection: SearchProviderSelection;
1417
+ try {
1418
+ selection = resolveRequestedProvider(requested);
1419
+ } catch {
1420
+ return undefined; // The core reports the same validation error.
1421
+ }
1422
+ const explicit: string[] = Array.isArray(selection) ? selection : [selection];
1423
+ if (explicit.includes("kimi")) {
1424
+ return "Kimi search is not supported over MCP: it authenticates only through Pi's /login kimi-coding. Choose another provider, or search from Pi.";
1425
+ }
1426
+ if (explicit.includes("openai")) {
1427
+ let available: boolean;
1428
+ try {
1429
+ available = await isOpenAISearchAvailable();
1430
+ } catch {
1431
+ return undefined; // The core reports the same configuration error.
1432
+ }
1433
+ if (!available) {
1434
+ return `OpenAI search over MCP needs an API key: set openaiApiKey in ${WEB_SEARCH_CONFIG_PATH} or OPENAI_API_KEY. ChatGPT/Codex sign-in, openaiUseProviderBaseUrl, and Pi model credentials work only inside Pi.`;
1435
+ }
1436
+ }
1437
+ return undefined;
1438
+ }
1439
+
1440
+ function standaloneFetchRejection(params: FetchContentCallParams, fetchModes: FetchModeConfig): string | undefined {
1441
+ if (params.mode === "answer") {
1442
+ return "fetch_content mode \"answer\" is not supported over MCP: page answers use Pi's models. Use mode \"readable\" or \"raw\".";
1443
+ }
1444
+ if (params.mode === undefined && fetchModes.defaultMode === "answer") {
1445
+ return `fetch.defaultMode in ${WEB_SEARCH_CONFIG_PATH} is "answer", which is not supported over MCP. Pass mode "readable" or "raw".`;
1446
+ }
1447
+ return undefined;
1448
+ }
1449
+
1450
+ /** Core for hosts without Pi: no extension context, curator, or summaries; results
1451
+ * live in a bounded in-memory store; includeContent waits for the page fetch. */
1452
+ export function createStandaloneWebToolCore(): StandaloneWebToolCore {
1453
+ const config = loadConfig();
1454
+ const settings: WebToolCoreSettings = {
1455
+ toolNames: { ...DEFAULT_TOOL_NAMES },
1456
+ enabledTools: {
1457
+ webSearch: isToolEnabled(config, "webSearch"),
1458
+ sourceCheck: isToolEnabled(config, "sourceCheck"),
1459
+ fetchContent: isToolEnabled(config, "fetchContent"),
1460
+ getSearchContent: isToolEnabled(config, "getSearchContent"),
1461
+ },
1462
+ maxInlineContentChars: getMaxInlineContentChars(config),
1463
+ fetchModes: resolveFetchModeConfig(config),
1464
+ };
1465
+ const storedIds: string[] = [];
1466
+ const remember = (id: string) => {
1467
+ storedIds.push(id);
1468
+ while (storedIds.length > MAX_STORED_RESULTS) deleteResult(storedIds.shift()!);
1469
+ };
1470
+ const core = createWebToolCore({
1471
+ settings,
1472
+ storeFetchedContent(id, data) {
1473
+ storeResult(id, data);
1474
+ remember(id);
1475
+ },
1476
+ publishResult(data) {
1477
+ remember(data.id);
1478
+ },
1479
+ extractOptions: { rejectDirectImages: STANDALONE_DIRECT_IMAGE_ERROR },
1480
+ });
1481
+
1482
+ return {
1483
+ enabledToolNames: (Object.keys(DEFAULT_TOOL_NAMES) as (keyof ToolNames)[])
1484
+ .filter((key) => settings.enabledTools[key])
1485
+ .map((key) => DEFAULT_TOOL_NAMES[key]),
1486
+ async webSearch(params, signal) {
1487
+ const rejection = await standaloneProviderRejection(params.provider);
1488
+ return rejection ? standaloneError(rejection) : markToolError(await core.webSearch(params, signal));
1489
+ },
1490
+ async fetchContent(params, signal) {
1491
+ const rejection = standaloneFetchRejection(params, settings.fetchModes);
1492
+ return rejection ? standaloneError(rejection) : markToolError(await core.fetchContent(params, signal));
1493
+ },
1494
+ async getSearchContent(params, signal) {
1495
+ return markToolError(await core.getSearchContent(params, signal));
1496
+ },
1497
+ async sourceCheck(params, signal) {
1498
+ const rejection = await standaloneProviderRejection(params.provider);
1499
+ return rejection ? standaloneError(rejection) : markToolError(await core.sourceCheck(params, signal));
1500
+ },
1501
+ };
1502
+ }