@humain/terminal 0.0.2 → 0.0.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (688) hide show
  1. package/CHANGELOG.md +251 -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/config.d.ts.map +1 -1
  75. package/dist/config.js +4 -3
  76. package/dist/config.js.map +1 -1
  77. package/dist/core/agent-session-services.d.ts +1 -0
  78. package/dist/core/agent-session-services.d.ts.map +1 -1
  79. package/dist/core/agent-session-services.js +1 -0
  80. package/dist/core/agent-session-services.js.map +1 -1
  81. package/dist/core/agent-session.d.ts +1 -10
  82. package/dist/core/agent-session.d.ts.map +1 -1
  83. package/dist/core/agent-session.js +72 -70
  84. package/dist/core/agent-session.js.map +1 -1
  85. package/dist/core/auth-storage.d.ts +25 -9
  86. package/dist/core/auth-storage.d.ts.map +1 -1
  87. package/dist/core/auth-storage.js +237 -39
  88. package/dist/core/auth-storage.js.map +1 -1
  89. package/dist/core/extensions/index.d.ts +1 -1
  90. package/dist/core/extensions/index.d.ts.map +1 -1
  91. package/dist/core/extensions/index.js.map +1 -1
  92. package/dist/core/extensions/loader.d.ts.map +1 -1
  93. package/dist/core/extensions/loader.js +60 -41
  94. package/dist/core/extensions/loader.js.map +1 -1
  95. package/dist/core/extensions/runner.d.ts +2 -1
  96. package/dist/core/extensions/runner.d.ts.map +1 -1
  97. package/dist/core/extensions/runner.js +3 -0
  98. package/dist/core/extensions/runner.js.map +1 -1
  99. package/dist/core/extensions/types.d.ts +27 -4
  100. package/dist/core/extensions/types.d.ts.map +1 -1
  101. package/dist/core/extensions/types.js.map +1 -1
  102. package/dist/core/http-dispatcher.d.ts.map +1 -1
  103. package/dist/core/http-dispatcher.js +5 -0
  104. package/dist/core/http-dispatcher.js.map +1 -1
  105. package/dist/core/keybindings.d.ts +45 -5
  106. package/dist/core/keybindings.d.ts.map +1 -1
  107. package/dist/core/keybindings.js.map +1 -1
  108. package/dist/core/model-config.d.ts +29 -5
  109. package/dist/core/model-config.d.ts.map +1 -1
  110. package/dist/core/model-config.js +4 -0
  111. package/dist/core/model-config.js.map +1 -1
  112. package/dist/core/model-registry.d.ts +5 -3
  113. package/dist/core/model-registry.d.ts.map +1 -1
  114. package/dist/core/model-registry.js +13 -10
  115. package/dist/core/model-registry.js.map +1 -1
  116. package/dist/core/model-resolver.d.ts +4 -3
  117. package/dist/core/model-resolver.d.ts.map +1 -1
  118. package/dist/core/model-resolver.js +42 -10
  119. package/dist/core/model-resolver.js.map +1 -1
  120. package/dist/core/model-runtime.d.ts +30 -13
  121. package/dist/core/model-runtime.d.ts.map +1 -1
  122. package/dist/core/model-runtime.js +233 -73
  123. package/dist/core/model-runtime.js.map +1 -1
  124. package/dist/core/models-store.d.ts +12 -7
  125. package/dist/core/models-store.d.ts.map +1 -1
  126. package/dist/core/models-store.js +83 -14
  127. package/dist/core/models-store.js.map +1 -1
  128. package/dist/core/package-manager.d.ts +6 -3
  129. package/dist/core/package-manager.d.ts.map +1 -1
  130. package/dist/core/package-manager.js +80 -61
  131. package/dist/core/package-manager.js.map +1 -1
  132. package/dist/core/pi-manifest.d.ts +8 -0
  133. package/dist/core/pi-manifest.d.ts.map +1 -0
  134. package/dist/core/pi-manifest.js +28 -0
  135. package/dist/core/pi-manifest.js.map +1 -0
  136. package/dist/core/provider-composer.d.ts +4 -1
  137. package/dist/core/provider-composer.d.ts.map +1 -1
  138. package/dist/core/provider-composer.js +36 -15
  139. package/dist/core/provider-composer.js.map +1 -1
  140. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  141. package/dist/core/remote-catalog-provider.js +73 -67
  142. package/dist/core/remote-catalog-provider.js.map +1 -1
  143. package/dist/core/resource-loader.d.ts.map +1 -1
  144. package/dist/core/resource-loader.js +2 -2
  145. package/dist/core/resource-loader.js.map +1 -1
  146. package/dist/core/runtime-credentials.d.ts +5 -5
  147. package/dist/core/runtime-credentials.d.ts.map +1 -1
  148. package/dist/core/runtime-credentials.js +11 -8
  149. package/dist/core/runtime-credentials.js.map +1 -1
  150. package/dist/core/sdk.d.ts +1 -1
  151. package/dist/core/sdk.d.ts.map +1 -1
  152. package/dist/core/sdk.js +2 -2
  153. package/dist/core/sdk.js.map +1 -1
  154. package/dist/core/session-manager.d.ts.map +1 -1
  155. package/dist/core/session-manager.js +3 -1
  156. package/dist/core/session-manager.js.map +1 -1
  157. package/dist/core/settings-manager.d.ts +12 -0
  158. package/dist/core/settings-manager.d.ts.map +1 -1
  159. package/dist/core/settings-manager.js +40 -16
  160. package/dist/core/settings-manager.js.map +1 -1
  161. package/dist/core/system-prompt.d.ts.map +1 -1
  162. package/dist/core/system-prompt.js +8 -0
  163. package/dist/core/system-prompt.js.map +1 -1
  164. package/dist/core/tools/bash.d.ts +5 -1
  165. package/dist/core/tools/bash.d.ts.map +1 -1
  166. package/dist/core/tools/bash.js +16 -15
  167. package/dist/core/tools/bash.js.map +1 -1
  168. package/dist/core/tools/edit.d.ts +4 -0
  169. package/dist/core/tools/edit.d.ts.map +1 -1
  170. package/dist/core/tools/edit.js +11 -7
  171. package/dist/core/tools/edit.js.map +1 -1
  172. package/dist/core/tools/find.d.ts +7 -0
  173. package/dist/core/tools/find.d.ts.map +1 -1
  174. package/dist/core/tools/find.js +16 -19
  175. package/dist/core/tools/find.js.map +1 -1
  176. package/dist/core/tools/grep.d.ts +4 -0
  177. package/dist/core/tools/grep.d.ts.map +1 -1
  178. package/dist/core/tools/grep.js +5 -1
  179. package/dist/core/tools/grep.js.map +1 -1
  180. package/dist/core/tools/ls.d.ts +4 -0
  181. package/dist/core/tools/ls.d.ts.map +1 -1
  182. package/dist/core/tools/ls.js +5 -1
  183. package/dist/core/tools/ls.js.map +1 -1
  184. package/dist/core/tools/read.d.ts +4 -0
  185. package/dist/core/tools/read.d.ts.map +1 -1
  186. package/dist/core/tools/read.js +7 -3
  187. package/dist/core/tools/read.js.map +1 -1
  188. package/dist/core/tools/write.d.ts +4 -0
  189. package/dist/core/tools/write.d.ts.map +1 -1
  190. package/dist/core/tools/write.js +6 -2
  191. package/dist/core/tools/write.js.map +1 -1
  192. package/dist/extensions/llama/index.d.ts.map +1 -1
  193. package/dist/extensions/llama/index.js +11 -2
  194. package/dist/extensions/llama/index.js.map +1 -1
  195. package/dist/extensions/llama/provider.d.ts.map +1 -1
  196. package/dist/extensions/llama/provider.js +21 -7
  197. package/dist/extensions/llama/provider.js.map +1 -1
  198. package/dist/humain/agent-execution-protocol.d.ts +218 -0
  199. package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
  200. package/dist/humain/agent-execution-protocol.js +204 -0
  201. package/dist/humain/agent-execution-protocol.js.map +1 -0
  202. package/dist/humain/agent-execution-runtime.d.ts +35 -0
  203. package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
  204. package/dist/humain/agent-execution-runtime.js +170 -0
  205. package/dist/humain/agent-execution-runtime.js.map +1 -0
  206. package/dist/humain/index.d.ts.map +1 -1
  207. package/dist/humain/index.js +8 -7
  208. package/dist/humain/index.js.map +1 -1
  209. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +673 -0
  210. package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
  211. package/dist/humain/mcp-adapter/vendor/README.md +736 -0
  212. package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
  213. package/dist/humain/mcp-adapter/vendor/agent-dir.ts +68 -0
  214. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
  215. package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
  216. package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
  217. package/dist/humain/mcp-adapter/vendor/cli.js +230 -0
  218. package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
  219. package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
  220. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
  221. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +607 -0
  222. package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
  223. package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
  224. package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
  225. package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
  226. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
  227. package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
  228. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +16279 -0
  229. package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
  230. package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
  231. package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
  232. package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
  233. package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
  234. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
  235. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
  236. package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
  237. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
  238. package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
  239. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
  240. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
  241. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
  242. package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
  243. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
  244. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +667 -0
  245. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
  246. package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
  247. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +363 -0
  248. package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
  249. package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
  250. package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
  251. package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
  252. package/dist/humain/mcp-adapter/vendor/package.json +179 -0
  253. package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
  254. package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
  255. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
  256. package/dist/humain/mcp-adapter/vendor/request-headers-command.ts +336 -0
  257. package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
  258. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
  259. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
  260. package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
  261. package/dist/humain/mcp-adapter/vendor/server-manager.ts +1129 -0
  262. package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
  263. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
  264. package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
  265. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
  266. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +296 -0
  267. package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
  268. package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
  269. package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
  270. package/dist/humain/mcp-adapter/vendor/types.ts +942 -0
  271. package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
  272. package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
  273. package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
  274. package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
  275. package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
  276. package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
  277. package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
  278. package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
  279. package/dist/humain/mcp-adapter.d.ts +3 -0
  280. package/dist/humain/mcp-adapter.d.ts.map +1 -0
  281. package/dist/humain/mcp-adapter.js +5 -0
  282. package/dist/humain/mcp-adapter.js.map +1 -0
  283. package/dist/humain/pi-agent-execution-host.d.ts +34 -0
  284. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
  285. package/dist/humain/pi-agent-execution-host.js +77 -0
  286. package/dist/humain/pi-agent-execution-host.js.map +1 -0
  287. package/dist/humain/web-access/host.d.ts +4 -0
  288. package/dist/humain/web-access/host.d.ts.map +1 -0
  289. package/dist/humain/web-access/host.js +3 -0
  290. package/dist/humain/web-access/host.js.map +1 -0
  291. package/dist/humain/web-access/index.d.ts +3 -0
  292. package/dist/humain/web-access/index.d.ts.map +1 -0
  293. package/dist/humain/web-access/index.js +5 -0
  294. package/dist/humain/web-access/index.js.map +1 -0
  295. package/dist/humain/web-access/vendor/activity.d.ts +34 -0
  296. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
  297. package/dist/humain/web-access/vendor/activity.js +68 -0
  298. package/dist/humain/web-access/vendor/activity.js.map +1 -0
  299. package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
  300. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
  301. package/dist/humain/web-access/vendor/anysearch.js +167 -0
  302. package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
  303. package/dist/humain/web-access/vendor/auth-fetch.d.ts +13 -0
  304. package/dist/humain/web-access/vendor/auth-fetch.d.ts.map +1 -0
  305. package/dist/humain/web-access/vendor/auth-fetch.js +134 -0
  306. package/dist/humain/web-access/vendor/auth-fetch.js.map +1 -0
  307. package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
  308. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
  309. package/dist/humain/web-access/vendor/bocha.js +219 -0
  310. package/dist/humain/web-access/vendor/bocha.js.map +1 -0
  311. package/dist/humain/web-access/vendor/brave.d.ts +4 -0
  312. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
  313. package/dist/humain/web-access/vendor/brave.js +194 -0
  314. package/dist/humain/web-access/vendor/brave.js.map +1 -0
  315. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
  316. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
  317. package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
  318. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
  319. package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
  320. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
  321. package/dist/humain/web-access/vendor/brightdata.js +519 -0
  322. package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
  323. package/dist/humain/web-access/vendor/chrome-cookies.d.ts +23 -0
  324. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
  325. package/dist/humain/web-access/vendor/chrome-cookies.js +522 -0
  326. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
  327. package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
  328. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
  329. package/dist/humain/web-access/vendor/content-find.js +117 -0
  330. package/dist/humain/web-access/vendor/content-find.js.map +1 -0
  331. package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
  332. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
  333. package/dist/humain/web-access/vendor/credential-source.js +151 -0
  334. package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
  335. package/dist/humain/web-access/vendor/curator-page.d.ts +30 -0
  336. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
  337. package/dist/humain/web-access/vendor/curator-page.js +3556 -0
  338. package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
  339. package/dist/humain/web-access/vendor/curator-server.d.ts +94 -0
  340. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
  341. package/dist/humain/web-access/vendor/curator-server.js +690 -0
  342. package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
  343. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
  344. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
  345. package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
  346. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
  347. package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
  348. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
  349. package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
  350. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
  351. package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
  352. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
  353. package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
  354. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
  355. package/dist/humain/web-access/vendor/exa.d.ts +10 -0
  356. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
  357. package/dist/humain/web-access/vendor/exa.js +426 -0
  358. package/dist/humain/web-access/vendor/exa.js.map +1 -0
  359. package/dist/humain/web-access/vendor/extract.d.ts +48 -0
  360. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
  361. package/dist/humain/web-access/vendor/extract.js +1126 -0
  362. package/dist/humain/web-access/vendor/extract.js.map +1 -0
  363. package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
  364. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
  365. package/dist/humain/web-access/vendor/feature-config.js +27 -0
  366. package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
  367. package/dist/humain/web-access/vendor/fetch-params.d.ts +27 -0
  368. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
  369. package/dist/humain/web-access/vendor/fetch-params.js +71 -0
  370. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
  371. package/dist/humain/web-access/vendor/firecrawl.d.ts +19 -0
  372. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
  373. package/dist/humain/web-access/vendor/firecrawl.js +370 -0
  374. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
  375. package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
  376. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
  377. package/dist/humain/web-access/vendor/gemini-api.js +230 -0
  378. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
  379. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
  380. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
  381. package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
  382. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
  383. package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
  384. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
  385. package/dist/humain/web-access/vendor/gemini-search.js +832 -0
  386. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
  387. package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
  388. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
  389. package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
  390. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
  391. package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
  392. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
  393. package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
  394. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
  395. package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
  396. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
  397. package/dist/humain/web-access/vendor/gemini-web.js +385 -0
  398. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
  399. package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
  400. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
  401. package/dist/humain/web-access/vendor/github-api.js +160 -0
  402. package/dist/humain/web-access/vendor/github-api.js.map +1 -0
  403. package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
  404. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
  405. package/dist/humain/web-access/vendor/github-extract.js +635 -0
  406. package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
  407. package/dist/humain/web-access/vendor/index.d.ts +4 -0
  408. package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
  409. package/dist/humain/web-access/vendor/index.js +3076 -0
  410. package/dist/humain/web-access/vendor/index.js.map +1 -0
  411. package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
  412. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
  413. package/dist/humain/web-access/vendor/jina-search.js +255 -0
  414. package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
  415. package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
  416. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
  417. package/dist/humain/web-access/vendor/kagi.js +262 -0
  418. package/dist/humain/web-access/vendor/kagi.js.map +1 -0
  419. package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
  420. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
  421. package/dist/humain/web-access/vendor/ollama.js +216 -0
  422. package/dist/humain/web-access/vendor/ollama.js.map +1 -0
  423. package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
  424. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
  425. package/dist/humain/web-access/vendor/openai-search.js +459 -0
  426. package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
  427. package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
  428. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
  429. package/dist/humain/web-access/vendor/page-query.js +79 -0
  430. package/dist/humain/web-access/vendor/page-query.js.map +1 -0
  431. package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
  432. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
  433. package/dist/humain/web-access/vendor/parallel.js +343 -0
  434. package/dist/humain/web-access/vendor/parallel.js.map +1 -0
  435. package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
  436. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
  437. package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
  438. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
  439. package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
  440. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
  441. package/dist/humain/web-access/vendor/perplexity.js +159 -0
  442. package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
  443. package/dist/humain/web-access/vendor/querit.d.ts +10 -0
  444. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
  445. package/dist/humain/web-access/vendor/querit.js +335 -0
  446. package/dist/humain/web-access/vendor/querit.js.map +1 -0
  447. package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
  448. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
  449. package/dist/humain/web-access/vendor/render-search-error.js +130 -0
  450. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
  451. package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
  452. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
  453. package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
  454. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
  455. package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
  456. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
  457. package/dist/humain/web-access/vendor/search1api.js +251 -0
  458. package/dist/humain/web-access/vendor/search1api.js.map +1 -0
  459. package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
  460. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
  461. package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
  462. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
  463. package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
  464. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
  465. package/dist/humain/web-access/vendor/searxng.js +238 -0
  466. package/dist/humain/web-access/vendor/searxng.js.map +1 -0
  467. package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
  468. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
  469. package/dist/humain/web-access/vendor/serpbase.js +211 -0
  470. package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
  471. package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
  472. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
  473. package/dist/humain/web-access/vendor/serpdive.js +267 -0
  474. package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
  475. package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
  476. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
  477. package/dist/humain/web-access/vendor/source-check.js +205 -0
  478. package/dist/humain/web-access/vendor/source-check.js.map +1 -0
  479. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
  480. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
  481. package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
  482. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
  483. package/dist/humain/web-access/vendor/storage.d.ts +55 -0
  484. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
  485. package/dist/humain/web-access/vendor/storage.js +485 -0
  486. package/dist/humain/web-access/vendor/storage.js.map +1 -0
  487. package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
  488. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
  489. package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
  490. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
  491. package/dist/humain/web-access/vendor/summary-review.d.ts +26 -0
  492. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
  493. package/dist/humain/web-access/vendor/summary-review.js +344 -0
  494. package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
  495. package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
  496. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
  497. package/dist/humain/web-access/vendor/tavily.js +194 -0
  498. package/dist/humain/web-access/vendor/tavily.js.map +1 -0
  499. package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
  500. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
  501. package/dist/humain/web-access/vendor/tinyfish.js +331 -0
  502. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
  503. package/dist/humain/web-access/vendor/utils.d.ts +20 -0
  504. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
  505. package/dist/humain/web-access/vendor/utils.js +91 -0
  506. package/dist/humain/web-access/vendor/utils.js.map +1 -0
  507. package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
  508. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
  509. package/dist/humain/web-access/vendor/video-extract.js +335 -0
  510. package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
  511. package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
  512. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
  513. package/dist/humain/web-access/vendor/xai-search.js +331 -0
  514. package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
  515. package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
  516. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
  517. package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
  518. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
  519. package/dist/index.d.ts +7 -4
  520. package/dist/index.d.ts.map +1 -1
  521. package/dist/index.js +5 -2
  522. package/dist/index.js.map +1 -1
  523. package/dist/main.d.ts +2 -2
  524. package/dist/main.d.ts.map +1 -1
  525. package/dist/main.js +169 -102
  526. package/dist/main.js.map +1 -1
  527. package/dist/modes/agent-exec-mode.d.ts +14 -0
  528. package/dist/modes/agent-exec-mode.d.ts.map +1 -0
  529. package/dist/modes/agent-exec-mode.js +92 -0
  530. package/dist/modes/agent-exec-mode.js.map +1 -0
  531. package/dist/modes/index.d.ts +4 -2
  532. package/dist/modes/index.d.ts.map +1 -1
  533. package/dist/modes/index.js +2 -1
  534. package/dist/modes/index.js.map +1 -1
  535. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  536. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  537. package/dist/modes/interactive/components/assistant-message.js +13 -4
  538. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  539. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  540. package/dist/modes/interactive/components/custom-editor.js +7 -0
  541. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  542. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  543. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  544. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  545. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  546. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  547. package/dist/modes/interactive/components/footer.js +1 -1
  548. package/dist/modes/interactive/components/footer.js.map +1 -1
  549. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  550. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  551. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  552. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  553. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  554. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  555. package/dist/modes/interactive/components/mermaid.js +75 -0
  556. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  557. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  558. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  559. package/dist/modes/interactive/components/model-selector.js +16 -4
  560. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  561. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  562. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  563. package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
  564. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  565. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  566. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  567. package/dist/modes/interactive/components/settings-selector.js +30 -0
  568. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  569. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  570. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  571. package/dist/modes/interactive/components/user-message.js +9 -2
  572. package/dist/modes/interactive/components/user-message.js.map +1 -1
  573. package/dist/modes/interactive/interactive-mode.d.ts +45 -9
  574. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  575. package/dist/modes/interactive/interactive-mode.js +581 -211
  576. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  577. package/dist/modes/interactive/theme/dark.json +1 -0
  578. package/dist/modes/interactive/theme/light.json +1 -0
  579. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  580. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  581. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  582. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  583. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  584. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  585. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  586. package/dist/modes/interactive/theme/theme.js +24 -6
  587. package/dist/modes/interactive/theme/theme.js.map +1 -1
  588. package/dist/modes/json-event.d.ts +28 -0
  589. package/dist/modes/json-event.d.ts.map +1 -0
  590. package/dist/modes/json-event.js +12 -0
  591. package/dist/modes/json-event.js.map +1 -0
  592. package/dist/modes/print-mode.d.ts.map +1 -1
  593. package/dist/modes/print-mode.js +12 -2
  594. package/dist/modes/print-mode.js.map +1 -1
  595. package/dist/modes/rpc/rpc-client.d.ts +12 -5
  596. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  597. package/dist/modes/rpc/rpc-client.js +55 -1
  598. package/dist/modes/rpc/rpc-client.js.map +1 -1
  599. package/dist/modes/rpc/rpc-mode.d.ts +1 -1
  600. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  601. package/dist/modes/rpc/rpc-mode.js +13 -3
  602. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  603. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  604. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  605. package/dist/modes/rpc/rpc-types.js.map +1 -1
  606. package/dist/package-manager-cli.d.ts.map +1 -1
  607. package/dist/package-manager-cli.js +11 -9
  608. package/dist/package-manager-cli.js.map +1 -1
  609. package/dist/rpc-entry.d.ts.map +1 -1
  610. package/dist/rpc-entry.js +3 -2
  611. package/dist/rpc-entry.js.map +1 -1
  612. package/dist/server/create-harness.d.ts +26 -0
  613. package/dist/server/create-harness.d.ts.map +1 -0
  614. package/dist/server/create-harness.js +104 -0
  615. package/dist/server/create-harness.js.map +1 -0
  616. package/dist/utils/abort.d.ts +5 -0
  617. package/dist/utils/abort.d.ts.map +1 -0
  618. package/dist/utils/abort.js +48 -0
  619. package/dist/utils/abort.js.map +1 -0
  620. package/dist/utils/clipboard.d.ts +1 -1
  621. package/dist/utils/clipboard.d.ts.map +1 -1
  622. package/dist/utils/clipboard.js +22 -2
  623. package/dist/utils/clipboard.js.map +1 -1
  624. package/dist/utils/management-http.d.ts +23 -0
  625. package/dist/utils/management-http.d.ts.map +1 -0
  626. package/dist/utils/management-http.js +50 -0
  627. package/dist/utils/management-http.js.map +1 -0
  628. package/dist/utils/paths.d.ts +3 -0
  629. package/dist/utils/paths.d.ts.map +1 -1
  630. package/dist/utils/paths.js +23 -1
  631. package/dist/utils/paths.js.map +1 -1
  632. package/dist/utils/tool-result-images.d.ts +19 -0
  633. package/dist/utils/tool-result-images.d.ts.map +1 -0
  634. package/dist/utils/tool-result-images.js +45 -0
  635. package/dist/utils/tool-result-images.js.map +1 -0
  636. package/dist/utils/tools-manager.d.ts.map +1 -1
  637. package/dist/utils/tools-manager.js +13 -25
  638. package/dist/utils/tools-manager.js.map +1 -1
  639. package/dist/utils/version-check.d.ts +4 -0
  640. package/dist/utils/version-check.d.ts.map +1 -1
  641. package/dist/utils/version-check.js +23 -5
  642. package/dist/utils/version-check.js.map +1 -1
  643. package/docs/compaction.md +2 -2
  644. package/docs/custom-provider.md +7 -5
  645. package/docs/extensions.md +30 -5
  646. package/docs/humain-terminal.md +21 -1
  647. package/docs/json.md +24 -19
  648. package/docs/keybindings.md +46 -14
  649. package/docs/models.md +32 -11
  650. package/docs/providers.md +9 -1
  651. package/docs/quickstart.md +39 -37
  652. package/docs/rpc.md +31 -11
  653. package/docs/sdk.md +21 -2
  654. package/docs/security.md +21 -21
  655. package/docs/session-format.md +14 -14
  656. package/docs/settings.md +4 -1
  657. package/docs/themes.md +5 -3
  658. package/docs/usage.md +7 -0
  659. package/examples/extensions/custom-compaction.ts +3 -18
  660. package/examples/extensions/custom-provider-anthropic/index.ts +5 -1
  661. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  662. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  663. package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
  664. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  665. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  666. package/examples/extensions/gondolin/package-lock.json +2 -2
  667. package/examples/extensions/gondolin/package.json +1 -1
  668. package/examples/extensions/handoff.ts +4 -13
  669. package/examples/extensions/qna.ts +5 -9
  670. package/examples/extensions/sandbox/package-lock.json +2 -2
  671. package/examples/extensions/sandbox/package.json +1 -1
  672. package/examples/extensions/summarize.ts +9 -20
  673. package/examples/extensions/with-deps/package-lock.json +2 -2
  674. package/examples/extensions/with-deps/package.json +1 -1
  675. package/examples/rpc-extension-ui.ts +11 -2
  676. package/examples/sdk/02-custom-model.ts +2 -3
  677. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  678. package/examples/sdk/12-full-control.ts +1 -1
  679. package/examples/sdk/README.md +1 -1
  680. package/npm-shrinkwrap.json +2771 -535
  681. package/package.json +40 -11
  682. package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
  683. package/src/humain/mcp-adapter/upstream.json +7 -0
  684. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +673 -0
  685. package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
  686. package/src/humain/web-access/UPSTREAM.md +17 -0
  687. package/src/humain/web-access/upstream.json +23 -0
  688. package/src/humain/web-access/vendor/LICENSE +21 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-extract.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/video-extract.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve, extname, basename, join, dirname } from \"node:path\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { canAttachImages } from \"./feature-config.ts\";\nimport { isGeminiWebAvailable, queryWithCookies } from \"./gemini-web.ts\";\nimport { queryGeminiApiWithVideo, getApiKey, fetchGeminiApi, getVersionedApiBase, getUploadBase, redactGeminiApiResponse } from \"./gemini-api.ts\";\nimport { extractHeadingTitle, type ExtractedContent, type ExtractOptions, type FrameResult } from \"./extract.ts\";\nimport { readExecError, trimErrorText, mapFfmpegError, getWebSearchConfigPath } from \"./utils.ts\";\n\nconst CONFIG_PATH = getWebSearchConfigPath();\n\nconst DEFAULT_VIDEO_PROMPT = `Extract the complete content of this video. Include:\n1. Video title (infer from content if not explicit), duration\n2. A brief summary (2-3 sentences)\n3. Full transcript with timestamps\n4. Descriptions of any code, terminal commands, diagrams, slides, or UI shown on screen\n\nFormat as markdown.`;\n\nconst VIDEO_EXTENSIONS: Record<string, string> = {\n\t\".mp4\": \"video/mp4\",\n\t\".mov\": \"video/quicktime\",\n\t\".webm\": \"video/webm\",\n\t\".avi\": \"video/x-msvideo\",\n\t\".mpeg\": \"video/mpeg\",\n\t\".mpg\": \"video/mpeg\",\n\t\".wmv\": \"video/x-ms-wmv\",\n\t\".flv\": \"video/x-flv\",\n\t\".3gp\": \"video/3gpp\",\n\t\".3gpp\": \"video/3gpp\",\n};\n\nfunction shouldRethrow(err: unknown): boolean {\n\tconst message = err instanceof Error ? err.message : String(err);\n\treturn message.startsWith(\"Failed to parse \");\n}\n\ninterface VideoFileInfo {\n\tabsolutePath: string;\n\tmimeType: string;\n\tsizeBytes: number;\n\tmaxSizeBytes: number;\n\twithinUploadLimit: boolean;\n}\n\ninterface VideoConfig {\n\tenabled: boolean;\n\tpreferredModel: string;\n\tmaxSizeMB: number;\n}\n\nfunction normalizePreferredModel(value: unknown, fallback: string): string {\n\tif (typeof value !== \"string\") return fallback;\n\tconst normalized = value.trim();\n\treturn normalized.length > 0 ? normalized : fallback;\n}\n\nfunction normalizeEnabled(value: unknown, fallback: boolean): boolean {\n\treturn typeof value === \"boolean\" ? value : fallback;\n}\n\nfunction normalizeMaxSizeMB(value: unknown, fallback: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n\treturn value > 0 ? value : fallback;\n}\n\nconst VIDEO_CONFIG_DEFAULTS: VideoConfig = {\n\tenabled: true,\n\tpreferredModel: \"gemini-3.6-flash\",\n\tmaxSizeMB: 50,\n};\n\nlet cachedVideoConfig: VideoConfig | null = null;\n\nfunction loadVideoConfig(): VideoConfig {\n\tif (cachedVideoConfig) return cachedVideoConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedVideoConfig = { ...VIDEO_CONFIG_DEFAULTS };\n\t\treturn cachedVideoConfig;\n\t}\n\n\tconst rawText = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet raw: { video?: { enabled?: boolean; preferredModel?: string; maxSizeMB?: number } };\n\ttry {\n\t\traw = JSON.parse(rawText) as { video?: { enabled?: boolean; preferredModel?: string; maxSizeMB?: number } };\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\tconst v = raw.video ?? {};\n\tcachedVideoConfig = {\n\t\tenabled: normalizeEnabled(v.enabled, VIDEO_CONFIG_DEFAULTS.enabled),\n\t\tpreferredModel: normalizePreferredModel(v.preferredModel, VIDEO_CONFIG_DEFAULTS.preferredModel),\n\t\tmaxSizeMB: normalizeMaxSizeMB(v.maxSizeMB, VIDEO_CONFIG_DEFAULTS.maxSizeMB),\n\t};\n\treturn cachedVideoConfig;\n}\n\nexport function isVideoFile(input: string): VideoFileInfo | null {\n\tconst config = loadVideoConfig();\n\tif (!config.enabled) return null;\n\n\tconst isFilePath = input.startsWith(\"/\") || input.startsWith(\"./\") || input.startsWith(\"../\") || input.startsWith(\"file://\");\n\tif (!isFilePath) return null;\n\n\tlet filePath = input;\n\tif (input.startsWith(\"file://\")) {\n\t\ttry {\n\t\t\tfilePath = decodeURIComponent(new URL(input).pathname);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tconst ext = extname(filePath).toLowerCase();\n\tconst mimeType = VIDEO_EXTENSIONS[ext];\n\tif (!mimeType) return null;\n\n\tconst absolutePath = resolveFilePath(filePath);\n\tif (!absolutePath) return null;\n\n\tlet stat: ReturnType<typeof statSync>;\n\ttry {\n\t\tstat = statSync(absolutePath);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (!stat.isFile()) return null;\n\n\tconst maxBytes = config.maxSizeMB * 1024 * 1024;\n\treturn {\n\t\tabsolutePath,\n\t\tmimeType,\n\t\tsizeBytes: stat.size,\n\t\tmaxSizeBytes: maxBytes,\n\t\twithinUploadLimit: stat.size <= maxBytes,\n\t};\n}\n\nfunction resolveFilePath(filePath: string): string | null {\n\tconst absolutePath = resolve(filePath);\n\tif (existsSync(absolutePath)) return absolutePath;\n\n\tconst dir = dirname(absolutePath);\n\tconst base = basename(absolutePath);\n\tif (!existsSync(dir)) return null;\n\n\ttry {\n\t\tconst normalizedBase = normalizeSpaces(base);\n\t\tconst match = readdirSync(dir).find(f => normalizeSpaces(f) === normalizedBase);\n\t\treturn match ? join(dir, match) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizeSpaces(s: string): string {\n\treturn s.replace(/[\\u00A0\\u2000-\\u200B\\u202F\\u205F\\u3000\\uFEFF]/g, \" \");\n}\n\nexport async function extractVideo(\n\tinfo: VideoFileInfo,\n\tsignal?: AbortSignal,\n\toptions?: ExtractOptions,\n): Promise<ExtractedContent | null> {\n\tconst config = loadVideoConfig();\n\tconst effectivePrompt = options?.prompt ?? DEFAULT_VIDEO_PROMPT;\n\tconst effectiveModel = options?.model ?? config.preferredModel;\n\tconst displayName = basename(info.absolutePath);\n\tif (!info.withinUploadLimit) {\n\t\tconst sizeMB = (info.sizeBytes / 1024 / 1024).toFixed(1);\n\t\tconst maxSizeMB = (info.maxSizeBytes / 1024 / 1024).toFixed(1);\n\t\tconst error = `Local video ${displayName} is ${sizeMB} MiB, above configured video.maxSizeMB (${maxSizeMB} MiB) for Gemini analysis. Use timestamp/frames for ffmpeg frame extraction, increase video.maxSizeMB, or compress the file.`;\n\t\treturn { url: info.absolutePath, title: displayName, content: error, error };\n\t}\n\tconst activityId = activityMonitor.logStart({ type: \"fetch\", url: `video:${displayName}` });\n\n\tconst result = await tryVideoGeminiApi(info, effectivePrompt, effectiveModel, signal)\n\t\t?? await tryVideoGeminiWeb(info, effectivePrompt, effectiveModel, signal);\n\n\tif (result) {\n\t\tif (canAttachImages()) {\n\t\t\tconst thumbnail = await extractVideoFrame(info.absolutePath);\n\t\t\tif (!(\"error\" in thumbnail)) {\n\t\t\t\tresult.thumbnail = thumbnail;\n\t\t\t}\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, 200);\n\t\treturn result;\n\t}\n\n\tif (signal?.aborted) {\n\t\tactivityMonitor.logComplete(activityId, 0);\n\t\treturn null;\n\t}\n\n\tactivityMonitor.logError(activityId, \"all video extraction paths failed\");\n\treturn null;\n}\n\nfunction mapFfprobeError(err: unknown): string {\n\tconst { code, stderr, message } = readExecError(err);\n\tif (code === \"ENOENT\") return \"ffprobe is not installed. Install ffmpeg which includes ffprobe\";\n\tconst snippet = trimErrorText(stderr || message);\n\treturn snippet ? `ffprobe failed: ${snippet}` : \"ffprobe failed\";\n}\n\nexport async function extractVideoFrame(filePath: string, seconds: number = 1): Promise<FrameResult> {\n\ttry {\n\t\tconst buffer = execFileSync(\"ffmpeg\", [\n\t\t\t\"-ss\", String(seconds), \"-i\", filePath,\n\t\t\t\"-frames:v\", \"1\", \"-f\", \"image2pipe\", \"-vcodec\", \"mjpeg\", \"pipe:1\",\n\t\t], { maxBuffer: 5 * 1024 * 1024, timeout: 10000, stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n\t\tif (buffer.length === 0) return { error: \"ffmpeg failed: empty output\" };\n\t\treturn { data: buffer.toString(\"base64\"), mimeType: \"image/jpeg\" };\n\t} catch (err) {\n\t\treturn { error: mapFfmpegError(err) };\n\t}\n}\n\nexport async function getLocalVideoDuration(filePath: string): Promise<number | { error: string }> {\n\ttry {\n\t\tconst output = execFileSync(\"ffprobe\", [\n\t\t\t\"-v\", \"quiet\",\n\t\t\t\"-show_entries\", \"format=duration\",\n\t\t\t\"-of\", \"csv=p=0\",\n\t\t\tfilePath,\n\t\t], { timeout: 10000, encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n\t\tconst duration = Number.parseFloat(output);\n\t\tif (!Number.isFinite(duration)) return { error: \"ffprobe failed: invalid duration output\" };\n\t\treturn duration;\n\t} catch (err) {\n\t\treturn { error: mapFfprobeError(err) };\n\t}\n}\n\nasync function tryVideoGeminiWeb(\n\tinfo: VideoFileInfo,\n\tprompt: string,\n\tmodel: string,\n\tsignal?: AbortSignal,\n): Promise<ExtractedContent | null> {\n\ttry {\n\t\tconst cookies = await isGeminiWebAvailable();\n\t\tif (!cookies) return null;\n\t\tif (signal?.aborted) return null;\n\n\t\tconst text = await queryWithCookies(prompt, cookies, {\n\t\t\tfiles: [info.absolutePath],\n\t\t\t...(model !== \"gemini-3.6-flash\" ? { model } : {}),\n\t\t\tsignal,\n\t\t\ttimeoutMs: 180000,\n\t\t});\n\n\t\treturn {\n\t\t\turl: info.absolutePath,\n\t\t\ttitle: extractVideoTitle(text, info.absolutePath),\n\t\t\tcontent: text,\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tif (shouldRethrow(err)) throw err;\n\t\treturn null;\n\t}\n}\n\nasync function tryVideoGeminiApi(\n\tinfo: VideoFileInfo,\n\tprompt: string,\n\tmodel: string,\n\tsignal?: AbortSignal,\n): Promise<ExtractedContent | null> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) return null;\n\tif (signal?.aborted) return null;\n\n\tlet fileName: string | null = null;\n\ttry {\n\t\tconst uploaded = await uploadToFilesApi(info, apiKey, signal);\n\t\tfileName = uploaded.name;\n\n\t\tawait pollFileState(fileName, apiKey, signal, 120000);\n\n\t\tconst text = await queryGeminiApiWithVideo(prompt, uploaded.uri, {\n\t\t\tapiKey,\n\t\t\tmodel,\n\t\t\tmimeType: info.mimeType,\n\t\t\tsignal,\n\t\t\ttimeoutMs: 120000,\n\t\t});\n\n\t\treturn {\n\t\t\turl: info.absolutePath,\n\t\t\ttitle: extractVideoTitle(text, info.absolutePath),\n\t\t\tcontent: text,\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tif (shouldRethrow(err)) throw err;\n\t\treturn null;\n\t} finally {\n\t\tif (fileName) deleteGeminiFile(fileName, apiKey);\n\t}\n}\n\nasync function uploadToFilesApi(\n\tinfo: VideoFileInfo,\n\tapiKey: string,\n\tsignal?: AbortSignal,\n): Promise<{ name: string; uri: string }> {\n\tconst displayName = basename(info.absolutePath);\n\n\tconst initRes = await fetchGeminiApi(`${getUploadBase()}/files`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"X-Goog-Upload-Protocol\": \"resumable\",\n\t\t\t\"X-Goog-Upload-Command\": \"start\",\n\t\t\t\"X-Goog-Upload-Header-Content-Length\": String(info.sizeBytes),\n\t\t\t\"X-Goog-Upload-Header-Content-Type\": info.mimeType,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify({ file: { display_name: displayName } }),\n\t\tsignal,\n\t}, apiKey);\n\n\tif (!initRes.ok) {\n\t\tconst text = redactGeminiApiResponse(initRes, await initRes.text(), apiKey);\n\t\tthrow new Error(`File upload init failed: ${initRes.status} (${text.slice(0, 200)})`);\n\t}\n\n\tconst uploadUrl = initRes.headers.get(\"x-goog-upload-url\");\n\tif (!uploadUrl) throw new Error(\"No upload URL in response headers\");\n\n\tconst fileData = await readFile(info.absolutePath);\n\tconst uploadRes = await fetchGeminiApi(uploadUrl, {\n\t\tmethod: \"PUT\",\n\t\theaders: {\n\t\t\t\"Content-Length\": String(info.sizeBytes),\n\t\t\t\"X-Goog-Upload-Offset\": \"0\",\n\t\t\t\"X-Goog-Upload-Command\": \"upload, finalize\",\n\t\t},\n\t\tbody: fileData,\n\t\tsignal,\n\t}, apiKey);\n\n\tif (!uploadRes.ok) {\n\t\tconst text = redactGeminiApiResponse(uploadRes, await uploadRes.text(), apiKey);\n\t\tthrow new Error(`File upload failed: ${uploadRes.status} (${text.slice(0, 200)})`);\n\t}\n\n\tconst result = await uploadRes.json() as { file: { name: string; uri: string } };\n\treturn result.file;\n}\n\nasync function pollFileState(\n\tfileName: string,\n\tapiKey: string,\n\tsignal?: AbortSignal,\n\ttimeoutMs: number = 120000,\n): Promise<void> {\n\tconst deadline = Date.now() + timeoutMs;\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) throw new Error(\"Aborted\");\n\n\t\tconst res = await fetchGeminiApi(`${getVersionedApiBase()}/${fileName}`, { signal }, apiKey);\n\t\tif (!res.ok) throw new Error(`File state check failed: ${res.status}`);\n\n\t\tconst data = await res.json() as { state: string };\n\t\tif (data.state === \"ACTIVE\") return;\n\t\tif (data.state === \"FAILED\") throw new Error(\"File processing failed\");\n\n\t\tawait new Promise(r => setTimeout(r, 5000));\n\t}\n\n\tthrow new Error(\"File processing timed out\");\n}\n\nfunction deleteGeminiFile(fileName: string, apiKey: string): void {\n\tvoid fetchGeminiApi(`${getVersionedApiBase()}/${fileName}`, { method: \"DELETE\" }, apiKey).catch((err) => {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconsole.error(`Failed to delete Gemini file ${fileName}: ${message}`);\n\t});\n}\n\nfunction extractVideoTitle(text: string, filePath: string): string {\n\treturn extractHeadingTitle(text) ?? basename(filePath, extname(filePath));\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import type { ExtensionContext } from "../host.ts";
