@theowlops/boombot 0.0.0-stage → 1.1.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 (544) hide show
  1. package/README.md +69 -3
  2. package/dist/LICENSE +21 -0
  3. package/dist/bin/boombot.js +16 -0
  4. package/dist/cli/api-key.js +123 -0
  5. package/dist/cli/bin-bun.js +17 -0
  6. package/dist/cli/bin.js +34 -0
  7. package/dist/cli/cli/cli-error.js +61 -0
  8. package/dist/cli/cli/dispatch.js +138 -0
  9. package/dist/cli/cli/help.js +83 -0
  10. package/dist/cli/cli/parser.js +89 -0
  11. package/dist/cli/cli/registry.js +185 -0
  12. package/dist/cli/cli/spec.js +41 -0
  13. package/dist/cli/cli/suggest.js +125 -0
  14. package/dist/cli/cli/version.js +30 -0
  15. package/dist/cli/cli/vocabulary.js +87 -0
  16. package/dist/cli/commands/doctor.js +365 -0
  17. package/dist/cli/commands/gateway.js +290 -0
  18. package/dist/cli/commands/migrate.js +270 -0
  19. package/dist/cli/commands/plugin.js +97 -0
  20. package/dist/cli/commands/setup.js +244 -0
  21. package/dist/cli/config-file.js +133 -0
  22. package/dist/cli/master-key.js +78 -0
  23. package/dist/cli/open-browser.js +59 -0
  24. package/dist/cli/web-assets.js +58 -0
  25. package/dist/gateway/auth.js +46 -0
  26. package/dist/gateway/config-format.js +202 -0
  27. package/dist/gateway/config.js +427 -0
  28. package/dist/gateway/context.js +1 -0
  29. package/dist/gateway/env-file.js +129 -0
  30. package/dist/gateway/events.js +172 -0
  31. package/dist/gateway/guard/tagging.js +505 -0
  32. package/dist/gateway/handlers/index.js +66 -0
  33. package/dist/gateway/handlers/memory.js +54 -0
  34. package/dist/gateway/handlers/providers.js +73 -0
  35. package/dist/gateway/handlers/registry.js +39 -0
  36. package/dist/gateway/handlers/sessions.js +188 -0
  37. package/dist/gateway/handlers/system.js +12 -0
  38. package/dist/gateway/handlers/tasks.js +191 -0
  39. package/dist/gateway/handlers/turn.js +100 -0
  40. package/dist/gateway/index.js +126 -0
  41. package/dist/gateway/main.js +23 -0
  42. package/dist/gateway/server.js +354 -0
  43. package/dist/gateway/services/context-limits.js +75 -0
  44. package/dist/gateway/services/history-normalizer.js +42 -0
  45. package/dist/gateway/services/image-pipeline.js +56 -0
  46. package/dist/gateway/services/key-roulette-client.js +43 -0
  47. package/dist/gateway/services/llm-client.js +593 -0
  48. package/dist/gateway/services/llm-decoder.js +200 -0
  49. package/dist/gateway/services/local-fallback.js +135 -0
  50. package/dist/gateway/services/memory.js +511 -0
  51. package/dist/gateway/services/persistent-memory.js +196 -0
  52. package/dist/gateway/services/providers.js +44 -0
  53. package/dist/gateway/services/tasks.js +237 -0
  54. package/dist/gateway/services/verification.js +124 -0
  55. package/dist/gateway/services/vision-payload.js +48 -0
  56. package/dist/gateway/services.js +257 -0
  57. package/dist/gateway/session-snapshot.js +19 -0
  58. package/dist/gateway/sessions.js +701 -0
  59. package/dist/gateway/static.js +239 -0
  60. package/dist/gateway/turns/clarify-tool.js +57 -0
  61. package/dist/gateway/turns/cronjob-tool.js +96 -0
  62. package/dist/gateway/turns/deferred-tools.js +154 -0
  63. package/dist/gateway/turns/execute-code-tool.js +84 -0
  64. package/dist/gateway/turns/file-tool-defs.js +178 -0
  65. package/dist/gateway/turns/file-tool-ops.js +178 -0
  66. package/dist/gateway/turns/file-tool-scan.js +182 -0
  67. package/dist/gateway/turns/file-tool.js +302 -0
  68. package/dist/gateway/turns/index.js +416 -0
  69. package/dist/gateway/turns/jev-middleware.js +91 -0
  70. package/dist/gateway/turns/local-reply.js +156 -0
  71. package/dist/gateway/turns/mcp-client.js +643 -0
  72. package/dist/gateway/turns/memory-tool.js +171 -0
  73. package/dist/gateway/turns/middleware.js +96 -0
  74. package/dist/gateway/turns/python-core.js +397 -0
  75. package/dist/gateway/turns/routing/index.js +3 -0
  76. package/dist/gateway/turns/routing/intent-classifier.js +60 -0
  77. package/dist/gateway/turns/routing/planner-adapter.js +91 -0
  78. package/dist/gateway/turns/routing/types.js +1 -0
  79. package/dist/gateway/turns/runtime-deps.js +228 -0
  80. package/dist/gateway/turns/self-config-tool.js +277 -0
  81. package/dist/gateway/turns/service-types.js +11 -0
  82. package/dist/gateway/turns/service.js +820 -0
  83. package/dist/gateway/turns/session-adapter.js +158 -0
  84. package/dist/gateway/turns/session-tool.js +49 -0
  85. package/dist/gateway/turns/shell-tool.js +190 -0
  86. package/dist/gateway/turns/skill-tool.js +239 -0
  87. package/dist/gateway/turns/spillover.js +201 -0
  88. package/dist/gateway/turns/subagent-tool.js +140 -0
  89. package/dist/gateway/turns/system-prompt.js +121 -0
  90. package/dist/gateway/turns/tool-schema.js +90 -0
  91. package/dist/gateway/turns/turn-utils.js +58 -0
  92. package/dist/gateway/turns/vision-tool.js +120 -0
  93. package/dist/gateway/types.js +1 -0
  94. package/dist/native/win32-x64/boombot-native-host.exe +0 -0
  95. package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
  96. package/dist/node_modules/@boombot/channels/handlers.js +109 -0
  97. package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
  98. package/dist/node_modules/@boombot/channels/index.js +12 -0
  99. package/dist/node_modules/@boombot/channels/package.json +9 -0
  100. package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
  101. package/dist/node_modules/@boombot/channels/service.js +608 -0
  102. package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
  103. package/dist/node_modules/@boombot/channels/tool.js +46 -0
  104. package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
  105. package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
  106. package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
  107. package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
  108. package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
  109. package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
  110. package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
  111. package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
  112. package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
  113. package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
  114. package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
  115. package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
  116. package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
  117. package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
  118. package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
  119. package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
  120. package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
  121. package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
  122. package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
  123. package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
  124. package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
  125. package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
  126. package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
  127. package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
  128. package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
  129. package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
  130. package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
  131. package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
  132. package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
  133. package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
  134. package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
  135. package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
  136. package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
  137. package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
  138. package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
  139. package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
  140. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
  141. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
  142. package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
  143. package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
  144. package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
  145. package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
  146. package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
  147. package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
  148. package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
  149. package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
  150. package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
  151. package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
  152. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
  153. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
  154. package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
  155. package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
  156. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
  157. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
  158. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
  159. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
  160. package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
  161. package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
  162. package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
  163. package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
  164. package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
  165. package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
  166. package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
  167. package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
  168. package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
  169. package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
  170. package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
  171. package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
  172. package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
  173. package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
  174. package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
  175. package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
  176. package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
  177. package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
  178. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
  179. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
  180. package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
  181. package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
  182. package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
  183. package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
  184. package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
  185. package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
  186. package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
  187. package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
  188. package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
  189. package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
  190. package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
  191. package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
  192. package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
  193. package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
  194. package/dist/node_modules/@boombot/core/index.d.ts +9 -0
  195. package/dist/node_modules/@boombot/core/index.js +9 -0
  196. package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
  197. package/dist/node_modules/@boombot/core/jev/index.js +2 -0
  198. package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
  199. package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
  200. package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
  201. package/dist/node_modules/@boombot/core/jev/types.js +1 -0
  202. package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
  203. package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
  204. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
  205. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
  206. package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
  207. package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
  208. package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
  209. package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
  210. package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
  211. package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
  212. package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
  213. package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
  214. package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
  215. package/dist/node_modules/@boombot/core/memory/index.js +23 -0
  216. package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
  217. package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
  218. package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
  219. package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
  220. package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
  221. package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
  222. package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
  223. package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
  224. package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
  225. package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
  226. package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
  227. package/dist/node_modules/@boombot/core/memory/search.js +158 -0
  228. package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
  229. package/dist/node_modules/@boombot/core/memory/store.js +289 -0
  230. package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
  231. package/dist/node_modules/@boombot/core/memory/types.js +21 -0
  232. package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
  233. package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
  234. package/dist/node_modules/@boombot/core/package.json +9 -0
  235. package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
  236. package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
  237. package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
  238. package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
  239. package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
  240. package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
  241. package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
  242. package/dist/node_modules/@boombot/core/research/config.js +206 -0
  243. package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
  244. package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
  245. package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
  246. package/dist/node_modules/@boombot/core/research/factory.js +46 -0
  247. package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
  248. package/dist/node_modules/@boombot/core/research/http.js +250 -0
  249. package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
  250. package/dist/node_modules/@boombot/core/research/index.js +10 -0
  251. package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
  252. package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
  253. package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
  254. package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
  255. package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
  256. package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
  257. package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
  258. package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
  259. package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
  260. package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
  261. package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
  262. package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
  263. package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
  264. package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
  265. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
  266. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
  267. package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
  268. package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
  269. package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
  270. package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
  271. package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
  272. package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
  273. package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
  274. package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
  275. package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
  276. package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
  277. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
  278. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
  279. package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
  280. package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
  281. package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
  282. package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
  283. package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
  284. package/dist/node_modules/@boombot/core/research/tools.js +251 -0
  285. package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
  286. package/dist/node_modules/@boombot/core/research/types.js +8 -0
  287. package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
  288. package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
  289. package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
  290. package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
  291. package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
  292. package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
  293. package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
  294. package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
  295. package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
  296. package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
  297. package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
  298. package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
  299. package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
  300. package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
  301. package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
  302. package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
  303. package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
  304. package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
  305. package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
  306. package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
  307. package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
  308. package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
  309. package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
  310. package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
  311. package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
  312. package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
  313. package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
  314. package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
  315. package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
  316. package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
  317. package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
  318. package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
  319. package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
  320. package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
  321. package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
  322. package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
  323. package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
  324. package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
  325. package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
  326. package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
  327. package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
  328. package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
  329. package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
  330. package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
  331. package/dist/node_modules/@boombot/plugins/index.js +2 -0
  332. package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
  333. package/dist/node_modules/@boombot/plugins/installer.js +487 -0
  334. package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
  335. package/dist/node_modules/@boombot/plugins/manager.js +243 -0
  336. package/dist/node_modules/@boombot/plugins/package.json +9 -0
  337. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
  338. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
  339. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
  340. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
  341. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
  342. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
  343. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
  344. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
  345. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
  346. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
  347. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
  348. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
  349. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
  350. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
  351. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
  352. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
  353. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
  354. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
  355. package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
  356. package/dist/node_modules/@boombot/protocol/index.js +3 -0
  357. package/dist/node_modules/@boombot/protocol/package.json +9 -0
  358. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
  359. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
  360. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
  361. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
  362. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
  363. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
  364. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
  365. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
  366. package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
  367. package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
  368. package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
  369. package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
  370. package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
  371. package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
  372. package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
  373. package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
  374. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
  375. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
  376. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
  377. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
  378. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
  379. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
  380. package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
  381. package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
  382. package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
  383. package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
  384. package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
  385. package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
  386. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
  387. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
  388. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
  389. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
  390. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
  391. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
  392. package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
  393. package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
  394. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
  395. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
  396. package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
  397. package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
  398. package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
  399. package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
  400. package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
  401. package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
  402. package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
  403. package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
  404. package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
  405. package/dist/node_modules/@boombot/sandbox/index.js +13 -0
  406. package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
  407. package/dist/node_modules/@boombot/sandbox/native.js +224 -0
  408. package/dist/node_modules/@boombot/sandbox/package.json +9 -0
  409. package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
  410. package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
  411. package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
  412. package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
  413. package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
  414. package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
  415. package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
  416. package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
  417. package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
  418. package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
  419. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
  420. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
  421. package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
  422. package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
  423. package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
  424. package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
  425. package/dist/node_modules/@boombot/security/index.d.ts +5 -0
  426. package/dist/node_modules/@boombot/security/index.js +9 -0
  427. package/dist/node_modules/@boombot/security/package.json +9 -0
  428. package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
  429. package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
  430. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
  431. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
  432. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
  433. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
  434. package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
  435. package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
  436. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
  437. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
  438. package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
  439. package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
  440. package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
  441. package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
  442. package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
  443. package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
  444. package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
  445. package/dist/node_modules/@boombot/security/security/approval.js +140 -0
  446. package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
  447. package/dist/node_modules/@boombot/security/security/audit.js +70 -0
  448. package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
  449. package/dist/node_modules/@boombot/security/security/index.js +12 -0
  450. package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
  451. package/dist/node_modules/@boombot/security/security/trust.js +87 -0
  452. package/dist/package.json +5 -0
  453. package/dist/proto/agent_core.proto +56 -0
  454. package/dist/python/agent-core-python/pyproject.toml +40 -0
  455. package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
  456. package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
  457. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
  458. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
  459. package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
  460. package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
  461. package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
  462. package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
  463. package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
  464. package/dist/python/agent-core-python/uv.lock +2856 -0
  465. package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
  466. package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
  467. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  468. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  469. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  470. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  471. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  472. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  473. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  474. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  475. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  476. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  477. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  478. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  479. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  480. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  481. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  482. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  483. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  484. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  485. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  486. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  487. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  488. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  489. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  490. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  491. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  492. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  493. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  494. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  495. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  496. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  497. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  498. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  499. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  500. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  501. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  502. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  503. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  504. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  505. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  506. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  507. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  508. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  509. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  510. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  511. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  512. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  513. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  514. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  515. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  516. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  517. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  518. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  519. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  520. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  521. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  522. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  523. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  524. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  525. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  526. package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
  527. package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
  528. package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
  529. package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
  530. package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
  531. package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
  532. package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
  533. package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
  534. package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
  535. package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
  536. package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
  537. package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
  538. package/dist/web/assets/index-BL8bi7Yt.css +1 -0
  539. package/dist/web/assets/index-CuPR73Tn.js +73 -0
  540. package/dist/web/favicon.svg +4 -0
  541. package/dist/web/index.html +26 -0
  542. package/dist/web/logo.jpg +0 -0
  543. package/dist/web/logo.png +0 -0
  544. package/package.json +51 -4
