@humain/terminal 0.0.2 → 0.0.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (680) hide show
  1. package/CHANGELOG.md +241 -24
  2. package/README.md +143 -119
  3. package/dist/cli/args.d.ts +4 -2
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +37 -39
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-check.d.ts +19 -0
  8. package/dist/cli/auth-check.d.ts.map +1 -0
  9. package/dist/cli/auth-check.js +50 -0
  10. package/dist/cli/auth-check.js.map +1 -0
  11. package/dist/cli/auth-command.d.ts +24 -0
  12. package/dist/cli/auth-command.d.ts.map +1 -0
  13. package/dist/cli/auth-command.js +103 -0
  14. package/dist/cli/auth-command.js.map +1 -0
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js +2 -2
  17. package/dist/cli/config-selector.js.map +1 -1
  18. package/dist/cli/credential-print.d.ts +5 -15
  19. package/dist/cli/credential-print.d.ts.map +1 -1
  20. package/dist/cli/credential-print.js +42 -83
  21. package/dist/cli/credential-print.js.map +1 -1
  22. package/dist/cli/experimental/auth.d.ts +16 -0
  23. package/dist/cli/experimental/auth.d.ts.map +1 -0
  24. package/dist/cli/experimental/auth.js +13 -0
  25. package/dist/cli/experimental/auth.js.map +1 -0
  26. package/dist/cli/experimental/cli.d.ts +6 -0
  27. package/dist/cli/experimental/cli.d.ts.map +1 -0
  28. package/dist/cli/experimental/cli.js +5 -0
  29. package/dist/cli/experimental/cli.js.map +1 -0
  30. package/dist/cli/experimental/command-options.d.ts +17 -0
  31. package/dist/cli/experimental/command-options.d.ts.map +1 -0
  32. package/dist/cli/experimental/command-options.js +35 -0
  33. package/dist/cli/experimental/command-options.js.map +1 -0
  34. package/dist/cli/experimental/command.d.ts +63 -0
  35. package/dist/cli/experimental/command.d.ts.map +1 -0
  36. package/dist/cli/experimental/command.js +130 -0
  37. package/dist/cli/experimental/command.js.map +1 -0
  38. package/dist/cli/experimental/commands/client.d.ts +13 -0
  39. package/dist/cli/experimental/commands/client.d.ts.map +1 -0
  40. package/dist/cli/experimental/commands/client.js +25 -0
  41. package/dist/cli/experimental/commands/client.js.map +1 -0
  42. package/dist/cli/experimental/commands/pi.d.ts +15 -0
  43. package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
  44. package/dist/cli/experimental/commands/pi.js +28 -0
  45. package/dist/cli/experimental/commands/pi.js.map +1 -0
  46. package/dist/cli/experimental/commands/server.d.ts +13 -0
  47. package/dist/cli/experimental/commands/server.d.ts.map +1 -0
  48. package/dist/cli/experimental/commands/server.js +25 -0
  49. package/dist/cli/experimental/commands/server.js.map +1 -0
  50. package/dist/cli/experimental/transport-address.d.ts +10 -0
  51. package/dist/cli/experimental/transport-address.d.ts.map +1 -0
  52. package/dist/cli/experimental/transport-address.js +38 -0
  53. package/dist/cli/experimental/transport-address.js.map +1 -0
  54. package/dist/cli/list-models.d.ts +1 -1
  55. package/dist/cli/list-models.d.ts.map +1 -1
  56. package/dist/cli/list-models.js +2 -2
  57. package/dist/cli/list-models.js.map +1 -1
  58. package/dist/cli/startup-ui.d.ts +1 -1
  59. package/dist/cli/startup-ui.d.ts.map +1 -1
  60. package/dist/cli/startup-ui.js +2 -2
  61. package/dist/cli/startup-ui.js.map +1 -1
  62. package/dist/client/index.d.ts +3 -0
  63. package/dist/client/index.d.ts.map +1 -0
  64. package/dist/client/index.js +3 -0
  65. package/dist/client/index.js.map +1 -0
  66. package/dist/client/remote-session.d.ts +53 -0
  67. package/dist/client/remote-session.d.ts.map +1 -0
  68. package/dist/client/remote-session.js +340 -0
  69. package/dist/client/remote-session.js.map +1 -0
  70. package/dist/client/transcript.d.ts +12 -0
  71. package/dist/client/transcript.d.ts.map +1 -0
  72. package/dist/client/transcript.js +98 -0
  73. package/dist/client/transcript.js.map +1 -0
  74. package/dist/core/agent-session-services.d.ts +1 -0
  75. package/dist/core/agent-session-services.d.ts.map +1 -1
  76. package/dist/core/agent-session-services.js +1 -0
  77. package/dist/core/agent-session-services.js.map +1 -1
  78. package/dist/core/agent-session.d.ts +1 -10
  79. package/dist/core/agent-session.d.ts.map +1 -1
  80. package/dist/core/agent-session.js +72 -70
  81. package/dist/core/agent-session.js.map +1 -1
  82. package/dist/core/auth-storage.d.ts +25 -9
  83. package/dist/core/auth-storage.d.ts.map +1 -1
  84. package/dist/core/auth-storage.js +237 -39
  85. package/dist/core/auth-storage.js.map +1 -1
  86. package/dist/core/extensions/index.d.ts +1 -1
  87. package/dist/core/extensions/index.d.ts.map +1 -1
  88. package/dist/core/extensions/index.js.map +1 -1
  89. package/dist/core/extensions/loader.d.ts.map +1 -1
  90. package/dist/core/extensions/loader.js +60 -41
  91. package/dist/core/extensions/loader.js.map +1 -1
  92. package/dist/core/extensions/runner.d.ts +2 -1
  93. package/dist/core/extensions/runner.d.ts.map +1 -1
  94. package/dist/core/extensions/runner.js +3 -0
  95. package/dist/core/extensions/runner.js.map +1 -1
  96. package/dist/core/extensions/types.d.ts +27 -4
  97. package/dist/core/extensions/types.d.ts.map +1 -1
  98. package/dist/core/extensions/types.js.map +1 -1
  99. package/dist/core/http-dispatcher.d.ts.map +1 -1
  100. package/dist/core/http-dispatcher.js +5 -0
  101. package/dist/core/http-dispatcher.js.map +1 -1
  102. package/dist/core/keybindings.d.ts +45 -5
  103. package/dist/core/keybindings.d.ts.map +1 -1
  104. package/dist/core/keybindings.js.map +1 -1
  105. package/dist/core/model-config.d.ts +29 -5
  106. package/dist/core/model-config.d.ts.map +1 -1
  107. package/dist/core/model-config.js +4 -0
  108. package/dist/core/model-config.js.map +1 -1
  109. package/dist/core/model-registry.d.ts +5 -3
  110. package/dist/core/model-registry.d.ts.map +1 -1
  111. package/dist/core/model-registry.js +13 -10
  112. package/dist/core/model-registry.js.map +1 -1
  113. package/dist/core/model-resolver.d.ts +4 -3
  114. package/dist/core/model-resolver.d.ts.map +1 -1
  115. package/dist/core/model-resolver.js +42 -10
  116. package/dist/core/model-resolver.js.map +1 -1
  117. package/dist/core/model-runtime.d.ts +30 -13
  118. package/dist/core/model-runtime.d.ts.map +1 -1
  119. package/dist/core/model-runtime.js +233 -73
  120. package/dist/core/model-runtime.js.map +1 -1
  121. package/dist/core/models-store.d.ts +12 -7
  122. package/dist/core/models-store.d.ts.map +1 -1
  123. package/dist/core/models-store.js +83 -14
  124. package/dist/core/models-store.js.map +1 -1
  125. package/dist/core/package-manager.d.ts +6 -3
  126. package/dist/core/package-manager.d.ts.map +1 -1
  127. package/dist/core/package-manager.js +80 -61
  128. package/dist/core/package-manager.js.map +1 -1
  129. package/dist/core/pi-manifest.d.ts +8 -0
  130. package/dist/core/pi-manifest.d.ts.map +1 -0
  131. package/dist/core/pi-manifest.js +28 -0
  132. package/dist/core/pi-manifest.js.map +1 -0
  133. package/dist/core/provider-composer.d.ts +4 -1
  134. package/dist/core/provider-composer.d.ts.map +1 -1
  135. package/dist/core/provider-composer.js +36 -15
  136. package/dist/core/provider-composer.js.map +1 -1
  137. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  138. package/dist/core/remote-catalog-provider.js +73 -67
  139. package/dist/core/remote-catalog-provider.js.map +1 -1
  140. package/dist/core/resource-loader.d.ts.map +1 -1
  141. package/dist/core/resource-loader.js +2 -2
  142. package/dist/core/resource-loader.js.map +1 -1
  143. package/dist/core/runtime-credentials.d.ts +5 -5
  144. package/dist/core/runtime-credentials.d.ts.map +1 -1
  145. package/dist/core/runtime-credentials.js +11 -8
  146. package/dist/core/runtime-credentials.js.map +1 -1
  147. package/dist/core/sdk.d.ts +1 -1
  148. package/dist/core/sdk.d.ts.map +1 -1
  149. package/dist/core/sdk.js +2 -2
  150. package/dist/core/sdk.js.map +1 -1
  151. package/dist/core/session-manager.d.ts.map +1 -1
  152. package/dist/core/session-manager.js +3 -1
  153. package/dist/core/session-manager.js.map +1 -1
  154. package/dist/core/settings-manager.d.ts +12 -0
  155. package/dist/core/settings-manager.d.ts.map +1 -1
  156. package/dist/core/settings-manager.js +40 -16
  157. package/dist/core/settings-manager.js.map +1 -1
  158. package/dist/core/system-prompt.d.ts.map +1 -1
  159. package/dist/core/system-prompt.js +8 -0
  160. package/dist/core/system-prompt.js.map +1 -1
  161. package/dist/core/tools/bash.d.ts +5 -1
  162. package/dist/core/tools/bash.d.ts.map +1 -1
  163. package/dist/core/tools/bash.js +16 -15
  164. package/dist/core/tools/bash.js.map +1 -1
  165. package/dist/core/tools/edit.d.ts +4 -0
  166. package/dist/core/tools/edit.d.ts.map +1 -1
  167. package/dist/core/tools/edit.js +11 -7
  168. package/dist/core/tools/edit.js.map +1 -1
  169. package/dist/core/tools/find.d.ts +7 -0
  170. package/dist/core/tools/find.d.ts.map +1 -1
  171. package/dist/core/tools/find.js +16 -19
  172. package/dist/core/tools/find.js.map +1 -1
  173. package/dist/core/tools/grep.d.ts +4 -0
  174. package/dist/core/tools/grep.d.ts.map +1 -1
  175. package/dist/core/tools/grep.js +5 -1
  176. package/dist/core/tools/grep.js.map +1 -1
  177. package/dist/core/tools/ls.d.ts +4 -0
  178. package/dist/core/tools/ls.d.ts.map +1 -1
  179. package/dist/core/tools/ls.js +5 -1
  180. package/dist/core/tools/ls.js.map +1 -1
  181. package/dist/core/tools/read.d.ts +4 -0
  182. package/dist/core/tools/read.d.ts.map +1 -1
  183. package/dist/core/tools/read.js +7 -3
  184. package/dist/core/tools/read.js.map +1 -1
  185. package/dist/core/tools/write.d.ts +4 -0
  186. package/dist/core/tools/write.d.ts.map +1 -1
  187. package/dist/core/tools/write.js +6 -2
  188. package/dist/core/tools/write.js.map +1 -1
  189. package/dist/extensions/llama/index.d.ts.map +1 -1
  190. package/dist/extensions/llama/index.js +11 -2
  191. package/dist/extensions/llama/index.js.map +1 -1
  192. package/dist/extensions/llama/provider.d.ts.map +1 -1
  193. package/dist/extensions/llama/provider.js +21 -7
  194. package/dist/extensions/llama/provider.js.map +1 -1
  195. package/dist/humain/agent-execution-protocol.d.ts +218 -0
  196. package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
  197. package/dist/humain/agent-execution-protocol.js +204 -0
  198. package/dist/humain/agent-execution-protocol.js.map +1 -0
  199. package/dist/humain/agent-execution-runtime.d.ts +35 -0
  200. package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
  201. package/dist/humain/agent-execution-runtime.js +170 -0
  202. package/dist/humain/agent-execution-runtime.js.map +1 -0
  203. package/dist/humain/index.d.ts.map +1 -1
  204. package/dist/humain/index.js +8 -7
  205. package/dist/humain/index.js.map +1 -1
  206. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  207. package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
  208. package/dist/humain/mcp-adapter/vendor/README.md +733 -0
  209. package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
  210. package/dist/humain/mcp-adapter/vendor/agent-dir.ts +60 -0
  211. package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
  212. package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
  213. package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
  214. package/dist/humain/mcp-adapter/vendor/cli.js +209 -0
  215. package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
  216. package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
  217. package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
  218. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +604 -0
  219. package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
  220. package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
  221. package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
  222. package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
  223. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
  224. package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
  225. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +15923 -0
  226. package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
  227. package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
  228. package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
  229. package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
  230. package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
  231. package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
  232. package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
  233. package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
  234. package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
  235. package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
  236. package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
  237. package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
  238. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
  239. package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
  240. package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
  241. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +666 -0
  242. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
  243. package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
  244. package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +353 -0
  245. package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
  246. package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
  247. package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
  248. package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
  249. package/dist/humain/mcp-adapter/vendor/package.json +178 -0
  250. package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
  251. package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
  252. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
  253. package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
  254. package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
  255. package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
  256. package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
  257. package/dist/humain/mcp-adapter/vendor/server-manager.ts +1124 -0
  258. package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
  259. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
  260. package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
  261. package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
  262. package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +276 -0
  263. package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
  264. package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
  265. package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
  266. package/dist/humain/mcp-adapter/vendor/types.ts +859 -0
  267. package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
  268. package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
  269. package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
  270. package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
  271. package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
  272. package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
  273. package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
  274. package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
  275. package/dist/humain/mcp-adapter.d.ts +3 -0
  276. package/dist/humain/mcp-adapter.d.ts.map +1 -0
  277. package/dist/humain/mcp-adapter.js +5 -0
  278. package/dist/humain/mcp-adapter.js.map +1 -0
  279. package/dist/humain/pi-agent-execution-host.d.ts +34 -0
  280. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
  281. package/dist/humain/pi-agent-execution-host.js +77 -0
  282. package/dist/humain/pi-agent-execution-host.js.map +1 -0
  283. package/dist/humain/web-access/host.d.ts +4 -0
  284. package/dist/humain/web-access/host.d.ts.map +1 -0
  285. package/dist/humain/web-access/host.js +3 -0
  286. package/dist/humain/web-access/host.js.map +1 -0
  287. package/dist/humain/web-access/index.d.ts +3 -0
  288. package/dist/humain/web-access/index.d.ts.map +1 -0
  289. package/dist/humain/web-access/index.js +5 -0
  290. package/dist/humain/web-access/index.js.map +1 -0
  291. package/dist/humain/web-access/vendor/activity.d.ts +34 -0
  292. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
  293. package/dist/humain/web-access/vendor/activity.js +68 -0
  294. package/dist/humain/web-access/vendor/activity.js.map +1 -0
  295. package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
  296. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
  297. package/dist/humain/web-access/vendor/anysearch.js +167 -0
  298. package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
  299. package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
  300. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
  301. package/dist/humain/web-access/vendor/bocha.js +219 -0
  302. package/dist/humain/web-access/vendor/bocha.js.map +1 -0
  303. package/dist/humain/web-access/vendor/brave.d.ts +4 -0
  304. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
  305. package/dist/humain/web-access/vendor/brave.js +194 -0
  306. package/dist/humain/web-access/vendor/brave.js.map +1 -0
  307. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
  308. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
  309. package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
  310. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
  311. package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
  312. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
  313. package/dist/humain/web-access/vendor/brightdata.js +519 -0
  314. package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
  315. package/dist/humain/web-access/vendor/chrome-cookies.d.ts +10 -0
  316. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
  317. package/dist/humain/web-access/vendor/chrome-cookies.js +438 -0
  318. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
  319. package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
  320. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
  321. package/dist/humain/web-access/vendor/content-find.js +117 -0
  322. package/dist/humain/web-access/vendor/content-find.js.map +1 -0
  323. package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
  324. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
  325. package/dist/humain/web-access/vendor/credential-source.js +151 -0
  326. package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
  327. package/dist/humain/web-access/vendor/curator-page.d.ts +29 -0
  328. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
  329. package/dist/humain/web-access/vendor/curator-page.js +3554 -0
  330. package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
  331. package/dist/humain/web-access/vendor/curator-server.d.ts +93 -0
  332. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
  333. package/dist/humain/web-access/vendor/curator-server.js +688 -0
  334. package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
  335. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
  336. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
  337. package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
  338. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
  339. package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
  340. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
  341. package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
  342. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
  343. package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
  344. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
  345. package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
  346. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
  347. package/dist/humain/web-access/vendor/exa.d.ts +10 -0
  348. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
  349. package/dist/humain/web-access/vendor/exa.js +426 -0
  350. package/dist/humain/web-access/vendor/exa.js.map +1 -0
  351. package/dist/humain/web-access/vendor/extract.d.ts +46 -0
  352. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
  353. package/dist/humain/web-access/vendor/extract.js +1064 -0
  354. package/dist/humain/web-access/vendor/extract.js.map +1 -0
  355. package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
  356. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
  357. package/dist/humain/web-access/vendor/feature-config.js +27 -0
  358. package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
  359. package/dist/humain/web-access/vendor/fetch-params.d.ts +25 -0
  360. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
  361. package/dist/humain/web-access/vendor/fetch-params.js +57 -0
  362. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
  363. package/dist/humain/web-access/vendor/firecrawl.d.ts +12 -0
  364. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
  365. package/dist/humain/web-access/vendor/firecrawl.js +239 -0
  366. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
  367. package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
  368. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
  369. package/dist/humain/web-access/vendor/gemini-api.js +230 -0
  370. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
  371. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
  372. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
  373. package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
  374. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
  375. package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
  376. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
  377. package/dist/humain/web-access/vendor/gemini-search.js +814 -0
  378. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
  379. package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
  380. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
  381. package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
  382. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
  383. package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
  384. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
  385. package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
  386. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
  387. package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
  388. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
  389. package/dist/humain/web-access/vendor/gemini-web.js +385 -0
  390. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
  391. package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
  392. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
  393. package/dist/humain/web-access/vendor/github-api.js +160 -0
  394. package/dist/humain/web-access/vendor/github-api.js.map +1 -0
  395. package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
  396. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
  397. package/dist/humain/web-access/vendor/github-extract.js +635 -0
  398. package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
  399. package/dist/humain/web-access/vendor/index.d.ts +4 -0
  400. package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
  401. package/dist/humain/web-access/vendor/index.js +3002 -0
  402. package/dist/humain/web-access/vendor/index.js.map +1 -0
  403. package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
  404. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
  405. package/dist/humain/web-access/vendor/jina-search.js +255 -0
  406. package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
  407. package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
  408. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
  409. package/dist/humain/web-access/vendor/kagi.js +262 -0
  410. package/dist/humain/web-access/vendor/kagi.js.map +1 -0
  411. package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
  412. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
  413. package/dist/humain/web-access/vendor/ollama.js +216 -0
  414. package/dist/humain/web-access/vendor/ollama.js.map +1 -0
  415. package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
  416. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
  417. package/dist/humain/web-access/vendor/openai-search.js +459 -0
  418. package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
  419. package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
  420. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
  421. package/dist/humain/web-access/vendor/page-query.js +79 -0
  422. package/dist/humain/web-access/vendor/page-query.js.map +1 -0
  423. package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
  424. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
  425. package/dist/humain/web-access/vendor/parallel.js +343 -0
  426. package/dist/humain/web-access/vendor/parallel.js.map +1 -0
  427. package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
  428. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
  429. package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
  430. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
  431. package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
  432. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
  433. package/dist/humain/web-access/vendor/perplexity.js +159 -0
  434. package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
  435. package/dist/humain/web-access/vendor/querit.d.ts +10 -0
  436. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
  437. package/dist/humain/web-access/vendor/querit.js +335 -0
  438. package/dist/humain/web-access/vendor/querit.js.map +1 -0
  439. package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
  440. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
  441. package/dist/humain/web-access/vendor/render-search-error.js +130 -0
  442. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
  443. package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
  444. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
  445. package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
  446. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
  447. package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
  448. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
  449. package/dist/humain/web-access/vendor/search1api.js +251 -0
  450. package/dist/humain/web-access/vendor/search1api.js.map +1 -0
  451. package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
  452. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
  453. package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
  454. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
  455. package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
  456. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
  457. package/dist/humain/web-access/vendor/searxng.js +238 -0
  458. package/dist/humain/web-access/vendor/searxng.js.map +1 -0
  459. package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
  460. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
  461. package/dist/humain/web-access/vendor/serpbase.js +211 -0
  462. package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
  463. package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
  464. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
  465. package/dist/humain/web-access/vendor/serpdive.js +267 -0
  466. package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
  467. package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
  468. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
  469. package/dist/humain/web-access/vendor/source-check.js +205 -0
  470. package/dist/humain/web-access/vendor/source-check.js.map +1 -0
  471. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
  472. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
  473. package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
  474. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
  475. package/dist/humain/web-access/vendor/storage.d.ts +55 -0
  476. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
  477. package/dist/humain/web-access/vendor/storage.js +485 -0
  478. package/dist/humain/web-access/vendor/storage.js.map +1 -0
  479. package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
  480. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
  481. package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
  482. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
  483. package/dist/humain/web-access/vendor/summary-review.d.ts +24 -0
  484. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
  485. package/dist/humain/web-access/vendor/summary-review.js +341 -0
  486. package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
  487. package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
  488. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
  489. package/dist/humain/web-access/vendor/tavily.js +194 -0
  490. package/dist/humain/web-access/vendor/tavily.js.map +1 -0
  491. package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
  492. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
  493. package/dist/humain/web-access/vendor/tinyfish.js +331 -0
  494. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
  495. package/dist/humain/web-access/vendor/utils.d.ts +20 -0
  496. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
  497. package/dist/humain/web-access/vendor/utils.js +91 -0
  498. package/dist/humain/web-access/vendor/utils.js.map +1 -0
  499. package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
  500. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
  501. package/dist/humain/web-access/vendor/video-extract.js +335 -0
  502. package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
  503. package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
  504. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
  505. package/dist/humain/web-access/vendor/xai-search.js +331 -0
  506. package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
  507. package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
  508. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
  509. package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
  510. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
  511. package/dist/index.d.ts +7 -4
  512. package/dist/index.d.ts.map +1 -1
  513. package/dist/index.js +5 -2
  514. package/dist/index.js.map +1 -1
  515. package/dist/main.d.ts +2 -2
  516. package/dist/main.d.ts.map +1 -1
  517. package/dist/main.js +169 -102
  518. package/dist/main.js.map +1 -1
  519. package/dist/modes/agent-exec-mode.d.ts +14 -0
  520. package/dist/modes/agent-exec-mode.d.ts.map +1 -0
  521. package/dist/modes/agent-exec-mode.js +92 -0
  522. package/dist/modes/agent-exec-mode.js.map +1 -0
  523. package/dist/modes/index.d.ts +4 -2
  524. package/dist/modes/index.d.ts.map +1 -1
  525. package/dist/modes/index.js +2 -1
  526. package/dist/modes/index.js.map +1 -1
  527. package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
  528. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  529. package/dist/modes/interactive/components/assistant-message.js +13 -4
  530. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  531. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  532. package/dist/modes/interactive/components/custom-editor.js +7 -0
  533. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  534. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  535. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  536. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  537. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  538. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  539. package/dist/modes/interactive/components/footer.js +1 -1
  540. package/dist/modes/interactive/components/footer.js.map +1 -1
  541. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  542. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  543. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  544. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  545. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  546. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  547. package/dist/modes/interactive/components/mermaid.js +75 -0
  548. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  549. package/dist/modes/interactive/components/model-selector.d.ts +1 -1
  550. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  551. package/dist/modes/interactive/components/model-selector.js +16 -4
  552. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  553. package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
  554. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  555. package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
  556. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  557. package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
  558. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  559. package/dist/modes/interactive/components/settings-selector.js +30 -0
  560. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  561. package/dist/modes/interactive/components/user-message.d.ts +3 -1
  562. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  563. package/dist/modes/interactive/components/user-message.js +9 -2
  564. package/dist/modes/interactive/components/user-message.js.map +1 -1
  565. package/dist/modes/interactive/interactive-mode.d.ts +45 -9
  566. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  567. package/dist/modes/interactive/interactive-mode.js +581 -211
  568. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  569. package/dist/modes/interactive/theme/dark.json +1 -0
  570. package/dist/modes/interactive/theme/light.json +1 -0
  571. package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
  572. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  573. package/dist/modes/interactive/theme/theme-controller.js +10 -1
  574. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  575. package/dist/modes/interactive/theme/theme-schema.json +5 -1
  576. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  577. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  578. package/dist/modes/interactive/theme/theme.js +24 -6
  579. package/dist/modes/interactive/theme/theme.js.map +1 -1
  580. package/dist/modes/json-event.d.ts +28 -0
  581. package/dist/modes/json-event.d.ts.map +1 -0
  582. package/dist/modes/json-event.js +12 -0
  583. package/dist/modes/json-event.js.map +1 -0
  584. package/dist/modes/print-mode.d.ts.map +1 -1
  585. package/dist/modes/print-mode.js +12 -2
  586. package/dist/modes/print-mode.js.map +1 -1
  587. package/dist/modes/rpc/rpc-client.d.ts +12 -5
  588. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  589. package/dist/modes/rpc/rpc-client.js +55 -1
  590. package/dist/modes/rpc/rpc-client.js.map +1 -1
  591. package/dist/modes/rpc/rpc-mode.d.ts +1 -1
  592. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  593. package/dist/modes/rpc/rpc-mode.js +13 -3
  594. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  595. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  596. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  597. package/dist/modes/rpc/rpc-types.js.map +1 -1
  598. package/dist/package-manager-cli.d.ts.map +1 -1
  599. package/dist/package-manager-cli.js +11 -9
  600. package/dist/package-manager-cli.js.map +1 -1
  601. package/dist/rpc-entry.d.ts.map +1 -1
  602. package/dist/rpc-entry.js +3 -2
  603. package/dist/rpc-entry.js.map +1 -1
  604. package/dist/server/create-harness.d.ts +26 -0
  605. package/dist/server/create-harness.d.ts.map +1 -0
  606. package/dist/server/create-harness.js +104 -0
  607. package/dist/server/create-harness.js.map +1 -0
  608. package/dist/utils/abort.d.ts +5 -0
  609. package/dist/utils/abort.d.ts.map +1 -0
  610. package/dist/utils/abort.js +48 -0
  611. package/dist/utils/abort.js.map +1 -0
  612. package/dist/utils/clipboard.d.ts +1 -1
  613. package/dist/utils/clipboard.d.ts.map +1 -1
  614. package/dist/utils/clipboard.js +22 -2
  615. package/dist/utils/clipboard.js.map +1 -1
  616. package/dist/utils/management-http.d.ts +23 -0
  617. package/dist/utils/management-http.d.ts.map +1 -0
  618. package/dist/utils/management-http.js +50 -0
  619. package/dist/utils/management-http.js.map +1 -0
  620. package/dist/utils/paths.d.ts +3 -0
  621. package/dist/utils/paths.d.ts.map +1 -1
  622. package/dist/utils/paths.js +23 -1
  623. package/dist/utils/paths.js.map +1 -1
  624. package/dist/utils/tool-result-images.d.ts +19 -0
  625. package/dist/utils/tool-result-images.d.ts.map +1 -0
  626. package/dist/utils/tool-result-images.js +45 -0
  627. package/dist/utils/tool-result-images.js.map +1 -0
  628. package/dist/utils/tools-manager.d.ts.map +1 -1
  629. package/dist/utils/tools-manager.js +13 -25
  630. package/dist/utils/tools-manager.js.map +1 -1
  631. package/dist/utils/version-check.d.ts +4 -0
  632. package/dist/utils/version-check.d.ts.map +1 -1
  633. package/dist/utils/version-check.js +23 -5
  634. package/dist/utils/version-check.js.map +1 -1
  635. package/docs/compaction.md +2 -2
  636. package/docs/custom-provider.md +7 -5
  637. package/docs/extensions.md +30 -5
  638. package/docs/humain-terminal.md +21 -1
  639. package/docs/json.md +24 -19
  640. package/docs/keybindings.md +46 -14
  641. package/docs/models.md +32 -11
  642. package/docs/providers.md +9 -1
  643. package/docs/quickstart.md +39 -37
  644. package/docs/rpc.md +31 -11
  645. package/docs/sdk.md +21 -2
  646. package/docs/security.md +21 -21
  647. package/docs/session-format.md +14 -14
  648. package/docs/settings.md +4 -1
  649. package/docs/themes.md +5 -3
  650. package/docs/usage.md +7 -0
  651. package/examples/extensions/custom-compaction.ts +3 -18
  652. package/examples/extensions/custom-provider-anthropic/index.ts +5 -1
  653. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  654. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  655. package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
  656. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  657. package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
  658. package/examples/extensions/gondolin/package-lock.json +2 -2
  659. package/examples/extensions/gondolin/package.json +1 -1
  660. package/examples/extensions/handoff.ts +4 -13
  661. package/examples/extensions/qna.ts +5 -9
  662. package/examples/extensions/sandbox/package-lock.json +2 -2
  663. package/examples/extensions/sandbox/package.json +1 -1
  664. package/examples/extensions/summarize.ts +9 -20
  665. package/examples/extensions/with-deps/package-lock.json +2 -2
  666. package/examples/extensions/with-deps/package.json +1 -1
  667. package/examples/rpc-extension-ui.ts +11 -2
  668. package/examples/sdk/02-custom-model.ts +2 -3
  669. package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
  670. package/examples/sdk/12-full-control.ts +1 -1
  671. package/examples/sdk/README.md +1 -1
  672. package/npm-shrinkwrap.json +2771 -535
  673. package/package.json +40 -11
  674. package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
  675. package/src/humain/mcp-adapter/upstream.json +7 -0
  676. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
  677. package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
  678. package/src/humain/web-access/UPSTREAM.md +17 -0
  679. package/src/humain/web-access/upstream.json +23 -0
  680. package/src/humain/web-access/vendor/LICENSE +21 -0
