@humain/terminal 0.0.2 → 0.0.3-beta.0

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 (680) hide show
  1. package/CHANGELOG.md +241 -24
  2. package/README.md +143 -119
  3. package/dist/cli/args.d.ts +4 -2
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +37 -39
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-check.d.ts +19 -0
  8. package/dist/cli/auth-check.d.ts.map +1 -0
  9. package/dist/cli/auth-check.js +50 -0
  10. package/dist/cli/auth-check.js.map +1 -0
  11. package/dist/cli/auth-command.d.ts +24 -0
  12. package/dist/cli/auth-command.d.ts.map +1 -0
  13. package/dist/cli/auth-command.js +103 -0
  14. package/dist/cli/auth-command.js.map +1 -0
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js +2 -2
  17. package/dist/cli/config-selector.js.map +1 -1
  18. package/dist/cli/credential-print.d.ts +5 -15
  19. package/dist/cli/credential-print.d.ts.map +1 -1
  20. package/dist/cli/credential-print.js +42 -83
  21. package/dist/cli/credential-print.js.map +1 -1
  22. package/dist/cli/experimental/auth.d.ts +16 -0
  23. package/dist/cli/experimental/auth.d.ts.map +1 -0
  24. package/dist/cli/experimental/auth.js +13 -0
  25. package/dist/cli/experimental/auth.js.map +1 -0
  26. package/dist/cli/experimental/cli.d.ts +6 -0
  27. package/dist/cli/experimental/cli.d.ts.map +1 -0
  28. package/dist/cli/experimental/cli.js +5 -0
  29. package/dist/cli/experimental/cli.js.map +1 -0
  30. package/dist/cli/experimental/command-options.d.ts +17 -0
  31. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  32. package/dist/cli/experimental/command-options.js +35 -0
  33. package/dist/cli/experimental/command-options.js.map +1 -0
  34. package/dist/cli/experimental/command.d.ts +63 -0
  35. package/dist/cli/experimental/command.d.ts.map +1 -0
  36. package/dist/cli/experimental/command.js +130 -0
  37. package/dist/cli/experimental/command.js.map +1 -0
  38. package/dist/cli/experimental/commands/client.d.ts +13 -0
  39. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  40. package/dist/cli/experimental/commands/client.js +25 -0
  41. package/dist/cli/experimental/commands/client.js.map +1 -0
  42. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  43. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/pi.js +28 -0
  45. package/dist/cli/experimental/commands/pi.js.map +1 -0
  46. package/dist/cli/experimental/commands/server.d.ts +13 -0
  47. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  48. package/dist/cli/experimental/commands/server.js +25 -0
  49. package/dist/cli/experimental/commands/server.js.map +1 -0
  50. package/dist/cli/experimental/transport-address.d.ts +10 -0
  51. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  52. package/dist/cli/experimental/transport-address.js +38 -0
  53. package/dist/cli/experimental/transport-address.js.map +1 -0
  54. package/dist/cli/list-models.d.ts +1 -1
  55. package/dist/cli/list-models.d.ts.map +1 -1
  56. package/dist/cli/list-models.js +2 -2
  57. package/dist/cli/list-models.js.map +1 -1
  58. package/dist/cli/startup-ui.d.ts +1 -1
  59. package/dist/cli/startup-ui.d.ts.map +1 -1
  60. package/dist/cli/startup-ui.js +2 -2
  61. package/dist/cli/startup-ui.js.map +1 -1
  62. package/dist/client/index.d.ts +3 -0
  63. package/dist/client/index.d.ts.map +1 -0
  64. package/dist/client/index.js +3 -0
  65. package/dist/client/index.js.map +1 -0
  66. package/dist/client/remote-session.d.ts +53 -0
  67. package/dist/client/remote-session.d.ts.map +1 -0
  68. package/dist/client/remote-session.js +340 -0
  69. package/dist/client/remote-session.js.map +1 -0
  70. package/dist/client/transcript.d.ts +12 -0
  71. package/dist/client/transcript.d.ts.map +1 -0
  72. package/dist/client/transcript.js +98 -0
  73. package/dist/client/transcript.js.map +1 -0
  74. package/dist/core/agent-session-services.d.ts +1 -0
  75. package/dist/core/agent-session-services.d.ts.map +1 -1
  76. package/dist/core/agent-session-services.js +1 -0
  77. package/dist/core/agent-session-services.js.map +1 -1
  78. package/dist/core/agent-session.d.ts +1 -10
  79. package/dist/core/agent-session.d.ts.map +1 -1
  80. package/dist/core/agent-session.js +72 -70
  81. package/dist/core/agent-session.js.map +1 -1
  82. package/dist/core/auth-storage.d.ts +25 -9
  83. package/dist/core/auth-storage.d.ts.map +1 -1
  84. package/dist/core/auth-storage.js +237 -39
  85. package/dist/core/auth-storage.js.map +1 -1
  86. package/dist/core/extensions/index.d.ts +1 -1
  87. package/dist/core/extensions/index.d.ts.map +1 -1
  88. package/dist/core/extensions/index.js.map +1 -1
  89. package/dist/core/extensions/loader.d.ts.map +1 -1
  90. package/dist/core/extensions/loader.js +60 -41
  91. package/dist/core/extensions/loader.js.map +1 -1
  92. package/dist/core/extensions/runner.d.ts +2 -1
  93. package/dist/core/extensions/runner.d.ts.map +1 -1
  94. package/dist/core/extensions/runner.js +3 -0
  95. package/dist/core/extensions/runner.js.map +1 -1
  96. package/dist/core/extensions/types.d.ts +27 -4
  97. package/dist/core/extensions/types.d.ts.map +1 -1
  98. package/dist/core/extensions/types.js.map +1 -1
  99. package/dist/core/http-dispatcher.d.ts.map +1 -1
  100. package/dist/core/http-dispatcher.js +5 -0
  101. package/dist/core/http-dispatcher.js.map +1 -1
  102. package/dist/core/keybindings.d.ts +45 -5
  103. package/dist/core/keybindings.d.ts.map +1 -1
  104. package/dist/core/keybindings.js.map +1 -1
  105. package/dist/core/model-config.d.ts +29 -5
  106. package/dist/core/model-config.d.ts.map +1 -1
  107. package/dist/core/model-config.js +4 -0
  108. package/dist/core/model-config.js.map +1 -1
  109. package/dist/core/model-registry.d.ts +5 -3
  110. package/dist/core/model-registry.d.ts.map +1 -1
  111. package/dist/core/model-registry.js +13 -10
  112. package/dist/core/model-registry.js.map +1 -1
  113. package/dist/core/model-resolver.d.ts +4 -3
  114. package/dist/core/model-resolver.d.ts.map +1 -1
  115. package/dist/core/model-resolver.js +42 -10
  116. package/dist/core/model-resolver.js.map +1 -1
  117. package/dist/core/model-runtime.d.ts +30 -13
  118. package/dist/core/model-runtime.d.ts.map +1 -1
  119. package/dist/core/model-runtime.js +233 -73
  120. package/dist/core/model-runtime.js.map +1 -1
  121. package/dist/core/models-store.d.ts +12 -7
  122. package/dist/core/models-store.d.ts.map +1 -1
  123. package/dist/core/models-store.js +83 -14
  124. package/dist/core/models-store.js.map +1 -1
  125. package/dist/core/package-manager.d.ts +6 -3
  126. package/dist/core/package-manager.d.ts.map +1 -1
  127. package/dist/core/package-manager.js +80 -61
  128. package/dist/core/package-manager.js.map +1 -1
  129. package/dist/core/pi-manifest.d.ts +8 -0
  130. package/dist/core/pi-manifest.d.ts.map +1 -0
  131. package/dist/core/pi-manifest.js +28 -0
  132. package/dist/core/pi-manifest.js.map +1 -0
  133. package/dist/core/provider-composer.d.ts +4 -1
  134. package/dist/core/provider-composer.d.ts.map +1 -1
  135. package/dist/core/provider-composer.js +36 -15
  136. package/dist/core/provider-composer.js.map +1 -1
  137. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  138. package/dist/core/remote-catalog-provider.js +73 -67
  139. package/dist/core/remote-catalog-provider.js.map +1 -1
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +2 -2
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/runtime-credentials.d.ts +5 -5
  144. package/dist/core/runtime-credentials.d.ts.map +1 -1
  145. package/dist/core/runtime-credentials.js +11 -8
  146. package/dist/core/runtime-credentials.js.map +1 -1
  147. package/dist/core/sdk.d.ts +1 -1
  148. package/dist/core/sdk.d.ts.map +1 -1
  149. package/dist/core/sdk.js +2 -2
  150. package/dist/core/sdk.js.map +1 -1
  151. package/dist/core/session-manager.d.ts.map +1 -1
  152. package/dist/core/session-manager.js +3 -1
  153. package/dist/core/session-manager.js.map +1 -1
  154. package/dist/core/settings-manager.d.ts +12 -0
  155. package/dist/core/settings-manager.d.ts.map +1 -1
  156. package/dist/core/settings-manager.js +40 -16
  157. package/dist/core/settings-manager.js.map +1 -1
  158. package/dist/core/system-prompt.d.ts.map +1 -1
  159. package/dist/core/system-prompt.js +8 -0
  160. package/dist/core/system-prompt.js.map +1 -1
  161. package/dist/core/tools/bash.d.ts +5 -1
  162. package/dist/core/tools/bash.d.ts.map +1 -1
  163. package/dist/core/tools/bash.js +16 -15
  164. package/dist/core/tools/bash.js.map +1 -1
  165. package/dist/core/tools/edit.d.ts +4 -0
  166. package/dist/core/tools/edit.d.ts.map +1 -1
  167. package/dist/core/tools/edit.js +11 -7
  168. package/dist/core/tools/edit.js.map +1 -1
  169. package/dist/core/tools/find.d.ts +7 -0
  170. package/dist/core/tools/find.d.ts.map +1 -1
  171. package/dist/core/tools/find.js +16 -19
  172. package/dist/core/tools/find.js.map +1 -1
  173. package/dist/core/tools/grep.d.ts +4 -0
  174. package/dist/core/tools/grep.d.ts.map +1 -1
  175. package/dist/core/tools/grep.js +5 -1
  176. package/dist/core/tools/grep.js.map +1 -1
  177. package/dist/core/tools/ls.d.ts +4 -0
  178. package/dist/core/tools/ls.d.ts.map +1 -1
  179. package/dist/core/tools/ls.js +5 -1
  180. package/dist/core/tools/ls.js.map +1 -1
  181. package/dist/core/tools/read.d.ts +4 -0
  182. package/dist/core/tools/read.d.ts.map +1 -1
  183. package/dist/core/tools/read.js +7 -3
  184. package/dist/core/tools/read.js.map +1 -1
  185. package/dist/core/tools/write.d.ts +4 -0
  186. package/dist/core/tools/write.d.ts.map +1 -1
  187. package/dist/core/tools/write.js +6 -2
  188. package/dist/core/tools/write.js.map +1 -1
  189. package/dist/extensions/llama/index.d.ts.map +1 -1
  190. package/dist/extensions/llama/index.js +11 -2
  191. package/dist/extensions/llama/index.js.map +1 -1
  192. package/dist/extensions/llama/provider.d.ts.map +1 -1
  193. package/dist/extensions/llama/provider.js +21 -7
  194. package/dist/extensions/llama/provider.js.map +1 -1
  195. package/dist/humain/agent-execution-protocol.d.ts +218 -0
  196. package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
  197. package/dist/humain/agent-execution-protocol.js +204 -0
  198. package/dist/humain/agent-execution-protocol.js.map +1 -0
  199. package/dist/humain/agent-execution-runtime.d.ts +35 -0
  200. package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
  201. package/dist/humain/agent-execution-runtime.js +170 -0
  202. package/dist/humain/agent-execution-runtime.js.map +1 -0
  203. package/dist/humain/index.d.ts.map +1 -1
  204. package/dist/humain/index.js +8 -7
  205. package/dist/humain/index.js.map +1 -1
  206. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  207. package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
  208. package/dist/humain/mcp-adapter/vendor/README.md +733 -0
  209. package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
  210. package/dist/humain/mcp-adapter/vendor/agent-dir.ts +60 -0
  211. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
  212. package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
  213. package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
  214. package/dist/humain/mcp-adapter/vendor/cli.js +209 -0
  215. package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
  216. package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
  217. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
  218. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +604 -0
  219. package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
  220. package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
  221. package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
  222. package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
  223. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
  224. package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
  225. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +15923 -0
  226. package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
  227. package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
  228. package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
  229. package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
  230. package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
  231. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
  232. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
  233. package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
  234. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
  235. package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
  236. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
  237. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
  238. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
  239. package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
  240. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
  241. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +666 -0
  242. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
  243. package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
  244. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +353 -0
  245. package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
  246. package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
  247. package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
  248. package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
  249. package/dist/humain/mcp-adapter/vendor/package.json +178 -0
  250. package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
  251. package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
  252. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
  253. package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
  254. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
  255. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
  256. package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
  257. package/dist/humain/mcp-adapter/vendor/server-manager.ts +1124 -0
  258. package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
  259. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
  260. package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
  261. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
  262. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +276 -0
  263. package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
  264. package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
  265. package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
  266. package/dist/humain/mcp-adapter/vendor/types.ts +859 -0
  267. package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
  268. package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
  269. package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
  270. package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
  271. package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
  272. package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
  273. package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
  274. package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
  275. package/dist/humain/mcp-adapter.d.ts +3 -0
  276. package/dist/humain/mcp-adapter.d.ts.map +1 -0
  277. package/dist/humain/mcp-adapter.js +5 -0
  278. package/dist/humain/mcp-adapter.js.map +1 -0
  279. package/dist/humain/pi-agent-execution-host.d.ts +34 -0
  280. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
  281. package/dist/humain/pi-agent-execution-host.js +77 -0
  282. package/dist/humain/pi-agent-execution-host.js.map +1 -0
  283. package/dist/humain/web-access/host.d.ts +4 -0
  284. package/dist/humain/web-access/host.d.ts.map +1 -0
  285. package/dist/humain/web-access/host.js +3 -0
  286. package/dist/humain/web-access/host.js.map +1 -0
  287. package/dist/humain/web-access/index.d.ts +3 -0
  288. package/dist/humain/web-access/index.d.ts.map +1 -0
  289. package/dist/humain/web-access/index.js +5 -0
  290. package/dist/humain/web-access/index.js.map +1 -0
  291. package/dist/humain/web-access/vendor/activity.d.ts +34 -0
  292. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
  293. package/dist/humain/web-access/vendor/activity.js +68 -0
  294. package/dist/humain/web-access/vendor/activity.js.map +1 -0
  295. package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
  296. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
  297. package/dist/humain/web-access/vendor/anysearch.js +167 -0
  298. package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
  299. package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
  300. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
  301. package/dist/humain/web-access/vendor/bocha.js +219 -0
  302. package/dist/humain/web-access/vendor/bocha.js.map +1 -0
  303. package/dist/humain/web-access/vendor/brave.d.ts +4 -0
  304. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
  305. package/dist/humain/web-access/vendor/brave.js +194 -0
  306. package/dist/humain/web-access/vendor/brave.js.map +1 -0
  307. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
  308. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
  309. package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
  310. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
  311. package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
  312. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
  313. package/dist/humain/web-access/vendor/brightdata.js +519 -0
  314. package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
  315. package/dist/humain/web-access/vendor/chrome-cookies.d.ts +10 -0
  316. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
  317. package/dist/humain/web-access/vendor/chrome-cookies.js +438 -0
  318. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
  319. package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
  320. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
  321. package/dist/humain/web-access/vendor/content-find.js +117 -0
  322. package/dist/humain/web-access/vendor/content-find.js.map +1 -0
  323. package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
  324. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
  325. package/dist/humain/web-access/vendor/credential-source.js +151 -0
  326. package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
  327. package/dist/humain/web-access/vendor/curator-page.d.ts +29 -0
  328. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
  329. package/dist/humain/web-access/vendor/curator-page.js +3554 -0
  330. package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
  331. package/dist/humain/web-access/vendor/curator-server.d.ts +93 -0
  332. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
  333. package/dist/humain/web-access/vendor/curator-server.js +688 -0
  334. package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
  335. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
  336. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
  337. package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
  338. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
  339. package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
  340. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
  341. package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
  342. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
  343. package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
  344. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
  345. package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
  346. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
  347. package/dist/humain/web-access/vendor/exa.d.ts +10 -0
  348. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
  349. package/dist/humain/web-access/vendor/exa.js +426 -0
  350. package/dist/humain/web-access/vendor/exa.js.map +1 -0
  351. package/dist/humain/web-access/vendor/extract.d.ts +46 -0
  352. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
  353. package/dist/humain/web-access/vendor/extract.js +1064 -0
  354. package/dist/humain/web-access/vendor/extract.js.map +1 -0
  355. package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
  356. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
  357. package/dist/humain/web-access/vendor/feature-config.js +27 -0
  358. package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
  359. package/dist/humain/web-access/vendor/fetch-params.d.ts +25 -0
  360. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
  361. package/dist/humain/web-access/vendor/fetch-params.js +57 -0
  362. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
  363. package/dist/humain/web-access/vendor/firecrawl.d.ts +12 -0
  364. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
  365. package/dist/humain/web-access/vendor/firecrawl.js +239 -0
  366. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
  367. package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
  368. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
  369. package/dist/humain/web-access/vendor/gemini-api.js +230 -0
  370. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
  371. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
  372. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
  373. package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
  374. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
  375. package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
  376. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
  377. package/dist/humain/web-access/vendor/gemini-search.js +814 -0
  378. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
  379. package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
  380. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
  381. package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
  382. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
  383. package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
  384. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
  385. package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
  386. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
  387. package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
  388. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
  389. package/dist/humain/web-access/vendor/gemini-web.js +385 -0
  390. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
  391. package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
  392. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
  393. package/dist/humain/web-access/vendor/github-api.js +160 -0
  394. package/dist/humain/web-access/vendor/github-api.js.map +1 -0
  395. package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
  396. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
  397. package/dist/humain/web-access/vendor/github-extract.js +635 -0
  398. package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
  399. package/dist/humain/web-access/vendor/index.d.ts +4 -0
  400. package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
  401. package/dist/humain/web-access/vendor/index.js +3002 -0
  402. package/dist/humain/web-access/vendor/index.js.map +1 -0
  403. package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
  404. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
  405. package/dist/humain/web-access/vendor/jina-search.js +255 -0
  406. package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
  407. package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
  408. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
  409. package/dist/humain/web-access/vendor/kagi.js +262 -0
  410. package/dist/humain/web-access/vendor/kagi.js.map +1 -0
  411. package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
  412. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
  413. package/dist/humain/web-access/vendor/ollama.js +216 -0
  414. package/dist/humain/web-access/vendor/ollama.js.map +1 -0
  415. package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
  416. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
  417. package/dist/humain/web-access/vendor/openai-search.js +459 -0
  418. package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
  419. package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
  420. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
  421. package/dist/humain/web-access/vendor/page-query.js +79 -0
  422. package/dist/humain/web-access/vendor/page-query.js.map +1 -0
  423. package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
  424. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
  425. package/dist/humain/web-access/vendor/parallel.js +343 -0
  426. package/dist/humain/web-access/vendor/parallel.js.map +1 -0
  427. package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
  428. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
  429. package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
  430. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
  431. package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
  432. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
  433. package/dist/humain/web-access/vendor/perplexity.js +159 -0
  434. package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
  435. package/dist/humain/web-access/vendor/querit.d.ts +10 -0
  436. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
  437. package/dist/humain/web-access/vendor/querit.js +335 -0
  438. package/dist/humain/web-access/vendor/querit.js.map +1 -0
  439. package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
  440. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
  441. package/dist/humain/web-access/vendor/render-search-error.js +130 -0
  442. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
  443. package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
  444. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
  445. package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
  446. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
  447. package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
  448. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
  449. package/dist/humain/web-access/vendor/search1api.js +251 -0
  450. package/dist/humain/web-access/vendor/search1api.js.map +1 -0
  451. package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
  452. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
  453. package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
  454. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
  455. package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
  456. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
  457. package/dist/humain/web-access/vendor/searxng.js +238 -0
  458. package/dist/humain/web-access/vendor/searxng.js.map +1 -0
  459. package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
  460. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
  461. package/dist/humain/web-access/vendor/serpbase.js +211 -0
  462. package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
  463. package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
  464. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
  465. package/dist/humain/web-access/vendor/serpdive.js +267 -0
  466. package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
  467. package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
  468. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
  469. package/dist/humain/web-access/vendor/source-check.js +205 -0
  470. package/dist/humain/web-access/vendor/source-check.js.map +1 -0
  471. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
  472. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
  473. package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
  474. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
  475. package/dist/humain/web-access/vendor/storage.d.ts +55 -0
  476. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
  477. package/dist/humain/web-access/vendor/storage.js +485 -0
  478. package/dist/humain/web-access/vendor/storage.js.map +1 -0
  479. package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
  480. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
  481. package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
  482. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
  483. package/dist/humain/web-access/vendor/summary-review.d.ts +24 -0
  484. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
  485. package/dist/humain/web-access/vendor/summary-review.js +341 -0
  486. package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
  487. package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
  488. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
  489. package/dist/humain/web-access/vendor/tavily.js +194 -0
  490. package/dist/humain/web-access/vendor/tavily.js.map +1 -0
  491. package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
  492. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
  493. package/dist/humain/web-access/vendor/tinyfish.js +331 -0
  494. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
  495. package/dist/humain/web-access/vendor/utils.d.ts +20 -0
  496. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
  497. package/dist/humain/web-access/vendor/utils.js +91 -0
  498. package/dist/humain/web-access/vendor/utils.js.map +1 -0
  499. package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
  500. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
  501. package/dist/humain/web-access/vendor/video-extract.js +335 -0
  502. package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
  503. package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
  504. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
  505. package/dist/humain/web-access/vendor/xai-search.js +331 -0
  506. package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
  507. package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
  508. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
  509. package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
  510. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
  511. package/dist/index.d.ts +7 -4
  512. package/dist/index.d.ts.map +1 -1
  513. package/dist/index.js +5 -2
  514. package/dist/index.js.map +1 -1
  515. package/dist/main.d.ts +2 -2
  516. package/dist/main.d.ts.map +1 -1
  517. package/dist/main.js +169 -102
  518. package/dist/main.js.map +1 -1
  519. package/dist/modes/agent-exec-mode.d.ts +14 -0
  520. package/dist/modes/agent-exec-mode.d.ts.map +1 -0
  521. package/dist/modes/agent-exec-mode.js +92 -0
  522. package/dist/modes/agent-exec-mode.js.map +1 -0
  523. package/dist/modes/index.d.ts +4 -2
  524. package/dist/modes/index.d.ts.map +1 -1
  525. package/dist/modes/index.js +2 -1
  526. package/dist/modes/index.js.map +1 -1
  527. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  528. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  529. package/dist/modes/interactive/components/assistant-message.js +13 -4
  530. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  531. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  532. package/dist/modes/interactive/components/custom-editor.js +7 -0
  533. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  534. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  535. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  536. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  537. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  538. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  539. package/dist/modes/interactive/components/footer.js +1 -1
  540. package/dist/modes/interactive/components/footer.js.map +1 -1
  541. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  542. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  543. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  544. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  545. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  546. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  547. package/dist/modes/interactive/components/mermaid.js +75 -0
  548. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  549. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  550. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  551. package/dist/modes/interactive/components/model-selector.js +16 -4
  552. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  553. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  554. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  555. package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
  556. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  557. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  558. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  559. package/dist/modes/interactive/components/settings-selector.js +30 -0
  560. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  561. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  562. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  563. package/dist/modes/interactive/components/user-message.js +9 -2
  564. package/dist/modes/interactive/components/user-message.js.map +1 -1
  565. package/dist/modes/interactive/interactive-mode.d.ts +45 -9
  566. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  567. package/dist/modes/interactive/interactive-mode.js +581 -211
  568. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  569. package/dist/modes/interactive/theme/dark.json +1 -0
  570. package/dist/modes/interactive/theme/light.json +1 -0
  571. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  572. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  573. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  574. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  575. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  576. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  577. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  578. package/dist/modes/interactive/theme/theme.js +24 -6
  579. package/dist/modes/interactive/theme/theme.js.map +1 -1
  580. package/dist/modes/json-event.d.ts +28 -0
  581. package/dist/modes/json-event.d.ts.map +1 -0
  582. package/dist/modes/json-event.js +12 -0
  583. package/dist/modes/json-event.js.map +1 -0
  584. package/dist/modes/print-mode.d.ts.map +1 -1
  585. package/dist/modes/print-mode.js +12 -2
  586. package/dist/modes/print-mode.js.map +1 -1
  587. package/dist/modes/rpc/rpc-client.d.ts +12 -5
  588. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  589. package/dist/modes/rpc/rpc-client.js +55 -1
  590. package/dist/modes/rpc/rpc-client.js.map +1 -1
  591. package/dist/modes/rpc/rpc-mode.d.ts +1 -1
  592. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  593. package/dist/modes/rpc/rpc-mode.js +13 -3
  594. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  595. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  596. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  597. package/dist/modes/rpc/rpc-types.js.map +1 -1
  598. package/dist/package-manager-cli.d.ts.map +1 -1
  599. package/dist/package-manager-cli.js +11 -9
  600. package/dist/package-manager-cli.js.map +1 -1
  601. package/dist/rpc-entry.d.ts.map +1 -1
  602. package/dist/rpc-entry.js +3 -2
  603. package/dist/rpc-entry.js.map +1 -1
  604. package/dist/server/create-harness.d.ts +26 -0
  605. package/dist/server/create-harness.d.ts.map +1 -0
  606. package/dist/server/create-harness.js +104 -0
  607. package/dist/server/create-harness.js.map +1 -0
  608. package/dist/utils/abort.d.ts +5 -0
  609. package/dist/utils/abort.d.ts.map +1 -0
  610. package/dist/utils/abort.js +48 -0
  611. package/dist/utils/abort.js.map +1 -0
  612. package/dist/utils/clipboard.d.ts +1 -1
  613. package/dist/utils/clipboard.d.ts.map +1 -1
  614. package/dist/utils/clipboard.js +22 -2
  615. package/dist/utils/clipboard.js.map +1 -1
  616. package/dist/utils/management-http.d.ts +23 -0
  617. package/dist/utils/management-http.d.ts.map +1 -0
  618. package/dist/utils/management-http.js +50 -0
  619. package/dist/utils/management-http.js.map +1 -0
  620. package/dist/utils/paths.d.ts +3 -0
  621. package/dist/utils/paths.d.ts.map +1 -1
  622. package/dist/utils/paths.js +23 -1
  623. package/dist/utils/paths.js.map +1 -1
  624. package/dist/utils/tool-result-images.d.ts +19 -0
  625. package/dist/utils/tool-result-images.d.ts.map +1 -0
  626. package/dist/utils/tool-result-images.js +45 -0
  627. package/dist/utils/tool-result-images.js.map +1 -0
  628. package/dist/utils/tools-manager.d.ts.map +1 -1
  629. package/dist/utils/tools-manager.js +13 -25
  630. package/dist/utils/tools-manager.js.map +1 -1
  631. package/dist/utils/version-check.d.ts +4 -0
  632. package/dist/utils/version-check.d.ts.map +1 -1
  633. package/dist/utils/version-check.js +23 -5
  634. package/dist/utils/version-check.js.map +1 -1
  635. package/docs/compaction.md +2 -2
  636. package/docs/custom-provider.md +7 -5
  637. package/docs/extensions.md +30 -5
  638. package/docs/humain-terminal.md +21 -1
  639. package/docs/json.md +24 -19
  640. package/docs/keybindings.md +46 -14
  641. package/docs/models.md +32 -11
  642. package/docs/providers.md +9 -1
  643. package/docs/quickstart.md +39 -37
  644. package/docs/rpc.md +31 -11
  645. package/docs/sdk.md +21 -2
  646. package/docs/security.md +21 -21
  647. package/docs/session-format.md +14 -14
  648. package/docs/settings.md +4 -1
  649. package/docs/themes.md +5 -3
  650. package/docs/usage.md +7 -0
  651. package/examples/extensions/custom-compaction.ts +3 -18
  652. package/examples/extensions/custom-provider-anthropic/index.ts +5 -1
  653. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  654. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  655. package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
  656. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  657. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  658. package/examples/extensions/gondolin/package-lock.json +2 -2
  659. package/examples/extensions/gondolin/package.json +1 -1
  660. package/examples/extensions/handoff.ts +4 -13
  661. package/examples/extensions/qna.ts +5 -9
  662. package/examples/extensions/sandbox/package-lock.json +2 -2
  663. package/examples/extensions/sandbox/package.json +1 -1
  664. package/examples/extensions/summarize.ts +9 -20
  665. package/examples/extensions/with-deps/package-lock.json +2 -2
  666. package/examples/extensions/with-deps/package.json +1 -1
  667. package/examples/rpc-extension-ui.ts +11 -2
  668. package/examples/sdk/02-custom-model.ts +2 -3
  669. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  670. package/examples/sdk/12-full-control.ts +1 -1
  671. package/examples/sdk/README.md +1 -1
  672. package/npm-shrinkwrap.json +2771 -535
  673. package/package.json +40 -11
  674. package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
  675. package/src/humain/mcp-adapter/upstream.json +7 -0
  676. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  677. package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
  678. package/src/humain/web-access/UPSTREAM.md +17 -0
  679. package/src/humain/web-access/upstream.json +23 -0
  680. package/src/humain/web-access/vendor/LICENSE +21 -0