@@ -0,0 +1,567 @@
1
+ /**
2
+ * Minimal PDF text extractor — hand-written, zero npm dependencies.
3
+ *
4
+ * Only `node:zlib` (via `./guards.ts` quotas) is used, for `/FlateDecode`
5
+ * content streams. This is a deliberate trade-off, documented honestly:
6
+ *
7
+ * - COVERED: text-based PDFs from common generators (FlateDecode or
8
+ * uncompressed content streams, `Tj`/`TJ`/`'`/`"` operators, literal and
9
+ * hex strings, WinAnsi/PDFDocEncoding bytes, UTF-16BE strings, and
10
+ * `/ToUnicode` CMaps — the subsetted-font encoding arXiv/LaTeX PDFs use).
11
+ * - NOT covered: encrypted PDFs (rejected), scanned/image-only PDFs (no OCR —
12
+ * text extraction correctly yields nothing), exotic filters (ASCII85,
13
+ * LZW, CCITT images are skipped), fonts with NEITHER a standard encoding
14
+ * NOR a ToUnicode map (byte values are emitted best-effort).
15
+ *
16
+ * A full renderer (pdf.js, poppler) would cover more, but both violate the
17
+ * project's zero-new-runtime-dep / easy-self-host philosophy — poppler is an
18
+ * OS package that may not exist on the host, pdf.js is megabytes of npm.
19
+ * For `research.extract`/`research.deep`, "most text out of most PDFs" is
20
+ * the right weight class.
21
+ */
22
+ import { Buffer } from 'node:buffer';
23
+ import { DecompressionQuota, DocumentParseError, MAX_PDF_STREAMS, MAX_ZIP_ENTRY_BYTES, assertDocumentSize, } from './guards.js';
24
+ /** Windows-1252-ish byte → char mapping (covers PDFDocEncoding's printable range). */
25
+ const BYTE_TO_CHAR = (() => {
26
+ const win1252 = {
27
+ 0x80: 0x20ac, 0x82: 0x201a, 0x83: 0x0192, 0x84: 0x201e, 0x85: 0x2026,
28
+ 0x86: 0x2020, 0x87: 0x2021, 0x88: 0x02c6, 0x89: 0x2030, 0x8a: 0x0160,
29
+ 0x8b: 0x2039, 0x8c: 0x0152, 0x8e: 0x017d, 0x91: 0x2018, 0x92: 0x2019,
30
+ 0x93: 0x201c, 0x94: 0x201d, 0x95: 0x2022, 0x96: 0x2013, 0x97: 0x2014,
31
+ 0x98: 0x02dc, 0x99: 0x2122, 0x9a: 0x0161, 0x9b: 0x203a, 0x9c: 0x0153,
32
+ 0x9e: 0x017e, 0x9f: 0x0178,
33
+ };
34
+ const table = new Array(256);
35
+ for (let b = 0; b < 256; b += 1) {
36
+ if (b < 0x80)
37
+ table[b] = String.fromCharCode(b);
38
+ else if (win1252[b] !== undefined)
39
+ table[b] = String.fromCodePoint(win1252[b]);
40
+ else
41
+ table[b] = String.fromCharCode(b);
42
+ }
43
+ return table;
44
+ })();
45
+ /** Decode one PDF string's raw bytes: UTF-16BE when BOM'd, else byte-mapped. */
46
+ function decodePdfBytes(raw) {
47
+ if (raw.length >= 2 && raw[0] === 0xfe && raw[1] === 0xff) {
48
+ let out = '';
49
+ for (let i = 2; i + 1 < raw.length; i += 2) {
50
+ const hi = raw[i] ?? 0;
51
+ const lo = raw[i + 1] ?? 0;
52
+ const code = (hi << 8) | lo;
53
+ // Skip a BOM re-appearing mid-string; lone surrogates are dropped
54
+ // rather than emitted as mojibake.
55
+ if (code === 0xfeff)
56
+ continue;
57
+ out += String.fromCharCode(code);
58
+ }
59
+ return out;
60
+ }
61
+ let out = '';
62
+ for (const b of raw)
63
+ out += BYTE_TO_CHAR[b] ?? '';
64
+ return out;
65
+ }
66
+ /** Decode a CMap destination hex string (UTF-16BE code units). */
67
+ function decodeUtf16Hex(hex) {
68
+ let out = '';
69
+ for (let i = 0; i + 4 <= hex.length; i += 4) {
70
+ out += String.fromCharCode(parseInt(hex.slice(i, i + 4), 16));
71
+ }
72
+ return out;
73
+ }
74
+ /**
75
+ * A regex group that is present by construction (the match could not have
76
+ * succeeded without it). Throws rather than threading `| undefined`
77
+ * through every CMap call site.
78
+ */
79
+ function grp(m, i) {
80
+ const v = m[i];
81
+ if (v === undefined)
82
+ throw new Error(`CMap match missing group ${i}`);
83
+ return v;
84
+ }
85
+ /**
86
+ * Parse a `begincmap ... endcmap` stream: `beginbfchar` pairs and
87
+ * `beginbfrange` ranges (both the `<dst>` and `[<dst> ...]` forms).
88
+ * Anything unrecognized is skipped — a partial map beats no map.
89
+ */
90
+ function parseCMap(cmapText) {
91
+ let bytesPerChar = 1;
92
+ const rangeBlock = /begincodespacerange([\s\S]*?)endcodespacerange/.exec(cmapText);
93
+ if (rangeBlock !== null) {
94
+ let longest = 0;
95
+ for (const m of grp(rangeBlock, 1).matchAll(/<([0-9a-fA-F]+)>/g)) {
96
+ longest = Math.max(longest, grp(m, 1).length / 2);
97
+ }
98
+ if (longest > 0)
99
+ bytesPerChar = Math.min(longest, 2);
100
+ }
101
+ const map = new Map();
102
+ for (const block of cmapText.matchAll(/beginbfchar([\s\S]*?)endbfchar/g)) {
103
+ for (const p of grp(block, 1).matchAll(/<([0-9a-fA-F]+)>\s*<([0-9a-fA-F]+)>/g)) {
104
+ map.set(parseInt(grp(p, 1), 16), decodeUtf16Hex(grp(p, 2)));
105
+ }
106
+ }
107
+ for (const block of cmapText.matchAll(/beginbfrange([\s\S]*?)endbfrange/g)) {
108
+ for (const t of grp(block, 1).matchAll(/<([0-9a-fA-F]+)>\s*<([0-9a-fA-F]+)>\s*(?:<([0-9a-fA-F]+)>|\[([^\]]*)\])/g)) {
109
+ const lo = parseInt(grp(t, 1), 16);
110
+ const hi = parseInt(grp(t, 2), 16);
111
+ // A hostile or sloppy CMap could declare a gigantic range; cap it.
112
+ const end = Math.min(hi, lo + 65535);
113
+ if (t[3] !== undefined) {
114
+ const dstLo = parseInt(grp(t, 3), 16);
115
+ for (let c = lo; c <= end; c += 1) {
116
+ map.set(c, String.fromCodePoint(dstLo + (c - lo)));
117
+ }
118
+ }
119
+ else if (t[4] !== undefined) {
120
+ const dsts = [...grp(t, 4).matchAll(/<([0-9a-fA-F]+)>/g)].map((m) => decodeUtf16Hex(grp(m, 1)));
121
+ for (let c = lo; c <= end && c - lo < dsts.length; c += 1) {
122
+ const dst = dsts[c - lo];
123
+ if (dst !== undefined)
124
+ map.set(c, dst);
125
+ }
126
+ }
127
+ }
128
+ }
129
+ return { bytesPerChar, map };
130
+ }
131
+ /** Map indirect object numbers to their bodies (on stream-stripped text). */
132
+ function buildObjectMap(stripped) {
133
+ const map = new Map();
134
+ const re = /(\d+)\s+0\s+obj([\s\S]*?)endobj/g;
135
+ for (;;) {
136
+ const m = re.exec(stripped);
137
+ if (m === null)
138
+ break;
139
+ map.set(parseInt(grp(m, 1), 10), grp(m, 2));
140
+ }
141
+ return map;
142
+ }
143
+ /**
144
+ * Resolve font resource names (`F1`) to their `/ToUnicode` CMaps by walking
145
+ * `/Resources → /Font → font object → /ToUnicode`. `cmapTexts` carries the
146
+ * already-inflated CMap streams keyed by object number (collected by
147
+ * `extractStreams`). Best-effort throughout: a PDF without this structure
148
+ * simply yields an empty map and falls back to byte decoding.
149
+ */
150
+ function buildFontCMaps(stripped, cmapTexts) {
151
+ const out = new Map();
152
+ try {
153
+ const objMap = buildObjectMap(stripped);
154
+ const fontToUnicode = new Map();
155
+ for (const [num, body] of objMap) {
156
+ const t = /\/ToUnicode\s+(\d+)\s+0\s+R/.exec(body);
157
+ if (t !== null)
158
+ fontToUnicode.set(num, parseInt(grp(t, 1), 10));
159
+ }
160
+ if (fontToUnicode.size === 0)
161
+ return out;
162
+ // Font resource names (`F1` in `/F1 12 Tf`): for each font object, find
163
+ // every `/Name <fontObj> 0 R` reference sitting inside a `<<...>>` dict.
164
+ // This covers both inline `/Resources << /Font << /F1 9 0 R >> >>` and
165
+ // the common indirection where the name→object dict lives in its own
166
+ // object (`11 0 obj << /F1 9 0 R >>`). A stray match (e.g. `/Parent`)
167
+ // is harmless: the map is only consulted for names seen before `Tf`.
168
+ const nameToFont = new Map();
169
+ for (const fontNum of fontToUnicode.keys()) {
170
+ const refRe = new RegExp(`/([A-Za-z0-9_+\\-.]+)\\s+${fontNum}\\s+0\\s+R`, 'g');
171
+ for (const m of stripped.matchAll(refRe)) {
172
+ const open = stripped.lastIndexOf('<<', m.index);
173
+ if (open < 0)
174
+ continue;
175
+ if (stripped.slice(open, m.index).includes('>>'))
176
+ continue;
177
+ nameToFont.set(grp(m, 1), fontNum);
178
+ }
179
+ }
180
+ for (const [name, fontNum] of nameToFont) {
181
+ const uniNum = fontToUnicode.get(fontNum);
182
+ if (uniNum === undefined)
183
+ continue;
184
+ const cmapText = cmapTexts.get(uniNum);
185
+ if (cmapText === undefined)
186
+ continue;
187
+ try {
188
+ out.set(name, parseCMap(cmapText));
189
+ }
190
+ catch {
191
+ // A broken CMap must not fail the document.
192
+ }
193
+ }
194
+ }
195
+ catch {
196
+ // CMap resolution is best-effort; byte decoding remains.
197
+ }
198
+ return out;
199
+ }
200
+ /**
201
+ * Extract the text-showing operations of one content stream.
202
+ * Handles `(literal) Tj`, `<hex> Tj`, `[...] TJ`, `'...'` and `"..."`.
203
+ * `cmaps` maps PDF font resource names (`F1` in `/F1 12 Tf`) to their
204
+ * `/ToUnicode` CMaps; strings set in a mapped font are decoded through it.
205
+ */
206
+ function extractContentText(content, cmaps) {
207
+ const parts = [];
208
+ let i = 0;
209
+ const n = content.length;
210
+ let currentFont;
211
+ const skipWs = () => {
212
+ while (i < n) {
213
+ const c = content[i];
214
+ if (c === ' ' || c === '\t' || c === '\n' || c === '\r' || c === '\f' || c === '\0')
215
+ i += 1;
216
+ else
217
+ break;
218
+ }
219
+ };
220
+ /** Read an operator token at the current position (after whitespace). */
221
+ const readOperator = () => {
222
+ skipWs();
223
+ const start = i;
224
+ while (i < n) {
225
+ const c = content[i] ?? '';
226
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === "'" || c === '"' || c === '*')
227
+ i += 1;
228
+ else
229
+ break;
230
+ }
231
+ return content.slice(start, i);
232
+ };
233
+ /** Parse a balanced literal string; `i` points at `(`. Returns raw bytes. */
234
+ const readLiteral = () => {
235
+ i += 1; // '('
236
+ const bytes = [];
237
+ let depth = 1;
238
+ while (i < n && depth > 0) {
239
+ const c = content[i] ?? '';
240
+ if (c === '\\') {
241
+ const e = content[i + 1];
242
+ i += 2;
243
+ if (e === undefined)
244
+ break;
245
+ if (e === 'n')
246
+ bytes.push(0x0a);
247
+ else if (e === 'r')
248
+ bytes.push(0x0d);
249
+ else if (e === 't')
250
+ bytes.push(0x09);
251
+ else if (e === 'b')
252
+ bytes.push(0x08);
253
+ else if (e === 'f')
254
+ bytes.push(0x0c);
255
+ else if (e === '(')
256
+ bytes.push(0x28);
257
+ else if (e === ')')
258
+ bytes.push(0x29);
259
+ else if (e === '\\')
260
+ bytes.push(0x5c);
261
+ else if (e === '\n') { /* line continuation — nothing */ }
262
+ else if (e === '\r') {
263
+ if (content[i] === '\n')
264
+ i += 1;
265
+ }
266
+ else if (e >= '0' && e <= '7') {
267
+ let oct = e;
268
+ for (let k = 0; k < 2; k += 1) {
269
+ const d = content[i];
270
+ if (d !== undefined && d >= '0' && d <= '7') {
271
+ oct += d;
272
+ i += 1;
273
+ }
274
+ else
275
+ break;
276
+ }
277
+ bytes.push(parseInt(oct, 8) & 0xff);
278
+ }
279
+ else {
280
+ bytes.push(e.charCodeAt(0) & 0xff);
281
+ }
282
+ }
283
+ else if (c === '(') {
284
+ depth += 1;
285
+ bytes.push(0x28);
286
+ i += 1;
287
+ }
288
+ else if (c === ')') {
289
+ depth -= 1;
290
+ if (depth > 0)
291
+ bytes.push(0x29);
292
+ i += 1;
293
+ }
294
+ else {
295
+ bytes.push(c.charCodeAt(0) & 0xff);
296
+ i += 1;
297
+ }
298
+ }
299
+ return Uint8Array.from(bytes);
300
+ };
301
+ /** Parse a hex string; `i` points at `<` (not `<<`). */
302
+ const readHex = () => {
303
+ i += 1; // '<'
304
+ let hex = '';
305
+ while (i < n && content[i] !== '>') {
306
+ const c = content[i] ?? '';
307
+ if (c !== ' ' && c !== '\t' && c !== '\n' && c !== '\r' && c !== '\f')
308
+ hex += c;
309
+ i += 1;
310
+ }
311
+ i += 1; // '>'
312
+ if (hex.length % 2 === 1)
313
+ hex += '0';
314
+ const out = new Uint8Array(hex.length / 2);
315
+ for (let k = 0; k < out.length; k += 1) {
316
+ out[k] = parseInt(hex.slice(k * 2, k * 2 + 2), 16);
317
+ }
318
+ return out;
319
+ };
320
+ /** Decode one string's bytes: the current font's ToUnicode CMap wins, else byte mapping. */
321
+ const decodeString = (raw) => {
322
+ const cmap = currentFont !== undefined ? cmaps.get(currentFont) : undefined;
323
+ if (cmap === undefined)
324
+ return decodePdfBytes(raw);
325
+ let out = '';
326
+ const step = cmap.bytesPerChar;
327
+ for (let k = 0; k < raw.length; k += step) {
328
+ let code = 0;
329
+ for (let b = 0; b < step && k + b < raw.length; b += 1) {
330
+ code = (code << 8) | (raw[k + b] ?? 0);
331
+ }
332
+ out += cmap.map.get(code) ?? decodePdfBytes(raw.slice(k, k + step));
333
+ }
334
+ return out;
335
+ };
336
+ while (i < n) {
337
+ skipWs();
338
+ if (i >= n)
339
+ break;
340
+ const c = content[i] ?? '';
341
+ if (c === '/') {
342
+ // Possible `/F1 12 Tf` — track the current font for ToUnicode decoding.
343
+ const nameMatch = /^\/([A-Za-z0-9_+\-.]+)/.exec(content.slice(i));
344
+ if (nameMatch !== null) {
345
+ const afterName = i + nameMatch[0].length;
346
+ const tfMatch = /^\s*\d+(?:\.\d+)?\s+Tf\b/.exec(content.slice(afterName));
347
+ if (tfMatch !== null) {
348
+ currentFont = nameMatch[1];
349
+ i = afterName + tfMatch[0].length;
350
+ continue;
351
+ }
352
+ }
353
+ i += 1;
354
+ }
355
+ else if (c === '(') {
356
+ const raw = readLiteral();
357
+ const op = readOperator();
358
+ if (op === 'Tj')
359
+ parts.push(decodeString(raw));
360
+ else if (op === "'") {
361
+ // ' = T* + Tj: next line of text.
362
+ parts.push(decodeString(raw));
363
+ parts.push('\n');
364
+ }
365
+ else if (op === '"') {
366
+ // " = Tw Tc + ': operands (aw ac) precede the string.
367
+ parts.push(decodeString(raw));
368
+ parts.push('\n');
369
+ }
370
+ }
371
+ else if (c === '<' && content[i + 1] !== '<') {
372
+ const raw = readHex();
373
+ const op = readOperator();
374
+ if (op === 'Tj')
375
+ parts.push(decodeString(raw));
376
+ }
377
+ else if (c === '[') {
378
+ i += 1; // '['
379
+ const items = [];
380
+ for (;;) {
381
+ skipWs();
382
+ if (i >= n)
383
+ break;
384
+ const t = content[i] ?? '';
385
+ if (t === ']') {
386
+ i += 1;
387
+ break;
388
+ }
389
+ if (t === '(')
390
+ items.push(decodeString(readLiteral()));
391
+ else if (t === '<' && content[i + 1] !== '<')
392
+ items.push(decodeString(readHex()));
393
+ else
394
+ i += 1; // kerning numbers and anything else
395
+ }
396
+ if (readOperator() === 'TJ')
397
+ parts.push(items.join(' '));
398
+ }
399
+ else if (c === 'T' && content[i + 1] === '*') {
400
+ i += 2;
401
+ parts.push('\n');
402
+ }
403
+ else {
404
+ i += 1;
405
+ }
406
+ }
407
+ return parts.join(' ').replace(/ \n /g, '\n').replace(/ \n/g, '\n');
408
+ }
409
+ /**
410
+ * Inflate FlateDecode content streams (quota-guarded); pass through
411
+ * unfiltered streams; skip anything else (images, exotic filters).
412
+ * One corrupt stream never kills the document — it is skipped.
413
+ *
414
+ * `/ToUnicode` CMap streams are inflated here too (they are just streams);
415
+ * `extractPdfText` separates them by content (`begincmap`) afterwards.
416
+ */
417
+ async function extractStreams(bytes, quota) {
418
+ const latin = Buffer.from(bytes).toString('latin1');
419
+ const out = [];
420
+ const re = /stream\r?\n([\s\S]*?)\r?\nendstream/g;
421
+ let count = 0;
422
+ for (;;) {
423
+ const m = re.exec(latin);
424
+ if (m === null)
425
+ break;
426
+ count += 1;
427
+ if (count > MAX_PDF_STREAMS) {
428
+ throw new DocumentParseError('ARCHIVE_LIMIT', `PDF declares more than ${MAX_PDF_STREAMS} content streams.`);
429
+ }
430
+ // The stream's owner is the last `N 0 obj` header before it
431
+ // (objects never nest, so the nearest header owns the stream).
432
+ const before = latin.slice(Math.max(0, m.index - 4000), m.index);
433
+ let objNum;
434
+ for (const om of before.matchAll(/(\d+)\s+0\s+obj/g)) {
435
+ objNum = parseInt(grp(om, 1), 10);
436
+ }
437
+ // Look at the stream's own dictionary only: the nearest `<<` before
438
+ // `stream`, so a previous object's /Filter can't mislabel this one.
439
+ const dictOpen = latin.lastIndexOf('<<', m.index);
440
+ const dictText = dictOpen >= 0 && m.index - dictOpen < 4000
441
+ ? latin.slice(dictOpen, m.index)
442
+ : '';
443
+ const filterMatch = /\/Filter\s*(\[[^\]]*\]|\/[A-Za-z0-9]+)/.exec(dictText);
444
+ const filterText = filterMatch !== null ? grp(filterMatch, 1) : '';
445
+ try {
446
+ if (filterText.includes('FlateDecode')) {
447
+ const raw = Buffer.from(m[1] ?? '', 'latin1');
448
+ // PDF FlateDecode is zlib-wrapped (RFC 1950), not raw deflate.
449
+ const inflated = await quota.inflate(raw, MAX_ZIP_ENTRY_BYTES, `pdf-stream#${count}`);
450
+ out.push({ text: Buffer.from(inflated).toString('latin1'), objNum });
451
+ }
452
+ else if (filterText === '') {
453
+ out.push({ text: m[1] ?? '', objNum });
454
+ }
455
+ // else: image/exotic filter — skipped, not text.
456
+ }
457
+ catch {
458
+ // One bad stream is skipped; the document still parses.
459
+ }
460
+ }
461
+ return out;
462
+ }
463
+ /** Best-effort `/Title (...)` lookup on stream-stripped text. */
464
+ function findInfoString(stripped, key) {
465
+ const at = stripped.indexOf(`/${key}`);
466
+ if (at < 0)
467
+ return undefined;
468
+ let i = at + key.length + 1;
469
+ while (i < stripped.length && /\s/.test(stripped[i] ?? ''))
470
+ i += 1;
471
+ if (stripped[i] !== '(')
472
+ return undefined;
473
+ i += 1;
474
+ const bytes = [];
475
+ let depth = 1;
476
+ while (i < stripped.length && depth > 0) {
477
+ const c = stripped[i] ?? '';
478
+ if (c === '\\') {
479
+ const e = stripped[i + 1] ?? '';
480
+ bytes.push(e.charCodeAt(0) & 0xff);
481
+ i += 2;
482
+ }
483
+ else if (c === '(') {
484
+ depth += 1;
485
+ bytes.push(0x28);
486
+ i += 1;
487
+ }
488
+ else if (c === ')') {
489
+ depth -= 1;
490
+ if (depth > 0)
491
+ bytes.push(0x29);
492
+ i += 1;
493
+ }
494
+ else {
495
+ bytes.push(c.charCodeAt(0) & 0xff);
496
+ i += 1;
497
+ }
498
+ }
499
+ if (depth !== 0)
500
+ return undefined;
501
+ return decodePdfBytes(Uint8Array.from(bytes));
502
+ }
503
+ /**
504
+ * Extract text from PDF `bytes`. Throws {@link DocumentParseError} with
505
+ * `CORRUPT_DOCUMENT` (not a PDF), `UNSUPPORTED_TYPE` (encrypted),
506
+ * `DOCUMENT_TOO_LARGE`, or `ARCHIVE_LIMIT` (stream bomb).
507
+ */
508
+ export async function extractPdfText(bytes) {
509
+ assertDocumentSize(bytes.length, 'PDF');
510
+ // Skip a UTF-8 BOM and leading whitespace before the header.
511
+ let p = 0;
512
+ while (p < bytes.length) {
513
+ const b = bytes[p] ?? 0;
514
+ if (b === 0x20 || b === 0x09 || b === 0x0a || b === 0x0d)
515
+ p += 1;
516
+ else if (b === 0xef && bytes[p + 1] === 0xbb && bytes[p + 2] === 0xbf)
517
+ p += 3;
518
+ else
519
+ break;
520
+ }
521
+ const magic = [0x25, 0x50, 0x44, 0x46, 0x2d]; // '%PDF-'
522
+ for (let k = 0; k < magic.length; k += 1) {
523
+ if (bytes[p + k] !== magic[k]) {
524
+ throw new DocumentParseError('CORRUPT_DOCUMENT', 'Not a PDF file (missing %PDF- header).');
525
+ }
526
+ }
527
+ const latin = Buffer.from(bytes).toString('latin1');
528
+ // Scan for /Encrypt outside content streams — inside a stream the token
529
+ // could be literal page text, which must not false-positive.
530
+ const stripped = latin.replace(/stream\r?\n[\s\S]*?\r?\nendstream/g, '');
531
+ if (/\/Encrypt\b/.test(stripped)) {
532
+ throw new DocumentParseError('UNSUPPORTED_TYPE', 'Encrypted PDFs are not supported.');
533
+ }
534
+ const quota = new DecompressionQuota();
535
+ const streams = await extractStreams(bytes, quota);
536
+ // Separate /ToUnicode CMap streams from content streams by content.
537
+ const cmapTexts = new Map();
538
+ const contentTexts = [];
539
+ for (const s of streams) {
540
+ if (s.objNum !== undefined &&
541
+ s.text.includes('begincmap') &&
542
+ s.text.includes('endcmap')) {
543
+ cmapTexts.set(s.objNum, s.text);
544
+ }
545
+ else {
546
+ contentTexts.push(s.text);
547
+ }
548
+ }
549
+ // Resolve /ToUnicode CMaps before extracting text (best-effort; a
550
+ // failure here only loses the mapping, never the document).
551
+ const cmaps = buildFontCMaps(stripped, cmapTexts);
552
+ if (contentTexts.length === 0) {
553
+ // A header alone is not a document: image-only PDFs still carry
554
+ // (image) streams, so zero content streams means this is not a real PDF.
555
+ throw new DocumentParseError('CORRUPT_DOCUMENT', 'PDF has no content streams.');
556
+ }
557
+ const texts = contentTexts
558
+ .map((s) => extractContentText(s, cmaps).trim())
559
+ .filter((t) => t !== '');
560
+ const title = findInfoString(stripped, 'Title') ?? '';
561
+ const pageMatches = stripped.match(/\/Type\s*\/Page(?![A-Za-z])/g);
562
+ return {
563
+ text: texts.join('\n\n'),
564
+ title,
565
+ pageCount: pageMatches !== null ? pageMatches.length : undefined,
566
+ };
567
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * arXiv search provider (free, no key).
3
+ *
4
+ * Uses the arXiv OAI-style query API (`export.arxiv.org/api/query`).
5
+ * The XML response is parsed with a small purpose-built parser — no XML
6
+ * dependency, no DOM. HTML entities in text nodes are decoded.
7
+ */
8
+ import type { ResearchProvider } from '../types.js';
9
+ export declare function createArxivProvider(): ResearchProvider;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * arXiv search provider (free, no key).
3
+ *
4
+ * Uses the arXiv OAI-style query API (`export.arxiv.org/api/query`).
5
+ * The XML response is parsed with a small purpose-built parser — no XML
6
+ * dependency, no DOM. HTML entities in text nodes are decoded.
7
+ */
8
+ import { fetchText, truncate, withRetry } from '../http.js';
9
+ const MAX_RESULTS = 20;
10
+ function decodeEntities(text) {
11
+ return text
12
+ .replace(/&amp;/g, '&')
13
+ .replace(/&lt;/g, '<')
14
+ .replace(/&gt;/g, '>')
15
+ .replace(/&quot;/g, '"')
16
+ .replace(/&#39;/g, "'")
17
+ .replace(/&apos;/g, "'");
18
+ }
19
+ function collapseWhitespace(text) {
20
+ return decodeEntities(text).replace(/\s+/g, ' ').trim();
21
+ }
22
+ /** Extract the text of the first `<tag>…</tag>` block inside `xml`. */
23
+ function tagText(xml, tag) {
24
+ const re = new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${tag}>`);
25
+ const match = re.exec(xml);
26
+ return match?.[1] === undefined ? undefined : collapseWhitespace(match[1]);
27
+ }
28
+ function parseEntries(xml) {
29
+ const entries = [];
30
+ const entryRe = /<entry>([\s\S]*?)<\/entry>/g;
31
+ for (const match of xml.matchAll(entryRe)) {
32
+ const body = match[1] ?? '';
33
+ const title = tagText(body, 'title');
34
+ const id = tagText(body, 'id');
35
+ if (title === undefined || id === undefined)
36
+ continue;
37
+ entries.push({
38
+ title,
39
+ id,
40
+ summary: tagText(body, 'summary') ?? '',
41
+ published: tagText(body, 'published'),
42
+ });
43
+ }
44
+ return entries;
45
+ }
46
+ export function createArxivProvider() {
47
+ return {
48
+ id: 'arxiv',
49
+ kind: 'free',
50
+ async search(query, opts = {}) {
51
+ const limit = Math.min(Math.max(opts.limit ?? 8, 1), MAX_RESULTS);
52
+ const params = new URLSearchParams({
53
+ search_query: `all:${query}`,
54
+ start: '0',
55
+ max_results: String(limit),
56
+ sortBy: 'relevance',
57
+ sortOrder: 'descending',
58
+ });
59
+ const url = `https://export.arxiv.org/api/query?${params.toString()}`;
60
+ const xml = await withRetry(() => fetchText(url, { signal: opts.signal, timeoutMs: 15_000 }));
61
+ return parseEntries(xml)
62
+ .slice(0, limit)
63
+ .map((entry) => ({
64
+ title: entry.title,
65
+ url: entry.id.replace('http://', 'https://'),
66
+ snippet: truncate(entry.summary, 300),
67
+ source: 'arxiv',
68
+ publishedAt: entry.published,
69
+ }));
70
+ },
71
+ };
72
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Brave Search adapter (paid, API key required).
3
+ *
4
+ * Wraps the Brave Search API (`/res/v1/web/search`). The key travels in
5
+ * the `X-Subscription-Token` header — never in the URL, never logged.
6
+ */
7
+ import type { ResearchProvider } from '../types.js';
8
+ export interface BraveProviderOptions {
9
+ readonly apiKey: string;
10
+ }
11
+ export declare function createBraveProvider(options: BraveProviderOptions): ResearchProvider;