@@ -0,0 +1,267 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { activityMonitor } from "./activity.js";
3
+ import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
+ import { getWebSearchConfigPath } from "./utils.js";
5
+ const SERPDIVE_API_URL = "https://api.serpdive.com/v1/search";
6
+ const CONFIG_PATH = getWebSearchConfigPath();
7
+ const SEARCH_TIMEOUT_MS = 60_000;
8
+ // Retrieval depth. The default is deliberately the free tier: this provider
9
+ // ships inside someone else's framework, and installing it must never start
10
+ // spending on a user's behalf without them choosing it.
11
+ // krill — free, fair use, no synthesized answer (see buildAnswer below)
12
+ // mako — the fact-carrying sentences of each page, 1 credit
13
+ // moby — the full readable content of every page, 1.5 credits
14
+ // Pricing: https://serpdive.com/pricing
15
+ const MODELS = ["krill", "mako", "moby"];
16
+ const DEFAULT_MODEL = "krill";
17
+ let cachedConfig = null;
18
+ function loadConfig() {
19
+ if (cachedConfig)
20
+ return cachedConfig;
21
+ if (!existsSync(CONFIG_PATH)) {
22
+ cachedConfig = {};
23
+ return cachedConfig;
24
+ }
25
+ const raw = readFileSync(CONFIG_PATH, "utf-8");
26
+ try {
27
+ cachedConfig = JSON.parse(raw);
28
+ return cachedConfig;
29
+ }
30
+ catch (err) {
31
+ const message = err instanceof Error ? err.message : String(err);
32
+ throw new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);
33
+ }
34
+ }
35
+ async function getApiKey(signal) {
36
+ return resolveCredential({
37
+ provider: "SERPdive",
38
+ configuredValue: loadConfig().serpdiveApiKey,
39
+ environmentValue: process.env.SERPDIVE_API_KEY,
40
+ signal,
41
+ });
42
+ }
43
+ async function requireApiKey(signal) {
44
+ const apiKey = await getApiKey(signal);
45
+ if (!apiKey) {
46
+ throw new Error("SERPdive API key not found. Either:\n" +
47
+ ` 1. Create ${CONFIG_PATH} with { "serpdiveApiKey": "your-key" }\n` +
48
+ " 2. Set SERPDIVE_API_KEY environment variable\n" +
49
+ "Get a key at https://serpdive.com/dashboard/keys");
50
+ }
51
+ return apiKey;
52
+ }
53
+ // An unknown value falls back to the free default rather than failing: a typo
54
+ // in a config file must not cost the user money, and must not break search.
55
+ function resolveModel() {
56
+ const raw = process.env.SERPDIVE_MODEL ?? loadConfig().serpdiveModel;
57
+ if (typeof raw !== "string")
58
+ return DEFAULT_MODEL;
59
+ const value = raw.trim().toLowerCase();
60
+ return MODELS.includes(value) ? value : DEFAULT_MODEL;
61
+ }
62
+ function normalizeCount(value) {
63
+ if (typeof value !== "number" || !Number.isFinite(value))
64
+ return 5;
65
+ return Math.max(1, Math.min(Math.floor(value), 20));
66
+ }
67
+ function normalizeDomain(value) {
68
+ let input = value.trim().toLowerCase();
69
+ if (!input)
70
+ return null;
71
+ if (input.startsWith("-"))
72
+ input = input.slice(1).trim();
73
+ if (!input)
74
+ return null;
75
+ try {
76
+ const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
77
+ input = parsed.hostname;
78
+ }
79
+ catch {
80
+ input = input.split("/")[0]?.split(":")[0] ?? "";
81
+ }
82
+ input = input.replace(/^\.+|\.+$/g, "");
83
+ return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
84
+ }
85
+ function parseDomainFilter(domainFilter) {
86
+ const filters = { include: [], exclude: [] };
87
+ if (!domainFilter?.length)
88
+ return filters;
89
+ for (const raw of domainFilter) {
90
+ const domain = normalizeDomain(raw);
91
+ if (!domain)
92
+ continue;
93
+ const target = raw.trim().startsWith("-") ? filters.exclude : filters.include;
94
+ if (!target.includes(domain))
95
+ target.push(domain);
96
+ }
97
+ return filters;
98
+ }
99
+ function domainMatches(hostname, domain) {
100
+ return hostname === domain || hostname.endsWith(`.${domain}`);
101
+ }
102
+ // SERPdive exposes no include/exclude domain parameter, so the filter is applied
103
+ // here, on what came back. It can therefore only ever narrow a page of results —
104
+ // it cannot ask the engine for more pages from a given domain.
105
+ function passesDomainFilters(url, filters) {
106
+ if (filters.include.length === 0 && filters.exclude.length === 0)
107
+ return true;
108
+ let hostname;
109
+ try {
110
+ hostname = new URL(url).hostname.toLowerCase();
111
+ }
112
+ catch {
113
+ return false;
114
+ }
115
+ if (filters.exclude.some((domain) => domainMatches(hostname, domain)))
116
+ return false;
117
+ if (filters.include.length === 0)
118
+ return true;
119
+ return filters.include.some((domain) => domainMatches(hostname, domain));
120
+ }
121
+ // SERPdive has NO time-range parameter. Recency is expressed inside the question
122
+ // and read by the engine, which biases ranking toward recent pages — it is a
123
+ // hint, never a guaranteed freshness filter, and results outside the window can
124
+ // still come back.
125
+ function applyRecencyHint(query, recencyFilter) {
126
+ if (!recencyFilter)
127
+ return query;
128
+ const hints = {
129
+ day: "past 24 hours",
130
+ week: "past week",
131
+ month: "past month",
132
+ year: "past year",
133
+ };
134
+ const hint = hints[recencyFilter];
135
+ return hint ? `${query} ${hint}` : query;
136
+ }
137
+ function requestSignal(signal) {
138
+ const timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);
139
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
140
+ }
141
+ function errorMessage(err) {
142
+ return err instanceof Error ? err.message : String(err);
143
+ }
144
+ function mapResults(results, numResults, filters) {
145
+ if (!Array.isArray(results))
146
+ return [];
147
+ const mapped = [];
148
+ for (const item of results) {
149
+ if (!item?.url || !passesDomainFilters(item.url, filters))
150
+ continue;
151
+ mapped.push({
152
+ title: item.title || `Source ${mapped.length + 1}`,
153
+ url: item.url,
154
+ snippet: typeof item.content === "string" ? item.content.replace(/\s+/g, " ").trim() : "",
155
+ });
156
+ if (mapped.length >= numResults)
157
+ break;
158
+ }
159
+ return mapped;
160
+ }
161
+ function mapInlineContent(results, filters) {
162
+ if (!Array.isArray(results))
163
+ return [];
164
+ return results.flatMap((item) => {
165
+ if (!item?.url || !passesDomainFilters(item.url, filters))
166
+ return [];
167
+ if (typeof item.content !== "string" || item.content.trim().length === 0)
168
+ return [];
169
+ return [{
170
+ url: item.url,
171
+ title: item.title || "",
172
+ content: item.content,
173
+ error: null,
174
+ }];
175
+ });
176
+ }
177
+ // The free krill tier returns extracted content but no synthesized answer, so
178
+ // one is assembled from the sources — the same shape brave.ts and searxng.ts
179
+ // produce for providers that do not synthesize. mako and moby ask the API for a
180
+ // real answer and use it when it comes back.
181
+ function buildAnswer(apiAnswer, results) {
182
+ if (typeof apiAnswer === "string" && apiAnswer.trim().length > 0)
183
+ return apiAnswer;
184
+ return results
185
+ .map((result) => {
186
+ if (result.snippet)
187
+ return `${result.snippet}\nSource: ${result.title} (${result.url})`;
188
+ return `Source: ${result.title} (${result.url})`;
189
+ })
190
+ .join("\n\n");
191
+ }
192
+ export function isSerpdiveAvailable() {
193
+ return hasCredentialSource({
194
+ provider: "SERPdive",
195
+ configuredValue: loadConfig().serpdiveApiKey,
196
+ environmentValue: process.env.SERPDIVE_API_KEY,
197
+ });
198
+ }
199
+ export async function searchWithSerpdive(query, options = {}) {
200
+ const apiKey = await requireApiKey(options.signal);
201
+ const numResults = normalizeCount(options.numResults);
202
+ const filters = parseDomainFilter(options.domainFilter);
203
+ const model = resolveModel();
204
+ const body = {
205
+ query: applyRecencyHint(query, options.recencyFilter),
206
+ model,
207
+ // max_results is a CAP, never a minimum: the engine returns what it
208
+ // judges relevant, up to this many. Asking for more does not produce more.
209
+ max_results: Math.min(numResults, 10),
210
+ // krill has no answer synthesis — asking for one there is silently ignored
211
+ // by the API, so it is not asked for at all.
212
+ ...(model === "krill" ? {} : { answer: true }),
213
+ };
214
+ const activityId = activityMonitor.logStart({ type: "api", query });
215
+ let response;
216
+ try {
217
+ response = await fetch(SERPDIVE_API_URL, {
218
+ method: "POST",
219
+ headers: {
220
+ "Authorization": `Bearer ${apiKey}`,
221
+ "Content-Type": "application/json",
222
+ },
223
+ body: JSON.stringify(body),
224
+ signal: requestSignal(options.signal),
225
+ });
226
+ }
227
+ catch (err) {
228
+ const message = errorMessage(err);
229
+ const redactedMessage = redactCredential(message, apiKey);
230
+ if (redactedMessage.toLowerCase().includes("abort"))
231
+ activityMonitor.logComplete(activityId, 0);
232
+ else
233
+ activityMonitor.logError(activityId, redactedMessage);
234
+ if (redactedMessage === message)
235
+ throw err;
236
+ const redactedError = new Error(redactedMessage);
237
+ if (err instanceof Error)
238
+ redactedError.name = err.name;
239
+ throw redactedError;
240
+ }
241
+ if (!response.ok) {
242
+ activityMonitor.logComplete(activityId, response.status);
243
+ const errorText = redactCredential(await response.text(), apiKey);
244
+ throw new Error(`SERPdive API error ${response.status}: ${errorText.slice(0, 300)}`);
245
+ }
246
+ let data;
247
+ try {
248
+ data = await response.json();
249
+ }
250
+ catch (err) {
251
+ activityMonitor.logComplete(activityId, response.status);
252
+ throw new Error(`SERPdive API returned invalid JSON: ${errorMessage(err)}`);
253
+ }
254
+ activityMonitor.logComplete(activityId, response.status);
255
+ const results = mapResults(data.results, numResults, filters);
256
+ const result = {
257
+ answer: buildAnswer(data.answer, results),
258
+ results,
259
+ };
260
+ if (options.includeContent) {
261
+ const inlineContent = mapInlineContent(data.results, filters);
262
+ if (inlineContent.length > 0)
263
+ result.inlineContent = inlineContent;
264
+ }
265
+ return result;
266
+ }
267
+ //# sourceMappingURL=serpdive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serpdive.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/serpdive.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst SERPDIVE_API_URL = \"https://api.serpdive.com/v1/search\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\n// Retrieval depth. The default is deliberately the free tier: this provider\n// ships inside someone else's framework, and installing it must never start\n// spending on a user's behalf without them choosing it.\n// krill — free, fair use, no synthesized answer (see buildAnswer below)\n// mako — the fact-carrying sentences of each page, 1 credit\n// moby — the full readable content of every page, 1.5 credits\n// Pricing: https://serpdive.com/pricing\nconst MODELS = [\"krill\", \"mako\", \"moby\"] as const;\ntype SerpdiveModel = (typeof MODELS)[number];\nconst DEFAULT_MODEL: SerpdiveModel = \"krill\";\n\ninterface WebSearchConfig {\n\tserpdiveApiKey?: unknown;\n\tserpdiveModel?: unknown;\n}\n\ninterface SerpdiveResult {\n\turl?: string;\n\ttitle?: string | null;\n\tdate?: string;\n\tcontent?: string;\n}\n\ninterface SerpdiveResponse {\n\tquery?: string;\n\tmodel?: string;\n\tanswer?: string | null;\n\tresults?: SerpdiveResult[];\n}\n\ninterface SerpdiveSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\ttry {\n\t\tcachedConfig = JSON.parse(raw) as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"SERPdive\",\n\t\tconfiguredValue: loadConfig().serpdiveApiKey,\n\t\tenvironmentValue: process.env.SERPDIVE_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"SERPdive API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"serpdiveApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set SERPDIVE_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://serpdive.com/dashboard/keys\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\n// An unknown value falls back to the free default rather than failing: a typo\n// in a config file must not cost the user money, and must not break search.\nfunction resolveModel(): SerpdiveModel {\n\tconst raw = process.env.SERPDIVE_MODEL ?? loadConfig().serpdiveModel;\n\tif (typeof raw !== \"string\") return DEFAULT_MODEL;\n\tconst value = raw.trim().toLowerCase();\n\treturn (MODELS as readonly string[]).includes(value) ? value as SerpdiveModel : DEFAULT_MODEL;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nfunction parseDomainFilter(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tif (!domainFilter?.length) return filters;\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction domainMatches(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\n// SERPdive exposes no include/exclude domain parameter, so the filter is applied\n// here, on what came back. It can therefore only ever narrow a page of results —\n// it cannot ask the engine for more pages from a given domain.\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tif (filters.exclude.some((domain) => domainMatches(hostname, domain))) return false;\n\tif (filters.include.length === 0) return true;\n\treturn filters.include.some((domain) => domainMatches(hostname, domain));\n}\n\n// SERPdive has NO time-range parameter. Recency is expressed inside the question\n// and read by the engine, which biases ranking toward recent pages — it is a\n// hint, never a guaranteed freshness filter, and results outside the window can\n// still come back.\nfunction applyRecencyHint(query: string, recencyFilter: SearchOptions[\"recencyFilter\"]): string {\n\tif (!recencyFilter) return query;\n\tconst hints: Record<string, string> = {\n\t\tday: \"past 24 hours\",\n\t\tweek: \"past week\",\n\t\tmonth: \"past month\",\n\t\tyear: \"past year\",\n\t};\n\tconst hint = hints[recencyFilter];\n\treturn hint ? `${query} ${hint}` : query;\n}\n\nfunction requestSignal(signal?: AbortSignal): AbortSignal {\n\tconst timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\treturn signal ? AbortSignal.any([signal, timeout]) : timeout;\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction mapResults(\n\tresults: SerpdiveResult[] | undefined,\n\tnumResults: number,\n\tfilters: DomainFilters,\n): SearchResponse[\"results\"] {\n\tif (!Array.isArray(results)) return [];\n\tconst mapped: SearchResponse[\"results\"] = [];\n\tfor (const item of results) {\n\t\tif (!item?.url || !passesDomainFilters(item.url, filters)) continue;\n\t\tmapped.push({\n\t\t\ttitle: item.title || `Source ${mapped.length + 1}`,\n\t\t\turl: item.url,\n\t\t\tsnippet: typeof item.content === \"string\" ? item.content.replace(/\\s+/g, \" \").trim() : \"\",\n\t\t});\n\t\tif (mapped.length >= numResults) break;\n\t}\n\treturn mapped;\n}\n\nfunction mapInlineContent(results: SerpdiveResult[] | undefined, filters: DomainFilters): ExtractedContent[] {\n\tif (!Array.isArray(results)) return [];\n\treturn results.flatMap((item) => {\n\t\tif (!item?.url || !passesDomainFilters(item.url, filters)) return [];\n\t\tif (typeof item.content !== \"string\" || item.content.trim().length === 0) return [];\n\t\treturn [{\n\t\t\turl: item.url,\n\t\t\ttitle: item.title || \"\",\n\t\t\tcontent: item.content,\n\t\t\terror: null,\n\t\t}];\n\t});\n}\n\n// The free krill tier returns extracted content but no synthesized answer, so\n// one is assembled from the sources — the same shape brave.ts and searxng.ts\n// produce for providers that do not synthesize. mako and moby ask the API for a\n// real answer and use it when it comes back.\nfunction buildAnswer(apiAnswer: string | null | undefined, results: SearchResponse[\"results\"]): string {\n\tif (typeof apiAnswer === \"string\" && apiAnswer.trim().length > 0) return apiAnswer;\n\treturn results\n\t\t.map((result) => {\n\t\t\tif (result.snippet) return `${result.snippet}\\nSource: ${result.title} (${result.url})`;\n\t\t\treturn `Source: ${result.title} (${result.url})`;\n\t\t})\n\t\t.join(\"\\n\\n\");\n}\n\nexport function isSerpdiveAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"SERPdive\",\n\t\tconfiguredValue: loadConfig().serpdiveApiKey,\n\t\tenvironmentValue: process.env.SERPDIVE_API_KEY,\n\t});\n}\n\nexport async function searchWithSerpdive(query: string, options: SerpdiveSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst filters = parseDomainFilter(options.domainFilter);\n\tconst model = resolveModel();\n\tconst body: Record<string, unknown> = {\n\t\tquery: applyRecencyHint(query, options.recencyFilter),\n\t\tmodel,\n\t\t// max_results is a CAP, never a minimum: the engine returns what it\n\t\t// judges relevant, up to this many. Asking for more does not produce more.\n\t\tmax_results: Math.min(numResults, 10),\n\t\t// krill has no answer synthesis — asking for one there is silently ignored\n\t\t// by the API, so it is not asked for at all.\n\t\t...(model === \"krill\" ? {} : { answer: true }),\n\t};\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(SERPDIVE_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Authorization\": `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t\tsignal: requestSignal(options.signal),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`SERPdive API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\n\tlet data: SerpdiveResponse;\n\ttry {\n\t\tdata = await response.json() as SerpdiveResponse;\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`SERPdive API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = mapResults(data.results, numResults, filters);\n\tconst result: SearchResponse = {\n\t\tanswer: buildAnswer(data.answer, results),\n\t\tresults,\n\t};\n\tif (options.includeContent) {\n\t\tconst inlineContent = mapInlineContent(data.results, filters);\n\t\tif (inlineContent.length > 0) result.inlineContent = inlineContent;\n\t}\n\treturn result;\n}\n"]}
@@ -0,0 +1,99 @@
1
+ import type { SearchResult } from "./perplexity.ts";
2
+ import type { ExtractedContent } from "./extract.ts";
3
+ export type SourceQuality = "official_docs" | "vendor_docs" | "repo_issue" | "blog" | "forum" | "news" | "unknown";
4
+ export type ClaimStatus = "supported" | "contradicted" | "unclear" | "missing-evidence";
5
+ export type RecencyFilter = "day" | "week" | "month" | "year";
6
+ export interface ResearchSource {
7
+ rank: number;
8
+ url: string;
9
+ title: string;
10
+ snippet?: string;
11
+ fetch_timestamp?: number;
12
+ content_hash?: string;
13
+ quality: SourceQuality;
14
+ fetched?: boolean;
15
+ fetch_error?: string;
16
+ }
17
+ export interface ResearchPassage {
18
+ passage_id: string;
19
+ source_url: string;
20
+ source_rank: number;
21
+ text: string;
22
+ extraction_span?: {
23
+ start: number;
24
+ end: number;
25
+ };
26
+ content_hash?: string;
27
+ }
28
+ export interface ClaimAssessment {
29
+ claim: string;
30
+ status: ClaimStatus;
31
+ supporting_passages: string[];
32
+ contradicting_passages: string[];
33
+ rationale: string;
34
+ confidence: number;
35
+ }
36
+ export interface ResearchArtifact {
37
+ id: string;
38
+ type: "research";
39
+ timestamp: number;
40
+ query: string;
41
+ sources: ResearchSource[];
42
+ passages: ResearchPassage[];
43
+ claims?: ClaimAssessment[];
44
+ provider?: string;
45
+ summary?: string;
46
+ content_hash?: string;
47
+ filters?: {
48
+ recency?: RecencyFilter;
49
+ domain_include?: string[];
50
+ domain_exclude?: string[];
51
+ };
52
+ errors?: Array<{
53
+ query: string;
54
+ error: string;
55
+ }>;
56
+ }
57
+ export interface ResearchSearchRequest {
58
+ query: string;
59
+ numResults: number;
60
+ recencyFilter?: RecencyFilter;
61
+ domainFilter?: string[];
62
+ }
63
+ export interface ResearchSearchResult {
64
+ url: string;
65
+ title: string;
66
+ snippet: string;
67
+ rank: number;
68
+ }
69
+ export interface ResearchSearchResponse {
70
+ provider: string;
71
+ results: ResearchSearchResult[];
72
+ summary?: string;
73
+ }
74
+ export interface ResearchProvider {
75
+ name: string;
76
+ search(req: ResearchSearchRequest): Promise<ResearchSearchResponse>;
77
+ }
78
+ export declare function classifySource(url: string): SourceQuality;
79
+ export declare function hashContent(text: string): string;
80
+ export declare function buildPassages(sources: ResearchSource[], fetched?: ExtractedContent[], hint?: string): ResearchPassage[];
81
+ export declare function assessClaim(claim: string, passages: ResearchPassage[]): ClaimAssessment;
82
+ interface RankedSearchResult extends SearchResult {
83
+ rank?: number;
84
+ }
85
+ export interface BuildArtifactInput {
86
+ query: string;
87
+ provider?: string;
88
+ summary?: string;
89
+ results: RankedSearchResult[];
90
+ fetched?: ExtractedContent[];
91
+ recency?: RecencyFilter;
92
+ domainFilter?: string[];
93
+ }
94
+ export declare function buildResearchArtifact(input: BuildArtifactInput): ResearchArtifact;
95
+ export declare function withClaimAssessment(artifact: ResearchArtifact, claims: string[]): ResearchArtifact;
96
+ export declare function storeResearchArtifact(artifact: ResearchArtifact): void;
97
+ export declare function getResearchArtifact(id: string): ResearchArtifact | null;
98
+ export {};
99
+ //# sourceMappingURL=source-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-check.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/source-check.ts"],"names":[],"mappings":"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","sourcesContent":["// Structured source checking and machine-readable research artifacts.\nimport { createHash } from \"node:crypto\";\nimport { generateId, getResult, storeResult } from \"./storage.ts\";\nimport type { SearchResult } from \"./perplexity.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\n\nexport type SourceQuality = \"official_docs\" | \"vendor_docs\" | \"repo_issue\" | \"blog\" | \"forum\" | \"news\" | \"unknown\";\nexport type ClaimStatus = \"supported\" | \"contradicted\" | \"unclear\" | \"missing-evidence\";\nexport type RecencyFilter = \"day\" | \"week\" | \"month\" | \"year\";\n\nexport interface ResearchSource {\n\trank: number;\n\turl: string;\n\ttitle: string;\n\tsnippet?: string;\n\tfetch_timestamp?: number;\n\tcontent_hash?: string;\n\tquality: SourceQuality;\n\tfetched?: boolean;\n\tfetch_error?: string;\n}\n\nexport interface ResearchPassage {\n\tpassage_id: string;\n\tsource_url: string;\n\tsource_rank: number;\n\ttext: string;\n\textraction_span?: { start: number; end: number };\n\tcontent_hash?: string;\n}\n\nexport interface ClaimAssessment {\n\tclaim: string;\n\tstatus: ClaimStatus;\n\tsupporting_passages: string[];\n\tcontradicting_passages: string[];\n\trationale: string;\n\tconfidence: number;\n}\n\nexport interface ResearchArtifact {\n\tid: string;\n\ttype: \"research\";\n\ttimestamp: number;\n\tquery: string;\n\tsources: ResearchSource[];\n\tpassages: ResearchPassage[];\n\tclaims?: ClaimAssessment[];\n\tprovider?: string;\n\tsummary?: string;\n\tcontent_hash?: string;\n\tfilters?: { recency?: RecencyFilter; domain_include?: string[]; domain_exclude?: string[] };\n\terrors?: Array<{ query: string; error: string }>;\n}\n\nexport interface ResearchSearchRequest {\n\tquery: string;\n\tnumResults: number;\n\trecencyFilter?: RecencyFilter;\n\tdomainFilter?: string[];\n}\nexport interface ResearchSearchResult { url: string; title: string; snippet: string; rank: number }\nexport interface ResearchSearchResponse { provider: string; results: ResearchSearchResult[]; summary?: string }\nexport interface ResearchProvider { name: string; search(req: ResearchSearchRequest): Promise<ResearchSearchResponse> }\n\nconst OFFICIAL_DOCS_HOSTS = /^(developers\\.|docs\\.|learn\\.|reference\\.)|\\.github\\.io$/i;\nconst OFFICIAL_DOCS_PATHS = /\\/(docs?|reference)(\\/|\\b)/i;\nconst VENDOR_DOCS_PATHS = /\\/(documentation|docs?)\\//i;\nconst REPO_ISSUE_PATHS = /\\/(issues|pull|pulls)\\//i;\nconst BLOG_HOSTS = /(medium\\.com|substack\\.com|dev\\.to|hashnode\\.)/i;\nconst BLOG_PATHS = /\\/blogs?\\//i;\nconst FORUM_HOSTS = /(stackoverflow\\.com|serverfault\\.com|superuser\\.com|discourse\\.|community\\.)/i;\nconst FORUM_PATHS = /\\/(forum|forums|threads)\\//i;\nconst NEWS_HOSTS = /(reuters\\.com|bloomberg\\.com|techcrunch\\.com|theverge\\.com|arstechnica\\.com|wired\\.com|cnet\\.com|zdnet\\.com)/i;\nconst NEWS_PATHS = /\\/news(\\/|$)/i;\n\nexport function classifySource(url: string): SourceQuality {\n\tlet host = \"\";\n\tlet path = \"\";\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\thost = parsed.hostname;\n\t\tpath = parsed.pathname;\n\t} catch {\n\t\treturn \"unknown\";\n\t}\n\tif (REPO_ISSUE_PATHS.test(path)) return \"repo_issue\";\n\tif (OFFICIAL_DOCS_HOSTS.test(host) || OFFICIAL_DOCS_PATHS.test(path)) return \"official_docs\";\n\tif (VENDOR_DOCS_PATHS.test(path)) return \"vendor_docs\";\n\tif (NEWS_HOSTS.test(host) || NEWS_PATHS.test(path)) return \"news\";\n\tif (FORUM_HOSTS.test(host) || FORUM_PATHS.test(path)) return \"forum\";\n\tif (BLOG_HOSTS.test(host) || BLOG_PATHS.test(path)) return \"blog\";\n\treturn \"unknown\";\n}\n\nexport function hashContent(text: string): string {\n\treturn `sha256:${createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\")}`;\n}\n\ninterface Span { text: string; start: number; end: number }\n\nfunction tokenize(value: string): string[] {\n\treturn [...new Set(value.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 3))];\n}\n\nfunction extractRelevantSpans(content: string, hint: string): Span[] {\n\tconst sentences: Span[] = [];\n\tconst sentencePattern = /[^.!?]+(?:[.!?]+(?=\\s|$)|$)/g;\n\tfor (const match of content.matchAll(sentencePattern)) {\n\t\tconst raw = match[0];\n\t\tconst text = raw.trim();\n\t\tif (text.length > 0 && text.length <= 400) {\n\t\t\tconst start = (match.index ?? 0) + raw.indexOf(text);\n\t\t\tsentences.push({ text, start, end: start + text.length });\n\t\t}\n\t}\n\tconst terms = tokenize(hint);\n\tif (terms.length === 0) return [];\n\treturn sentences\n\t\t.map((sentence, index) => ({ sentence, index, score: terms.filter((term) => sentence.text.toLowerCase().includes(term)).length }))\n\t\t.filter((item) => item.score > 0)\n\t\t.sort((a, b) => b.score - a.score || a.index - b.index)\n\t\t.slice(0, 3)\n\t\t.map(({ sentence }) => sentence);\n}\n\nfunction passageId(sourceRank: number, index: number): string {\n\treturn `p-${sourceRank}-${index}`;\n}\n\nexport function buildPassages(sources: ResearchSource[], fetched: ExtractedContent[] = [], hint = \"\"): ResearchPassage[] {\n\tconst passages: ResearchPassage[] = [];\n\tconst fetchedByUrl = new Map(fetched.map((item) => [item.url, item]));\n\tfor (const source of sources) {\n\t\tif (source.snippet) {\n\t\t\tpassages.push({\n\t\t\t\tpassage_id: passageId(source.rank, 0),\n\t\t\t\tsource_url: source.url,\n\t\t\t\tsource_rank: source.rank,\n\t\t\t\ttext: source.snippet,\n\t\t\t\tcontent_hash: hashContent(source.snippet),\n\t\t\t});\n\t\t}\n\t\tconst page = fetchedByUrl.get(source.url);\n\t\tif (page && !page.error && page.content) {\n\t\t\tconst passageHint = source.snippet?.trim() || hint;\n\t\t\tfor (const [index, span] of extractRelevantSpans(page.content, passageHint).entries()) {\n\t\t\t\tpassages.push({\n\t\t\t\t\tpassage_id: passageId(source.rank, index + 1),\n\t\t\t\t\tsource_url: source.url,\n\t\t\t\t\tsource_rank: source.rank,\n\t\t\t\t\ttext: span.text,\n\t\t\t\t\textraction_span: { start: span.start, end: span.end },\n\t\t\t\t\tcontent_hash: hashContent(span.text),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn passages;\n}\n\nconst CONTRADICTION_MARKERS = [\"not true\", \"false\", \"incorrect\", \"debunked\", \"retracted\", \"no longer\", \"never\", \"denied\", \"contrary\", \"misleading\"];\nconst SUPPORT_MARKERS = [\"yes\", \"true\", \"correct\", \"confirmed\", \"according to\", \"shows that\", \"demonstrates\", \"reported\", \"verified\", \"established\"];\n\nfunction containsPhrase(value: string, phrase: string): boolean {\n\tconst escaped = phrase.trim().toLowerCase().split(/\\s+/).map((term) => term.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\"\\\\s+\");\n\treturn new RegExp(`(?:^|[^a-z0-9])${escaped}(?=$|[^a-z0-9])`, \"i\").test(value);\n}\n\nfunction markerIsNegated(value: string, marker: string): boolean {\n\tconst escaped = marker.trim().toLowerCase().split(/\\s+/).map((term) => term.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")).join(\"\\\\s+\");\n\tconst markerPattern = new RegExp(`(?:^|[^a-z0-9])${escaped}(?=$|[^a-z0-9])`, \"i\");\n\tconst match = markerPattern.exec(value);\n\tif (!match || match.index === undefined) return false;\n\tconst matchedMarker = match[0].replace(/^[^a-z0-9]+/i, \"\");\n\tconst beforeMarker = value.slice(0, match.index + match[0].length - matchedMarker.length);\n\treturn /(?:^|[^a-z0-9])(?:not|no|never|without)\\s+$/i.test(beforeMarker);\n}\n\nfunction hasPolarityMarker(value: string, markers: string[], allowNegated = false): boolean {\n\treturn markers.some((marker) => containsPhrase(value, marker) && (allowNegated || !markerIsNegated(value, marker)));\n}\n\nexport function assessClaim(claim: string, passages: ResearchPassage[]): ClaimAssessment {\n\tconst terms = tokenize(claim);\n\tif (terms.length === 0 || passages.length === 0) {\n\t\treturn { claim, status: \"missing-evidence\", supporting_passages: [], contradicting_passages: [], rationale: \"No passages available that discuss the claim's terms.\", confidence: 0.2 };\n\t}\n\tconst supporting: string[] = [];\n\tconst contradicting: string[] = [];\n\tfor (const passage of passages) {\n\t\tconst lower = passage.text.toLowerCase();\n\t\tconst overlap = terms.filter((term) => containsPhrase(lower, term)).length;\n\t\tif (overlap < Math.max(2, Math.ceil(terms.length / 4))) continue;\n\t\tconst contra = hasPolarityMarker(lower, CONTRADICTION_MARKERS);\n\t\tconst support = hasPolarityMarker(lower, SUPPORT_MARKERS);\n\t\tif (contra && !support) contradicting.push(passage.passage_id);\n\t\telse if (support && !contra) supporting.push(passage.passage_id);\n\t}\n\tif (contradicting.length > 0 && supporting.length === 0) {\n\t\treturn { claim, status: \"contradicted\", supporting_passages: [], contradicting_passages: contradicting, rationale: `${contradicting.length} passage(s) contradict the claim; none support it.`, confidence: Math.min(0.85, 0.5 + contradicting.length * 0.1) };\n\t}\n\tif (supporting.length > 0 && contradicting.length === 0) {\n\t\treturn { claim, status: \"supported\", supporting_passages: supporting, contradicting_passages: [], rationale: `${supporting.length} passage(s) support the claim; none contradict it.`, confidence: Math.min(0.85, 0.5 + supporting.length * 0.1) };\n\t}\n\tif (supporting.length > 0 || contradicting.length > 0) {\n\t\treturn { claim, status: \"unclear\", supporting_passages: supporting, contradicting_passages: contradicting, rationale: `${supporting.length} supporting and ${contradicting.length} contradicting passage(s); evidence is mixed.`, confidence: 0.4 };\n\t}\n\treturn { claim, status: \"unclear\", supporting_passages: [], contradicting_passages: [], rationale: \"Passages mention the claim's terms but contain no clear support or contradiction markers.\", confidence: 0.3 };\n}\n\ninterface RankedSearchResult extends SearchResult {\n\trank?: number;\n}\n\nexport interface BuildArtifactInput {\n\tquery: string;\n\tprovider?: string;\n\tsummary?: string;\n\tresults: RankedSearchResult[];\n\tfetched?: ExtractedContent[];\n\trecency?: RecencyFilter;\n\tdomainFilter?: string[];\n}\n\nexport function buildResearchArtifact(input: BuildArtifactInput): ResearchArtifact {\n\tconst filters = input.domainFilter ?? [];\n\tconst fetchedByUrl = new Map((input.fetched ?? []).map((page) => [page.url, page]));\n\tconst sources: ResearchSource[] = [];\n\tconst seen = new Set<string>();\n\tfor (const [index, result] of input.results.entries()) {\n\t\tif (seen.has(result.url)) continue;\n\t\tseen.add(result.url);\n\t\tconst page = fetchedByUrl.get(result.url);\n\t\tconst fetched = Boolean(page && !page.error);\n\t\tsources.push({\n\t\t\trank: result.rank ?? index + 1,\n\t\t\turl: result.url,\n\t\t\ttitle: result.title,\n\t\t\tsnippet: result.snippet,\n\t\t\tquality: classifySource(result.url),\n\t\t\tfetched,\n\t\t\t...(page ? { fetch_timestamp: Date.now() } : {}),\n\t\t\t...(page && !page.error ? { content_hash: hashContent(page.content) } : {}),\n\t\t\t...(page?.error ? { fetch_error: page.error } : {}),\n\t\t});\n\t}\n\tconst passages = buildPassages(sources, input.fetched, input.query);\n\tconst domainInclude = filters.filter((domain) => !domain.startsWith(\"-\"));\n\tconst domainExclude = filters.filter((domain) => domain.startsWith(\"-\")).map((domain) => domain.slice(1));\n\treturn {\n\t\tid: generateId(),\n\t\ttype: \"research\",\n\t\ttimestamp: Date.now(),\n\t\tquery: input.query,\n\t\tsources,\n\t\tpassages,\n\t\t...(input.provider !== undefined ? { provider: input.provider } : {}),\n\t\t...(input.summary !== undefined ? { summary: input.summary } : {}),\n\t\t...(passages.length > 0 ? { content_hash: hashContent(passages.map((passage) => passage.text).join(\"\\n\")) } : {}),\n\t\tfilters: {\n\t\t\t...(input.recency !== undefined ? { recency: input.recency } : {}),\n\t\t\tdomain_include: domainInclude,\n\t\t\tdomain_exclude: domainExclude,\n\t\t},\n\t};\n}\n\nexport function withClaimAssessment(artifact: ResearchArtifact, claims: string[]): ResearchArtifact {\n\treturn { ...artifact, claims: claims.map((claim) => assessClaim(claim, artifact.passages)) };\n}\n\nexport function storeResearchArtifact(artifact: ResearchArtifact): void {\n\tif (!artifact.id) throw new Error(\"Research artifact id must not be empty\");\n\tstoreResult(artifact.id, { id: artifact.id, type: \"research\", timestamp: artifact.timestamp, artifact });\n}\n\nexport function getResearchArtifact(id: string): ResearchArtifact | null {\n\tconst data = getResult(id);\n\tif (!data || data.type !== \"research\" || !data.artifact || typeof data.artifact !== \"object\") return null;\n\treturn data.artifact as ResearchArtifact;\n}\n"]}
@@ -0,0 +1,205 @@
1
+ // Structured source checking and machine-readable research artifacts.
2
+ import { createHash } from "node:crypto";
3
+ import { generateId, getResult, storeResult } from "./storage.js";
4
+ const OFFICIAL_DOCS_HOSTS = /^(developers\.|docs\.|learn\.|reference\.)|\.github\.io$/i;
5
+ const OFFICIAL_DOCS_PATHS = /\/(docs?|reference)(\/|\b)/i;
6
+ const VENDOR_DOCS_PATHS = /\/(documentation|docs?)\//i;
7
+ const REPO_ISSUE_PATHS = /\/(issues|pull|pulls)\//i;
8
+ const BLOG_HOSTS = /(medium\.com|substack\.com|dev\.to|hashnode\.)/i;
9
+ const BLOG_PATHS = /\/blogs?\//i;
10
+ const FORUM_HOSTS = /(stackoverflow\.com|serverfault\.com|superuser\.com|discourse\.|community\.)/i;
11
+ const FORUM_PATHS = /\/(forum|forums|threads)\//i;
12
+ const NEWS_HOSTS = /(reuters\.com|bloomberg\.com|techcrunch\.com|theverge\.com|arstechnica\.com|wired\.com|cnet\.com|zdnet\.com)/i;
13
+ const NEWS_PATHS = /\/news(\/|$)/i;
14
+ export function classifySource(url) {
15
+ let host = "";
16
+ let path = "";
17
+ try {
18
+ const parsed = new URL(url);
19
+ host = parsed.hostname;
20
+ path = parsed.pathname;
21
+ }
22
+ catch {
23
+ return "unknown";
24
+ }
25
+ if (REPO_ISSUE_PATHS.test(path))
26
+ return "repo_issue";
27
+ if (OFFICIAL_DOCS_HOSTS.test(host) || OFFICIAL_DOCS_PATHS.test(path))
28
+ return "official_docs";
29
+ if (VENDOR_DOCS_PATHS.test(path))
30
+ return "vendor_docs";
31
+ if (NEWS_HOSTS.test(host) || NEWS_PATHS.test(path))
32
+ return "news";
33
+ if (FORUM_HOSTS.test(host) || FORUM_PATHS.test(path))
34
+ return "forum";
35
+ if (BLOG_HOSTS.test(host) || BLOG_PATHS.test(path))
36
+ return "blog";
37
+ return "unknown";
38
+ }
39
+ export function hashContent(text) {
40
+ return `sha256:${createHash("sha256").update(text, "utf8").digest("hex")}`;
41
+ }
42
+ function tokenize(value) {
43
+ return [...new Set(value.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 3))];
44
+ }
45
+ function extractRelevantSpans(content, hint) {
46
+ const sentences = [];
47
+ const sentencePattern = /[^.!?]+(?:[.!?]+(?=\s|$)|$)/g;
48
+ for (const match of content.matchAll(sentencePattern)) {
49
+ const raw = match[0];
50
+ const text = raw.trim();
51
+ if (text.length > 0 && text.length <= 400) {
52
+ const start = (match.index ?? 0) + raw.indexOf(text);
53
+ sentences.push({ text, start, end: start + text.length });
54
+ }
55
+ }
56
+ const terms = tokenize(hint);
57
+ if (terms.length === 0)
58
+ return [];
59
+ return sentences
60
+ .map((sentence, index) => ({ sentence, index, score: terms.filter((term) => sentence.text.toLowerCase().includes(term)).length }))
61
+ .filter((item) => item.score > 0)
62
+ .sort((a, b) => b.score - a.score || a.index - b.index)
63
+ .slice(0, 3)
64
+ .map(({ sentence }) => sentence);
65
+ }
66
+ function passageId(sourceRank, index) {
67
+ return `p-${sourceRank}-${index}`;
68
+ }
69
+ export function buildPassages(sources, fetched = [], hint = "") {
70
+ const passages = [];
71
+ const fetchedByUrl = new Map(fetched.map((item) => [item.url, item]));
72
+ for (const source of sources) {
73
+ if (source.snippet) {
74
+ passages.push({
75
+ passage_id: passageId(source.rank, 0),
76
+ source_url: source.url,
77
+ source_rank: source.rank,
78
+ text: source.snippet,
79
+ content_hash: hashContent(source.snippet),
80
+ });
81
+ }
82
+ const page = fetchedByUrl.get(source.url);
83
+ if (page && !page.error && page.content) {
84
+ const passageHint = source.snippet?.trim() || hint;
85
+ for (const [index, span] of extractRelevantSpans(page.content, passageHint).entries()) {
86
+ passages.push({
87
+ passage_id: passageId(source.rank, index + 1),
88
+ source_url: source.url,
89
+ source_rank: source.rank,
90
+ text: span.text,
91
+ extraction_span: { start: span.start, end: span.end },
92
+ content_hash: hashContent(span.text),
93
+ });
94
+ }
95
+ }
96
+ }
97
+ return passages;
98
+ }
99
+ const CONTRADICTION_MARKERS = ["not true", "false", "incorrect", "debunked", "retracted", "no longer", "never", "denied", "contrary", "misleading"];
100
+ const SUPPORT_MARKERS = ["yes", "true", "correct", "confirmed", "according to", "shows that", "demonstrates", "reported", "verified", "established"];
101
+ function containsPhrase(value, phrase) {
102
+ const escaped = phrase.trim().toLowerCase().split(/\s+/).map((term) => term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("\\s+");
103
+ return new RegExp(`(?:^|[^a-z0-9])${escaped}(?=$|[^a-z0-9])`, "i").test(value);
104
+ }
105
+ function markerIsNegated(value, marker) {
106
+ const escaped = marker.trim().toLowerCase().split(/\s+/).map((term) => term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("\\s+");
107
+ const markerPattern = new RegExp(`(?:^|[^a-z0-9])${escaped}(?=$|[^a-z0-9])`, "i");
108
+ const match = markerPattern.exec(value);
109
+ if (!match || match.index === undefined)
110
+ return false;
111
+ const matchedMarker = match[0].replace(/^[^a-z0-9]+/i, "");
112
+ const beforeMarker = value.slice(0, match.index + match[0].length - matchedMarker.length);
113
+ return /(?:^|[^a-z0-9])(?:not|no|never|without)\s+$/i.test(beforeMarker);
114
+ }
115
+ function hasPolarityMarker(value, markers, allowNegated = false) {
116
+ return markers.some((marker) => containsPhrase(value, marker) && (allowNegated || !markerIsNegated(value, marker)));
117
+ }
118
+ export function assessClaim(claim, passages) {
119
+ const terms = tokenize(claim);
120
+ if (terms.length === 0 || passages.length === 0) {
121
+ return { claim, status: "missing-evidence", supporting_passages: [], contradicting_passages: [], rationale: "No passages available that discuss the claim's terms.", confidence: 0.2 };
122
+ }
123
+ const supporting = [];
124
+ const contradicting = [];
125
+ for (const passage of passages) {
126
+ const lower = passage.text.toLowerCase();
127
+ const overlap = terms.filter((term) => containsPhrase(lower, term)).length;
128
+ if (overlap < Math.max(2, Math.ceil(terms.length / 4)))
129
+ continue;
130
+ const contra = hasPolarityMarker(lower, CONTRADICTION_MARKERS);
131
+ const support = hasPolarityMarker(lower, SUPPORT_MARKERS);
132
+ if (contra && !support)
133
+ contradicting.push(passage.passage_id);
134
+ else if (support && !contra)
135
+ supporting.push(passage.passage_id);
136
+ }
137
+ if (contradicting.length > 0 && supporting.length === 0) {
138
+ return { claim, status: "contradicted", supporting_passages: [], contradicting_passages: contradicting, rationale: `${contradicting.length} passage(s) contradict the claim; none support it.`, confidence: Math.min(0.85, 0.5 + contradicting.length * 0.1) };
139
+ }
140
+ if (supporting.length > 0 && contradicting.length === 0) {
141
+ return { claim, status: "supported", supporting_passages: supporting, contradicting_passages: [], rationale: `${supporting.length} passage(s) support the claim; none contradict it.`, confidence: Math.min(0.85, 0.5 + supporting.length * 0.1) };
142
+ }
143
+ if (supporting.length > 0 || contradicting.length > 0) {
144
+ return { claim, status: "unclear", supporting_passages: supporting, contradicting_passages: contradicting, rationale: `${supporting.length} supporting and ${contradicting.length} contradicting passage(s); evidence is mixed.`, confidence: 0.4 };
145
+ }
146
+ return { claim, status: "unclear", supporting_passages: [], contradicting_passages: [], rationale: "Passages mention the claim's terms but contain no clear support or contradiction markers.", confidence: 0.3 };
147
+ }
148
+ export function buildResearchArtifact(input) {
149
+ const filters = input.domainFilter ?? [];
150
+ const fetchedByUrl = new Map((input.fetched ?? []).map((page) => [page.url, page]));
151
+ const sources = [];
152
+ const seen = new Set();
153
+ for (const [index, result] of input.results.entries()) {
154
+ if (seen.has(result.url))
155
+ continue;
156
+ seen.add(result.url);
157
+ const page = fetchedByUrl.get(result.url);
158
+ const fetched = Boolean(page && !page.error);
159
+ sources.push({
160
+ rank: result.rank ?? index + 1,
161
+ url: result.url,
162
+ title: result.title,
163
+ snippet: result.snippet,
164
+ quality: classifySource(result.url),
165
+ fetched,
166
+ ...(page ? { fetch_timestamp: Date.now() } : {}),
167
+ ...(page && !page.error ? { content_hash: hashContent(page.content) } : {}),
168
+ ...(page?.error ? { fetch_error: page.error } : {}),
169
+ });
170
+ }
171
+ const passages = buildPassages(sources, input.fetched, input.query);
172
+ const domainInclude = filters.filter((domain) => !domain.startsWith("-"));
173
+ const domainExclude = filters.filter((domain) => domain.startsWith("-")).map((domain) => domain.slice(1));
174
+ return {
175
+ id: generateId(),
176
+ type: "research",
177
+ timestamp: Date.now(),
178
+ query: input.query,
179
+ sources,
180
+ passages,
181
+ ...(input.provider !== undefined ? { provider: input.provider } : {}),
182
+ ...(input.summary !== undefined ? { summary: input.summary } : {}),
183
+ ...(passages.length > 0 ? { content_hash: hashContent(passages.map((passage) => passage.text).join("\n")) } : {}),
184
+ filters: {
185
+ ...(input.recency !== undefined ? { recency: input.recency } : {}),
186
+ domain_include: domainInclude,
187
+ domain_exclude: domainExclude,
188
+ },
189
+ };
190
+ }
191
+ export function withClaimAssessment(artifact, claims) {
192
+ return { ...artifact, claims: claims.map((claim) => assessClaim(claim, artifact.passages)) };
193
+ }
194
+ export function storeResearchArtifact(artifact) {
195
+ if (!artifact.id)
196
+ throw new Error("Research artifact id must not be empty");
197
+ storeResult(artifact.id, { id: artifact.id, type: "research", timestamp: artifact.timestamp, artifact });
198
+ }
199
+ export function getResearchArtifact(id) {
200
+ const data = getResult(id);
201
+ if (!data || data.type !== "research" || !data.artifact || typeof data.artifact !== "object")
202
+ return null;
203
+ return data.artifact;
204
+ }
205
+ //# sourceMappingURL=source-check.js.map