@@ -0,0 +1,68 @@
1
+ export class ActivityMonitor {
2
+ entries = [];
3
+ maxEntries = 10;
4
+ listeners = new Set();
5
+ rateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };
6
+ nextId = 1;
7
+ logStart(partial) {
8
+ const id = `act-${this.nextId++}`;
9
+ const entry = {
10
+ ...partial,
11
+ id,
12
+ startTime: Date.now(),
13
+ status: null,
14
+ };
15
+ this.entries.push(entry);
16
+ if (this.entries.length > this.maxEntries) {
17
+ this.entries.shift();
18
+ }
19
+ this.notify();
20
+ return id;
21
+ }
22
+ logComplete(id, status) {
23
+ const entry = this.entries.find((e) => e.id === id);
24
+ if (entry) {
25
+ entry.endTime = Date.now();
26
+ entry.status = status;
27
+ this.notify();
28
+ }
29
+ }
30
+ logError(id, error) {
31
+ const entry = this.entries.find((e) => e.id === id);
32
+ if (entry) {
33
+ entry.endTime = Date.now();
34
+ entry.error = error;
35
+ this.notify();
36
+ }
37
+ }
38
+ getEntries() {
39
+ return this.entries;
40
+ }
41
+ getRateLimitInfo() {
42
+ return this.rateLimitInfo;
43
+ }
44
+ updateRateLimit(info) {
45
+ this.rateLimitInfo = info;
46
+ this.notify();
47
+ }
48
+ onUpdate(callback) {
49
+ this.listeners.add(callback);
50
+ return () => this.listeners.delete(callback);
51
+ }
52
+ clear() {
53
+ this.entries = [];
54
+ this.rateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };
55
+ this.notify();
56
+ }
57
+ notify() {
58
+ for (const cb of this.listeners) {
59
+ try {
60
+ cb();
61
+ }
62
+ catch {
63
+ }
64
+ }
65
+ }
66
+ }
67
+ export const activityMonitor = new ActivityMonitor();
68
+ //# sourceMappingURL=activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/activity.ts"],"names":[],"mappings":"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","sourcesContent":["// Types\nexport interface ActivityEntry {\n\tid: string;\n\ttype: \"api\" | \"fetch\";\n\tstartTime: number;\n\tendTime?: number;\n\n\t// For API calls\n\tquery?: string;\n\n\t// For URL fetches\n\turl?: string;\n\n\t// Result - status is number (HTTP code) or null (pending/network error)\n\tstatus: number | null;\n\terror?: string;\n}\n\nexport interface RateLimitInfo {\n\tused: number;\n\tmax: number;\n\toldestTimestamp: number | null;\n\twindowMs: number;\n}\n\nexport class ActivityMonitor {\n\tprivate entries: ActivityEntry[] = [];\n\tprivate readonly maxEntries = 10;\n\tprivate listeners = new Set<() => void>();\n\tprivate rateLimitInfo: RateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };\n\tprivate nextId = 1;\n\n\tlogStart(partial: Omit<ActivityEntry, \"id\" | \"startTime\" | \"status\">): string {\n\t\tconst id = `act-${this.nextId++}`;\n\t\tconst entry: ActivityEntry = {\n\t\t\t...partial,\n\t\t\tid,\n\t\t\tstartTime: Date.now(),\n\t\t\tstatus: null,\n\t\t};\n\t\tthis.entries.push(entry);\n\t\tif (this.entries.length > this.maxEntries) {\n\t\t\tthis.entries.shift();\n\t\t}\n\t\tthis.notify();\n\t\treturn id;\n\t}\n\n\tlogComplete(id: string, status: number): void {\n\t\tconst entry = this.entries.find((e) => e.id === id);\n\t\tif (entry) {\n\t\t\tentry.endTime = Date.now();\n\t\t\tentry.status = status;\n\t\t\tthis.notify();\n\t\t}\n\t}\n\n\tlogError(id: string, error: string): void {\n\t\tconst entry = this.entries.find((e) => e.id === id);\n\t\tif (entry) {\n\t\t\tentry.endTime = Date.now();\n\t\t\tentry.error = error;\n\t\t\tthis.notify();\n\t\t}\n\t}\n\n\tgetEntries(): readonly ActivityEntry[] {\n\t\treturn this.entries;\n\t}\n\n\tgetRateLimitInfo(): RateLimitInfo {\n\t\treturn this.rateLimitInfo;\n\t}\n\n\tupdateRateLimit(info: RateLimitInfo): void {\n\t\tthis.rateLimitInfo = info;\n\t\tthis.notify();\n\t}\n\n\tonUpdate(callback: () => void): () => void {\n\t\tthis.listeners.add(callback);\n\t\treturn () => this.listeners.delete(callback);\n\t}\n\n\tclear(): void {\n\t\tthis.entries = [];\n\t\tthis.rateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };\n\t\tthis.notify();\n\t}\n\n\tprivate notify(): void {\n\t\tfor (const cb of this.listeners) {\n\t\t\ttry {\n\t\t\t\tcb();\n\t\t\t} catch {\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport const activityMonitor = new ActivityMonitor();\n"]}
@@ -0,0 +1,8 @@
1
+ import type { SearchOptions, SearchResponse } from "./perplexity.ts";
2
+ interface AnySearchSearchOptions extends SearchOptions {
3
+ includeContent?: boolean;
4
+ }
5
+ export declare function isAnySearchAvailable(): boolean;
6
+ export declare function searchWithAnySearch(query: string, options?: AnySearchSearchOptions): Promise<SearchResponse>;
7
+ export {};
8
+ //# sourceMappingURL=anysearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anysearch.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/anysearch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAmBrE,UAAU,sBAAuB,SAAQ,aAAa;IACrD,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAiGD,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,cAAc,CAAC,CAkEtH","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst ANYSEARCH_API_URL = \"https://api.anysearch.com/v1/search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 30_000;\n\ninterface WebSearchConfig {\n\tanysearchApiKey?: unknown;\n}\n\ninterface AnySearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n\tcontent: string;\n}\n\ninterface AnySearchSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\ninterface AnySearchResponse {\n\tcode: 0;\n\tdata: {\n\t\tresults: AnySearchResult[];\n\t\tmetadata: Record<string, unknown>;\n\t};\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"AnySearch\",\n\t\tconfiguredValue: loadConfig().anysearchApiKey,\n\t\tenvironmentValue: process.env.ANYSEARCH_API_KEY,\n\t\tsignal,\n\t});\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`AnySearch API returned invalid response: ${message}`);\n}\n\nfunction parseResponse(value: unknown): AnySearchResponse {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow invalidResponse(\"expected an object envelope\");\n\t}\n\tconst envelope = value as Record<string, unknown>;\n\tif (envelope.code !== 0) throw invalidResponse(\"expected code 0\");\n\tif (!envelope.data || typeof envelope.data !== \"object\" || Array.isArray(envelope.data)) {\n\t\tthrow invalidResponse(\"expected data object\");\n\t}\n\tconst data = envelope.data as Record<string, unknown>;\n\tif (!Array.isArray(data.results)) throw invalidResponse(\"expected data.results array\");\n\tif (!data.metadata || typeof data.metadata !== \"object\" || Array.isArray(data.metadata)) {\n\t\tthrow invalidResponse(\"expected data.metadata object\");\n\t}\n\n\tconst results: AnySearchResult[] = [];\n\tfor (const [index, value] of data.results.entries()) {\n\t\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\t\tthrow invalidResponse(`expected data.results[${index}] object`);\n\t\t}\n\t\tconst result = value as Record<string, unknown>;\n\t\tconst { title, url, snippet, content } = result;\n\t\tif (typeof title !== \"string\") throw invalidResponse(`expected data.results[${index}].title string`);\n\t\tif (typeof url !== \"string\") throw invalidResponse(`expected data.results[${index}].url string`);\n\t\tif (typeof snippet !== \"string\") throw invalidResponse(`expected data.results[${index}].snippet string`);\n\t\tif (typeof content !== \"string\") throw invalidResponse(`expected data.results[${index}].content string`);\n\t\tif (!url) throw invalidResponse(`expected data.results[${index}].url to be non-empty`);\n\t\tresults.push({ title, url, snippet, content });\n\t}\n\n\treturn { code: 0, data: { results, metadata: data.metadata as Record<string, unknown> } };\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\nexport function isAnySearchAvailable(): boolean {\n\treturn true;\n}\n\nexport async function searchWithAnySearch(query: string, options: AnySearchSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await getApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst body = { query, max_results: numResults };\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\n\ttry {\n\t\tresponse = await fetch(ANYSEARCH_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t\tsignal: options.signal\n\t\t\t\t? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])\n\t\t\t\t: AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`AnySearch API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`AnySearch API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\n\tlet data: AnySearchResponse;\n\ttry {\n\t\tdata = parseResponse(rawData);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow err;\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = data.data.results.slice(0, numResults).map((result) => ({\n\t\ttitle: result.title,\n\t\turl: result.url,\n\t\tsnippet: result.snippet,\n\t}));\n\tconst mapped: SearchResponse = { answer: buildAnswer(results), results };\n\tif (options.includeContent) {\n\t\tconst inlineContent: ExtractedContent[] = data.data.results.slice(0, numResults)\n\t\t\t.filter(result => result.content.length > 0)\n\t\t\t.map(result => ({ url: result.url, title: result.title, content: result.content, error: null }));\n\t\tif (inlineContent.length > 0) mapped.inlineContent = inlineContent;\n\t}\n\treturn mapped;\n}\n"]}
@@ -0,0 +1,167 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { activityMonitor } from "./activity.js";
3
+ import { redactCredential, resolveCredential } from "./credential-source.js";
4
+ import { getWebSearchConfigPath } from "./utils.js";
5
+ const ANYSEARCH_API_URL = "https://api.anysearch.com/v1/search";
6
+ const CONFIG_PATH = getWebSearchConfigPath();
7
+ const SEARCH_TIMEOUT_MS = 30_000;
8
+ let cachedConfig = null;
9
+ function loadConfig() {
10
+ if (cachedConfig)
11
+ return cachedConfig;
12
+ if (!existsSync(CONFIG_PATH)) {
13
+ cachedConfig = {};
14
+ return cachedConfig;
15
+ }
16
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
17
+ let parsed;
18
+ try {
19
+ parsed = JSON.parse(raw);
20
+ }
21
+ catch (err) {
22
+ const message = err instanceof Error ? err.message : String(err);
23
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
24
+ }
25
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
26
+ throw new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);
27
+ }
28
+ cachedConfig = parsed;
29
+ return cachedConfig;
30
+ }
31
+ async function getApiKey(signal) {
32
+ return resolveCredential({
33
+ provider: "AnySearch",
34
+ configuredValue: loadConfig().anysearchApiKey,
35
+ environmentValue: process.env.ANYSEARCH_API_KEY,
36
+ signal,
37
+ });
38
+ }
39
+ function normalizeCount(value) {
40
+ if (typeof value !== "number" || !Number.isFinite(value))
41
+ return 5;
42
+ return Math.max(1, Math.min(Math.floor(value), 20));
43
+ }
44
+ function errorMessage(err) {
45
+ return err instanceof Error ? err.message : String(err);
46
+ }
47
+ function invalidResponse(message) {
48
+ return new Error(`AnySearch API returned invalid response: ${message}`);
49
+ }
50
+ function parseResponse(value) {
51
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
52
+ throw invalidResponse("expected an object envelope");
53
+ }
54
+ const envelope = value;
55
+ if (envelope.code !== 0)
56
+ throw invalidResponse("expected code 0");
57
+ if (!envelope.data || typeof envelope.data !== "object" || Array.isArray(envelope.data)) {
58
+ throw invalidResponse("expected data object");
59
+ }
60
+ const data = envelope.data;
61
+ if (!Array.isArray(data.results))
62
+ throw invalidResponse("expected data.results array");
63
+ if (!data.metadata || typeof data.metadata !== "object" || Array.isArray(data.metadata)) {
64
+ throw invalidResponse("expected data.metadata object");
65
+ }
66
+ const results = [];
67
+ for (const [index, value] of data.results.entries()) {
68
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
69
+ throw invalidResponse(`expected data.results[${index}] object`);
70
+ }
71
+ const result = value;
72
+ const { title, url, snippet, content } = result;
73
+ if (typeof title !== "string")
74
+ throw invalidResponse(`expected data.results[${index}].title string`);
75
+ if (typeof url !== "string")
76
+ throw invalidResponse(`expected data.results[${index}].url string`);
77
+ if (typeof snippet !== "string")
78
+ throw invalidResponse(`expected data.results[${index}].snippet string`);
79
+ if (typeof content !== "string")
80
+ throw invalidResponse(`expected data.results[${index}].content string`);
81
+ if (!url)
82
+ throw invalidResponse(`expected data.results[${index}].url to be non-empty`);
83
+ results.push({ title, url, snippet, content });
84
+ }
85
+ return { code: 0, data: { results, metadata: data.metadata } };
86
+ }
87
+ function buildAnswer(results) {
88
+ return results
89
+ .map((result) => result.snippet
90
+ ? `${result.snippet}\nSource: ${result.title} (${result.url})`
91
+ : `Source: ${result.title} (${result.url})`)
92
+ .join("\n\n");
93
+ }
94
+ export function isAnySearchAvailable() {
95
+ return true;
96
+ }
97
+ export async function searchWithAnySearch(query, options = {}) {
98
+ const apiKey = await getApiKey(options.signal);
99
+ const numResults = normalizeCount(options.numResults);
100
+ const body = { query, max_results: numResults };
101
+ const activityId = activityMonitor.logStart({ type: "api", query });
102
+ let response;
103
+ try {
104
+ response = await fetch(ANYSEARCH_API_URL, {
105
+ method: "POST",
106
+ headers: {
107
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
108
+ "Content-Type": "application/json",
109
+ },
110
+ body: JSON.stringify(body),
111
+ signal: options.signal
112
+ ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])
113
+ : AbortSignal.timeout(SEARCH_TIMEOUT_MS),
114
+ });
115
+ }
116
+ catch (err) {
117
+ const message = errorMessage(err);
118
+ const redactedMessage = redactCredential(message, apiKey);
119
+ if (redactedMessage.toLowerCase().includes("abort"))
120
+ activityMonitor.logComplete(activityId, 0);
121
+ else
122
+ activityMonitor.logError(activityId, redactedMessage);
123
+ if (redactedMessage === message)
124
+ throw err;
125
+ const redactedError = new Error(redactedMessage);
126
+ if (err instanceof Error)
127
+ redactedError.name = err.name;
128
+ throw redactedError;
129
+ }
130
+ if (!response.ok) {
131
+ activityMonitor.logComplete(activityId, response.status);
132
+ const errorText = redactCredential(await response.text(), apiKey);
133
+ throw new Error(`AnySearch API error ${response.status}: ${errorText.slice(0, 300)}`);
134
+ }
135
+ let rawData;
136
+ try {
137
+ rawData = await response.json();
138
+ }
139
+ catch (err) {
140
+ activityMonitor.logComplete(activityId, response.status);
141
+ throw new Error(`AnySearch API returned invalid JSON: ${errorMessage(err)}`);
142
+ }
143
+ let data;
144
+ try {
145
+ data = parseResponse(rawData);
146
+ }
147
+ catch (err) {
148
+ activityMonitor.logComplete(activityId, response.status);
149
+ throw err;
150
+ }
151
+ activityMonitor.logComplete(activityId, response.status);
152
+ const results = data.data.results.slice(0, numResults).map((result) => ({
153
+ title: result.title,
154
+ url: result.url,
155
+ snippet: result.snippet,
156
+ }));
157
+ const mapped = { answer: buildAnswer(results), results };
158
+ if (options.includeContent) {
159
+ const inlineContent = data.data.results.slice(0, numResults)
160
+ .filter(result => result.content.length > 0)
161
+ .map(result => ({ url: result.url, title: result.title, content: result.content, error: null }));
162
+ if (inlineContent.length > 0)
163
+ mapped.inlineContent = inlineContent;
164
+ }
165
+ return mapped;
166
+ }
167
+ //# sourceMappingURL=anysearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anysearch.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/anysearch.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst ANYSEARCH_API_URL = \"https://api.anysearch.com/v1/search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 30_000;\n\ninterface WebSearchConfig {\n\tanysearchApiKey?: unknown;\n}\n\ninterface AnySearchResult {\n\ttitle: string;\n\turl: string;\n\tsnippet: string;\n\tcontent: string;\n}\n\ninterface AnySearchSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\ninterface AnySearchResponse {\n\tcode: 0;\n\tdata: {\n\t\tresults: AnySearchResult[];\n\t\tmetadata: Record<string, unknown>;\n\t};\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"AnySearch\",\n\t\tconfiguredValue: loadConfig().anysearchApiKey,\n\t\tenvironmentValue: process.env.ANYSEARCH_API_KEY,\n\t\tsignal,\n\t});\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`AnySearch API returned invalid response: ${message}`);\n}\n\nfunction parseResponse(value: unknown): AnySearchResponse {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow invalidResponse(\"expected an object envelope\");\n\t}\n\tconst envelope = value as Record<string, unknown>;\n\tif (envelope.code !== 0) throw invalidResponse(\"expected code 0\");\n\tif (!envelope.data || typeof envelope.data !== \"object\" || Array.isArray(envelope.data)) {\n\t\tthrow invalidResponse(\"expected data object\");\n\t}\n\tconst data = envelope.data as Record<string, unknown>;\n\tif (!Array.isArray(data.results)) throw invalidResponse(\"expected data.results array\");\n\tif (!data.metadata || typeof data.metadata !== \"object\" || Array.isArray(data.metadata)) {\n\t\tthrow invalidResponse(\"expected data.metadata object\");\n\t}\n\n\tconst results: AnySearchResult[] = [];\n\tfor (const [index, value] of data.results.entries()) {\n\t\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\t\tthrow invalidResponse(`expected data.results[${index}] object`);\n\t\t}\n\t\tconst result = value as Record<string, unknown>;\n\t\tconst { title, url, snippet, content } = result;\n\t\tif (typeof title !== \"string\") throw invalidResponse(`expected data.results[${index}].title string`);\n\t\tif (typeof url !== \"string\") throw invalidResponse(`expected data.results[${index}].url string`);\n\t\tif (typeof snippet !== \"string\") throw invalidResponse(`expected data.results[${index}].snippet string`);\n\t\tif (typeof content !== \"string\") throw invalidResponse(`expected data.results[${index}].content string`);\n\t\tif (!url) throw invalidResponse(`expected data.results[${index}].url to be non-empty`);\n\t\tresults.push({ title, url, snippet, content });\n\t}\n\n\treturn { code: 0, data: { results, metadata: data.metadata as Record<string, unknown> } };\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\nexport function isAnySearchAvailable(): boolean {\n\treturn true;\n}\n\nexport async function searchWithAnySearch(query: string, options: AnySearchSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await getApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst body = { query, max_results: numResults };\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\n\ttry {\n\t\tresponse = await fetch(ANYSEARCH_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t\tsignal: options.signal\n\t\t\t\t? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])\n\t\t\t\t: AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`AnySearch API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`AnySearch API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\n\tlet data: AnySearchResponse;\n\ttry {\n\t\tdata = parseResponse(rawData);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow err;\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = data.data.results.slice(0, numResults).map((result) => ({\n\t\ttitle: result.title,\n\t\turl: result.url,\n\t\tsnippet: result.snippet,\n\t}));\n\tconst mapped: SearchResponse = { answer: buildAnswer(results), results };\n\tif (options.includeContent) {\n\t\tconst inlineContent: ExtractedContent[] = data.data.results.slice(0, numResults)\n\t\t\t.filter(result => result.content.length > 0)\n\t\t\t.map(result => ({ url: result.url, title: result.title, content: result.content, error: null }));\n\t\tif (inlineContent.length > 0) mapped.inlineContent = inlineContent;\n\t}\n\treturn mapped;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SearchOptions, SearchResponse } from "./perplexity.ts";
2
+ export declare function isBochaAvailable(): boolean;
3
+ export declare function searchWithBocha(query: string, options?: SearchOptions): Promise<SearchResponse>;
4
+ //# sourceMappingURL=bocha.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bocha.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/bocha.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAoKrE,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAkDzG","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst BOCHA_SEARCH_URL = \"https://api.bochaai.com/v1/web-search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tbochaApiKey?: unknown;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Bocha\",\n\t\tconfiguredValue: loadConfig().bochaApiKey,\n\t\tenvironmentValue: process.env.BOCHA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Bocha API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"bochaApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set BOCHA_API_KEY environment variable\\n\" +\n\t\t\t\"Create a key at https://open.bochaai.com/\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 8;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction mapFreshness(value: SearchOptions[\"recencyFilter\"]): string {\n\tswitch (value) {\n\t\tcase \"day\": return \"oneDay\";\n\t\tcase \"week\": return \"oneWeek\";\n\t\tcase \"month\": return \"oneMonth\";\n\t\tcase \"year\": return \"oneYear\";\n\t\tdefault: return \"noLimit\";\n\t}\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction parseDomainFilter(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tfor (const raw of domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tconst matches = (domain: string) => hostname === domain || hostname.endsWith(`.${domain}`);\n\tif (filters.exclude.some(matches)) return false;\n\treturn filters.include.length === 0 || filters.include.some(matches);\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`Bocha API returned invalid response: ${message}`);\n}\n\nfunction firstString(...values: unknown[]): string | null {\n\tfor (const value of values) {\n\t\tif (typeof value === \"string\" && value.trim()) return value.trim();\n\t}\n\treturn null;\n}\n\nfunction parseSearchResponse(value: unknown): { results: SearchResponse[\"results\"] } {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected an object envelope\");\n\tconst envelope = value as Record<string, unknown>;\n\tif (envelope.code !== undefined && Number(envelope.code) !== 200) {\n\t\tthrow invalidResponse(`code ${String(envelope.code)}: ${firstString(envelope.msg) ?? \"unknown error\"}`);\n\t}\n\tconst data = envelope.data;\n\tconst pages = (typeof data === \"object\" && data !== null && !Array.isArray(data))\n\t\t? (data as Record<string, unknown>).webPages\n\t\t: undefined;\n\tconst items = (typeof pages === \"object\" && pages !== null && !Array.isArray(pages))\n\t\t? (pages as Record<string, unknown>).value\n\t\t: undefined;\n\tif (!Array.isArray(items)) throw invalidResponse(\"missing data.webPages.value array\");\n\tconst results: SearchResponse[\"results\"] = [];\n\tfor (const item of items) {\n\t\tif (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n\t\tconst entry = item as Record<string, unknown>;\n\t\tconst url = firstString(entry.url, entry.link, entry.href);\n\t\tif (!url) continue;\n\t\tconst title = firstString(entry.title, entry.name) ?? url;\n\t\tconst snippet = firstString(entry.summary, entry.snippet, entry.description, entry.content) ?? \"\";\n\t\tresults.push({ title, url, snippet });\n\t}\n\treturn { results };\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results.map((result) => result.snippet\n\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t: `Source: ${result.title} (${result.url})`).join(\"\\n\\n\");\n}\n\nexport function isBochaAvailable(): boolean {\n\treturn hasCredentialSource({ provider: \"Bocha\", configuredValue: loadConfig().bochaApiKey, environmentValue: process.env.BOCHA_API_KEY });\n}\n\nexport async function searchWithBocha(query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst filters = parseDomainFilter(options.domainFilter);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(BOCHA_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ query, count: numResults, freshness: mapFreshness(options.recencyFilter), summary: true }),\n\t\t\tsignal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Bocha API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Bocha API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tlet parsed: { results: SearchResponse[\"results\"] };\n\ttry {\n\t\tparsed = parseSearchResponse(rawData);\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = parsed.results.filter((result) => passesDomainFilters(result.url, filters)).slice(0, numResults);\n\treturn { answer: buildAnswer(results), results };\n}\n"]}
@@ -0,0 +1,219 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { activityMonitor } from "./activity.js";
3
+ import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
+ import { getWebSearchConfigPath } from "./utils.js";
5
+ const BOCHA_SEARCH_URL = "https://api.bochaai.com/v1/web-search";
6
+ const CONFIG_PATH = getWebSearchConfigPath();
7
+ const SEARCH_TIMEOUT_MS = 60_000;
8
+ let cachedConfig = null;
9
+ function loadConfig() {
10
+ if (cachedConfig)
11
+ return cachedConfig;
12
+ if (!existsSync(CONFIG_PATH)) {
13
+ cachedConfig = {};
14
+ return cachedConfig;
15
+ }
16
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
17
+ let parsed;
18
+ try {
19
+ parsed = JSON.parse(raw);
20
+ }
21
+ catch (err) {
22
+ const message = err instanceof Error ? err.message : String(err);
23
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
24
+ }
25
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
26
+ throw new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);
27
+ }
28
+ cachedConfig = parsed;
29
+ return cachedConfig;
30
+ }
31
+ async function getApiKey(signal) {
32
+ return resolveCredential({
33
+ provider: "Bocha",
34
+ configuredValue: loadConfig().bochaApiKey,
35
+ environmentValue: process.env.BOCHA_API_KEY,
36
+ signal,
37
+ });
38
+ }
39
+ async function requireApiKey(signal) {
40
+ const apiKey = await getApiKey(signal);
41
+ if (!apiKey) {
42
+ throw new Error("Bocha API key not found. Either:\n" +
43
+ ` 1. Create ${CONFIG_PATH} with { "bochaApiKey": "your-key" }\n` +
44
+ " 2. Set BOCHA_API_KEY environment variable\n" +
45
+ "Create a key at https://open.bochaai.com/");
46
+ }
47
+ return apiKey;
48
+ }
49
+ function normalizeCount(value) {
50
+ if (typeof value !== "number" || !Number.isFinite(value))
51
+ return 8;
52
+ return Math.max(1, Math.min(Math.floor(value), 20));
53
+ }
54
+ function mapFreshness(value) {
55
+ switch (value) {
56
+ case "day": return "oneDay";
57
+ case "week": return "oneWeek";
58
+ case "month": return "oneMonth";
59
+ case "year": return "oneYear";
60
+ default: return "noLimit";
61
+ }
62
+ }
63
+ function normalizeDomain(value) {
64
+ let input = value.trim().toLowerCase();
65
+ if (!input)
66
+ return null;
67
+ if (input.startsWith("-"))
68
+ input = input.slice(1).trim();
69
+ if (!input)
70
+ return null;
71
+ try {
72
+ const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
73
+ input = parsed.hostname;
74
+ }
75
+ catch {
76
+ input = input.split("/")[0]?.split(":")[0] ?? "";
77
+ }
78
+ input = input.replace(/^\.+|\.+$/g, "");
79
+ return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
80
+ }
81
+ function parseDomainFilter(domainFilter) {
82
+ const filters = { include: [], exclude: [] };
83
+ for (const raw of domainFilter ?? []) {
84
+ const domain = normalizeDomain(raw);
85
+ if (!domain)
86
+ continue;
87
+ const target = raw.trim().startsWith("-") ? filters.exclude : filters.include;
88
+ if (!target.includes(domain))
89
+ target.push(domain);
90
+ }
91
+ return filters;
92
+ }
93
+ function passesDomainFilters(url, filters) {
94
+ if (filters.include.length === 0 && filters.exclude.length === 0)
95
+ return true;
96
+ let hostname;
97
+ try {
98
+ hostname = new URL(url).hostname.toLowerCase();
99
+ }
100
+ catch {
101
+ return false;
102
+ }
103
+ const matches = (domain) => hostname === domain || hostname.endsWith(`.${domain}`);
104
+ if (filters.exclude.some(matches))
105
+ return false;
106
+ return filters.include.length === 0 || filters.include.some(matches);
107
+ }
108
+ function errorMessage(err) {
109
+ return err instanceof Error ? err.message : String(err);
110
+ }
111
+ function invalidResponse(message) {
112
+ return new Error(`Bocha API returned invalid response: ${message}`);
113
+ }
114
+ function firstString(...values) {
115
+ for (const value of values) {
116
+ if (typeof value === "string" && value.trim())
117
+ return value.trim();
118
+ }
119
+ return null;
120
+ }
121
+ function parseSearchResponse(value) {
122
+ if (!value || typeof value !== "object" || Array.isArray(value))
123
+ throw invalidResponse("expected an object envelope");
124
+ const envelope = value;
125
+ if (envelope.code !== undefined && Number(envelope.code) !== 200) {
126
+ throw invalidResponse(`code ${String(envelope.code)}: ${firstString(envelope.msg) ?? "unknown error"}`);
127
+ }
128
+ const data = envelope.data;
129
+ const pages = (typeof data === "object" && data !== null && !Array.isArray(data))
130
+ ? data.webPages
131
+ : undefined;
132
+ const items = (typeof pages === "object" && pages !== null && !Array.isArray(pages))
133
+ ? pages.value
134
+ : undefined;
135
+ if (!Array.isArray(items))
136
+ throw invalidResponse("missing data.webPages.value array");
137
+ const results = [];
138
+ for (const item of items) {
139
+ if (!item || typeof item !== "object" || Array.isArray(item))
140
+ continue;
141
+ const entry = item;
142
+ const url = firstString(entry.url, entry.link, entry.href);
143
+ if (!url)
144
+ continue;
145
+ const title = firstString(entry.title, entry.name) ?? url;
146
+ const snippet = firstString(entry.summary, entry.snippet, entry.description, entry.content) ?? "";
147
+ results.push({ title, url, snippet });
148
+ }
149
+ return { results };
150
+ }
151
+ function buildAnswer(results) {
152
+ return results.map((result) => result.snippet
153
+ ? `${result.snippet}\nSource: ${result.title} (${result.url})`
154
+ : `Source: ${result.title} (${result.url})`).join("\n\n");
155
+ }
156
+ export function isBochaAvailable() {
157
+ return hasCredentialSource({ provider: "Bocha", configuredValue: loadConfig().bochaApiKey, environmentValue: process.env.BOCHA_API_KEY });
158
+ }
159
+ export async function searchWithBocha(query, options = {}) {
160
+ const apiKey = await requireApiKey(options.signal);
161
+ const numResults = normalizeCount(options.numResults);
162
+ const filters = parseDomainFilter(options.domainFilter);
163
+ const activityId = activityMonitor.logStart({ type: "api", query });
164
+ let response;
165
+ try {
166
+ response = await fetch(BOCHA_SEARCH_URL, {
167
+ method: "POST",
168
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", Accept: "application/json" },
169
+ body: JSON.stringify({ query, count: numResults, freshness: mapFreshness(options.recencyFilter), summary: true }),
170
+ signal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),
171
+ });
172
+ }
173
+ catch (err) {
174
+ const message = errorMessage(err);
175
+ const redactedMessage = redactCredential(message, apiKey);
176
+ if (redactedMessage.toLowerCase().includes("abort"))
177
+ activityMonitor.logComplete(activityId, 0);
178
+ else
179
+ activityMonitor.logError(activityId, redactedMessage);
180
+ if (redactedMessage === message)
181
+ throw err;
182
+ const redactedError = new Error(redactedMessage);
183
+ if (err instanceof Error)
184
+ redactedError.name = err.name;
185
+ throw redactedError;
186
+ }
187
+ if (!response.ok) {
188
+ activityMonitor.logComplete(activityId, response.status);
189
+ const errorText = redactCredential(await response.text(), apiKey);
190
+ throw new Error(`Bocha API error ${response.status}: ${errorText.slice(0, 300)}`);
191
+ }
192
+ let rawData;
193
+ try {
194
+ rawData = await response.json();
195
+ }
196
+ catch (err) {
197
+ activityMonitor.logComplete(activityId, response.status);
198
+ throw new Error(`Bocha API returned invalid JSON: ${errorMessage(err)}`);
199
+ }
200
+ let parsed;
201
+ try {
202
+ parsed = parseSearchResponse(rawData);
203
+ }
204
+ catch (err) {
205
+ const message = errorMessage(err);
206
+ const redactedMessage = redactCredential(message, apiKey);
207
+ activityMonitor.logError(activityId, redactedMessage);
208
+ if (redactedMessage === message)
209
+ throw err;
210
+ const redactedError = new Error(redactedMessage);
211
+ if (err instanceof Error)
212
+ redactedError.name = err.name;
213
+ throw redactedError;
214
+ }
215
+ activityMonitor.logComplete(activityId, response.status);
216
+ const results = parsed.results.filter((result) => passesDomainFilters(result.url, filters)).slice(0, numResults);
217
+ return { answer: buildAnswer(results), results };
218
+ }
219
+ //# sourceMappingURL=bocha.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bocha.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/bocha.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst BOCHA_SEARCH_URL = \"https://api.bochaai.com/v1/web-search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tbochaApiKey?: unknown;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Bocha\",\n\t\tconfiguredValue: loadConfig().bochaApiKey,\n\t\tenvironmentValue: process.env.BOCHA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Bocha API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"bochaApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set BOCHA_API_KEY environment variable\\n\" +\n\t\t\t\"Create a key at https://open.bochaai.com/\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 8;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction mapFreshness(value: SearchOptions[\"recencyFilter\"]): string {\n\tswitch (value) {\n\t\tcase \"day\": return \"oneDay\";\n\t\tcase \"week\": return \"oneWeek\";\n\t\tcase \"month\": return \"oneMonth\";\n\t\tcase \"year\": return \"oneYear\";\n\t\tdefault: return \"noLimit\";\n\t}\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction parseDomainFilter(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tfor (const raw of domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tconst matches = (domain: string) => hostname === domain || hostname.endsWith(`.${domain}`);\n\tif (filters.exclude.some(matches)) return false;\n\treturn filters.include.length === 0 || filters.include.some(matches);\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`Bocha API returned invalid response: ${message}`);\n}\n\nfunction firstString(...values: unknown[]): string | null {\n\tfor (const value of values) {\n\t\tif (typeof value === \"string\" && value.trim()) return value.trim();\n\t}\n\treturn null;\n}\n\nfunction parseSearchResponse(value: unknown): { results: SearchResponse[\"results\"] } {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected an object envelope\");\n\tconst envelope = value as Record<string, unknown>;\n\tif (envelope.code !== undefined && Number(envelope.code) !== 200) {\n\t\tthrow invalidResponse(`code ${String(envelope.code)}: ${firstString(envelope.msg) ?? \"unknown error\"}`);\n\t}\n\tconst data = envelope.data;\n\tconst pages = (typeof data === \"object\" && data !== null && !Array.isArray(data))\n\t\t? (data as Record<string, unknown>).webPages\n\t\t: undefined;\n\tconst items = (typeof pages === \"object\" && pages !== null && !Array.isArray(pages))\n\t\t? (pages as Record<string, unknown>).value\n\t\t: undefined;\n\tif (!Array.isArray(items)) throw invalidResponse(\"missing data.webPages.value array\");\n\tconst results: SearchResponse[\"results\"] = [];\n\tfor (const item of items) {\n\t\tif (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n\t\tconst entry = item as Record<string, unknown>;\n\t\tconst url = firstString(entry.url, entry.link, entry.href);\n\t\tif (!url) continue;\n\t\tconst title = firstString(entry.title, entry.name) ?? url;\n\t\tconst snippet = firstString(entry.summary, entry.snippet, entry.description, entry.content) ?? \"\";\n\t\tresults.push({ title, url, snippet });\n\t}\n\treturn { results };\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results.map((result) => result.snippet\n\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t: `Source: ${result.title} (${result.url})`).join(\"\\n\\n\");\n}\n\nexport function isBochaAvailable(): boolean {\n\treturn hasCredentialSource({ provider: \"Bocha\", configuredValue: loadConfig().bochaApiKey, environmentValue: process.env.BOCHA_API_KEY });\n}\n\nexport async function searchWithBocha(query: string, options: SearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst filters = parseDomainFilter(options.domainFilter);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(BOCHA_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ query, count: numResults, freshness: mapFreshness(options.recencyFilter), summary: true }),\n\t\t\tsignal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Bocha API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Bocha API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tlet parsed: { results: SearchResponse[\"results\"] };\n\ttry {\n\t\tparsed = parseSearchResponse(rawData);\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = parsed.results.filter((result) => passesDomainFilters(result.url, filters)).slice(0, numResults);\n\treturn { answer: buildAnswer(results), results };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SearchOptions, SearchResponse } from "./perplexity.ts";
2
+ export declare function isBraveAvailable(): boolean;
3
+ export declare function searchWithBrave(query: string, options?: SearchOptions): Promise<SearchResponse>;
4
+ //# sourceMappingURL=brave.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brave.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/brave.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAqHnF,wBAAgB,gBAAgB,IAAI,OAAO,CAM1C;AAED,wBAAsB,eAAe,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GACzB,OAAO,CAAC,cAAc,CAAC,CAuFzB","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResult, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst BRAVE_API_URL = \"https://api.search.brave.com/res/v1/web/search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 30_000;\n\ninterface WebSearchConfig {\n\tbraveApiKey?: unknown;\n}\n\ninterface NormalizedDomainFilters {\n\tallowed: string[];\n\tblocked: string[];\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\ttry {\n\t\tcachedConfig = JSON.parse(raw) as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Brave\",\n\t\tconfiguredValue: loadConfig().braveApiKey,\n\t\tenvironmentValue: process.env.BRAVE_API_KEY,\n\t\tsignal,\n\t});\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction normalizeDomainFilters(domainFilter: string[] | undefined): NormalizedDomainFilters {\n\tconst filters: NormalizedDomainFilters = { allowed: [], blocked: [] };\n\tif (!domainFilter?.length) return filters;\n\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.blocked : filters.allowed;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\n\treturn filters;\n}\n\nfunction buildBraveQuery(query: string, domainFilter: string[] | undefined): string {\n\tconst filters = normalizeDomainFilters(domainFilter);\n\tconst parts = [query];\n\n\tif (filters.allowed.length === 1) {\n\t\tparts.push(`site:${filters.allowed[0]}`);\n\t} else if (filters.allowed.length > 1) {\n\t\tparts.push(filters.allowed.map(domain => `site:${domain}`).join(\" OR \"));\n\t}\n\n\tfor (const domain of filters.blocked) {\n\t\tparts.push(`NOT site:${domain}`);\n\t}\n\n\treturn parts.join(\" \");\n}\n\nfunction hostMatchesDomain(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\nfunction matchesDomainFilters(url: string, filters: NormalizedDomainFilters): boolean {\n\tif (filters.allowed.length === 0 && filters.blocked.length === 0) return true;\n\n\tlet hostname = \"\";\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\n\tif (filters.allowed.length > 0 && !filters.allowed.some(domain => hostMatchesDomain(hostname, domain))) {\n\t\treturn false;\n\t}\n\n\treturn !filters.blocked.some(domain => hostMatchesDomain(hostname, domain));\n}\n\nexport function isBraveAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"Brave\",\n\t\tconfiguredValue: loadConfig().braveApiKey,\n\t\tenvironmentValue: process.env.BRAVE_API_KEY,\n\t});\n}\n\nexport async function searchWithBrave(\n\tquery: string,\n\toptions: SearchOptions = {},\n): Promise<SearchResponse> {\n\tconst apiKey = await getApiKey(options.signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Brave Search API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"braveApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set BRAVE_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://brave.com/search/api/\",\n\t\t);\n\t}\n\n\tconst numResults = normalizeCount(options.numResults);\n\tconst domainFilters = normalizeDomainFilters(options.domainFilter);\n\tconst searchQuery = buildBraveQuery(query, options.domainFilter);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query: searchQuery });\n\tconst params = new URLSearchParams({\n\t\tq: searchQuery,\n\t\tcount: String(options.domainFilter?.length ? 20 : numResults),\n\t});\n\n\tif (options.recencyFilter) {\n\t\tconst freshnessMap: Record<string, string> = {\n\t\t\tday: \"pd\",\n\t\t\tweek: \"pw\",\n\t\t\tmonth: \"pm\",\n\t\t\tyear: \"py\",\n\t\t};\n\t\tconst freshness = freshnessMap[options.recencyFilter];\n\t\tif (freshness) params.set(\"freshness\", freshness);\n\t}\n\n\ttry {\n\t\tconst response = await fetch(`${BRAVE_API_URL}?${params.toString()}`, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\t\"X-Subscription-Token\": apiKey,\n\t\t\t\t\"Accept\": \"application/json\",\n\t\t\t\t\"Accept-Encoding\": \"gzip\",\n\t\t\t},\n\t\t\tsignal: options.signal\n\t\t\t\t? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])\n\t\t\t\t: AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tactivityMonitor.logError(activityId, `HTTP ${response.status}`);\n\t\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\t\tthrow new Error(`Brave Search API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tconst data = await response.json() as {\n\t\t\tweb?: { results?: Array<{ title?: string; url?: string; description?: string }> };\n\t\t};\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\n\t\tconst results: SearchResult[] = [];\n\t\tfor (const item of data.web?.results ?? []) {\n\t\t\tif (!item.url || !matchesDomainFilters(item.url, domainFilters)) continue;\n\t\t\tresults.push({\n\t\t\t\ttitle: item.title || item.url,\n\t\t\t\turl: item.url,\n\t\t\t\tsnippet: item.description || \"\",\n\t\t\t});\n\t\t\tif (results.length >= numResults) break;\n\t\t}\n\n\t\tconst answer = results\n\t\t\t.map((result) => {\n\t\t\t\tif (result.snippet) return `${result.snippet}\\nSource: ${result.title} (${result.url})`;\n\t\t\t\treturn `Source: ${result.title} (${result.url})`;\n\t\t\t})\n\t\t\t.join(\"\\n\\n\");\n\n\t\treturn { answer, results };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n}\n"]}