2
+ import type { SearchOptions, SearchResponse } from "./perplexity.ts";
3
+ type ProviderHeaders = Record<string, string | null>;
4
+ interface XaiAuth {
5
+ apiKey: string;
6
+ model: string;
7
+ headers: ProviderHeaders;
8
+ }
9
+ export declare function resolveXaiAuth(ctx?: ExtensionContext, signal?: AbortSignal): Promise<XaiAuth | undefined>;
10
+ export declare function isXaiSearchAvailable(ctx?: ExtensionContext): Promise<boolean>;
11
+ export declare function searchWithXai(query: string, options?: SearchOptions, ctx?: ExtensionContext): Promise<SearchResponse>;
12
+ export {};
13
+ //# sourceMappingURL=xai-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/xai-search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAmCnF,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAErD,UAAU,OAAO;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,eAAe,CAAC;CACzB;AAyDD,wBAAsB,cAAc,CAAC,GAAG,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAqB/G;AAED,wBAAsB,oBAAoB,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAQnF;AAmJD,wBAAsB,aAAa,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,EAC3B,GAAG,CAAC,EAAE,gBAAgB,GACpB,OAAO,CAAC,cAAc,CAAC,CAkEzB","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport type { ExtensionContext } from \"../host.ts\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse, SearchResult } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\n// xAI's Agent Tools API: a hosted `web_search` tool on an OpenAI-compatible\n// Responses endpoint. The search runs inside xAI's own inference, so — unlike\n// every keyed backend here — it is paid for by whatever credential answers for\n// the model, including a SuperGrok / X Premium subscription resolved through\n// pi's model registry.\n//\n// Note for anyone extending this: xAI's older Live Search (`search_parameters`\n// on /v1/chat/completions) is GONE. It now answers 410 with \"Live search is\n// deprecated. Please switch to the Agent Tools API\". Do not add it back.\n//\n// The request body is deliberately minimal — model, input, tools — because that\n// is the shape verified against a live subscription account. `stream`,\n// `include`, `tool_choice` and `parallel_tool_calls` are all sent by the OpenAI\n// backend but were NOT verified here, and a 400 from an unsupported field would\n// cost the user their search. Sources come back in `web_search_call.action.sources`\n// without asking for them via `include`.\n\nconst XAI_RESPONSES_URL = \"https://api.x.ai/v1/responses\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\n// Ordered best-first. pi's builtin xai catalog is small and xAI retires models\n// briskly, so this is a preference list, not an assumption: the first one the\n// registry actually knows wins, and an unknown id is skipped rather than sent.\nconst AUTH_MODEL_CANDIDATES = [\"grok-4.5\", \"grok-4.3\", \"grok-build-0.1\"] as const;\n\ninterface WebSearchConfig {\n\txaiApiKey?: unknown;\n\txaiSearchModel?: unknown;\n}\n\ntype ProviderHeaders = Record<string, string | null>;\n\ninterface XaiAuth {\n\tapiKey: string;\n\tmodel: string;\n\theaders: ProviderHeaders;\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\nfunction resolveConfiguredSearchModel(value: unknown): string | undefined {\n\tif (value == null) return undefined;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new Error(`xaiSearchModel in ${CONFIG_PATH} must be a non-empty string`);\n\t}\n\treturn value.trim();\n}\n\nfunction toRequestHeaders(headers: ProviderHeaders): Record<string, string> {\n\tconst requestHeaders: Record<string, string> = {};\n\tfor (const [name, value] of Object.entries(headers)) {\n\t\tif (value !== null) requestHeaders[name] = value;\n\t}\n\treturn requestHeaders;\n}\n\n/**\n * Resolve auth from pi's model registry first, so a Grok subscription pays for\n * its own searches and no api key has to be configured at all. Mirrors how the\n * OpenAI backend picks up a Codex sign-in.\n */\nasync function resolvePiAuth(ctx: ExtensionContext, modelOverride?: string): Promise<XaiAuth | undefined> {\n\tfor (const modelId of AUTH_MODEL_CANDIDATES) {\n\t\ttry {\n\t\t\tconst model = ctx.modelRegistry.find(\"xai\", modelId);\n\t\t\tif (!model) continue;\n\t\t\tconst resolved = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (resolved.ok && resolved.apiKey) {\n\t\t\t\treturn { apiKey: resolved.apiKey, model: modelOverride ?? modelId, headers: resolved.headers ?? {} };\n\t\t\t}\n\t\t} catch {\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport async function resolveXaiAuth(ctx?: ExtensionContext, signal?: AbortSignal): Promise<XaiAuth | undefined> {\n\tconst config = loadConfig();\n\tconst modelOverride = resolveConfiguredSearchModel(config.xaiSearchModel);\n\tif (ctx) {\n\t\tconst auth = await resolvePiAuth(ctx, modelOverride);\n\t\tif (auth) return auth;\n\t}\n\n\tconst hasSource = hasCredentialSource({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t});\n\tif (!hasSource) return undefined;\n\tconst apiKey = await resolveCredential({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t\tsignal,\n\t});\n\treturn apiKey ? { apiKey, model: modelOverride ?? AUTH_MODEL_CANDIDATES[0], headers: {} } : undefined;\n}\n\nexport async function isXaiSearchAvailable(ctx?: ExtensionContext): Promise<boolean> {\n\tif (ctx && await resolvePiAuth(ctx)) return true;\n\tconst config = loadConfig();\n\treturn hasCredentialSource({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t});\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\n/**\n * Recency, result count and domain filters are folded into the prompt rather\n * than sent as tool parameters. xAI's filter field names are not verified, and\n * an unknown field risks a 400 that costs the whole search; steering through\n * the instruction text degrades to \"the model ignored it\" instead.\n */\nfunction buildInput(query: string, options: SearchOptions): string {\n\tconst lines = [\n\t\t\"Search the web and answer using only what the web results say.\",\n\t\t\"Cite your sources inline.\",\n\t];\n\n\tif (options.recencyFilter) {\n\t\tconst labels: Record<string, string> = {\n\t\t\tday: \"past 24 hours\",\n\t\t\tweek: \"past week\",\n\t\t\tmonth: \"past month\",\n\t\t\tyear: \"past year\",\n\t\t};\n\t\tlines.push(`Prefer sources from the ${labels[options.recencyFilter]}.`);\n\t}\n\n\tif (typeof options.numResults === \"number\" && Number.isFinite(options.numResults) && options.numResults > 0) {\n\t\tlines.push(`Prefer around ${Math.min(Math.floor(options.numResults), 20)} distinct sources.`);\n\t}\n\n\tconst allowed: string[] = [];\n\tconst blocked: string[] = [];\n\tfor (const raw of options.domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? blocked : allowed;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\tif (allowed.length > 0) lines.push(`Only use sources from: ${allowed.slice(0, 100).join(\", \")}.`);\n\tif (blocked.length > 0) lines.push(`Do not use sources from: ${blocked.slice(0, 100).join(\", \")}.`);\n\n\treturn `${lines.join(\" \")}\\n\\n${query}`;\n}\n\nfunction addResult(results: SearchResult[], seen: Set<string>, url: unknown, title: unknown, snippet = \"\"): void {\n\tif (typeof url !== \"string\" || url.trim().length === 0) return;\n\tif (seen.has(url)) return;\n\tseen.add(url);\n\tresults.push({\n\t\ttitle: typeof title === \"string\" && title.trim().length > 0 ? title : url,\n\t\turl,\n\t\tsnippet,\n\t});\n}\n\nfunction extractSnippetAround(text: string, start: unknown, end: unknown): string {\n\tif (typeof start !== \"number\" || typeof end !== \"number\" || !text) return \"\";\n\tconst before = Math.max(0, start - 100);\n\tconst after = Math.min(text.length, end + 100);\n\tconst snippet = text.slice(before, after).replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\").trim();\n\treturn snippet.length > 300 ? `${snippet.slice(0, 297)}...` : snippet;\n}\n\nfunction extractAnswer(output: unknown[]): string {\n\tconst parts: string[] = [];\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"message\") continue;\n\t\tconst content = (item as { content?: unknown }).content;\n\t\tif (!Array.isArray(content)) continue;\n\t\tfor (const part of content) {\n\t\t\tif (!part || typeof part !== \"object\") continue;\n\t\t\tconst text = (part as { text?: unknown }).text;\n\t\t\tif (typeof text === \"string\" && text.trim().length > 0) parts.push(text);\n\t\t}\n\t}\n\treturn parts.join(\"\\n\").trim();\n}\n\n/**\n * Sources live in two places and neither is a top-level `citations` array:\n * `url_citation` annotations on the answer text (these carry titles and offsets,\n * so they go first and win the dedupe), and the raw `sources` each\n * `web_search_call` visited. A third-party extension that reads `data.citations`\n * silently returns answers with no sources at all — hence both paths here.\n */\nfunction extractSearchResults(output: unknown[], numResults: number | undefined): SearchResult[] {\n\tconst results: SearchResult[] = [];\n\tconst seenUrls = new Set<string>();\n\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"message\") continue;\n\t\tconst content = (item as { content?: unknown }).content;\n\t\tif (!Array.isArray(content)) continue;\n\t\tfor (const part of content) {\n\t\t\tif (!part || typeof part !== \"object\") continue;\n\t\t\tconst text = typeof (part as { text?: unknown }).text === \"string\" ? (part as { text: string }).text : \"\";\n\t\t\tconst annotations = (part as { annotations?: unknown }).annotations;\n\t\t\tif (!Array.isArray(annotations)) continue;\n\t\t\tfor (const annotation of annotations) {\n\t\t\t\tif (!annotation || typeof annotation !== \"object\") continue;\n\t\t\t\tif ((annotation as { type?: unknown }).type !== \"url_citation\") continue;\n\t\t\t\taddResult(\n\t\t\t\t\tresults,\n\t\t\t\t\tseenUrls,\n\t\t\t\t\t(annotation as { url?: unknown }).url,\n\t\t\t\t\t(annotation as { title?: unknown }).title,\n\t\t\t\t\textractSnippetAround(text, (annotation as { start_index?: unknown }).start_index, (annotation as { end_index?: unknown }).end_index),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"web_search_call\") continue;\n\t\tconst value = item as { action?: unknown; sources?: unknown; results?: unknown };\n\t\tconst actionSources = value.action && typeof value.action === \"object\"\n\t\t\t? (value.action as { sources?: unknown }).sources\n\t\t\t: undefined;\n\t\tfor (const group of [actionSources, value.sources, value.results]) {\n\t\t\tif (!Array.isArray(group)) continue;\n\t\t\tfor (const source of group) {\n\t\t\t\tif (!source || typeof source !== \"object\") continue;\n\t\t\t\tconst record = source as Record<string, unknown>;\n\t\t\t\taddResult(results, seenUrls, record.url ?? record.source_website_url, record.title ?? record.caption);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (typeof numResults === \"number\" && Number.isFinite(numResults) && numResults > 0) {\n\t\treturn results.slice(0, Math.min(Math.floor(numResults), 20));\n\t}\n\treturn results;\n}\n\nexport async function searchWithXai(\n\tquery: string,\n\toptions: SearchOptions = {},\n\tctx?: ExtensionContext,\n): Promise<SearchResponse> {\n\tconst auth = await resolveXaiAuth(ctx, options.signal);\n\tif (!auth) {\n\t\tthrow new Error(\n\t\t\t\"xAI web search unavailable. Either:\\n\" +\n\t\t\t\" 1. Use /login to sign in with a SuperGrok or X Premium subscription\\n\" +\n\t\t\t` 2. Create ${CONFIG_PATH} with { \"xaiApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 3. Set XAI_API_KEY environment variable\",\n\t\t);\n\t}\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\ttry {\n\t\tconst response = await fetch(XAI_RESPONSES_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...toRequestHeaders(auth.headers),\n\t\t\t\tAuthorization: `Bearer ${auth.apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: auth.model,\n\t\t\t\tinput: buildInput(query, options),\n\t\t\t\ttools: [{ type: \"web_search\" }],\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(), auth.apiKey);\n\t\t\tthrow new Error(`xAI API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tlet parsed: Record<string, unknown>;\n\t\ttry {\n\t\t\tparsed = await response.json() as Record<string, unknown>;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`xAI API returned invalid JSON: ${message}`);\n\t\t}\n\t\tconst output = Array.isArray(parsed.output) ? parsed.output : [];\n\t\tconst answer = extractAnswer(output);\n\t\tconst results = extractSearchResults(output, options.numResults);\n\n\t\tif (!answer && results.length === 0) {\n\t\t\tthrow new Error(\"xAI web_search returned no answer or sources\");\n\t\t}\n\n\t\tactivityMonitor.logComplete(activityId, response.status);\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, auth.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"]}
@@ -0,0 +1,331 @@
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
+ // xAI's Agent Tools API: a hosted `web_search` tool on an OpenAI-compatible
6
+ // Responses endpoint. The search runs inside xAI's own inference, so — unlike
7
+ // every keyed backend here — it is paid for by whatever credential answers for
8
+ // the model, including a SuperGrok / X Premium subscription resolved through
9
+ // pi's model registry.
10
+ //
11
+ // Note for anyone extending this: xAI's older Live Search (`search_parameters`
12
+ // on /v1/chat/completions) is GONE. It now answers 410 with "Live search is
13
+ // deprecated. Please switch to the Agent Tools API". Do not add it back.
14
+ //
15
+ // The request body is deliberately minimal — model, input, tools — because that
16
+ // is the shape verified against a live subscription account. `stream`,
17
+ // `include`, `tool_choice` and `parallel_tool_calls` are all sent by the OpenAI
18
+ // backend but were NOT verified here, and a 400 from an unsupported field would
19
+ // cost the user their search. Sources come back in `web_search_call.action.sources`
20
+ // without asking for them via `include`.
21
+ const XAI_RESPONSES_URL = "https://api.x.ai/v1/responses";
22
+ const CONFIG_PATH = getWebSearchConfigPath();
23
+ const SEARCH_TIMEOUT_MS = 60_000;
24
+ // Ordered best-first. pi's builtin xai catalog is small and xAI retires models
25
+ // briskly, so this is a preference list, not an assumption: the first one the
26
+ // registry actually knows wins, and an unknown id is skipped rather than sent.
27
+ const AUTH_MODEL_CANDIDATES = ["grok-4.5", "grok-4.3", "grok-build-0.1"];
28
+ let cachedConfig = null;
29
+ function loadConfig() {
30
+ if (cachedConfig)
31
+ return cachedConfig;
32
+ if (!existsSync(CONFIG_PATH)) {
33
+ cachedConfig = {};
34
+ return cachedConfig;
35
+ }
36
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
37
+ try {
38
+ cachedConfig = JSON.parse(raw);
39
+ return cachedConfig;
40
+ }
41
+ catch (err) {
42
+ const message = err instanceof Error ? err.message : String(err);
43
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
44
+ }
45
+ }
46
+ function resolveConfiguredSearchModel(value) {
47
+ if (value == null)
48
+ return undefined;
49
+ if (typeof value !== "string" || value.trim().length === 0) {
50
+ throw new Error(`xaiSearchModel in ${CONFIG_PATH} must be a non-empty string`);
51
+ }
52
+ return value.trim();
53
+ }
54
+ function toRequestHeaders(headers) {
55
+ const requestHeaders = {};
56
+ for (const [name, value] of Object.entries(headers)) {
57
+ if (value !== null)
58
+ requestHeaders[name] = value;
59
+ }
60
+ return requestHeaders;
61
+ }
62
+ /**
63
+ * Resolve auth from pi's model registry first, so a Grok subscription pays for
64
+ * its own searches and no api key has to be configured at all. Mirrors how the
65
+ * OpenAI backend picks up a Codex sign-in.
66
+ */
67
+ async function resolvePiAuth(ctx, modelOverride) {
68
+ for (const modelId of AUTH_MODEL_CANDIDATES) {
69
+ try {
70
+ const model = ctx.modelRegistry.find("xai", modelId);
71
+ if (!model)
72
+ continue;
73
+ const resolved = await ctx.modelRegistry.getApiKeyAndHeaders(model);
74
+ if (resolved.ok && resolved.apiKey) {
75
+ return { apiKey: resolved.apiKey, model: modelOverride ?? modelId, headers: resolved.headers ?? {} };
76
+ }
77
+ }
78
+ catch {
79
+ }
80
+ }
81
+ return undefined;
82
+ }
83
+ export async function resolveXaiAuth(ctx, signal) {
84
+ const config = loadConfig();
85
+ const modelOverride = resolveConfiguredSearchModel(config.xaiSearchModel);
86
+ if (ctx) {
87
+ const auth = await resolvePiAuth(ctx, modelOverride);
88
+ if (auth)
89
+ return auth;
90
+ }
91
+ const hasSource = hasCredentialSource({
92
+ provider: "xAI",
93
+ configuredValue: config.xaiApiKey,
94
+ environmentValue: process.env.XAI_API_KEY,
95
+ });
96
+ if (!hasSource)
97
+ return undefined;
98
+ const apiKey = await resolveCredential({
99
+ provider: "xAI",
100
+ configuredValue: config.xaiApiKey,
101
+ environmentValue: process.env.XAI_API_KEY,
102
+ signal,
103
+ });
104
+ return apiKey ? { apiKey, model: modelOverride ?? AUTH_MODEL_CANDIDATES[0], headers: {} } : undefined;
105
+ }
106
+ export async function isXaiSearchAvailable(ctx) {
107
+ if (ctx && await resolvePiAuth(ctx))
108
+ return true;
109
+ const config = loadConfig();
110
+ return hasCredentialSource({
111
+ provider: "xAI",
112
+ configuredValue: config.xaiApiKey,
113
+ environmentValue: process.env.XAI_API_KEY,
114
+ });
115
+ }
116
+ function normalizeDomain(value) {
117
+ let input = value.trim().toLowerCase();
118
+ if (!input)
119
+ return null;
120
+ if (input.startsWith("-"))
121
+ input = input.slice(1).trim();
122
+ if (!input)
123
+ return null;
124
+ try {
125
+ const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
126
+ input = parsed.hostname;
127
+ }
128
+ catch {
129
+ input = input.split("/")[0]?.split(":")[0] ?? "";
130
+ }
131
+ input = input.replace(/^\.+|\.+$/g, "");
132
+ return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
133
+ }
134
+ /**
135
+ * Recency, result count and domain filters are folded into the prompt rather
136
+ * than sent as tool parameters. xAI's filter field names are not verified, and
137
+ * an unknown field risks a 400 that costs the whole search; steering through
138
+ * the instruction text degrades to "the model ignored it" instead.
139
+ */
140
+ function buildInput(query, options) {
141
+ const lines = [
142
+ "Search the web and answer using only what the web results say.",
143
+ "Cite your sources inline.",
144
+ ];
145
+ if (options.recencyFilter) {
146
+ const labels = {
147
+ day: "past 24 hours",
148
+ week: "past week",
149
+ month: "past month",
150
+ year: "past year",
151
+ };
152
+ lines.push(`Prefer sources from the ${labels[options.recencyFilter]}.`);
153
+ }
154
+ if (typeof options.numResults === "number" && Number.isFinite(options.numResults) && options.numResults > 0) {
155
+ lines.push(`Prefer around ${Math.min(Math.floor(options.numResults), 20)} distinct sources.`);
156
+ }
157
+ const allowed = [];
158
+ const blocked = [];
159
+ for (const raw of options.domainFilter ?? []) {
160
+ const domain = normalizeDomain(raw);
161
+ if (!domain)
162
+ continue;
163
+ const target = raw.trim().startsWith("-") ? blocked : allowed;
164
+ if (!target.includes(domain))
165
+ target.push(domain);
166
+ }
167
+ if (allowed.length > 0)
168
+ lines.push(`Only use sources from: ${allowed.slice(0, 100).join(", ")}.`);
169
+ if (blocked.length > 0)
170
+ lines.push(`Do not use sources from: ${blocked.slice(0, 100).join(", ")}.`);
171
+ return `${lines.join(" ")}\n\n${query}`;
172
+ }
173
+ function addResult(results, seen, url, title, snippet = "") {
174
+ if (typeof url !== "string" || url.trim().length === 0)
175
+ return;
176
+ if (seen.has(url))
177
+ return;
178
+ seen.add(url);
179
+ results.push({
180
+ title: typeof title === "string" && title.trim().length > 0 ? title : url,
181
+ url,
182
+ snippet,
183
+ });
184
+ }
185
+ function extractSnippetAround(text, start, end) {
186
+ if (typeof start !== "number" || typeof end !== "number" || !text)
187
+ return "";
188
+ const before = Math.max(0, start - 100);
189
+ const after = Math.min(text.length, end + 100);
190
+ const snippet = text.slice(before, after).replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").trim();
191
+ return snippet.length > 300 ? `${snippet.slice(0, 297)}...` : snippet;
192
+ }
193
+ function extractAnswer(output) {
194
+ const parts = [];
195
+ for (const item of output) {
196
+ if (!item || typeof item !== "object" || item.type !== "message")
197
+ continue;
198
+ const content = item.content;
199
+ if (!Array.isArray(content))
200
+ continue;
201
+ for (const part of content) {
202
+ if (!part || typeof part !== "object")
203
+ continue;
204
+ const text = part.text;
205
+ if (typeof text === "string" && text.trim().length > 0)
206
+ parts.push(text);
207
+ }
208
+ }
209
+ return parts.join("\n").trim();
210
+ }
211
+ /**
212
+ * Sources live in two places and neither is a top-level `citations` array:
213
+ * `url_citation` annotations on the answer text (these carry titles and offsets,
214
+ * so they go first and win the dedupe), and the raw `sources` each
215
+ * `web_search_call` visited. A third-party extension that reads `data.citations`
216
+ * silently returns answers with no sources at all — hence both paths here.
217
+ */
218
+ function extractSearchResults(output, numResults) {
219
+ const results = [];
220
+ const seenUrls = new Set();
221
+ for (const item of output) {
222
+ if (!item || typeof item !== "object" || item.type !== "message")
223
+ continue;
224
+ const content = item.content;
225
+ if (!Array.isArray(content))
226
+ continue;
227
+ for (const part of content) {
228
+ if (!part || typeof part !== "object")
229
+ continue;
230
+ const text = typeof part.text === "string" ? part.text : "";
231
+ const annotations = part.annotations;
232
+ if (!Array.isArray(annotations))
233
+ continue;
234
+ for (const annotation of annotations) {
235
+ if (!annotation || typeof annotation !== "object")
236
+ continue;
237
+ if (annotation.type !== "url_citation")
238
+ continue;
239
+ addResult(results, seenUrls, annotation.url, annotation.title, extractSnippetAround(text, annotation.start_index, annotation.end_index));
240
+ }
241
+ }
242
+ }
243
+ for (const item of output) {
244
+ if (!item || typeof item !== "object" || item.type !== "web_search_call")
245
+ continue;
246
+ const value = item;
247
+ const actionSources = value.action && typeof value.action === "object"
248
+ ? value.action.sources
249
+ : undefined;
250
+ for (const group of [actionSources, value.sources, value.results]) {
251
+ if (!Array.isArray(group))
252
+ continue;
253
+ for (const source of group) {
254
+ if (!source || typeof source !== "object")
255
+ continue;
256
+ const record = source;
257
+ addResult(results, seenUrls, record.url ?? record.source_website_url, record.title ?? record.caption);
258
+ }
259
+ }
260
+ }
261
+ if (typeof numResults === "number" && Number.isFinite(numResults) && numResults > 0) {
262
+ return results.slice(0, Math.min(Math.floor(numResults), 20));
263
+ }
264
+ return results;
265
+ }
266
+ export async function searchWithXai(query, options = {}, ctx) {
267
+ const auth = await resolveXaiAuth(ctx, options.signal);
268
+ if (!auth) {
269
+ throw new Error("xAI web search unavailable. Either:\n" +
270
+ " 1. Use /login to sign in with a SuperGrok or X Premium subscription\n" +
271
+ ` 2. Create ${CONFIG_PATH} with { "xaiApiKey": "your-key" }\n` +
272
+ " 3. Set XAI_API_KEY environment variable");
273
+ }
274
+ const activityId = activityMonitor.logStart({ type: "api", query });
275
+ try {
276
+ const response = await fetch(XAI_RESPONSES_URL, {
277
+ method: "POST",
278
+ headers: {
279
+ ...toRequestHeaders(auth.headers),
280
+ Authorization: `Bearer ${auth.apiKey}`,
281
+ "Content-Type": "application/json",
282
+ },
283
+ body: JSON.stringify({
284
+ model: auth.model,
285
+ input: buildInput(query, options),
286
+ tools: [{ type: "web_search" }],
287
+ }),
288
+ signal: options.signal
289
+ ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal])
290
+ : AbortSignal.timeout(SEARCH_TIMEOUT_MS),
291
+ });
292
+ if (!response.ok) {
293
+ activityMonitor.logError(activityId, `HTTP ${response.status}`);
294
+ const errorText = redactCredential(await response.text(), auth.apiKey);
295
+ throw new Error(`xAI API error ${response.status}: ${errorText.slice(0, 300)}`);
296
+ }
297
+ let parsed;
298
+ try {
299
+ parsed = await response.json();
300
+ }
301
+ catch (err) {
302
+ const message = err instanceof Error ? err.message : String(err);
303
+ throw new Error(`xAI API returned invalid JSON: ${message}`);
304
+ }
305
+ const output = Array.isArray(parsed.output) ? parsed.output : [];
306
+ const answer = extractAnswer(output);
307
+ const results = extractSearchResults(output, options.numResults);
308
+ if (!answer && results.length === 0) {
309
+ throw new Error("xAI web_search returned no answer or sources");
310
+ }
311
+ activityMonitor.logComplete(activityId, response.status);
312
+ return { answer, results };
313
+ }
314
+ catch (err) {
315
+ const message = err instanceof Error ? err.message : String(err);
316
+ const redactedMessage = redactCredential(message, auth.apiKey);
317
+ if (redactedMessage.toLowerCase().includes("abort")) {
318
+ activityMonitor.logComplete(activityId, 0);
319
+ }
320
+ else {
321
+ activityMonitor.logError(activityId, redactedMessage);
322
+ }
323
+ if (redactedMessage === message)
324
+ throw err;
325
+ const redactedError = new Error(redactedMessage);
326
+ if (err instanceof Error)
327
+ redactedError.name = err.name;
328
+ throw redactedError;
329
+ }
330
+ }
331
+ //# sourceMappingURL=xai-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/xai-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport type { ExtensionContext } from \"../host.ts\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse, SearchResult } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\n// xAI's Agent Tools API: a hosted `web_search` tool on an OpenAI-compatible\n// Responses endpoint. The search runs inside xAI's own inference, so — unlike\n// every keyed backend here — it is paid for by whatever credential answers for\n// the model, including a SuperGrok / X Premium subscription resolved through\n// pi's model registry.\n//\n// Note for anyone extending this: xAI's older Live Search (`search_parameters`\n// on /v1/chat/completions) is GONE. It now answers 410 with \"Live search is\n// deprecated. Please switch to the Agent Tools API\". Do not add it back.\n//\n// The request body is deliberately minimal — model, input, tools — because that\n// is the shape verified against a live subscription account. `stream`,\n// `include`, `tool_choice` and `parallel_tool_calls` are all sent by the OpenAI\n// backend but were NOT verified here, and a 400 from an unsupported field would\n// cost the user their search. Sources come back in `web_search_call.action.sources`\n// without asking for them via `include`.\n\nconst XAI_RESPONSES_URL = \"https://api.x.ai/v1/responses\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\n// Ordered best-first. pi's builtin xai catalog is small and xAI retires models\n// briskly, so this is a preference list, not an assumption: the first one the\n// registry actually knows wins, and an unknown id is skipped rather than sent.\nconst AUTH_MODEL_CANDIDATES = [\"grok-4.5\", \"grok-4.3\", \"grok-build-0.1\"] as const;\n\ninterface WebSearchConfig {\n\txaiApiKey?: unknown;\n\txaiSearchModel?: unknown;\n}\n\ntype ProviderHeaders = Record<string, string | null>;\n\ninterface XaiAuth {\n\tapiKey: string;\n\tmodel: string;\n\theaders: ProviderHeaders;\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\nfunction resolveConfiguredSearchModel(value: unknown): string | undefined {\n\tif (value == null) return undefined;\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new Error(`xaiSearchModel in ${CONFIG_PATH} must be a non-empty string`);\n\t}\n\treturn value.trim();\n}\n\nfunction toRequestHeaders(headers: ProviderHeaders): Record<string, string> {\n\tconst requestHeaders: Record<string, string> = {};\n\tfor (const [name, value] of Object.entries(headers)) {\n\t\tif (value !== null) requestHeaders[name] = value;\n\t}\n\treturn requestHeaders;\n}\n\n/**\n * Resolve auth from pi's model registry first, so a Grok subscription pays for\n * its own searches and no api key has to be configured at all. Mirrors how the\n * OpenAI backend picks up a Codex sign-in.\n */\nasync function resolvePiAuth(ctx: ExtensionContext, modelOverride?: string): Promise<XaiAuth | undefined> {\n\tfor (const modelId of AUTH_MODEL_CANDIDATES) {\n\t\ttry {\n\t\t\tconst model = ctx.modelRegistry.find(\"xai\", modelId);\n\t\t\tif (!model) continue;\n\t\t\tconst resolved = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\t\t\tif (resolved.ok && resolved.apiKey) {\n\t\t\t\treturn { apiKey: resolved.apiKey, model: modelOverride ?? modelId, headers: resolved.headers ?? {} };\n\t\t\t}\n\t\t} catch {\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport async function resolveXaiAuth(ctx?: ExtensionContext, signal?: AbortSignal): Promise<XaiAuth | undefined> {\n\tconst config = loadConfig();\n\tconst modelOverride = resolveConfiguredSearchModel(config.xaiSearchModel);\n\tif (ctx) {\n\t\tconst auth = await resolvePiAuth(ctx, modelOverride);\n\t\tif (auth) return auth;\n\t}\n\n\tconst hasSource = hasCredentialSource({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t});\n\tif (!hasSource) return undefined;\n\tconst apiKey = await resolveCredential({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t\tsignal,\n\t});\n\treturn apiKey ? { apiKey, model: modelOverride ?? AUTH_MODEL_CANDIDATES[0], headers: {} } : undefined;\n}\n\nexport async function isXaiSearchAvailable(ctx?: ExtensionContext): Promise<boolean> {\n\tif (ctx && await resolvePiAuth(ctx)) return true;\n\tconst config = loadConfig();\n\treturn hasCredentialSource({\n\t\tprovider: \"xAI\",\n\t\tconfiguredValue: config.xaiApiKey,\n\t\tenvironmentValue: process.env.XAI_API_KEY,\n\t});\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\n/**\n * Recency, result count and domain filters are folded into the prompt rather\n * than sent as tool parameters. xAI's filter field names are not verified, and\n * an unknown field risks a 400 that costs the whole search; steering through\n * the instruction text degrades to \"the model ignored it\" instead.\n */\nfunction buildInput(query: string, options: SearchOptions): string {\n\tconst lines = [\n\t\t\"Search the web and answer using only what the web results say.\",\n\t\t\"Cite your sources inline.\",\n\t];\n\n\tif (options.recencyFilter) {\n\t\tconst labels: Record<string, string> = {\n\t\t\tday: \"past 24 hours\",\n\t\t\tweek: \"past week\",\n\t\t\tmonth: \"past month\",\n\t\t\tyear: \"past year\",\n\t\t};\n\t\tlines.push(`Prefer sources from the ${labels[options.recencyFilter]}.`);\n\t}\n\n\tif (typeof options.numResults === \"number\" && Number.isFinite(options.numResults) && options.numResults > 0) {\n\t\tlines.push(`Prefer around ${Math.min(Math.floor(options.numResults), 20)} distinct sources.`);\n\t}\n\n\tconst allowed: string[] = [];\n\tconst blocked: string[] = [];\n\tfor (const raw of options.domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? blocked : allowed;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\tif (allowed.length > 0) lines.push(`Only use sources from: ${allowed.slice(0, 100).join(\", \")}.`);\n\tif (blocked.length > 0) lines.push(`Do not use sources from: ${blocked.slice(0, 100).join(\", \")}.`);\n\n\treturn `${lines.join(\" \")}\\n\\n${query}`;\n}\n\nfunction addResult(results: SearchResult[], seen: Set<string>, url: unknown, title: unknown, snippet = \"\"): void {\n\tif (typeof url !== \"string\" || url.trim().length === 0) return;\n\tif (seen.has(url)) return;\n\tseen.add(url);\n\tresults.push({\n\t\ttitle: typeof title === \"string\" && title.trim().length > 0 ? title : url,\n\t\turl,\n\t\tsnippet,\n\t});\n}\n\nfunction extractSnippetAround(text: string, start: unknown, end: unknown): string {\n\tif (typeof start !== \"number\" || typeof end !== \"number\" || !text) return \"\";\n\tconst before = Math.max(0, start - 100);\n\tconst after = Math.min(text.length, end + 100);\n\tconst snippet = text.slice(before, after).replace(/\\[([^\\]]*)\\]\\([^)]*\\)/g, \"$1\").trim();\n\treturn snippet.length > 300 ? `${snippet.slice(0, 297)}...` : snippet;\n}\n\nfunction extractAnswer(output: unknown[]): string {\n\tconst parts: string[] = [];\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"message\") continue;\n\t\tconst content = (item as { content?: unknown }).content;\n\t\tif (!Array.isArray(content)) continue;\n\t\tfor (const part of content) {\n\t\t\tif (!part || typeof part !== \"object\") continue;\n\t\t\tconst text = (part as { text?: unknown }).text;\n\t\t\tif (typeof text === \"string\" && text.trim().length > 0) parts.push(text);\n\t\t}\n\t}\n\treturn parts.join(\"\\n\").trim();\n}\n\n/**\n * Sources live in two places and neither is a top-level `citations` array:\n * `url_citation` annotations on the answer text (these carry titles and offsets,\n * so they go first and win the dedupe), and the raw `sources` each\n * `web_search_call` visited. A third-party extension that reads `data.citations`\n * silently returns answers with no sources at all — hence both paths here.\n */\nfunction extractSearchResults(output: unknown[], numResults: number | undefined): SearchResult[] {\n\tconst results: SearchResult[] = [];\n\tconst seenUrls = new Set<string>();\n\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"message\") continue;\n\t\tconst content = (item as { content?: unknown }).content;\n\t\tif (!Array.isArray(content)) continue;\n\t\tfor (const part of content) {\n\t\t\tif (!part || typeof part !== \"object\") continue;\n\t\t\tconst text = typeof (part as { text?: unknown }).text === \"string\" ? (part as { text: string }).text : \"\";\n\t\t\tconst annotations = (part as { annotations?: unknown }).annotations;\n\t\t\tif (!Array.isArray(annotations)) continue;\n\t\t\tfor (const annotation of annotations) {\n\t\t\t\tif (!annotation || typeof annotation !== \"object\") continue;\n\t\t\t\tif ((annotation as { type?: unknown }).type !== \"url_citation\") continue;\n\t\t\t\taddResult(\n\t\t\t\t\tresults,\n\t\t\t\t\tseenUrls,\n\t\t\t\t\t(annotation as { url?: unknown }).url,\n\t\t\t\t\t(annotation as { title?: unknown }).title,\n\t\t\t\t\textractSnippetAround(text, (annotation as { start_index?: unknown }).start_index, (annotation as { end_index?: unknown }).end_index),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const item of output) {\n\t\tif (!item || typeof item !== \"object\" || (item as { type?: unknown }).type !== \"web_search_call\") continue;\n\t\tconst value = item as { action?: unknown; sources?: unknown; results?: unknown };\n\t\tconst actionSources = value.action && typeof value.action === \"object\"\n\t\t\t? (value.action as { sources?: unknown }).sources\n\t\t\t: undefined;\n\t\tfor (const group of [actionSources, value.sources, value.results]) {\n\t\t\tif (!Array.isArray(group)) continue;\n\t\t\tfor (const source of group) {\n\t\t\t\tif (!source || typeof source !== \"object\") continue;\n\t\t\t\tconst record = source as Record<string, unknown>;\n\t\t\t\taddResult(results, seenUrls, record.url ?? record.source_website_url, record.title ?? record.caption);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (typeof numResults === \"number\" && Number.isFinite(numResults) && numResults > 0) {\n\t\treturn results.slice(0, Math.min(Math.floor(numResults), 20));\n\t}\n\treturn results;\n}\n\nexport async function searchWithXai(\n\tquery: string,\n\toptions: SearchOptions = {},\n\tctx?: ExtensionContext,\n): Promise<SearchResponse> {\n\tconst auth = await resolveXaiAuth(ctx, options.signal);\n\tif (!auth) {\n\t\tthrow new Error(\n\t\t\t\"xAI web search unavailable. Either:\\n\" +\n\t\t\t\" 1. Use /login to sign in with a SuperGrok or X Premium subscription\\n\" +\n\t\t\t` 2. Create ${CONFIG_PATH} with { \"xaiApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 3. Set XAI_API_KEY environment variable\",\n\t\t);\n\t}\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\ttry {\n\t\tconst response = await fetch(XAI_RESPONSES_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...toRequestHeaders(auth.headers),\n\t\t\t\tAuthorization: `Bearer ${auth.apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: auth.model,\n\t\t\t\tinput: buildInput(query, options),\n\t\t\t\ttools: [{ type: \"web_search\" }],\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(), auth.apiKey);\n\t\t\tthrow new Error(`xAI API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tlet parsed: Record<string, unknown>;\n\t\ttry {\n\t\t\tparsed = await response.json() as Record<string, unknown>;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`xAI API returned invalid JSON: ${message}`);\n\t\t}\n\t\tconst output = Array.isArray(parsed.output) ? parsed.output : [];\n\t\tconst answer = extractAnswer(output);\n\t\tconst results = extractSearchResults(output, options.numResults);\n\n\t\tif (!answer && results.length === 0) {\n\t\t\tthrow new Error(\"xAI web_search returned no answer or sources\");\n\t\t}\n\n\t\tactivityMonitor.logComplete(activityId, response.status);\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, auth.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"]}
@@ -0,0 +1,27 @@
1
+ import { type ExtractedContent, type FrameResult, type VideoFrame } from "./extract.ts";
2
+ export declare function isYouTubeURL(url: string): {
3
+ isYouTube: boolean;
4
+ videoId: string | null;
5
+ };
6
+ export declare function isYouTubeEnabled(): boolean;
7
+ export declare function extractYouTube(url: string, signal?: AbortSignal, prompt?: string, model?: string): Promise<ExtractedContent | null>;
8
+ type StreamInfo = {
9
+ streamUrl: string;
10
+ duration: number | null;
11
+ };
12
+ type StreamResult = StreamInfo | {
13
+ error: string;
14
+ };
15
+ export declare function getYouTubeStreamInfo(videoId: string): Promise<StreamResult>;
16
+ export declare function extractYouTubeFrame(videoId: string, seconds: number, streamInfo?: StreamInfo): Promise<FrameResult>;
17
+ export declare function extractYouTubeFrames(videoId: string, timestamps: number[], streamInfo?: StreamInfo): Promise<{
18
+ frames: VideoFrame[];
19
+ duration: number | null;
20
+ error: string | null;
21
+ }>;
22
+ export declare function fetchYouTubeThumbnail(videoId: string): Promise<{
23
+ data: string;
24
+ mimeType: string;
25
+ } | null>;
26
+ export {};
27
+ //# sourceMappingURL=youtube-extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube-extract.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/youtube-extract.ts"],"names":[],"mappings":"AAOA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAuE7G,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAYxF;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAsB,cAAc,CACnC,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAoClC;AAED,KAAK,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AACjE,KAAK,YAAY,GAAG,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAenD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAgBjF;AAeD,wBAAsB,mBAAmB,CACxC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,UAAU,GACrB,OAAO,CAAC,WAAW,CAAC,CAItB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAAE,EACpB,UAAU,CAAC,EAAE,UAAU,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAWlF;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAY/G","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { canAttachImages } from \"./feature-config.ts\";\nimport { isGeminiWebAvailable, queryWithCookies } from \"./gemini-web.ts\";\nimport { isGeminiApiAvailable, queryGeminiApiWithVideo } from \"./gemini-api.ts\";\nimport { isPerplexityAvailable, searchWithPerplexity } from \"./perplexity.ts\";\nimport { extractHeadingTitle, type ExtractedContent, type FrameResult, type VideoFrame } from \"./extract.ts\";\nimport { formatSeconds, readExecError, isTimeoutError, trimErrorText, mapFfmpegError, getWebSearchConfigPath } from \"./utils.ts\";\n\nconst CONFIG_PATH = getWebSearchConfigPath();\n\nconst YOUTUBE_PROMPT = `Extract the complete content of this YouTube video. Include:\n1. Video title, channel name, and duration\n2. A brief summary (2-3 sentences)\n3. Full transcript with timestamps\n4. Descriptions of any code, terminal commands, diagrams, slides, or UI shown on screen\n\nFormat as markdown.`;\n\nconst YOUTUBE_REGEX =\n\t/(?:(?:www\\.|m\\.)?youtube\\.com\\/(?:watch\\?.*v=|shorts\\/|live\\/|embed\\/|v\\/)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/;\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction shouldRethrow(err: unknown): boolean {\n\treturn errorMessage(err).startsWith(\"Failed to parse \");\n}\n\nfunction addAttemptError(errors: string[], label: string, err: unknown): void {\n\tconst message = errorMessage(err).replace(/\\s+/g, \" \").trim();\n\tif (message) errors.push(`${label}: ${message}`);\n}\n\ninterface YouTubeConfig {\n\tenabled: boolean;\n\tpreferredModel: string;\n}\n\nfunction normalizePreferredModel(value: unknown, fallback: string): string {\n\tif (typeof value !== \"string\") return fallback;\n\tconst normalized = value.trim();\n\treturn normalized.length > 0 ? normalized : fallback;\n}\n\nfunction normalizeEnabled(value: unknown, fallback: boolean): boolean {\n\treturn typeof value === \"boolean\" ? value : fallback;\n}\n\nconst defaults: YouTubeConfig = { enabled: true, preferredModel: \"gemini-3.6-flash\" };\nlet cachedConfig: YouTubeConfig | null = null;\n\nfunction loadYouTubeConfig(): YouTubeConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = { ...defaults };\n\t\treturn cachedConfig;\n\t}\n\n\tconst rawText = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet raw: { youtube?: { enabled?: boolean; preferredModel?: string } };\n\ttry {\n\t\traw = JSON.parse(rawText) as { youtube?: { enabled?: boolean; preferredModel?: string } };\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\tconst yt = raw.youtube ?? {};\n\tcachedConfig = {\n\t\tenabled: normalizeEnabled(yt.enabled, defaults.enabled),\n\t\tpreferredModel: normalizePreferredModel(yt.preferredModel, defaults.preferredModel),\n\t};\n\treturn cachedConfig;\n}\n\nexport function isYouTubeURL(url: string): { isYouTube: boolean; videoId: string | null } {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tif (parsed.pathname === \"/playlist\") {\n\t\t\treturn { isYouTube: false, videoId: null };\n\t\t}\n\t} catch {\n\t}\n\n\tconst match = url.match(YOUTUBE_REGEX);\n\tif (!match) return { isYouTube: false, videoId: null };\n\treturn { isYouTube: true, videoId: match[1] };\n}\n\nexport function isYouTubeEnabled(): boolean {\n\treturn loadYouTubeConfig().enabled;\n}\n\nexport async function extractYouTube(\n\turl: string,\n\tsignal?: AbortSignal,\n\tprompt?: string,\n\tmodel?: string,\n): Promise<ExtractedContent | null> {\n\tconst config = loadYouTubeConfig();\n\tconst { videoId } = isYouTubeURL(url);\n\tconst canonicalUrl = videoId\n\t\t? `https://www.youtube.com/watch?v=${videoId}`\n\t\t: url;\n\tconst effectivePrompt = prompt ?? YOUTUBE_PROMPT;\n\tconst effectiveModel = model ?? config.preferredModel;\n\n\tconst activityId = activityMonitor.logStart({ type: \"fetch\", url: `youtube.com/${videoId ?? \"video\"}` });\n\tconst attemptErrors: string[] = [];\n\n\tconst result = await tryGeminiWeb(canonicalUrl, effectivePrompt, effectiveModel, signal, attemptErrors)\n\t\t?? await tryGeminiApi(canonicalUrl, effectivePrompt, effectiveModel, signal, attemptErrors)\n\t\t?? await tryPerplexity(url, effectivePrompt, signal, attemptErrors);\n\n\tif (result) {\n\t\tresult.url = url;\n\t\tif (!result.error && videoId && canAttachImages()) {\n\t\t\tconst thumb = await fetchYouTubeThumbnail(videoId);\n\t\t\tif (thumb) result.thumbnail = thumb;\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, result.error ? 0 : 200);\n\t\treturn result;\n\t}\n\n\tif (signal?.aborted) {\n\t\tactivityMonitor.logComplete(activityId, 0);\n\t\treturn null;\n\t}\n\n\tconst error = attemptErrors.length > 0\n\t\t? [\"Could not extract YouTube video content.\", \"\", ...attemptErrors.map(message => `- ${message}`)].join(\"\\n\")\n\t\t: \"Could not extract YouTube video content. Sign into Google in a supported Chromium browser for automatic access, or set GEMINI_API_KEY.\";\n\tactivityMonitor.logError(activityId, error);\n\treturn { url, title: \"\", content: \"\", error };\n}\n\ntype StreamInfo = { streamUrl: string; duration: number | null };\ntype StreamResult = StreamInfo | { error: string };\n\nfunction mapYtDlpError(err: unknown): string {\n\tconst { code, stderr, message } = readExecError(err);\n\tif (code === \"ENOENT\") return \"yt-dlp is not installed. Install with: brew install yt-dlp\";\n\tif (isTimeoutError(err)) return \"yt-dlp timed out fetching video info\";\n\tconst lower = stderr.toLowerCase();\n\tif (lower.includes(\"private\")) return \"Video is private or unavailable\";\n\tif (lower.includes(\"sign in\")) return \"Video is age-restricted and requires authentication\";\n\tif (lower.includes(\"not available\")) return \"Video is unavailable in your region or has been removed\";\n\tif (lower.includes(\"live\")) return \"Cannot extract frames from a live stream\";\n\tconst snippet = trimErrorText(stderr || message);\n\treturn snippet ? `yt-dlp failed: ${snippet}` : \"yt-dlp failed\";\n}\n\nexport async function getYouTubeStreamInfo(videoId: string): Promise<StreamResult> {\n\ttry {\n\t\tconst output = execFileSync(\"yt-dlp\", [\n\t\t\t\"--print\", \"duration\",\n\t\t\t\"-g\", `https://www.youtube.com/watch?v=${videoId}`,\n\t\t], { timeout: 15000, encoding: \"utf-8\", stdio: [\"pipe\", \"pipe\", \"pipe\"] }).trim();\n\t\tconst lines = output.split(/\\r?\\n/);\n\t\tconst rawDuration = lines[0]?.trim();\n\t\tconst streamUrl = lines[1]?.trim();\n\t\tif (!streamUrl) return { error: \"yt-dlp failed: missing stream URL\" };\n\t\tconst parsedDuration = rawDuration && rawDuration !== \"NA\" ? Number.parseFloat(rawDuration) : NaN;\n\t\tconst duration = Number.isFinite(parsedDuration) ? parsedDuration : null;\n\t\treturn { streamUrl, duration };\n\t} catch (err) {\n\t\treturn { error: mapYtDlpError(err) };\n\t}\n}\n\nasync function extractFrameFromStream(streamUrl: string, seconds: number): Promise<FrameResult> {\n\ttry {\n\t\tconst buffer = execFileSync(\"ffmpeg\", [\n\t\t\t\"-ss\", String(seconds), \"-i\", streamUrl,\n\t\t\t\"-frames:v\", \"1\", \"-f\", \"image2pipe\", \"-vcodec\", \"mjpeg\", \"pipe:1\",\n\t\t], { maxBuffer: 5 * 1024 * 1024, timeout: 30000, stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n\t\tif (buffer.length === 0) return { error: \"ffmpeg failed: empty output\" };\n\t\treturn { data: buffer.toString(\"base64\"), mimeType: \"image/jpeg\" };\n\t} catch (err) {\n\t\treturn { error: mapFfmpegError(err) };\n\t}\n}\n\nexport async function extractYouTubeFrame(\n\tvideoId: string,\n\tseconds: number,\n\tstreamInfo?: StreamInfo,\n): Promise<FrameResult> {\n\tconst info = streamInfo ?? await getYouTubeStreamInfo(videoId);\n\tif (\"error\" in info) return info;\n\treturn extractFrameFromStream(info.streamUrl, seconds);\n}\n\nexport async function extractYouTubeFrames(\n\tvideoId: string,\n\ttimestamps: number[],\n\tstreamInfo?: StreamInfo,\n): Promise<{ frames: VideoFrame[]; duration: number | null; error: string | null }> {\n\tconst info = streamInfo ?? await getYouTubeStreamInfo(videoId);\n\tif (\"error\" in info) return { frames: [], duration: null, error: info.error };\n\tconst results = await Promise.all(timestamps.map(async (t) => {\n\t\tconst frame = await extractFrameFromStream(info.streamUrl, t);\n\t\tif (\"error\" in frame) return { error: frame.error };\n\t\treturn { ...frame, timestamp: formatSeconds(t) };\n\t}));\n\tconst frames = results.filter((f): f is VideoFrame => \"data\" in f);\n\tconst errorResult = results.find((f): f is { error: string } => \"error\" in f);\n\treturn { frames, duration: info.duration, error: frames.length === 0 && errorResult ? errorResult.error : null };\n}\n\nexport async function fetchYouTubeThumbnail(videoId: string): Promise<{ data: string; mimeType: string } | null> {\n\ttry {\n\t\tconst res = await fetch(`https://img.youtube.com/vi/${videoId}/hqdefault.jpg`, {\n\t\t\tsignal: AbortSignal.timeout(5000),\n\t\t});\n\t\tif (!res.ok) return null;\n\t\tconst buffer = Buffer.from(await res.arrayBuffer());\n\t\tif (buffer.length === 0) return null;\n\t\treturn { data: buffer.toString(\"base64\"), mimeType: \"image/jpeg\" };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function tryGeminiWeb(\n\turl: string,\n\tprompt: string,\n\tmodel: string,\n\tsignal: AbortSignal | undefined,\n\tattemptErrors: string[],\n): Promise<ExtractedContent | null> {\n\ttry {\n\t\tconst cookies = await isGeminiWebAvailable();\n\t\tif (!cookies) return null;\n\n\t\tif (signal?.aborted) return null;\n\n\t\tconst text = await queryWithCookies(prompt, cookies, {\n\t\t\tyoutubeUrl: url,\n\t\t\t...(model !== \"gemini-3.6-flash\" ? { model } : {}),\n\t\t\tsignal,\n\t\t\ttimeoutMs: 120000,\n\t\t});\n\n\t\treturn {\n\t\t\turl,\n\t\t\ttitle: extractHeadingTitle(text) ?? \"YouTube Video\",\n\t\t\tcontent: text,\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tif (shouldRethrow(err)) throw err;\n\t\tif (!signal?.aborted) addAttemptError(attemptErrors, \"Gemini Web\", err);\n\t\treturn null;\n\t}\n}\n\nasync function tryGeminiApi(\n\turl: string,\n\tprompt: string,\n\tmodel: string,\n\tsignal: AbortSignal | undefined,\n\tattemptErrors: string[],\n): Promise<ExtractedContent | null> {\n\ttry {\n\t\tif (!isGeminiApiAvailable()) return null;\n\n\t\tif (signal?.aborted) return null;\n\n\t\tconst text = await queryGeminiApiWithVideo(prompt, url, {\n\t\t\tmodel,\n\t\t\tsignal,\n\t\t\ttimeoutMs: 120000,\n\t\t});\n\n\t\treturn {\n\t\t\turl,\n\t\t\ttitle: extractHeadingTitle(text) ?? \"YouTube Video\",\n\t\t\tcontent: text,\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tif (shouldRethrow(err)) throw err;\n\t\tif (!signal?.aborted) addAttemptError(attemptErrors, \"Gemini API\", err);\n\t\treturn null;\n\t}\n}\n\nasync function tryPerplexity(\n\turl: string,\n\tprompt: string,\n\tsignal: AbortSignal | undefined,\n\tattemptErrors: string[],\n): Promise<ExtractedContent | null> {\n\ttry {\n\t\tif (signal?.aborted || !isPerplexityAvailable()) return null;\n\n\t\tconst perplexityQuery = prompt === YOUTUBE_PROMPT\n\t\t\t? `Summarize this YouTube video in detail: ${url}`\n\t\t\t: `${prompt} YouTube video: ${url}`;\n\n\t\tconst { answer } = await searchWithPerplexity(\n\t\t\tperplexityQuery,\n\t\t\t{ signal },\n\t\t);\n\n\t\tif (!answer) return null;\n\n\t\tconst content =\n\t\t\t`# Video Summary (via Perplexity)\\n\\n${answer}\\n\\n` +\n\t\t\t`*Full video understanding requires Gemini access. Set GEMINI_API_KEY or sign into Google in a supported Chromium browser.*`;\n\n\t\treturn {\n\t\t\turl,\n\t\t\ttitle: \"Video Summary (via Perplexity)\",\n\t\t\tcontent,\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tif (shouldRethrow(err)) throw err;\n\t\tif (!signal?.aborted) addAttemptError(attemptErrors, \"Perplexity\", err);\n\t\treturn null;\n\t}\n}\n"]}