@m4ike1/ion-coding-agent 0.1.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 (1126) hide show
  1. package/CHANGELOG.md +5747 -0
  2. package/README.md +738 -0
  3. package/dist/bun/cli.d.ts +5 -0
  4. package/dist/bun/cli.d.ts.map +1 -0
  5. package/dist/bun/cli.js +5 -0
  6. package/dist/bun/cli.js.map +1 -0
  7. package/dist/bun/restore-sandbox-env.d.ts +17 -0
  8. package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
  9. package/dist/bun/restore-sandbox-env.js +36 -0
  10. package/dist/bun/restore-sandbox-env.js.map +1 -0
  11. package/dist/bun/runtime-setup.d.ts +2 -0
  12. package/dist/bun/runtime-setup.d.ts.map +1 -0
  13. package/dist/bun/runtime-setup.js +9 -0
  14. package/dist/bun/runtime-setup.js.map +1 -0
  15. package/dist/bun/sandbox-env-setup.d.ts +2 -0
  16. package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
  17. package/dist/bun/sandbox-env-setup.js +4 -0
  18. package/dist/bun/sandbox-env-setup.js.map +1 -0
  19. package/dist/bundle/chunks/anthropic-messages-RPVA4Z4Y.js +6 -0
  20. package/dist/bundle/chunks/anthropic.js +75 -0
  21. package/dist/bundle/chunks/azure-openai-responses-AJS3XTKL.js +2 -0
  22. package/dist/bundle/chunks/bedrock-converse-stream.js +78 -0
  23. package/dist/bundle/chunks/chunk-2MOZ6JBC.js +2 -0
  24. package/dist/bundle/chunks/chunk-3BIJ3AQO.js +12 -0
  25. package/dist/bundle/chunks/chunk-47K3I3YT.js +6 -0
  26. package/dist/bundle/chunks/chunk-4BN67GCJ.js +1664 -0
  27. package/dist/bundle/chunks/chunk-4PN6UIWX.js +2 -0
  28. package/dist/bundle/chunks/chunk-4TQA6ATT.js +4 -0
  29. package/dist/bundle/chunks/chunk-5NVSYJOG.js +2 -0
  30. package/dist/bundle/chunks/chunk-7OJL7DR5.js +2 -0
  31. package/dist/bundle/chunks/chunk-BEER2HEL.js +2 -0
  32. package/dist/bundle/chunks/chunk-CQX3HQAT.js +2 -0
  33. package/dist/bundle/chunks/chunk-FBMFFBV2.js +2 -0
  34. package/dist/bundle/chunks/chunk-GAZIWLQB.js +2 -0
  35. package/dist/bundle/chunks/chunk-HFYRAIWC.js +44 -0
  36. package/dist/bundle/chunks/chunk-IH7HUXWH.js +2 -0
  37. package/dist/bundle/chunks/chunk-LPP2XRBR.js +11 -0
  38. package/dist/bundle/chunks/chunk-LUTYILPM.js +25 -0
  39. package/dist/bundle/chunks/chunk-Q3ZNVFWD.js +42 -0
  40. package/dist/bundle/chunks/chunk-QNBVCBN3.js +2 -0
  41. package/dist/bundle/chunks/chunk-SWVWKUIA.js +2 -0
  42. package/dist/bundle/chunks/chunk-SY4QP6EI.js +2 -0
  43. package/dist/bundle/chunks/chunk-TVAWBPPS.js +2 -0
  44. package/dist/bundle/chunks/chunk-WPN6KEON.js +2 -0
  45. package/dist/bundle/chunks/chunk-WRID246J.js +2 -0
  46. package/dist/bundle/chunks/github-copilot.js +2 -0
  47. package/dist/bundle/chunks/google-generative-ai-S7SD5HC7.js +2 -0
  48. package/dist/bundle/chunks/google-vertex-NUNHA7QM.js +2 -0
  49. package/dist/bundle/chunks/https-proxy-agent-O2332S4O.js +13 -0
  50. package/dist/bundle/chunks/image-resize-worker.js +2 -0
  51. package/dist/bundle/chunks/ion-messages-KTW6MD7U.js +8 -0
  52. package/dist/bundle/chunks/kimi-coding.js +2 -0
  53. package/dist/bundle/chunks/lib-D4EQQPRR.js +9 -0
  54. package/dist/bundle/chunks/mistral-conversations-C7I3G2LA.js +5 -0
  55. package/dist/bundle/chunks/multipart-parser-PL2BXRDT.js +3 -0
  56. package/dist/bundle/chunks/node-7OQEATQA.js +2 -0
  57. package/dist/bundle/chunks/node-QIUI6CIW.js +16 -0
  58. package/dist/bundle/chunks/openai-codex-responses-2KRULDYR.js +10 -0
  59. package/dist/bundle/chunks/openai-codex.js +75 -0
  60. package/dist/bundle/chunks/openai-completions-64KX63FN.js +7 -0
  61. package/dist/bundle/chunks/openai-responses-QF3PPSTS.js +2 -0
  62. package/dist/bundle/chunks/openrouter-images-GQVXT3PO.js +2 -0
  63. package/dist/bundle/chunks/openrouter.js +75 -0
  64. package/dist/bundle/chunks/radius.js +75 -0
  65. package/dist/bundle/chunks/src-AZ7LBHGY.js +4 -0
  66. package/dist/bundle/chunks/xai.js +2 -0
  67. package/dist/bundle/cli.js +3 -0
  68. package/dist/bundle/index.js +2 -0
  69. package/dist/bundle/rpc-entry.js +3 -0
  70. package/dist/cli/args.d.ts +61 -0
  71. package/dist/cli/args.d.ts.map +1 -0
  72. package/dist/cli/args.js +440 -0
  73. package/dist/cli/args.js.map +1 -0
  74. package/dist/cli/auth-check.d.ts +19 -0
  75. package/dist/cli/auth-check.d.ts.map +1 -0
  76. package/dist/cli/auth-check.js +50 -0
  77. package/dist/cli/auth-check.js.map +1 -0
  78. package/dist/cli/auth-command.d.ts +24 -0
  79. package/dist/cli/auth-command.d.ts.map +1 -0
  80. package/dist/cli/auth-command.js +103 -0
  81. package/dist/cli/auth-command.js.map +1 -0
  82. package/dist/cli/config-selector.d.ts +16 -0
  83. package/dist/cli/config-selector.d.ts.map +1 -0
  84. package/dist/cli/config-selector.js +32 -0
  85. package/dist/cli/config-selector.js.map +1 -0
  86. package/dist/cli/credential-print.d.ts +13 -0
  87. package/dist/cli/credential-print.d.ts.map +1 -0
  88. package/dist/cli/credential-print.js +76 -0
  89. package/dist/cli/credential-print.js.map +1 -0
  90. package/dist/cli/file-processor.d.ts +15 -0
  91. package/dist/cli/file-processor.d.ts.map +1 -0
  92. package/dist/cli/file-processor.js +71 -0
  93. package/dist/cli/file-processor.js.map +1 -0
  94. package/dist/cli/initial-message.d.ts +18 -0
  95. package/dist/cli/initial-message.d.ts.map +1 -0
  96. package/dist/cli/initial-message.js +22 -0
  97. package/dist/cli/initial-message.js.map +1 -0
  98. package/dist/cli/list-models.d.ts +9 -0
  99. package/dist/cli/list-models.d.ts.map +1 -0
  100. package/dist/cli/list-models.js +98 -0
  101. package/dist/cli/list-models.js.map +1 -0
  102. package/dist/cli/project-trust.d.ts +10 -0
  103. package/dist/cli/project-trust.d.ts.map +1 -0
  104. package/dist/cli/project-trust.js +48 -0
  105. package/dist/cli/project-trust.js.map +1 -0
  106. package/dist/cli/session-picker.d.ts +10 -0
  107. package/dist/cli/session-picker.d.ts.map +1 -0
  108. package/dist/cli/session-picker.js +36 -0
  109. package/dist/cli/session-picker.js.map +1 -0
  110. package/dist/cli/setup.d.ts +2 -0
  111. package/dist/cli/setup.d.ts.map +1 -0
  112. package/dist/cli/setup.js +12 -0
  113. package/dist/cli/setup.js.map +1 -0
  114. package/dist/cli/startup-ui.d.ts +20 -0
  115. package/dist/cli/startup-ui.d.ts.map +1 -0
  116. package/dist/cli/startup-ui.js +185 -0
  117. package/dist/cli/startup-ui.js.map +1 -0
  118. package/dist/cli.d.ts +3 -0
  119. package/dist/cli.d.ts.map +1 -0
  120. package/dist/cli.js +6 -0
  121. package/dist/cli.js.map +1 -0
  122. package/dist/config.d.ts +122 -0
  123. package/dist/config.d.ts.map +1 -0
  124. package/dist/config.js +609 -0
  125. package/dist/config.js.map +1 -0
  126. package/dist/core/agent-session-runtime.d.ts +119 -0
  127. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  128. package/dist/core/agent-session-runtime.js +317 -0
  129. package/dist/core/agent-session-runtime.js.map +1 -0
  130. package/dist/core/agent-session-services.d.ts +86 -0
  131. package/dist/core/agent-session-services.d.ts.map +1 -0
  132. package/dist/core/agent-session-services.js +134 -0
  133. package/dist/core/agent-session-services.js.map +1 -0
  134. package/dist/core/agent-session.d.ts +725 -0
  135. package/dist/core/agent-session.d.ts.map +1 -0
  136. package/dist/core/agent-session.js +2968 -0
  137. package/dist/core/agent-session.js.map +1 -0
  138. package/dist/core/auth-guidance.d.ts +5 -0
  139. package/dist/core/auth-guidance.d.ts.map +1 -0
  140. package/dist/core/auth-guidance.js +21 -0
  141. package/dist/core/auth-guidance.js.map +1 -0
  142. package/dist/core/auth-storage.d.ts +72 -0
  143. package/dist/core/auth-storage.d.ts.map +1 -0
  144. package/dist/core/auth-storage.js +426 -0
  145. package/dist/core/auth-storage.js.map +1 -0
  146. package/dist/core/bash-executor.d.ts +32 -0
  147. package/dist/core/bash-executor.d.ts.map +1 -0
  148. package/dist/core/bash-executor.js +111 -0
  149. package/dist/core/bash-executor.js.map +1 -0
  150. package/dist/core/cache-stats.d.ts +49 -0
  151. package/dist/core/cache-stats.d.ts.map +1 -0
  152. package/dist/core/cache-stats.js +101 -0
  153. package/dist/core/cache-stats.js.map +1 -0
  154. package/dist/core/compaction/branch-summarization.d.ts +98 -0
  155. package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
  156. package/dist/core/compaction/branch-summarization.js +251 -0
  157. package/dist/core/compaction/branch-summarization.js.map +1 -0
  158. package/dist/core/compaction/compaction.d.ts +145 -0
  159. package/dist/core/compaction/compaction.d.ts.map +1 -0
  160. package/dist/core/compaction/compaction.js +690 -0
  161. package/dist/core/compaction/compaction.js.map +1 -0
  162. package/dist/core/compaction/index.d.ts +7 -0
  163. package/dist/core/compaction/index.d.ts.map +1 -0
  164. package/dist/core/compaction/index.js +7 -0
  165. package/dist/core/compaction/index.js.map +1 -0
  166. package/dist/core/compaction/utils.d.ts +38 -0
  167. package/dist/core/compaction/utils.d.ts.map +1 -0
  168. package/dist/core/compaction/utils.js +142 -0
  169. package/dist/core/compaction/utils.js.map +1 -0
  170. package/dist/core/defaults.d.ts +4 -0
  171. package/dist/core/defaults.d.ts.map +1 -0
  172. package/dist/core/defaults.js +11 -0
  173. package/dist/core/defaults.js.map +1 -0
  174. package/dist/core/diagnostics.d.ts +15 -0
  175. package/dist/core/diagnostics.d.ts.map +1 -0
  176. package/dist/core/diagnostics.js +2 -0
  177. package/dist/core/diagnostics.js.map +1 -0
  178. package/dist/core/event-bus.d.ts +9 -0
  179. package/dist/core/event-bus.d.ts.map +1 -0
  180. package/dist/core/event-bus.js +25 -0
  181. package/dist/core/event-bus.js.map +1 -0
  182. package/dist/core/exec.d.ts +29 -0
  183. package/dist/core/exec.d.ts.map +1 -0
  184. package/dist/core/exec.js +75 -0
  185. package/dist/core/exec.js.map +1 -0
  186. package/dist/core/experimental.d.ts +2 -0
  187. package/dist/core/experimental.d.ts.map +1 -0
  188. package/dist/core/experimental.js +4 -0
  189. package/dist/core/experimental.js.map +1 -0
  190. package/dist/core/export-html/ansi-to-html.d.ts +22 -0
  191. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  192. package/dist/core/export-html/ansi-to-html.js +249 -0
  193. package/dist/core/export-html/ansi-to-html.js.map +1 -0
  194. package/dist/core/export-html/index.d.ts +37 -0
  195. package/dist/core/export-html/index.d.ts.map +1 -0
  196. package/dist/core/export-html/index.js +226 -0
  197. package/dist/core/export-html/index.js.map +1 -0
  198. package/dist/core/export-html/template.css +1066 -0
  199. package/dist/core/export-html/template.html +55 -0
  200. package/dist/core/export-html/template.js +1871 -0
  201. package/dist/core/export-html/tool-renderer.d.ts +34 -0
  202. package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  203. package/dist/core/export-html/tool-renderer.js +108 -0
  204. package/dist/core/export-html/tool-renderer.js.map +1 -0
  205. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  206. package/dist/core/export-html/vendor/marked.min.js +78 -0
  207. package/dist/core/extensions/index.d.ts +12 -0
  208. package/dist/core/extensions/index.d.ts.map +1 -0
  209. package/dist/core/extensions/index.js +9 -0
  210. package/dist/core/extensions/index.js.map +1 -0
  211. package/dist/core/extensions/loader.d.ts +23 -0
  212. package/dist/core/extensions/loader.d.ts.map +1 -0
  213. package/dist/core/extensions/loader.js +655 -0
  214. package/dist/core/extensions/loader.js.map +1 -0
  215. package/dist/core/extensions/runner.d.ts +178 -0
  216. package/dist/core/extensions/runner.d.ts.map +1 -0
  217. package/dist/core/extensions/runner.js +1011 -0
  218. package/dist/core/extensions/runner.js.map +1 -0
  219. package/dist/core/extensions/types.d.ts +1375 -0
  220. package/dist/core/extensions/types.d.ts.map +1 -0
  221. package/dist/core/extensions/types.js +54 -0
  222. package/dist/core/extensions/types.js.map +1 -0
  223. package/dist/core/extensions/wrapper.d.ts +20 -0
  224. package/dist/core/extensions/wrapper.d.ts.map +1 -0
  225. package/dist/core/extensions/wrapper.js +41 -0
  226. package/dist/core/extensions/wrapper.js.map +1 -0
  227. package/dist/core/footer-data-provider.d.ts +64 -0
  228. package/dist/core/footer-data-provider.d.ts.map +1 -0
  229. package/dist/core/footer-data-provider.js +338 -0
  230. package/dist/core/footer-data-provider.js.map +1 -0
  231. package/dist/core/http-dispatcher.d.ts +22 -0
  232. package/dist/core/http-dispatcher.d.ts.map +1 -0
  233. package/dist/core/http-dispatcher.js +98 -0
  234. package/dist/core/http-dispatcher.js.map +1 -0
  235. package/dist/core/index.d.ts +13 -0
  236. package/dist/core/index.d.ts.map +1 -0
  237. package/dist/core/index.js +13 -0
  238. package/dist/core/index.js.map +1 -0
  239. package/dist/core/ion-manifest.d.ts +8 -0
  240. package/dist/core/ion-manifest.d.ts.map +1 -0
  241. package/dist/core/ion-manifest.js +26 -0
  242. package/dist/core/ion-manifest.js.map +1 -0
  243. package/dist/core/keybindings.d.ts +475 -0
  244. package/dist/core/keybindings.d.ts.map +1 -0
  245. package/dist/core/keybindings.js +321 -0
  246. package/dist/core/keybindings.js.map +1 -0
  247. package/dist/core/messages.d.ts +77 -0
  248. package/dist/core/messages.d.ts.map +1 -0
  249. package/dist/core/messages.js +123 -0
  250. package/dist/core/messages.js.map +1 -0
  251. package/dist/core/model-config.d.ts +591 -0
  252. package/dist/core/model-config.d.ts.map +1 -0
  253. package/dist/core/model-config.js +259 -0
  254. package/dist/core/model-config.js.map +1 -0
  255. package/dist/core/model-registry.d.ts +49 -0
  256. package/dist/core/model-registry.d.ts.map +1 -0
  257. package/dist/core/model-registry.js +115 -0
  258. package/dist/core/model-registry.js.map +1 -0
  259. package/dist/core/model-resolver.d.ts +124 -0
  260. package/dist/core/model-resolver.d.ts.map +1 -0
  261. package/dist/core/model-resolver.js +591 -0
  262. package/dist/core/model-resolver.js.map +1 -0
  263. package/dist/core/model-runtime.d.ts +101 -0
  264. package/dist/core/model-runtime.d.ts.map +1 -0
  265. package/dist/core/model-runtime.js +606 -0
  266. package/dist/core/model-runtime.js.map +1 -0
  267. package/dist/core/models-store.d.ts +22 -0
  268. package/dist/core/models-store.d.ts.map +1 -0
  269. package/dist/core/models-store.js +115 -0
  270. package/dist/core/models-store.js.map +1 -0
  271. package/dist/core/output-guard.d.ts +7 -0
  272. package/dist/core/output-guard.d.ts.map +1 -0
  273. package/dist/core/output-guard.js +89 -0
  274. package/dist/core/output-guard.js.map +1 -0
  275. package/dist/core/package-manager.d.ts +216 -0
  276. package/dist/core/package-manager.d.ts.map +1 -0
  277. package/dist/core/package-manager.js +2207 -0
  278. package/dist/core/package-manager.js.map +1 -0
  279. package/dist/core/project-trust.d.ts +15 -0
  280. package/dist/core/project-trust.d.ts.map +1 -0
  281. package/dist/core/project-trust.js +59 -0
  282. package/dist/core/project-trust.js.map +1 -0
  283. package/dist/core/prompt-templates.d.ts +54 -0
  284. package/dist/core/prompt-templates.d.ts.map +1 -0
  285. package/dist/core/prompt-templates.js +236 -0
  286. package/dist/core/prompt-templates.js.map +1 -0
  287. package/dist/core/provider-attribution.d.ts +4 -0
  288. package/dist/core/provider-attribution.d.ts.map +1 -0
  289. package/dist/core/provider-attribution.js +72 -0
  290. package/dist/core/provider-attribution.js.map +1 -0
  291. package/dist/core/provider-composer.d.ts +58 -0
  292. package/dist/core/provider-composer.d.ts.map +1 -0
  293. package/dist/core/provider-composer.js +402 -0
  294. package/dist/core/provider-composer.js.map +1 -0
  295. package/dist/core/radius.d.ts +2 -0
  296. package/dist/core/radius.d.ts.map +1 -0
  297. package/dist/core/radius.js +2 -0
  298. package/dist/core/radius.js.map +1 -0
  299. package/dist/core/remote-catalog-provider.d.ts +5 -0
  300. package/dist/core/remote-catalog-provider.d.ts.map +1 -0
  301. package/dist/core/remote-catalog-provider.js +137 -0
  302. package/dist/core/remote-catalog-provider.js.map +1 -0
  303. package/dist/core/resolve-config-value.d.ts +30 -0
  304. package/dist/core/resolve-config-value.d.ts.map +1 -0
  305. package/dist/core/resolve-config-value.js +247 -0
  306. package/dist/core/resolve-config-value.js.map +1 -0
  307. package/dist/core/resource-loader.d.ts +221 -0
  308. package/dist/core/resource-loader.d.ts.map +1 -0
  309. package/dist/core/resource-loader.js +875 -0
  310. package/dist/core/resource-loader.js.map +1 -0
  311. package/dist/core/runtime-credentials.d.ts +15 -0
  312. package/dist/core/runtime-credentials.d.ts.map +1 -0
  313. package/dist/core/runtime-credentials.js +39 -0
  314. package/dist/core/runtime-credentials.js.map +1 -0
  315. package/dist/core/sdk.d.ts +108 -0
  316. package/dist/core/sdk.d.ts.map +1 -0
  317. package/dist/core/sdk.js +285 -0
  318. package/dist/core/sdk.js.map +1 -0
  319. package/dist/core/session-cwd.d.ts +19 -0
  320. package/dist/core/session-cwd.d.ts.map +1 -0
  321. package/dist/core/session-cwd.js +38 -0
  322. package/dist/core/session-cwd.js.map +1 -0
  323. package/dist/core/session-export.d.ts +4 -0
  324. package/dist/core/session-export.d.ts.map +1 -0
  325. package/dist/core/session-export.js +32 -0
  326. package/dist/core/session-export.js.map +1 -0
  327. package/dist/core/session-index.d.ts +67 -0
  328. package/dist/core/session-index.d.ts.map +1 -0
  329. package/dist/core/session-index.js +376 -0
  330. package/dist/core/session-index.js.map +1 -0
  331. package/dist/core/session-manager.d.ts +376 -0
  332. package/dist/core/session-manager.d.ts.map +1 -0
  333. package/dist/core/session-manager.js +1587 -0
  334. package/dist/core/session-manager.js.map +1 -0
  335. package/dist/core/session-naming-runtime.d.ts +153 -0
  336. package/dist/core/session-naming-runtime.d.ts.map +1 -0
  337. package/dist/core/session-naming-runtime.js +336 -0
  338. package/dist/core/session-naming-runtime.js.map +1 -0
  339. package/dist/core/settings-diagnostics.d.ts +9 -0
  340. package/dist/core/settings-diagnostics.d.ts.map +1 -0
  341. package/dist/core/settings-diagnostics.js +21 -0
  342. package/dist/core/settings-diagnostics.js.map +1 -0
  343. package/dist/core/settings-manager.d.ts +375 -0
  344. package/dist/core/settings-manager.d.ts.map +1 -0
  345. package/dist/core/settings-manager.js +1110 -0
  346. package/dist/core/settings-manager.js.map +1 -0
  347. package/dist/core/skills.d.ts +60 -0
  348. package/dist/core/skills.d.ts.map +1 -0
  349. package/dist/core/skills.js +412 -0
  350. package/dist/core/skills.js.map +1 -0
  351. package/dist/core/slash-commands.d.ts +17 -0
  352. package/dist/core/slash-commands.d.ts.map +1 -0
  353. package/dist/core/slash-commands.js +33 -0
  354. package/dist/core/slash-commands.js.map +1 -0
  355. package/dist/core/source-info.d.ts +18 -0
  356. package/dist/core/source-info.d.ts.map +1 -0
  357. package/dist/core/source-info.js +19 -0
  358. package/dist/core/source-info.js.map +1 -0
  359. package/dist/core/system-prompt.d.ts +28 -0
  360. package/dist/core/system-prompt.d.ts.map +1 -0
  361. package/dist/core/system-prompt.js +118 -0
  362. package/dist/core/system-prompt.js.map +1 -0
  363. package/dist/core/telemetry.d.ts +3 -0
  364. package/dist/core/telemetry.d.ts.map +1 -0
  365. package/dist/core/telemetry.js +9 -0
  366. package/dist/core/telemetry.js.map +1 -0
  367. package/dist/core/timings.d.ts +10 -0
  368. package/dist/core/timings.d.ts.map +1 -0
  369. package/dist/core/timings.js +41 -0
  370. package/dist/core/timings.js.map +1 -0
  371. package/dist/core/tools/bash.d.ts +87 -0
  372. package/dist/core/tools/bash.d.ts.map +1 -0
  373. package/dist/core/tools/bash.js +295 -0
  374. package/dist/core/tools/bash.js.map +1 -0
  375. package/dist/core/tools/edit-diff.d.ts +101 -0
  376. package/dist/core/tools/edit-diff.d.ts.map +1 -0
  377. package/dist/core/tools/edit-diff.js +421 -0
  378. package/dist/core/tools/edit-diff.js.map +1 -0
  379. package/dist/core/tools/edit.d.ts +44 -0
  380. package/dist/core/tools/edit.d.ts.map +1 -0
  381. package/dist/core/tools/edit.js +147 -0
  382. package/dist/core/tools/edit.js.map +1 -0
  383. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  384. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  385. package/dist/core/tools/file-mutation-queue.js +52 -0
  386. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  387. package/dist/core/tools/find.d.ts +42 -0
  388. package/dist/core/tools/find.d.ts.map +1 -0
  389. package/dist/core/tools/find.js +251 -0
  390. package/dist/core/tools/find.js.map +1 -0
  391. package/dist/core/tools/grep.d.ts +53 -0
  392. package/dist/core/tools/grep.d.ts.map +1 -0
  393. package/dist/core/tools/grep.js +463 -0
  394. package/dist/core/tools/grep.js.map +1 -0
  395. package/dist/core/tools/index.d.ts +49 -0
  396. package/dist/core/tools/index.d.ts.map +1 -0
  397. package/dist/core/tools/index.js +147 -0
  398. package/dist/core/tools/index.js.map +1 -0
  399. package/dist/core/tools/ls.d.ts +48 -0
  400. package/dist/core/tools/ls.d.ts.map +1 -0
  401. package/dist/core/tools/ls.js +224 -0
  402. package/dist/core/tools/ls.js.map +1 -0
  403. package/dist/core/tools/output-accumulator.d.ts +52 -0
  404. package/dist/core/tools/output-accumulator.d.ts.map +1 -0
  405. package/dist/core/tools/output-accumulator.js +184 -0
  406. package/dist/core/tools/output-accumulator.js.map +1 -0
  407. package/dist/core/tools/path-utils.d.ts +10 -0
  408. package/dist/core/tools/path-utils.d.ts.map +1 -0
  409. package/dist/core/tools/path-utils.js +99 -0
  410. package/dist/core/tools/path-utils.js.map +1 -0
  411. package/dist/core/tools/powershell.d.ts +16 -0
  412. package/dist/core/tools/powershell.d.ts.map +1 -0
  413. package/dist/core/tools/powershell.js +39 -0
  414. package/dist/core/tools/powershell.js.map +1 -0
  415. package/dist/core/tools/read.d.ts +39 -0
  416. package/dist/core/tools/read.d.ts.map +1 -0
  417. package/dist/core/tools/read.js +165 -0
  418. package/dist/core/tools/read.js.map +1 -0
  419. package/dist/core/tools/render-utils.d.ts +24 -0
  420. package/dist/core/tools/render-utils.d.ts.map +1 -0
  421. package/dist/core/tools/render-utils.js +65 -0
  422. package/dist/core/tools/render-utils.js.map +1 -0
  423. package/dist/core/tools/renderers/bash.d.ts +12 -0
  424. package/dist/core/tools/renderers/bash.d.ts.map +1 -0
  425. package/dist/core/tools/renderers/bash.js +130 -0
  426. package/dist/core/tools/renderers/bash.js.map +1 -0
  427. package/dist/core/tools/renderers/edit.d.ts +23 -0
  428. package/dist/core/tools/renderers/edit.d.ts.map +1 -0
  429. package/dist/core/tools/renderers/edit.js +167 -0
  430. package/dist/core/tools/renderers/edit.js.map +1 -0
  431. package/dist/core/tools/renderers/find.d.ts +10 -0
  432. package/dist/core/tools/renderers/find.d.ts.map +1 -0
  433. package/dist/core/tools/renderers/find.js +64 -0
  434. package/dist/core/tools/renderers/find.js.map +1 -0
  435. package/dist/core/tools/renderers/grep.d.ts +10 -0
  436. package/dist/core/tools/renderers/grep.d.ts.map +1 -0
  437. package/dist/core/tools/renderers/grep.js +69 -0
  438. package/dist/core/tools/renderers/grep.js.map +1 -0
  439. package/dist/core/tools/renderers/index.d.ts +29 -0
  440. package/dist/core/tools/renderers/index.d.ts.map +1 -0
  441. package/dist/core/tools/renderers/index.js +50 -0
  442. package/dist/core/tools/renderers/index.js.map +1 -0
  443. package/dist/core/tools/renderers/ls.d.ts +10 -0
  444. package/dist/core/tools/renderers/ls.d.ts.map +1 -0
  445. package/dist/core/tools/renderers/ls.js +66 -0
  446. package/dist/core/tools/renderers/ls.js.map +1 -0
  447. package/dist/core/tools/renderers/read.d.ts +11 -0
  448. package/dist/core/tools/renderers/read.d.ts.map +1 -0
  449. package/dist/core/tools/renderers/read.js +129 -0
  450. package/dist/core/tools/renderers/read.js.map +1 -0
  451. package/dist/core/tools/renderers/webfetch.d.ts +11 -0
  452. package/dist/core/tools/renderers/webfetch.d.ts.map +1 -0
  453. package/dist/core/tools/renderers/webfetch.js +89 -0
  454. package/dist/core/tools/renderers/webfetch.js.map +1 -0
  455. package/dist/core/tools/renderers/write.d.ts +10 -0
  456. package/dist/core/tools/renderers/write.d.ts.map +1 -0
  457. package/dist/core/tools/renderers/write.js +153 -0
  458. package/dist/core/tools/renderers/write.js.map +1 -0
  459. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  460. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  461. package/dist/core/tools/tool-definition-wrapper.js +36 -0
  462. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  463. package/dist/core/tools/truncate.d.ts +70 -0
  464. package/dist/core/tools/truncate.d.ts.map +1 -0
  465. package/dist/core/tools/truncate.js +215 -0
  466. package/dist/core/tools/truncate.js.map +1 -0
  467. package/dist/core/tools/webextract.d.ts +36 -0
  468. package/dist/core/tools/webextract.d.ts.map +1 -0
  469. package/dist/core/tools/webextract.js +130 -0
  470. package/dist/core/tools/webextract.js.map +1 -0
  471. package/dist/core/tools/webfetch.d.ts +104 -0
  472. package/dist/core/tools/webfetch.d.ts.map +1 -0
  473. package/dist/core/tools/webfetch.js +231 -0
  474. package/dist/core/tools/webfetch.js.map +1 -0
  475. package/dist/core/tools/write.d.ts +30 -0
  476. package/dist/core/tools/write.d.ts.map +1 -0
  477. package/dist/core/tools/write.js +61 -0
  478. package/dist/core/tools/write.js.map +1 -0
  479. package/dist/core/trust-manager.d.ts +36 -0
  480. package/dist/core/trust-manager.d.ts.map +1 -0
  481. package/dist/core/trust-manager.js +203 -0
  482. package/dist/core/trust-manager.js.map +1 -0
  483. package/dist/core/usage-totals.d.ts +19 -0
  484. package/dist/core/usage-totals.d.ts.map +1 -0
  485. package/dist/core/usage-totals.js +52 -0
  486. package/dist/core/usage-totals.js.map +1 -0
  487. package/dist/core/webfetch/backend-exa.d.ts +65 -0
  488. package/dist/core/webfetch/backend-exa.d.ts.map +1 -0
  489. package/dist/core/webfetch/backend-exa.js +282 -0
  490. package/dist/core/webfetch/backend-exa.js.map +1 -0
  491. package/dist/core/webfetch/backend-firecrawl.d.ts +59 -0
  492. package/dist/core/webfetch/backend-firecrawl.d.ts.map +1 -0
  493. package/dist/core/webfetch/backend-firecrawl.js +339 -0
  494. package/dist/core/webfetch/backend-firecrawl.js.map +1 -0
  495. package/dist/core/webfetch/backend-undici.d.ts +21 -0
  496. package/dist/core/webfetch/backend-undici.d.ts.map +1 -0
  497. package/dist/core/webfetch/backend-undici.js +109 -0
  498. package/dist/core/webfetch/backend-undici.js.map +1 -0
  499. package/dist/core/webfetch/backend.d.ts +45 -0
  500. package/dist/core/webfetch/backend.d.ts.map +1 -0
  501. package/dist/core/webfetch/backend.js +9 -0
  502. package/dist/core/webfetch/backend.js.map +1 -0
  503. package/dist/core/webfetch/doc-store.d.ts +45 -0
  504. package/dist/core/webfetch/doc-store.d.ts.map +1 -0
  505. package/dist/core/webfetch/doc-store.js +57 -0
  506. package/dist/core/webfetch/doc-store.js.map +1 -0
  507. package/dist/core/webfetch/guardrails.d.ts +75 -0
  508. package/dist/core/webfetch/guardrails.d.ts.map +1 -0
  509. package/dist/core/webfetch/guardrails.js +195 -0
  510. package/dist/core/webfetch/guardrails.js.map +1 -0
  511. package/dist/core/webfetch/robots.d.ts +46 -0
  512. package/dist/core/webfetch/robots.d.ts.map +1 -0
  513. package/dist/core/webfetch/robots.js +153 -0
  514. package/dist/core/webfetch/robots.js.map +1 -0
  515. package/dist/core/webfetch/search-intent.d.ts +59 -0
  516. package/dist/core/webfetch/search-intent.d.ts.map +1 -0
  517. package/dist/core/webfetch/search-intent.js +89 -0
  518. package/dist/core/webfetch/search-intent.js.map +1 -0
  519. package/dist/core/webfetch/search-tags.d.ts +23 -0
  520. package/dist/core/webfetch/search-tags.d.ts.map +1 -0
  521. package/dist/core/webfetch/search-tags.js +118 -0
  522. package/dist/core/webfetch/search-tags.js.map +1 -0
  523. package/dist/env-compat.d.ts +2 -0
  524. package/dist/env-compat.d.ts.map +1 -0
  525. package/dist/env-compat.js +17 -0
  526. package/dist/env-compat.js.map +1 -0
  527. package/dist/extensions/cue/autocomplete.d.ts +126 -0
  528. package/dist/extensions/cue/autocomplete.d.ts.map +1 -0
  529. package/dist/extensions/cue/autocomplete.js +744 -0
  530. package/dist/extensions/cue/autocomplete.js.map +1 -0
  531. package/dist/extensions/cue/index.d.ts +3 -0
  532. package/dist/extensions/cue/index.d.ts.map +1 -0
  533. package/dist/extensions/cue/index.js +341 -0
  534. package/dist/extensions/cue/index.js.map +1 -0
  535. package/dist/extensions/index.d.ts +13 -0
  536. package/dist/extensions/index.d.ts.map +1 -0
  537. package/dist/extensions/index.js +18 -0
  538. package/dist/extensions/index.js.map +1 -0
  539. package/dist/extensions/llama/client.d.ts +67 -0
  540. package/dist/extensions/llama/client.d.ts.map +1 -0
  541. package/dist/extensions/llama/client.js +309 -0
  542. package/dist/extensions/llama/client.js.map +1 -0
  543. package/dist/extensions/llama/huggingface.d.ts +23 -0
  544. package/dist/extensions/llama/huggingface.d.ts.map +1 -0
  545. package/dist/extensions/llama/huggingface.js +141 -0
  546. package/dist/extensions/llama/huggingface.js.map +1 -0
  547. package/dist/extensions/llama/index.d.ts +3 -0
  548. package/dist/extensions/llama/index.d.ts.map +1 -0
  549. package/dist/extensions/llama/index.js +219 -0
  550. package/dist/extensions/llama/index.js.map +1 -0
  551. package/dist/extensions/llama/provider.d.ts +12 -0
  552. package/dist/extensions/llama/provider.d.ts.map +1 -0
  553. package/dist/extensions/llama/provider.js +146 -0
  554. package/dist/extensions/llama/provider.js.map +1 -0
  555. package/dist/extensions/llama/ui.d.ts +42 -0
  556. package/dist/extensions/llama/ui.d.ts.map +1 -0
  557. package/dist/extensions/llama/ui.js +416 -0
  558. package/dist/extensions/llama/ui.js.map +1 -0
  559. package/dist/index.d.ts +36 -0
  560. package/dist/index.d.ts.map +1 -0
  561. package/dist/index.js +48 -0
  562. package/dist/index.js.map +1 -0
  563. package/dist/main.d.ts +17 -0
  564. package/dist/main.d.ts.map +1 -0
  565. package/dist/main.js +820 -0
  566. package/dist/main.js.map +1 -0
  567. package/dist/migrations.d.ts +33 -0
  568. package/dist/migrations.d.ts.map +1 -0
  569. package/dist/migrations.js +288 -0
  570. package/dist/migrations.js.map +1 -0
  571. package/dist/modes/index.d.ts +10 -0
  572. package/dist/modes/index.d.ts.map +1 -0
  573. package/dist/modes/index.js +8 -0
  574. package/dist/modes/index.js.map +1 -0
  575. package/dist/modes/interactive/assets/clankolas.png +0 -0
  576. package/dist/modes/interactive/chat-viewport.d.ts +20 -0
  577. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -0
  578. package/dist/modes/interactive/chat-viewport.js +28 -0
  579. package/dist/modes/interactive/chat-viewport.js.map +1 -0
  580. package/dist/modes/interactive/components/armin.d.ts +34 -0
  581. package/dist/modes/interactive/components/armin.d.ts.map +1 -0
  582. package/dist/modes/interactive/components/armin.js +333 -0
  583. package/dist/modes/interactive/components/armin.js.map +1 -0
  584. package/dist/modes/interactive/components/assistant-message.d.ts +26 -0
  585. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
  586. package/dist/modes/interactive/components/assistant-message.js +171 -0
  587. package/dist/modes/interactive/components/assistant-message.js.map +1 -0
  588. package/dist/modes/interactive/components/bash-execution.d.ts +34 -0
  589. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
  590. package/dist/modes/interactive/components/bash-execution.js +175 -0
  591. package/dist/modes/interactive/components/bash-execution.js.map +1 -0
  592. package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
  593. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
  594. package/dist/modes/interactive/components/bordered-loader.js +54 -0
  595. package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
  596. package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
  597. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
  598. package/dist/modes/interactive/components/branch-summary-message.js +44 -0
  599. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
  600. package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
  601. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
  602. package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
  603. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
  604. package/dist/modes/interactive/components/config-selector.d.ts +102 -0
  605. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
  606. package/dist/modes/interactive/components/config-selector.js +770 -0
  607. package/dist/modes/interactive/components/config-selector.js.map +1 -0
  608. package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
  609. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
  610. package/dist/modes/interactive/components/countdown-timer.js +33 -0
  611. package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
  612. package/dist/modes/interactive/components/custom-editor.d.ts +30 -0
  613. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
  614. package/dist/modes/interactive/components/custom-editor.js +115 -0
  615. package/dist/modes/interactive/components/custom-editor.js.map +1 -0
  616. package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
  617. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
  618. package/dist/modes/interactive/components/custom-entry.js +52 -0
  619. package/dist/modes/interactive/components/custom-entry.js.map +1 -0
  620. package/dist/modes/interactive/components/custom-message.d.ts +22 -0
  621. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  622. package/dist/modes/interactive/components/custom-message.js +87 -0
  623. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  624. package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
  625. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
  626. package/dist/modes/interactive/components/daxnuts.js +140 -0
  627. package/dist/modes/interactive/components/daxnuts.js.map +1 -0
  628. package/dist/modes/interactive/components/diff.d.ts +12 -0
  629. package/dist/modes/interactive/components/diff.d.ts.map +1 -0
  630. package/dist/modes/interactive/components/diff.js +133 -0
  631. package/dist/modes/interactive/components/diff.js.map +1 -0
  632. package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
  633. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
  634. package/dist/modes/interactive/components/dynamic-border.js +21 -0
  635. package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
  636. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  637. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  638. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  639. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  640. package/dist/modes/interactive/components/extension-editor.d.ts +21 -0
  641. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  642. package/dist/modes/interactive/components/extension-editor.js +98 -0
  643. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  644. package/dist/modes/interactive/components/extension-input.d.ts +23 -0
  645. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  646. package/dist/modes/interactive/components/extension-input.js +61 -0
  647. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  648. package/dist/modes/interactive/components/extension-selector.d.ts +26 -0
  649. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  650. package/dist/modes/interactive/components/extension-selector.js +83 -0
  651. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  652. package/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
  653. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
  654. package/dist/modes/interactive/components/first-time-setup.js +103 -0
  655. package/dist/modes/interactive/components/first-time-setup.js.map +1 -0
  656. package/dist/modes/interactive/components/footer.d.ts +32 -0
  657. package/dist/modes/interactive/components/footer.d.ts.map +1 -0
  658. package/dist/modes/interactive/components/footer.js +230 -0
  659. package/dist/modes/interactive/components/footer.js.map +1 -0
  660. package/dist/modes/interactive/components/index.d.ts +34 -0
  661. package/dist/modes/interactive/components/index.d.ts.map +1 -0
  662. package/dist/modes/interactive/components/index.js +35 -0
  663. package/dist/modes/interactive/components/index.js.map +1 -0
  664. package/dist/modes/interactive/components/keybinding-hints.d.ts +13 -0
  665. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
  666. package/dist/modes/interactive/components/keybinding-hints.js +36 -0
  667. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
  668. package/dist/modes/interactive/components/login-dialog.d.ts +52 -0
  669. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
  670. package/dist/modes/interactive/components/login-dialog.js +188 -0
  671. package/dist/modes/interactive/components/login-dialog.js.map +1 -0
  672. package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
  673. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
  674. package/dist/modes/interactive/components/markdown-transform.js +19 -0
  675. package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
  676. package/dist/modes/interactive/components/mermaid.d.ts +11 -0
  677. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
  678. package/dist/modes/interactive/components/mermaid.js +75 -0
  679. package/dist/modes/interactive/components/mermaid.js.map +1 -0
  680. package/dist/modes/interactive/components/model-selector.d.ts +60 -0
  681. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
  682. package/dist/modes/interactive/components/model-selector.js +361 -0
  683. package/dist/modes/interactive/components/model-selector.js.map +1 -0
  684. package/dist/modes/interactive/components/oauth-selector.d.ts +33 -0
  685. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
  686. package/dist/modes/interactive/components/oauth-selector.js +163 -0
  687. package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
  688. package/dist/modes/interactive/components/scoped-models-selector.d.ts +46 -0
  689. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
  690. package/dist/modes/interactive/components/scoped-models-selector.js +326 -0
  691. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
  692. package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
  693. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
  694. package/dist/modes/interactive/components/session-selector-search.js +155 -0
  695. package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
  696. package/dist/modes/interactive/components/session-selector.d.ts +98 -0
  697. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
  698. package/dist/modes/interactive/components/session-selector.js +891 -0
  699. package/dist/modes/interactive/components/session-selector.js.map +1 -0
  700. package/dist/modes/interactive/components/settings-selector.d.ts +98 -0
  701. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
  702. package/dist/modes/interactive/components/settings-selector.js +745 -0
  703. package/dist/modes/interactive/components/settings-selector.js.map +1 -0
  704. package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
  705. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
  706. package/dist/modes/interactive/components/settings-submenu.js +165 -0
  707. package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
  708. package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
  709. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
  710. package/dist/modes/interactive/components/show-images-selector.js +39 -0
  711. package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
  712. package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
  713. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
  714. package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
  715. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
  716. package/dist/modes/interactive/components/status-indicator.d.ts +30 -0
  717. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
  718. package/dist/modes/interactive/components/status-indicator.js +67 -0
  719. package/dist/modes/interactive/components/status-indicator.js.map +1 -0
  720. package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
  721. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
  722. package/dist/modes/interactive/components/theme-selector.js +50 -0
  723. package/dist/modes/interactive/components/theme-selector.js.map +1 -0
  724. package/dist/modes/interactive/components/thinking-selector.d.ts +23 -0
  725. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
  726. package/dist/modes/interactive/components/thinking-selector.js +109 -0
  727. package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
  728. package/dist/modes/interactive/components/tool-execution.d.ts +80 -0
  729. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
  730. package/dist/modes/interactive/components/tool-execution.js +328 -0
  731. package/dist/modes/interactive/components/tool-execution.js.map +1 -0
  732. package/dist/modes/interactive/components/tree-selector.d.ts +94 -0
  733. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
  734. package/dist/modes/interactive/components/tree-selector.js +1245 -0
  735. package/dist/modes/interactive/components/tree-selector.js.map +1 -0
  736. package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  737. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  738. package/dist/modes/interactive/components/trust-selector.js +91 -0
  739. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  740. package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
  741. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
  742. package/dist/modes/interactive/components/user-message-selector.js +114 -0
  743. package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
  744. package/dist/modes/interactive/components/user-message.d.ts +16 -0
  745. package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
  746. package/dist/modes/interactive/components/user-message.js +49 -0
  747. package/dist/modes/interactive/components/user-message.js.map +1 -0
  748. package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
  749. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
  750. package/dist/modes/interactive/components/visual-truncate.js +33 -0
  751. package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
  752. package/dist/modes/interactive/external-editor.d.ts +12 -0
  753. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  754. package/dist/modes/interactive/external-editor.js +38 -0
  755. package/dist/modes/interactive/external-editor.js.map +1 -0
  756. package/dist/modes/interactive/interactive-mode.d.ts +471 -0
  757. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
  758. package/dist/modes/interactive/interactive-mode.js +5735 -0
  759. package/dist/modes/interactive/interactive-mode.js.map +1 -0
  760. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  761. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  762. package/dist/modes/interactive/model-catalog-refresh.js +34 -0
  763. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  764. package/dist/modes/interactive/model-search.d.ts +12 -0
  765. package/dist/modes/interactive/model-search.d.ts.map +1 -0
  766. package/dist/modes/interactive/model-search.js +15 -0
  767. package/dist/modes/interactive/model-search.js.map +1 -0
  768. package/dist/modes/interactive/session-share.d.ts +16 -0
  769. package/dist/modes/interactive/session-share.d.ts.map +1 -0
  770. package/dist/modes/interactive/session-share.js +184 -0
  771. package/dist/modes/interactive/session-share.js.map +1 -0
  772. package/dist/modes/interactive/theme/dark.json +91 -0
  773. package/dist/modes/interactive/theme/light.json +90 -0
  774. package/dist/modes/interactive/theme/theme-controller.d.ts +41 -0
  775. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -0
  776. package/dist/modes/interactive/theme/theme-controller.js +130 -0
  777. package/dist/modes/interactive/theme/theme-controller.js.map +1 -0
  778. package/dist/modes/interactive/theme/theme-json.d.ts +84 -0
  779. package/dist/modes/interactive/theme/theme-json.d.ts.map +1 -0
  780. package/dist/modes/interactive/theme/theme-json.js +130 -0
  781. package/dist/modes/interactive/theme/theme-json.js.map +1 -0
  782. package/dist/modes/interactive/theme/theme-schema.json +356 -0
  783. package/dist/modes/interactive/theme/theme.d.ts +131 -0
  784. package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
  785. package/dist/modes/interactive/theme/theme.js +991 -0
  786. package/dist/modes/interactive/theme/theme.js.map +1 -0
  787. package/dist/modes/interactive/tui-renderer.d.ts +21 -0
  788. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -0
  789. package/dist/modes/interactive/tui-renderer.js +66 -0
  790. package/dist/modes/interactive/tui-renderer.js.map +1 -0
  791. package/dist/modes/json-event.d.ts +34 -0
  792. package/dist/modes/json-event.d.ts.map +1 -0
  793. package/dist/modes/json-event.js +29 -0
  794. package/dist/modes/json-event.js.map +1 -0
  795. package/dist/modes/print-mode.d.ts +28 -0
  796. package/dist/modes/print-mode.d.ts.map +1 -0
  797. package/dist/modes/print-mode.js +142 -0
  798. package/dist/modes/print-mode.js.map +1 -0
  799. package/dist/modes/rpc/jsonl.d.ts +17 -0
  800. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  801. package/dist/modes/rpc/jsonl.js +49 -0
  802. package/dist/modes/rpc/jsonl.js.map +1 -0
  803. package/dist/modes/rpc/rpc-client.d.ts +254 -0
  804. package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
  805. package/dist/modes/rpc/rpc-client.js +495 -0
  806. package/dist/modes/rpc/rpc-client.js.map +1 -0
  807. package/dist/modes/rpc/rpc-mode.d.ts +20 -0
  808. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
  809. package/dist/modes/rpc/rpc-mode.js +657 -0
  810. package/dist/modes/rpc/rpc-mode.js.map +1 -0
  811. package/dist/modes/rpc/rpc-types.d.ts +469 -0
  812. package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
  813. package/dist/modes/rpc/rpc-types.js +8 -0
  814. package/dist/modes/rpc/rpc-types.js.map +1 -0
  815. package/dist/package-manager-cli.d.ts +9 -0
  816. package/dist/package-manager-cli.d.ts.map +1 -0
  817. package/dist/package-manager-cli.js +961 -0
  818. package/dist/package-manager-cli.js.map +1 -0
  819. package/dist/rpc-entry.d.ts +3 -0
  820. package/dist/rpc-entry.d.ts.map +1 -0
  821. package/dist/rpc-entry.js +12 -0
  822. package/dist/rpc-entry.js.map +1 -0
  823. package/dist/utils/abort.d.ts +5 -0
  824. package/dist/utils/abort.d.ts.map +1 -0
  825. package/dist/utils/abort.js +48 -0
  826. package/dist/utils/abort.js.map +1 -0
  827. package/dist/utils/ansi.d.ts +2 -0
  828. package/dist/utils/ansi.d.ts.map +1 -0
  829. package/dist/utils/ansi.js +52 -0
  830. package/dist/utils/ansi.js.map +1 -0
  831. package/dist/utils/changelog.d.ts +22 -0
  832. package/dist/utils/changelog.d.ts.map +1 -0
  833. package/dist/utils/changelog.js +165 -0
  834. package/dist/utils/changelog.js.map +1 -0
  835. package/dist/utils/child-process.d.ts +18 -0
  836. package/dist/utils/child-process.d.ts.map +1 -0
  837. package/dist/utils/child-process.js +106 -0
  838. package/dist/utils/child-process.js.map +1 -0
  839. package/dist/utils/clipboard-command.d.ts +7 -0
  840. package/dist/utils/clipboard-command.d.ts.map +1 -0
  841. package/dist/utils/clipboard-command.js +45 -0
  842. package/dist/utils/clipboard-command.js.map +1 -0
  843. package/dist/utils/clipboard-image.d.ts +11 -0
  844. package/dist/utils/clipboard-image.d.ts.map +1 -0
  845. package/dist/utils/clipboard-image.js +228 -0
  846. package/dist/utils/clipboard-image.js.map +1 -0
  847. package/dist/utils/clipboard.d.ts +4 -0
  848. package/dist/utils/clipboard.d.ts.map +1 -0
  849. package/dist/utils/clipboard.js +84 -0
  850. package/dist/utils/clipboard.js.map +1 -0
  851. package/dist/utils/deprecation.d.ts +4 -0
  852. package/dist/utils/deprecation.d.ts.map +1 -0
  853. package/dist/utils/deprecation.js +13 -0
  854. package/dist/utils/deprecation.js.map +1 -0
  855. package/dist/utils/exif-orientation.d.ts +5 -0
  856. package/dist/utils/exif-orientation.d.ts.map +1 -0
  857. package/dist/utils/exif-orientation.js +157 -0
  858. package/dist/utils/exif-orientation.js.map +1 -0
  859. package/dist/utils/frontmatter.d.ts +8 -0
  860. package/dist/utils/frontmatter.d.ts.map +1 -0
  861. package/dist/utils/frontmatter.js +27 -0
  862. package/dist/utils/frontmatter.js.map +1 -0
  863. package/dist/utils/fs-watch.d.ts +5 -0
  864. package/dist/utils/fs-watch.d.ts.map +1 -0
  865. package/dist/utils/fs-watch.js +25 -0
  866. package/dist/utils/fs-watch.js.map +1 -0
  867. package/dist/utils/git.d.ts +26 -0
  868. package/dist/utils/git.d.ts.map +1 -0
  869. package/dist/utils/git.js +195 -0
  870. package/dist/utils/git.js.map +1 -0
  871. package/dist/utils/html.d.ts +7 -0
  872. package/dist/utils/html.d.ts.map +1 -0
  873. package/dist/utils/html.js +40 -0
  874. package/dist/utils/html.js.map +1 -0
  875. package/dist/utils/image-convert.d.ts +10 -0
  876. package/dist/utils/image-convert.d.ts.map +1 -0
  877. package/dist/utils/image-convert.js +45 -0
  878. package/dist/utils/image-convert.js.map +1 -0
  879. package/dist/utils/image-process.d.ts +18 -0
  880. package/dist/utils/image-process.d.ts.map +1 -0
  881. package/dist/utils/image-process.js +83 -0
  882. package/dist/utils/image-process.js.map +1 -0
  883. package/dist/utils/image-resize-core.d.ts +30 -0
  884. package/dist/utils/image-resize-core.d.ts.map +1 -0
  885. package/dist/utils/image-resize-core.js +124 -0
  886. package/dist/utils/image-resize-core.js.map +1 -0
  887. package/dist/utils/image-resize-worker.d.ts +2 -0
  888. package/dist/utils/image-resize-worker.d.ts.map +1 -0
  889. package/dist/utils/image-resize-worker.js +31 -0
  890. package/dist/utils/image-resize-worker.js.map +1 -0
  891. package/dist/utils/image-resize.d.ts +16 -0
  892. package/dist/utils/image-resize.d.ts.map +1 -0
  893. package/dist/utils/image-resize.js +97 -0
  894. package/dist/utils/image-resize.js.map +1 -0
  895. package/dist/utils/ion-user-agent.d.ts +2 -0
  896. package/dist/utils/ion-user-agent.d.ts.map +1 -0
  897. package/dist/utils/ion-user-agent.js +5 -0
  898. package/dist/utils/ion-user-agent.js.map +1 -0
  899. package/dist/utils/json.d.ts +3 -0
  900. package/dist/utils/json.d.ts.map +1 -0
  901. package/dist/utils/json.js +7 -0
  902. package/dist/utils/json.js.map +1 -0
  903. package/dist/utils/management-http.d.ts +25 -0
  904. package/dist/utils/management-http.d.ts.map +1 -0
  905. package/dist/utils/management-http.js +54 -0
  906. package/dist/utils/management-http.js.map +1 -0
  907. package/dist/utils/mime.d.ts +3 -0
  908. package/dist/utils/mime.d.ts.map +1 -0
  909. package/dist/utils/mime.js +110 -0
  910. package/dist/utils/mime.js.map +1 -0
  911. package/dist/utils/open-browser.d.ts +9 -0
  912. package/dist/utils/open-browser.d.ts.map +1 -0
  913. package/dist/utils/open-browser.js +22 -0
  914. package/dist/utils/open-browser.js.map +1 -0
  915. package/dist/utils/paths.d.ts +34 -0
  916. package/dist/utils/paths.d.ts.map +1 -0
  917. package/dist/utils/paths.js +114 -0
  918. package/dist/utils/paths.js.map +1 -0
  919. package/dist/utils/photon.d.ts +21 -0
  920. package/dist/utils/photon.d.ts.map +1 -0
  921. package/dist/utils/photon.js +121 -0
  922. package/dist/utils/photon.js.map +1 -0
  923. package/dist/utils/shell.d.ts +34 -0
  924. package/dist/utils/shell.d.ts.map +1 -0
  925. package/dist/utils/shell.js +216 -0
  926. package/dist/utils/shell.js.map +1 -0
  927. package/dist/utils/sleep.d.ts +5 -0
  928. package/dist/utils/sleep.d.ts.map +1 -0
  929. package/dist/utils/sleep.js +17 -0
  930. package/dist/utils/sleep.js.map +1 -0
  931. package/dist/utils/syntax-highlight.d.ts +13 -0
  932. package/dist/utils/syntax-highlight.d.ts.map +1 -0
  933. package/dist/utils/syntax-highlight.js +177 -0
  934. package/dist/utils/syntax-highlight.js.map +1 -0
  935. package/dist/utils/text.d.ts +8 -0
  936. package/dist/utils/text.d.ts.map +1 -0
  937. package/dist/utils/text.js +9 -0
  938. package/dist/utils/text.js.map +1 -0
  939. package/dist/utils/tool-result-images.d.ts +19 -0
  940. package/dist/utils/tool-result-images.d.ts.map +1 -0
  941. package/dist/utils/tool-result-images.js +45 -0
  942. package/dist/utils/tool-result-images.js.map +1 -0
  943. package/dist/utils/tools-manager.d.ts +19 -0
  944. package/dist/utils/tools-manager.d.ts.map +1 -0
  945. package/dist/utils/tools-manager.js +382 -0
  946. package/dist/utils/tools-manager.js.map +1 -0
  947. package/dist/utils/version-check.d.ts +19 -0
  948. package/dist/utils/version-check.d.ts.map +1 -0
  949. package/dist/utils/version-check.js +79 -0
  950. package/dist/utils/version-check.js.map +1 -0
  951. package/dist/utils/windows-self-update.d.ts +3 -0
  952. package/dist/utils/windows-self-update.d.ts.map +1 -0
  953. package/dist/utils/windows-self-update.js +77 -0
  954. package/dist/utils/windows-self-update.js.map +1 -0
  955. package/docs/browser-extension.md +108 -0
  956. package/docs/compaction.md +444 -0
  957. package/docs/containerization.md +156 -0
  958. package/docs/custom-provider.md +777 -0
  959. package/docs/development.md +90 -0
  960. package/docs/docs.json +164 -0
  961. package/docs/environment-variables.md +101 -0
  962. package/docs/extensions.md +3033 -0
  963. package/docs/images/doom-extension.png +0 -0
  964. package/docs/images/exy.png +0 -0
  965. package/docs/images/interactive-mode.png +0 -0
  966. package/docs/images/tree-view.png +0 -0
  967. package/docs/index.md +85 -0
  968. package/docs/json.md +98 -0
  969. package/docs/keybindings.md +239 -0
  970. package/docs/llama-cpp.md +101 -0
  971. package/docs/models.md +574 -0
  972. package/docs/packages.md +228 -0
  973. package/docs/prompt-templates.md +96 -0
  974. package/docs/providers.md +321 -0
  975. package/docs/quickstart.md +168 -0
  976. package/docs/rpc.md +1618 -0
  977. package/docs/sdk.md +1226 -0
  978. package/docs/security.md +59 -0
  979. package/docs/session-format.md +450 -0
  980. package/docs/sessions.md +145 -0
  981. package/docs/settings.md +408 -0
  982. package/docs/shell-aliases.md +13 -0
  983. package/docs/skills.md +241 -0
  984. package/docs/terminal-setup.md +192 -0
  985. package/docs/termux.md +126 -0
  986. package/docs/themes.md +322 -0
  987. package/docs/tmux.md +63 -0
  988. package/docs/tui.md +961 -0
  989. package/docs/usage.md +327 -0
  990. package/docs/webfetch.md +119 -0
  991. package/docs/windows.md +39 -0
  992. package/examples/README.md +28 -0
  993. package/examples/extensions/README.md +213 -0
  994. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  995. package/examples/extensions/bash-spawn-hook.ts +30 -0
  996. package/examples/extensions/bookmark.ts +50 -0
  997. package/examples/extensions/border-status-editor.ts +150 -0
  998. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  999. package/examples/extensions/claude-rules.ts +86 -0
  1000. package/examples/extensions/commands.ts +72 -0
  1001. package/examples/extensions/confirm-destructive.ts +59 -0
  1002. package/examples/extensions/custom-compaction.ts +117 -0
  1003. package/examples/extensions/custom-footer.ts +64 -0
  1004. package/examples/extensions/custom-header.ts +73 -0
  1005. package/examples/extensions/custom-provider-anthropic/index.ts +611 -0
  1006. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  1007. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  1008. package/examples/extensions/custom-provider-gitlab-duo/index.ts +405 -0
  1009. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  1010. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  1011. package/examples/extensions/dirty-repo-guard.ts +56 -0
  1012. package/examples/extensions/doom-overlay/README.md +46 -0
  1013. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  1014. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  1015. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  1016. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  1017. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  1018. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  1019. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  1020. package/examples/extensions/doom-overlay/index.ts +74 -0
  1021. package/examples/extensions/doom-overlay/wad-finder.ts +55 -0
  1022. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  1023. package/examples/extensions/dynamic-resources/dynamic.json +81 -0
  1024. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  1025. package/examples/extensions/dynamic-resources/index.ts +15 -0
  1026. package/examples/extensions/dynamic-tools.ts +74 -0
  1027. package/examples/extensions/entry-renderer.ts +41 -0
  1028. package/examples/extensions/event-bus.ts +43 -0
  1029. package/examples/extensions/file-trigger.ts +41 -0
  1030. package/examples/extensions/git-checkpoint.ts +53 -0
  1031. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  1032. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  1033. package/examples/extensions/gondolin/index.ts +531 -0
  1034. package/examples/extensions/gondolin/package-lock.json +185 -0
  1035. package/examples/extensions/gondolin/package.json +19 -0
  1036. package/examples/extensions/handoff.ts +190 -0
  1037. package/examples/extensions/hello.ts +26 -0
  1038. package/examples/extensions/hidden-thinking-label.ts +53 -0
  1039. package/examples/extensions/inline-bash.ts +94 -0
  1040. package/examples/extensions/input-transform-streaming.ts +39 -0
  1041. package/examples/extensions/input-transform.ts +43 -0
  1042. package/examples/extensions/interactive-shell.ts +196 -0
  1043. package/examples/extensions/kimi-deferred-tools.ts +61 -0
  1044. package/examples/extensions/mac-system-theme.ts +47 -0
  1045. package/examples/extensions/message-renderer.ts +59 -0
  1046. package/examples/extensions/minimal-mode.ts +426 -0
  1047. package/examples/extensions/modal-editor.ts +85 -0
  1048. package/examples/extensions/model-status.ts +31 -0
  1049. package/examples/extensions/notify.ts +57 -0
  1050. package/examples/extensions/overlay-qa-tests.ts +1450 -0
  1051. package/examples/extensions/overlay-test.ts +153 -0
  1052. package/examples/extensions/permission-gate.ts +34 -0
  1053. package/examples/extensions/pirate.ts +47 -0
  1054. package/examples/extensions/plan-mode/README.md +66 -0
  1055. package/examples/extensions/plan-mode/index.ts +390 -0
  1056. package/examples/extensions/plan-mode/utils.ts +168 -0
  1057. package/examples/extensions/preset.ts +436 -0
  1058. package/examples/extensions/project-trust.ts +64 -0
  1059. package/examples/extensions/prompt-customizer.ts +97 -0
  1060. package/examples/extensions/protected-paths.ts +30 -0
  1061. package/examples/extensions/provider-payload.ts +18 -0
  1062. package/examples/extensions/qna.ts +118 -0
  1063. package/examples/extensions/question.ts +278 -0
  1064. package/examples/extensions/questionnaire.ts +440 -0
  1065. package/examples/extensions/rainbow-editor.ts +88 -0
  1066. package/examples/extensions/reload-runtime.ts +37 -0
  1067. package/examples/extensions/rpc-demo.ts +118 -0
  1068. package/examples/extensions/sandbox/index.ts +321 -0
  1069. package/examples/extensions/sandbox/package-lock.json +92 -0
  1070. package/examples/extensions/sandbox/package.json +19 -0
  1071. package/examples/extensions/send-user-message.ts +97 -0
  1072. package/examples/extensions/session-name.ts +27 -0
  1073. package/examples/extensions/shutdown-command.ts +63 -0
  1074. package/examples/extensions/snake.ts +343 -0
  1075. package/examples/extensions/space-invaders.ts +560 -0
  1076. package/examples/extensions/ssh.ts +220 -0
  1077. package/examples/extensions/status-line.ts +32 -0
  1078. package/examples/extensions/structured-output.ts +65 -0
  1079. package/examples/extensions/subagent/README.md +177 -0
  1080. package/examples/extensions/subagent/agents/planner.md +37 -0
  1081. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  1082. package/examples/extensions/subagent/agents/scout.md +50 -0
  1083. package/examples/extensions/subagent/agents/worker.md +24 -0
  1084. package/examples/extensions/subagent/agents.ts +157 -0
  1085. package/examples/extensions/subagent/index.ts +1038 -0
  1086. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  1087. package/examples/extensions/subagent/prompts/implement.md +10 -0
  1088. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  1089. package/examples/extensions/summarize.ts +199 -0
  1090. package/examples/extensions/system-prompt-header.ts +17 -0
  1091. package/examples/extensions/tic-tac-toe.ts +1008 -0
  1092. package/examples/extensions/timed-confirm.ts +70 -0
  1093. package/examples/extensions/titlebar-spinner.ts +58 -0
  1094. package/examples/extensions/todo.ts +297 -0
  1095. package/examples/extensions/tool-override.ts +144 -0
  1096. package/examples/extensions/tools.ts +146 -0
  1097. package/examples/extensions/trigger-compact.ts +50 -0
  1098. package/examples/extensions/truncated-tool.ts +195 -0
  1099. package/examples/extensions/widget-placement.ts +9 -0
  1100. package/examples/extensions/with-deps/index.ts +32 -0
  1101. package/examples/extensions/with-deps/package-lock.json +31 -0
  1102. package/examples/extensions/with-deps/package.json +22 -0
  1103. package/examples/extensions/working-indicator.ts +123 -0
  1104. package/examples/extensions/working-message-test.ts +25 -0
  1105. package/examples/plugins/ion-example-plugin/README.md +38 -0
  1106. package/examples/plugins/ion-example-plugin/package.json +10 -0
  1107. package/examples/plugins/ion-example-plugin/src/contract.ts +13 -0
  1108. package/examples/plugins/ion-example-plugin/src/session.ts +23 -0
  1109. package/examples/plugins/ion-example-plugin/src/tui.ts +31 -0
  1110. package/examples/rpc-extension-ui.ts +641 -0
  1111. package/examples/sdk/01-minimal.ts +26 -0
  1112. package/examples/sdk/02-custom-model.ts +49 -0
  1113. package/examples/sdk/03-custom-prompt.ts +70 -0
  1114. package/examples/sdk/04-skills.ts +55 -0
  1115. package/examples/sdk/05-tools.ts +48 -0
  1116. package/examples/sdk/06-extensions.ts +94 -0
  1117. package/examples/sdk/07-context-files.ts +42 -0
  1118. package/examples/sdk/08-prompt-templates.ts +51 -0
  1119. package/examples/sdk/09-api-keys-and-oauth.ts +34 -0
  1120. package/examples/sdk/10-settings.ts +53 -0
  1121. package/examples/sdk/11-sessions.ts +52 -0
  1122. package/examples/sdk/12-full-control.ts +74 -0
  1123. package/examples/sdk/13-session-runtime.ts +67 -0
  1124. package/examples/sdk/README.md +140 -0
  1125. package/npm-shrinkwrap.json +1912 -0
  1126. package/package.json +108 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Session-scoped store for fetched web documents.
3
+ *
4
+ * Documents are addressed by `web://<n>` refs (incremental per session, stable
5
+ * for citations) and read through windowed extraction so large pages never
6
+ * flood context: `extract` echoes the total plus the served window so the
7
+ * model can page with `offsetChars`/`lengthChars`.
8
+ *
9
+ * Search results are stored as incomplete stubs (title/url/snippet only);
10
+ * `webextract` upgrades a stub to the full fetched document on first read.
11
+ */
12
+ import type { WebDocument } from "./backend.ts";
13
+ export type WebDocumentSource = "firecrawl" | "undici";
14
+ export interface StoredWebDocument {
15
+ ref: string;
16
+ doc: WebDocument;
17
+ source: WebDocumentSource;
18
+ /** False for search-result stubs that have not been fetched yet. */
19
+ complete: boolean;
20
+ }
21
+ export interface ExtractWindow {
22
+ ref: string;
23
+ totalChars: number;
24
+ offsetChars: number;
25
+ lengthChars: number;
26
+ text: string;
27
+ }
28
+ export interface ExtractOptions {
29
+ offsetChars?: number;
30
+ lengthChars?: number;
31
+ }
32
+ export declare const WEBFETCH_DEFAULT_WINDOW_CHARS = 8000;
33
+ export declare class WebDocumentStore {
34
+ private readonly entries;
35
+ private nextId;
36
+ /** Store a document and return its `web://<n>` ref. Search stubs pass `complete: false`. */
37
+ store(doc: WebDocument, source: WebDocumentSource, complete?: boolean): string;
38
+ get(ref: string): StoredWebDocument | undefined;
39
+ /** Replace the document behind an existing ref (stub upgrade). Marks it complete. */
40
+ update(ref: string, doc: WebDocument, source: WebDocumentSource): void;
41
+ get size(): number;
42
+ /** Windowed read of a stored document. Offsets clamp into range; the window is echoed back for paging. */
43
+ extract(ref: string, options?: ExtractOptions): ExtractWindow;
44
+ }
45
+ //# sourceMappingURL=doc-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-store.d.ts","sourceRoot":"","sources":["../../../src/core/webfetch/doc-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,MAAM,CAAK;IAEnB,4FAA4F;IAC5F,KAAK,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,UAAO,GAAG,MAAM,CAK1E;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAE9C;IAED,qFAAqF;IACrF,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAMrE;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,0GAA0G;IAC1G,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CAiBhE;CACD","sourcesContent":["/**\n * Session-scoped store for fetched web documents.\n *\n * Documents are addressed by `web://<n>` refs (incremental per session, stable\n * for citations) and read through windowed extraction so large pages never\n * flood context: `extract` echoes the total plus the served window so the\n * model can page with `offsetChars`/`lengthChars`.\n *\n * Search results are stored as incomplete stubs (title/url/snippet only);\n * `webextract` upgrades a stub to the full fetched document on first read.\n */\n\nimport type { WebDocument } from \"./backend.ts\";\n\nexport type WebDocumentSource = \"firecrawl\" | \"undici\";\n\nexport interface StoredWebDocument {\n\tref: string;\n\tdoc: WebDocument;\n\tsource: WebDocumentSource;\n\t/** False for search-result stubs that have not been fetched yet. */\n\tcomplete: boolean;\n}\n\nexport interface ExtractWindow {\n\tref: string;\n\ttotalChars: number;\n\toffsetChars: number;\n\tlengthChars: number;\n\ttext: string;\n}\n\nexport interface ExtractOptions {\n\toffsetChars?: number;\n\tlengthChars?: number;\n}\n\nexport const WEBFETCH_DEFAULT_WINDOW_CHARS = 8_000;\n\nexport class WebDocumentStore {\n\tprivate readonly entries = new Map<string, StoredWebDocument>();\n\tprivate nextId = 1;\n\n\t/** Store a document and return its `web://<n>` ref. Search stubs pass `complete: false`. */\n\tstore(doc: WebDocument, source: WebDocumentSource, complete = true): string {\n\t\tconst ref = `web://${this.nextId}`;\n\t\tthis.nextId += 1;\n\t\tthis.entries.set(ref, { ref, doc, source, complete });\n\t\treturn ref;\n\t}\n\n\tget(ref: string): StoredWebDocument | undefined {\n\t\treturn this.entries.get(ref);\n\t}\n\n\t/** Replace the document behind an existing ref (stub upgrade). Marks it complete. */\n\tupdate(ref: string, doc: WebDocument, source: WebDocumentSource): void {\n\t\tconst stored = this.entries.get(ref);\n\t\tif (!stored) {\n\t\t\tthrow new Error(`Unknown web reference: ${ref}`);\n\t\t}\n\t\tthis.entries.set(ref, { ref, doc, source, complete: true });\n\t}\n\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/** Windowed read of a stored document. Offsets clamp into range; the window is echoed back for paging. */\n\textract(ref: string, options: ExtractOptions = {}): ExtractWindow {\n\t\tconst stored = this.entries.get(ref);\n\t\tif (!stored) {\n\t\t\tthrow new Error(`Unknown web reference: ${ref}`);\n\t\t}\n\t\tconst totalChars = stored.doc.markdown.length;\n\t\tconst offsetChars = Math.min(totalChars, Math.max(0, Math.floor(options.offsetChars ?? 0)));\n\t\tconst maxLength = totalChars - offsetChars;\n\t\tconst requested = options.lengthChars ?? WEBFETCH_DEFAULT_WINDOW_CHARS;\n\t\tconst lengthChars = Math.min(maxLength, Math.max(0, Math.floor(requested)));\n\t\treturn {\n\t\t\tref,\n\t\t\ttotalChars,\n\t\t\toffsetChars,\n\t\t\tlengthChars,\n\t\t\ttext: stored.doc.markdown.slice(offsetChars, offsetChars + lengthChars),\n\t\t};\n\t}\n}\n"]}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Session-scoped store for fetched web documents.
3
+ *
4
+ * Documents are addressed by `web://<n>` refs (incremental per session, stable
5
+ * for citations) and read through windowed extraction so large pages never
6
+ * flood context: `extract` echoes the total plus the served window so the
7
+ * model can page with `offsetChars`/`lengthChars`.
8
+ *
9
+ * Search results are stored as incomplete stubs (title/url/snippet only);
10
+ * `webextract` upgrades a stub to the full fetched document on first read.
11
+ */
12
+ export const WEBFETCH_DEFAULT_WINDOW_CHARS = 8_000;
13
+ export class WebDocumentStore {
14
+ entries = new Map();
15
+ nextId = 1;
16
+ /** Store a document and return its `web://<n>` ref. Search stubs pass `complete: false`. */
17
+ store(doc, source, complete = true) {
18
+ const ref = `web://${this.nextId}`;
19
+ this.nextId += 1;
20
+ this.entries.set(ref, { ref, doc, source, complete });
21
+ return ref;
22
+ }
23
+ get(ref) {
24
+ return this.entries.get(ref);
25
+ }
26
+ /** Replace the document behind an existing ref (stub upgrade). Marks it complete. */
27
+ update(ref, doc, source) {
28
+ const stored = this.entries.get(ref);
29
+ if (!stored) {
30
+ throw new Error(`Unknown web reference: ${ref}`);
31
+ }
32
+ this.entries.set(ref, { ref, doc, source, complete: true });
33
+ }
34
+ get size() {
35
+ return this.entries.size;
36
+ }
37
+ /** Windowed read of a stored document. Offsets clamp into range; the window is echoed back for paging. */
38
+ extract(ref, options = {}) {
39
+ const stored = this.entries.get(ref);
40
+ if (!stored) {
41
+ throw new Error(`Unknown web reference: ${ref}`);
42
+ }
43
+ const totalChars = stored.doc.markdown.length;
44
+ const offsetChars = Math.min(totalChars, Math.max(0, Math.floor(options.offsetChars ?? 0)));
45
+ const maxLength = totalChars - offsetChars;
46
+ const requested = options.lengthChars ?? WEBFETCH_DEFAULT_WINDOW_CHARS;
47
+ const lengthChars = Math.min(maxLength, Math.max(0, Math.floor(requested)));
48
+ return {
49
+ ref,
50
+ totalChars,
51
+ offsetChars,
52
+ lengthChars,
53
+ text: stored.doc.markdown.slice(offsetChars, offsetChars + lengthChars),
54
+ };
55
+ }
56
+ }
57
+ //# sourceMappingURL=doc-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-store.js","sourceRoot":"","sources":["../../../src/core/webfetch/doc-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA2BH,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AAEnD,MAAM,OAAO,gBAAgB;IACX,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACxD,MAAM,GAAG,CAAC,CAAC;IAEnB,4FAA4F;IAC5F,KAAK,CAAC,GAAgB,EAAE,MAAyB,EAAE,QAAQ,GAAG,IAAI,EAAU;QAC3E,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QACnC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtD,OAAO,GAAG,CAAC;IAAA,CACX;IAED,GAAG,CAAC,GAAW,EAAiC;QAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAA,CAC7B;IAED,qFAAqF;IACrF,MAAM,CAAC,GAAW,EAAE,GAAgB,EAAE,MAAyB,EAAQ;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAAA,CAC5D;IAED,IAAI,IAAI,GAAW;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAAA,CACzB;IAED,0GAA0G;IAC1G,OAAO,CAAC,GAAW,EAAE,OAAO,GAAmB,EAAE,EAAiB;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5F,MAAM,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,IAAI,6BAA6B,CAAC;QACvE,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC5E,OAAO;YACN,GAAG;YACH,UAAU;YACV,WAAW;YACX,WAAW;YACX,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAAC;SACvE,CAAC;IAAA,CACF;CACD","sourcesContent":["/**\n * Session-scoped store for fetched web documents.\n *\n * Documents are addressed by `web://<n>` refs (incremental per session, stable\n * for citations) and read through windowed extraction so large pages never\n * flood context: `extract` echoes the total plus the served window so the\n * model can page with `offsetChars`/`lengthChars`.\n *\n * Search results are stored as incomplete stubs (title/url/snippet only);\n * `webextract` upgrades a stub to the full fetched document on first read.\n */\n\nimport type { WebDocument } from \"./backend.ts\";\n\nexport type WebDocumentSource = \"firecrawl\" | \"undici\";\n\nexport interface StoredWebDocument {\n\tref: string;\n\tdoc: WebDocument;\n\tsource: WebDocumentSource;\n\t/** False for search-result stubs that have not been fetched yet. */\n\tcomplete: boolean;\n}\n\nexport interface ExtractWindow {\n\tref: string;\n\ttotalChars: number;\n\toffsetChars: number;\n\tlengthChars: number;\n\ttext: string;\n}\n\nexport interface ExtractOptions {\n\toffsetChars?: number;\n\tlengthChars?: number;\n}\n\nexport const WEBFETCH_DEFAULT_WINDOW_CHARS = 8_000;\n\nexport class WebDocumentStore {\n\tprivate readonly entries = new Map<string, StoredWebDocument>();\n\tprivate nextId = 1;\n\n\t/** Store a document and return its `web://<n>` ref. Search stubs pass `complete: false`. */\n\tstore(doc: WebDocument, source: WebDocumentSource, complete = true): string {\n\t\tconst ref = `web://${this.nextId}`;\n\t\tthis.nextId += 1;\n\t\tthis.entries.set(ref, { ref, doc, source, complete });\n\t\treturn ref;\n\t}\n\n\tget(ref: string): StoredWebDocument | undefined {\n\t\treturn this.entries.get(ref);\n\t}\n\n\t/** Replace the document behind an existing ref (stub upgrade). Marks it complete. */\n\tupdate(ref: string, doc: WebDocument, source: WebDocumentSource): void {\n\t\tconst stored = this.entries.get(ref);\n\t\tif (!stored) {\n\t\t\tthrow new Error(`Unknown web reference: ${ref}`);\n\t\t}\n\t\tthis.entries.set(ref, { ref, doc, source, complete: true });\n\t}\n\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/** Windowed read of a stored document. Offsets clamp into range; the window is echoed back for paging. */\n\textract(ref: string, options: ExtractOptions = {}): ExtractWindow {\n\t\tconst stored = this.entries.get(ref);\n\t\tif (!stored) {\n\t\t\tthrow new Error(`Unknown web reference: ${ref}`);\n\t\t}\n\t\tconst totalChars = stored.doc.markdown.length;\n\t\tconst offsetChars = Math.min(totalChars, Math.max(0, Math.floor(options.offsetChars ?? 0)));\n\t\tconst maxLength = totalChars - offsetChars;\n\t\tconst requested = options.lengthChars ?? WEBFETCH_DEFAULT_WINDOW_CHARS;\n\t\tconst lengthChars = Math.min(maxLength, Math.max(0, Math.floor(requested)));\n\t\treturn {\n\t\t\tref,\n\t\t\ttotalChars,\n\t\t\toffsetChars,\n\t\t\tlengthChars,\n\t\t\ttext: stored.doc.markdown.slice(offsetChars, offsetChars + lengthChars),\n\t\t};\n\t}\n}\n"]}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * SSRF guardrails for webfetch (patterns copied from Jina Reader — not vendored).
3
+ *
4
+ * - Only `http:`/`https:` targets are allowed.
5
+ * - Literal-IP targets are checked against non-public CIDRs.
6
+ * - Hostnames are resolved via DNS and **every** returned address is re-checked,
7
+ * including on every redirect hop (TOCTOU: re-validate on redirect).
8
+ * - Redirect chains are capped, response bytes are capped (with a
9
+ * `Content-Length` pre-check plus a streaming cutoff), and each hop has a
10
+ * per-request timeout.
11
+ */
12
+ export declare const WEBFETCH_MAX_REDIRECTS = 6;
13
+ export declare const WEBFETCH_MAX_BYTES = 2000000;
14
+ export declare const WEBFETCH_REQUEST_TIMEOUT_MS = 30000;
15
+ export declare const WEBFETCH_FIRECRAWL_MAX_LIMIT = 100;
16
+ export type WebfetchErrorCode = "invalid-url" | "blocked-host" | "redirect-limit" | "byte-limit" | "timeout" | "empty" | "transport" | "unavailable";
17
+ export declare class WebfetchError extends Error {
18
+ readonly code: WebfetchErrorCode;
19
+ constructor(message: string, code: WebfetchErrorCode);
20
+ }
21
+ /** True when `ip` is a literal IP address inside a blocked non-public range. Non-IP strings return false. */
22
+ export declare function isBlockedIpAddress(ip: string): boolean;
23
+ /** Parse and validate a web target URL. Only `http:`/`https:` are allowed. */
24
+ export declare function normalizeWebUrl(rawUrl: string): URL;
25
+ /** Reject literal-IP targets inside blocked ranges. Hostnames are checked via DNS separately. */
26
+ export declare function assertLiteralTargetAllowed(url: URL): void;
27
+ /** Reject when any resolved address is blocked. Every address is checked (fail closed). */
28
+ export declare function assertResolvedAddressesAllowed(addresses: string[], hostname: string): void;
29
+ export type DnsLookup = (hostname: string) => Promise<string[]>;
30
+ /**
31
+ * Fail-closed host check: literal IPs are checked directly, hostnames are
32
+ * resolved and every returned address is re-checked. Callers must invoke this
33
+ * for the initial URL and again for each redirect target.
34
+ */
35
+ export declare function assertHostAllowed(hostname: string, lookup?: DnsLookup): Promise<void>;
36
+ /** Enforce the byte cap against a `Content-Length` header before streaming the body. */
37
+ export declare function assertContentLengthAllowed(contentLength: string | null | undefined, maxBytes?: number): void;
38
+ /** Enforce the byte cap while streaming. Throws once `totalBytes` exceeds `maxBytes`. */
39
+ export declare function assertBytesWithinBudget(totalBytes: number, maxBytes?: number): void;
40
+ /** Clamp a search limit into `[min, max]`, falling back to `fallback` for missing/invalid values. */
41
+ export declare function clampLimit(limit: number | undefined, options: {
42
+ fallback: number;
43
+ min: number;
44
+ max: number;
45
+ }): number;
46
+ export interface GuardedBody {
47
+ statusCode: number;
48
+ headers: Record<string, string>;
49
+ body: AsyncIterable<Uint8Array>;
50
+ }
51
+ export type LowLevelRequestFn = (url: string, init: {
52
+ headers: Record<string, string>;
53
+ signal: AbortSignal;
54
+ }) => Promise<GuardedBody>;
55
+ export interface GuardedRequestOptions {
56
+ headers?: Record<string, string>;
57
+ timeoutMs?: number;
58
+ maxBytes?: number;
59
+ maxRedirects?: number;
60
+ signal?: AbortSignal;
61
+ lookup?: DnsLookup;
62
+ request?: LowLevelRequestFn;
63
+ }
64
+ export interface GuardedResponse extends GuardedBody {
65
+ finalUrl: string;
66
+ redirectCount: number;
67
+ }
68
+ /**
69
+ * GET a URL under the shared guardrails: scheme allowlist, literal-IP and DNS
70
+ * checks on the initial URL and every redirect hop, redirect cap,
71
+ * `Content-Length` pre-check, and per-hop timeout. Streaming byte cutoff is
72
+ * the caller's job via `assertBytesWithinBudget`.
73
+ */
74
+ export declare function guardedRequest(rawUrl: string, options?: GuardedRequestOptions): Promise<GuardedResponse>;
75
+ //# sourceMappingURL=guardrails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../../src/core/webfetch/guardrails.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SSRF guardrails for webfetch (patterns copied from Jina Reader — not vendored).\n *\n * - Only `http:`/`https:` targets are allowed.\n * - Literal-IP targets are checked against non-public CIDRs.\n * - Hostnames are resolved via DNS and **every** returned address is re-checked,\n * including on every redirect hop (TOCTOU: re-validate on redirect).\n * - Redirect chains are capped, response bytes are capped (with a\n * `Content-Length` pre-check plus a streaming cutoff), and each hop has a\n * per-request timeout.\n */\n\nimport { lookup as dnsLookupAll } from \"node:dns/promises\";\nimport { BlockList, isIP } from \"node:net\";\nimport { request as undiciRequest } from \"undici\";\n\nexport const WEBFETCH_MAX_REDIRECTS = 6;\nexport const WEBFETCH_MAX_BYTES = 2_000_000;\nexport const WEBFETCH_REQUEST_TIMEOUT_MS = 30_000;\nexport const WEBFETCH_FIRECRAWL_MAX_LIMIT = 100;\n\nexport type WebfetchErrorCode =\n\t| \"invalid-url\"\n\t| \"blocked-host\"\n\t| \"redirect-limit\"\n\t| \"byte-limit\"\n\t| \"timeout\"\n\t| \"empty\"\n\t| \"transport\"\n\t| \"unavailable\";\n\nexport class WebfetchError extends Error {\n\treadonly code: WebfetchErrorCode;\n\tconstructor(message: string, code: WebfetchErrorCode) {\n\t\tsuper(message);\n\t\tthis.name = \"WebfetchError\";\n\t\tthis.code = code;\n\t}\n}\n\nconst blockedRanges: Array<{ subnet: string; prefix: number; type: \"ipv4\" | \"ipv6\" }> = [\n\t{ subnet: \"10.0.0.0\", prefix: 8, type: \"ipv4\" },\n\t{ subnet: \"172.16.0.0\", prefix: 12, type: \"ipv4\" },\n\t{ subnet: \"192.168.0.0\", prefix: 16, type: \"ipv4\" },\n\t{ subnet: \"127.0.0.0\", prefix: 8, type: \"ipv4\" },\n\t{ subnet: \"169.254.0.0\", prefix: 16, type: \"ipv4\" },\n\t{ subnet: \"224.0.0.0\", prefix: 4, type: \"ipv4\" },\n\t{ subnet: \"100.64.0.0\", prefix: 10, type: \"ipv4\" },\n\t{ subnet: \"fc00::\", prefix: 7, type: \"ipv6\" },\n\t{ subnet: \"fe80::\", prefix: 10, type: \"ipv6\" },\n\t{ subnet: \"ff00::\", prefix: 8, type: \"ipv6\" },\n\t{ subnet: \"::1\", prefix: 128, type: \"ipv6\" },\n];\n\nconst blockedList = new BlockList();\nfor (const range of blockedRanges) {\n\tblockedList.addSubnet(range.subnet, range.prefix, range.type);\n}\n\n/** True when `ip` is a literal IP address inside a blocked non-public range. Non-IP strings return false. */\nexport function isBlockedIpAddress(ip: string): boolean {\n\tconst family = isIP(ip);\n\tif (family === 0) return false;\n\treturn blockedList.check(ip, family === 4 ? \"ipv4\" : \"ipv6\");\n}\n\n/** Parse and validate a web target URL. Only `http:`/`https:` are allowed. */\nexport function normalizeWebUrl(rawUrl: string): URL {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(rawUrl.trim());\n\t} catch {\n\t\tthrow new WebfetchError(`Invalid URL: ${rawUrl}`, \"invalid-url\");\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new WebfetchError(`Blocked URL scheme \"${url.protocol}\": only http and https are allowed`, \"blocked-host\");\n\t}\n\treturn url;\n}\n\n/** Reject literal-IP targets inside blocked ranges. Hostnames are checked via DNS separately. */\nexport function assertLiteralTargetAllowed(url: URL): void {\n\tconst bare = url.hostname.replace(/^\\[|\\]$/g, \"\");\n\tif (isIP(bare) !== 0 && isBlockedIpAddress(bare)) {\n\t\tthrow new WebfetchError(`Blocked request to private IP ${bare}`, \"blocked-host\");\n\t}\n}\n\n/** Reject when any resolved address is blocked. Every address is checked (fail closed). */\nexport function assertResolvedAddressesAllowed(addresses: string[], hostname: string): void {\n\tif (addresses.length === 0) {\n\t\tthrow new WebfetchError(`Could not resolve host \"${hostname}\"`, \"blocked-host\");\n\t}\n\tfor (const address of addresses) {\n\t\tif (isBlockedIpAddress(address)) {\n\t\t\tthrow new WebfetchError(`Blocked request to \"${hostname}\": resolves to private IP ${address}`, \"blocked-host\");\n\t\t}\n\t}\n}\n\nexport type DnsLookup = (hostname: string) => Promise<string[]>;\n\nasync function defaultLookup(hostname: string): Promise<string[]> {\n\tconst results = await dnsLookupAll(hostname, { all: true });\n\treturn results.map((result) => result.address);\n}\n\n/**\n * Fail-closed host check: literal IPs are checked directly, hostnames are\n * resolved and every returned address is re-checked. Callers must invoke this\n * for the initial URL and again for each redirect target.\n */\nexport async function assertHostAllowed(hostname: string, lookup: DnsLookup = defaultLookup): Promise<void> {\n\tconst bare = hostname.replace(/^\\[|\\]$/g, \"\");\n\tif (isIP(bare) !== 0) {\n\t\tif (isBlockedIpAddress(bare)) {\n\t\t\tthrow new WebfetchError(`Blocked request to private IP ${bare}`, \"blocked-host\");\n\t\t}\n\t\treturn;\n\t}\n\tlet addresses: string[];\n\ttry {\n\t\taddresses = await lookup(bare);\n\t} catch (error) {\n\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\tthrow new WebfetchError(`Could not resolve host \"${bare}\": ${reason}`, \"blocked-host\");\n\t}\n\tassertResolvedAddressesAllowed(addresses, bare);\n}\n\n/** Enforce the byte cap against a `Content-Length` header before streaming the body. */\nexport function assertContentLengthAllowed(\n\tcontentLength: string | null | undefined,\n\tmaxBytes: number = WEBFETCH_MAX_BYTES,\n): void {\n\tif (contentLength === null || contentLength === undefined) return;\n\tconst declared = Number.parseInt(contentLength.split(\",\")[0]?.trim() ?? \"\", 10);\n\tif (Number.isFinite(declared) && declared > maxBytes) {\n\t\tthrow new WebfetchError(\n\t\t\t`Response body exceeds ${maxBytes} byte limit (${declared} bytes declared)`,\n\t\t\t\"byte-limit\",\n\t\t);\n\t}\n}\n\n/** Enforce the byte cap while streaming. Throws once `totalBytes` exceeds `maxBytes`. */\nexport function assertBytesWithinBudget(totalBytes: number, maxBytes: number = WEBFETCH_MAX_BYTES): void {\n\tif (totalBytes > maxBytes) {\n\t\tthrow new WebfetchError(`Response body exceeds ${maxBytes} byte limit`, \"byte-limit\");\n\t}\n}\n\n/** Clamp a search limit into `[min, max]`, falling back to `fallback` for missing/invalid values. */\nexport function clampLimit(limit: number | undefined, options: { fallback: number; min: number; max: number }): number {\n\tif (limit === undefined || !Number.isFinite(limit)) return options.fallback;\n\treturn Math.min(options.max, Math.max(options.min, Math.floor(limit)));\n}\n\nexport interface GuardedBody {\n\tstatusCode: number;\n\theaders: Record<string, string>;\n\tbody: AsyncIterable<Uint8Array>;\n}\n\nexport type LowLevelRequestFn = (\n\turl: string,\n\tinit: { headers: Record<string, string>; signal: AbortSignal },\n) => Promise<GuardedBody>;\n\nasync function defaultLowLevelRequest(\n\turl: string,\n\tinit: { headers: Record<string, string>; signal: AbortSignal },\n): Promise<GuardedBody> {\n\tconst response = await undiciRequest(url, { method: \"GET\", headers: init.headers, signal: init.signal });\n\tconst headers: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(response.headers)) {\n\t\tif (value === undefined) continue;\n\t\theaders[key.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : String(value);\n\t}\n\treturn { statusCode: response.statusCode, headers, body: response.body as AsyncIterable<Uint8Array> };\n}\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\nexport interface GuardedRequestOptions {\n\theaders?: Record<string, string>;\n\ttimeoutMs?: number;\n\tmaxBytes?: number;\n\tmaxRedirects?: number;\n\tsignal?: AbortSignal;\n\tlookup?: DnsLookup;\n\trequest?: LowLevelRequestFn;\n}\n\nexport interface GuardedResponse extends GuardedBody {\n\tfinalUrl: string;\n\tredirectCount: number;\n}\n\n/**\n * GET a URL under the shared guardrails: scheme allowlist, literal-IP and DNS\n * checks on the initial URL and every redirect hop, redirect cap,\n * `Content-Length` pre-check, and per-hop timeout. Streaming byte cutoff is\n * the caller's job via `assertBytesWithinBudget`.\n */\nexport async function guardedRequest(rawUrl: string, options: GuardedRequestOptions = {}): Promise<GuardedResponse> {\n\tconst timeoutMs = options.timeoutMs ?? WEBFETCH_REQUEST_TIMEOUT_MS;\n\tconst maxBytes = options.maxBytes ?? WEBFETCH_MAX_BYTES;\n\tconst maxRedirects = options.maxRedirects ?? WEBFETCH_MAX_REDIRECTS;\n\tconst lookup = options.lookup ?? defaultLookup;\n\tconst request = options.request ?? defaultLowLevelRequest;\n\tconst headers = options.headers ?? {};\n\n\tlet current = normalizeWebUrl(rawUrl);\n\tassertLiteralTargetAllowed(current);\n\n\tfor (let redirectCount = 0; ; redirectCount++) {\n\t\tawait assertHostAllowed(current.hostname, lookup);\n\n\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\tconst signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;\n\t\tlet response: GuardedBody;\n\t\ttry {\n\t\t\tresponse = await request(current.href, { headers, signal });\n\t\t} catch (error) {\n\t\t\tif (timeoutSignal.aborted && !options.signal?.aborted) {\n\t\t\t\tthrow new WebfetchError(`Request to ${current.href} timed out after ${timeoutMs}ms`, \"timeout\");\n\t\t\t}\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Operation aborted\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst location = response.headers.location ?? response.headers.Location;\n\t\tif (location !== undefined && REDIRECT_STATUSES.has(response.statusCode)) {\n\t\t\tif (redirectCount >= maxRedirects) {\n\t\t\t\tthrow new WebfetchError(`Redirect chain exceeds ${maxRedirects} hops`, \"redirect-limit\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tcurrent = new URL(location, current.href);\n\t\t\t} catch {\n\t\t\t\tthrow new WebfetchError(`Invalid redirect target: ${location}`, \"invalid-url\");\n\t\t\t}\n\t\t\tif (current.protocol !== \"http:\" && current.protocol !== \"https:\") {\n\t\t\t\tthrow new WebfetchError(\n\t\t\t\t\t`Blocked redirect to scheme \"${current.protocol}\": only http and https are allowed`,\n\t\t\t\t\t\"blocked-host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertLiteralTargetAllowed(current);\n\t\t\tcontinue;\n\t\t}\n\n\t\tassertContentLengthAllowed(response.headers[\"content-length\"], maxBytes);\n\t\treturn { ...response, finalUrl: current.href, redirectCount };\n\t}\n}\n"]}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * SSRF guardrails for webfetch (patterns copied from Jina Reader — not vendored).
3
+ *
4
+ * - Only `http:`/`https:` targets are allowed.
5
+ * - Literal-IP targets are checked against non-public CIDRs.
6
+ * - Hostnames are resolved via DNS and **every** returned address is re-checked,
7
+ * including on every redirect hop (TOCTOU: re-validate on redirect).
8
+ * - Redirect chains are capped, response bytes are capped (with a
9
+ * `Content-Length` pre-check plus a streaming cutoff), and each hop has a
10
+ * per-request timeout.
11
+ */
12
+ import { lookup as dnsLookupAll } from "node:dns/promises";
13
+ import { BlockList, isIP } from "node:net";
14
+ import { request as undiciRequest } from "undici";
15
+ export const WEBFETCH_MAX_REDIRECTS = 6;
16
+ export const WEBFETCH_MAX_BYTES = 2_000_000;
17
+ export const WEBFETCH_REQUEST_TIMEOUT_MS = 30_000;
18
+ export const WEBFETCH_FIRECRAWL_MAX_LIMIT = 100;
19
+ export class WebfetchError extends Error {
20
+ code;
21
+ constructor(message, code) {
22
+ super(message);
23
+ this.name = "WebfetchError";
24
+ this.code = code;
25
+ }
26
+ }
27
+ const blockedRanges = [
28
+ { subnet: "10.0.0.0", prefix: 8, type: "ipv4" },
29
+ { subnet: "172.16.0.0", prefix: 12, type: "ipv4" },
30
+ { subnet: "192.168.0.0", prefix: 16, type: "ipv4" },
31
+ { subnet: "127.0.0.0", prefix: 8, type: "ipv4" },
32
+ { subnet: "169.254.0.0", prefix: 16, type: "ipv4" },
33
+ { subnet: "224.0.0.0", prefix: 4, type: "ipv4" },
34
+ { subnet: "100.64.0.0", prefix: 10, type: "ipv4" },
35
+ { subnet: "fc00::", prefix: 7, type: "ipv6" },
36
+ { subnet: "fe80::", prefix: 10, type: "ipv6" },
37
+ { subnet: "ff00::", prefix: 8, type: "ipv6" },
38
+ { subnet: "::1", prefix: 128, type: "ipv6" },
39
+ ];
40
+ const blockedList = new BlockList();
41
+ for (const range of blockedRanges) {
42
+ blockedList.addSubnet(range.subnet, range.prefix, range.type);
43
+ }
44
+ /** True when `ip` is a literal IP address inside a blocked non-public range. Non-IP strings return false. */
45
+ export function isBlockedIpAddress(ip) {
46
+ const family = isIP(ip);
47
+ if (family === 0)
48
+ return false;
49
+ return blockedList.check(ip, family === 4 ? "ipv4" : "ipv6");
50
+ }
51
+ /** Parse and validate a web target URL. Only `http:`/`https:` are allowed. */
52
+ export function normalizeWebUrl(rawUrl) {
53
+ let url;
54
+ try {
55
+ url = new URL(rawUrl.trim());
56
+ }
57
+ catch {
58
+ throw new WebfetchError(`Invalid URL: ${rawUrl}`, "invalid-url");
59
+ }
60
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
61
+ throw new WebfetchError(`Blocked URL scheme "${url.protocol}": only http and https are allowed`, "blocked-host");
62
+ }
63
+ return url;
64
+ }
65
+ /** Reject literal-IP targets inside blocked ranges. Hostnames are checked via DNS separately. */
66
+ export function assertLiteralTargetAllowed(url) {
67
+ const bare = url.hostname.replace(/^\[|\]$/g, "");
68
+ if (isIP(bare) !== 0 && isBlockedIpAddress(bare)) {
69
+ throw new WebfetchError(`Blocked request to private IP ${bare}`, "blocked-host");
70
+ }
71
+ }
72
+ /** Reject when any resolved address is blocked. Every address is checked (fail closed). */
73
+ export function assertResolvedAddressesAllowed(addresses, hostname) {
74
+ if (addresses.length === 0) {
75
+ throw new WebfetchError(`Could not resolve host "${hostname}"`, "blocked-host");
76
+ }
77
+ for (const address of addresses) {
78
+ if (isBlockedIpAddress(address)) {
79
+ throw new WebfetchError(`Blocked request to "${hostname}": resolves to private IP ${address}`, "blocked-host");
80
+ }
81
+ }
82
+ }
83
+ async function defaultLookup(hostname) {
84
+ const results = await dnsLookupAll(hostname, { all: true });
85
+ return results.map((result) => result.address);
86
+ }
87
+ /**
88
+ * Fail-closed host check: literal IPs are checked directly, hostnames are
89
+ * resolved and every returned address is re-checked. Callers must invoke this
90
+ * for the initial URL and again for each redirect target.
91
+ */
92
+ export async function assertHostAllowed(hostname, lookup = defaultLookup) {
93
+ const bare = hostname.replace(/^\[|\]$/g, "");
94
+ if (isIP(bare) !== 0) {
95
+ if (isBlockedIpAddress(bare)) {
96
+ throw new WebfetchError(`Blocked request to private IP ${bare}`, "blocked-host");
97
+ }
98
+ return;
99
+ }
100
+ let addresses;
101
+ try {
102
+ addresses = await lookup(bare);
103
+ }
104
+ catch (error) {
105
+ const reason = error instanceof Error ? error.message : String(error);
106
+ throw new WebfetchError(`Could not resolve host "${bare}": ${reason}`, "blocked-host");
107
+ }
108
+ assertResolvedAddressesAllowed(addresses, bare);
109
+ }
110
+ /** Enforce the byte cap against a `Content-Length` header before streaming the body. */
111
+ export function assertContentLengthAllowed(contentLength, maxBytes = WEBFETCH_MAX_BYTES) {
112
+ if (contentLength === null || contentLength === undefined)
113
+ return;
114
+ const declared = Number.parseInt(contentLength.split(",")[0]?.trim() ?? "", 10);
115
+ if (Number.isFinite(declared) && declared > maxBytes) {
116
+ throw new WebfetchError(`Response body exceeds ${maxBytes} byte limit (${declared} bytes declared)`, "byte-limit");
117
+ }
118
+ }
119
+ /** Enforce the byte cap while streaming. Throws once `totalBytes` exceeds `maxBytes`. */
120
+ export function assertBytesWithinBudget(totalBytes, maxBytes = WEBFETCH_MAX_BYTES) {
121
+ if (totalBytes > maxBytes) {
122
+ throw new WebfetchError(`Response body exceeds ${maxBytes} byte limit`, "byte-limit");
123
+ }
124
+ }
125
+ /** Clamp a search limit into `[min, max]`, falling back to `fallback` for missing/invalid values. */
126
+ export function clampLimit(limit, options) {
127
+ if (limit === undefined || !Number.isFinite(limit))
128
+ return options.fallback;
129
+ return Math.min(options.max, Math.max(options.min, Math.floor(limit)));
130
+ }
131
+ async function defaultLowLevelRequest(url, init) {
132
+ const response = await undiciRequest(url, { method: "GET", headers: init.headers, signal: init.signal });
133
+ const headers = {};
134
+ for (const [key, value] of Object.entries(response.headers)) {
135
+ if (value === undefined)
136
+ continue;
137
+ headers[key.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
138
+ }
139
+ return { statusCode: response.statusCode, headers, body: response.body };
140
+ }
141
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
142
+ /**
143
+ * GET a URL under the shared guardrails: scheme allowlist, literal-IP and DNS
144
+ * checks on the initial URL and every redirect hop, redirect cap,
145
+ * `Content-Length` pre-check, and per-hop timeout. Streaming byte cutoff is
146
+ * the caller's job via `assertBytesWithinBudget`.
147
+ */
148
+ export async function guardedRequest(rawUrl, options = {}) {
149
+ const timeoutMs = options.timeoutMs ?? WEBFETCH_REQUEST_TIMEOUT_MS;
150
+ const maxBytes = options.maxBytes ?? WEBFETCH_MAX_BYTES;
151
+ const maxRedirects = options.maxRedirects ?? WEBFETCH_MAX_REDIRECTS;
152
+ const lookup = options.lookup ?? defaultLookup;
153
+ const request = options.request ?? defaultLowLevelRequest;
154
+ const headers = options.headers ?? {};
155
+ let current = normalizeWebUrl(rawUrl);
156
+ assertLiteralTargetAllowed(current);
157
+ for (let redirectCount = 0;; redirectCount++) {
158
+ await assertHostAllowed(current.hostname, lookup);
159
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
160
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
161
+ let response;
162
+ try {
163
+ response = await request(current.href, { headers, signal });
164
+ }
165
+ catch (error) {
166
+ if (timeoutSignal.aborted && !options.signal?.aborted) {
167
+ throw new WebfetchError(`Request to ${current.href} timed out after ${timeoutMs}ms`, "timeout");
168
+ }
169
+ if (options.signal?.aborted) {
170
+ throw new Error("Operation aborted");
171
+ }
172
+ throw error;
173
+ }
174
+ const location = response.headers.location ?? response.headers.Location;
175
+ if (location !== undefined && REDIRECT_STATUSES.has(response.statusCode)) {
176
+ if (redirectCount >= maxRedirects) {
177
+ throw new WebfetchError(`Redirect chain exceeds ${maxRedirects} hops`, "redirect-limit");
178
+ }
179
+ try {
180
+ current = new URL(location, current.href);
181
+ }
182
+ catch {
183
+ throw new WebfetchError(`Invalid redirect target: ${location}`, "invalid-url");
184
+ }
185
+ if (current.protocol !== "http:" && current.protocol !== "https:") {
186
+ throw new WebfetchError(`Blocked redirect to scheme "${current.protocol}": only http and https are allowed`, "blocked-host");
187
+ }
188
+ assertLiteralTargetAllowed(current);
189
+ continue;
190
+ }
191
+ assertContentLengthAllowed(response.headers["content-length"], maxBytes);
192
+ return { ...response, finalUrl: current.href, redirectCount };
193
+ }
194
+ }
195
+ //# sourceMappingURL=guardrails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../../../src/core/webfetch/guardrails.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SSRF guardrails for webfetch (patterns copied from Jina Reader — not vendored).\n *\n * - Only `http:`/`https:` targets are allowed.\n * - Literal-IP targets are checked against non-public CIDRs.\n * - Hostnames are resolved via DNS and **every** returned address is re-checked,\n * including on every redirect hop (TOCTOU: re-validate on redirect).\n * - Redirect chains are capped, response bytes are capped (with a\n * `Content-Length` pre-check plus a streaming cutoff), and each hop has a\n * per-request timeout.\n */\n\nimport { lookup as dnsLookupAll } from \"node:dns/promises\";\nimport { BlockList, isIP } from \"node:net\";\nimport { request as undiciRequest } from \"undici\";\n\nexport const WEBFETCH_MAX_REDIRECTS = 6;\nexport const WEBFETCH_MAX_BYTES = 2_000_000;\nexport const WEBFETCH_REQUEST_TIMEOUT_MS = 30_000;\nexport const WEBFETCH_FIRECRAWL_MAX_LIMIT = 100;\n\nexport type WebfetchErrorCode =\n\t| \"invalid-url\"\n\t| \"blocked-host\"\n\t| \"redirect-limit\"\n\t| \"byte-limit\"\n\t| \"timeout\"\n\t| \"empty\"\n\t| \"transport\"\n\t| \"unavailable\";\n\nexport class WebfetchError extends Error {\n\treadonly code: WebfetchErrorCode;\n\tconstructor(message: string, code: WebfetchErrorCode) {\n\t\tsuper(message);\n\t\tthis.name = \"WebfetchError\";\n\t\tthis.code = code;\n\t}\n}\n\nconst blockedRanges: Array<{ subnet: string; prefix: number; type: \"ipv4\" | \"ipv6\" }> = [\n\t{ subnet: \"10.0.0.0\", prefix: 8, type: \"ipv4\" },\n\t{ subnet: \"172.16.0.0\", prefix: 12, type: \"ipv4\" },\n\t{ subnet: \"192.168.0.0\", prefix: 16, type: \"ipv4\" },\n\t{ subnet: \"127.0.0.0\", prefix: 8, type: \"ipv4\" },\n\t{ subnet: \"169.254.0.0\", prefix: 16, type: \"ipv4\" },\n\t{ subnet: \"224.0.0.0\", prefix: 4, type: \"ipv4\" },\n\t{ subnet: \"100.64.0.0\", prefix: 10, type: \"ipv4\" },\n\t{ subnet: \"fc00::\", prefix: 7, type: \"ipv6\" },\n\t{ subnet: \"fe80::\", prefix: 10, type: \"ipv6\" },\n\t{ subnet: \"ff00::\", prefix: 8, type: \"ipv6\" },\n\t{ subnet: \"::1\", prefix: 128, type: \"ipv6\" },\n];\n\nconst blockedList = new BlockList();\nfor (const range of blockedRanges) {\n\tblockedList.addSubnet(range.subnet, range.prefix, range.type);\n}\n\n/** True when `ip` is a literal IP address inside a blocked non-public range. Non-IP strings return false. */\nexport function isBlockedIpAddress(ip: string): boolean {\n\tconst family = isIP(ip);\n\tif (family === 0) return false;\n\treturn blockedList.check(ip, family === 4 ? \"ipv4\" : \"ipv6\");\n}\n\n/** Parse and validate a web target URL. Only `http:`/`https:` are allowed. */\nexport function normalizeWebUrl(rawUrl: string): URL {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(rawUrl.trim());\n\t} catch {\n\t\tthrow new WebfetchError(`Invalid URL: ${rawUrl}`, \"invalid-url\");\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n\t\tthrow new WebfetchError(`Blocked URL scheme \"${url.protocol}\": only http and https are allowed`, \"blocked-host\");\n\t}\n\treturn url;\n}\n\n/** Reject literal-IP targets inside blocked ranges. Hostnames are checked via DNS separately. */\nexport function assertLiteralTargetAllowed(url: URL): void {\n\tconst bare = url.hostname.replace(/^\\[|\\]$/g, \"\");\n\tif (isIP(bare) !== 0 && isBlockedIpAddress(bare)) {\n\t\tthrow new WebfetchError(`Blocked request to private IP ${bare}`, \"blocked-host\");\n\t}\n}\n\n/** Reject when any resolved address is blocked. Every address is checked (fail closed). */\nexport function assertResolvedAddressesAllowed(addresses: string[], hostname: string): void {\n\tif (addresses.length === 0) {\n\t\tthrow new WebfetchError(`Could not resolve host \"${hostname}\"`, \"blocked-host\");\n\t}\n\tfor (const address of addresses) {\n\t\tif (isBlockedIpAddress(address)) {\n\t\t\tthrow new WebfetchError(`Blocked request to \"${hostname}\": resolves to private IP ${address}`, \"blocked-host\");\n\t\t}\n\t}\n}\n\nexport type DnsLookup = (hostname: string) => Promise<string[]>;\n\nasync function defaultLookup(hostname: string): Promise<string[]> {\n\tconst results = await dnsLookupAll(hostname, { all: true });\n\treturn results.map((result) => result.address);\n}\n\n/**\n * Fail-closed host check: literal IPs are checked directly, hostnames are\n * resolved and every returned address is re-checked. Callers must invoke this\n * for the initial URL and again for each redirect target.\n */\nexport async function assertHostAllowed(hostname: string, lookup: DnsLookup = defaultLookup): Promise<void> {\n\tconst bare = hostname.replace(/^\\[|\\]$/g, \"\");\n\tif (isIP(bare) !== 0) {\n\t\tif (isBlockedIpAddress(bare)) {\n\t\t\tthrow new WebfetchError(`Blocked request to private IP ${bare}`, \"blocked-host\");\n\t\t}\n\t\treturn;\n\t}\n\tlet addresses: string[];\n\ttry {\n\t\taddresses = await lookup(bare);\n\t} catch (error) {\n\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\tthrow new WebfetchError(`Could not resolve host \"${bare}\": ${reason}`, \"blocked-host\");\n\t}\n\tassertResolvedAddressesAllowed(addresses, bare);\n}\n\n/** Enforce the byte cap against a `Content-Length` header before streaming the body. */\nexport function assertContentLengthAllowed(\n\tcontentLength: string | null | undefined,\n\tmaxBytes: number = WEBFETCH_MAX_BYTES,\n): void {\n\tif (contentLength === null || contentLength === undefined) return;\n\tconst declared = Number.parseInt(contentLength.split(\",\")[0]?.trim() ?? \"\", 10);\n\tif (Number.isFinite(declared) && declared > maxBytes) {\n\t\tthrow new WebfetchError(\n\t\t\t`Response body exceeds ${maxBytes} byte limit (${declared} bytes declared)`,\n\t\t\t\"byte-limit\",\n\t\t);\n\t}\n}\n\n/** Enforce the byte cap while streaming. Throws once `totalBytes` exceeds `maxBytes`. */\nexport function assertBytesWithinBudget(totalBytes: number, maxBytes: number = WEBFETCH_MAX_BYTES): void {\n\tif (totalBytes > maxBytes) {\n\t\tthrow new WebfetchError(`Response body exceeds ${maxBytes} byte limit`, \"byte-limit\");\n\t}\n}\n\n/** Clamp a search limit into `[min, max]`, falling back to `fallback` for missing/invalid values. */\nexport function clampLimit(limit: number | undefined, options: { fallback: number; min: number; max: number }): number {\n\tif (limit === undefined || !Number.isFinite(limit)) return options.fallback;\n\treturn Math.min(options.max, Math.max(options.min, Math.floor(limit)));\n}\n\nexport interface GuardedBody {\n\tstatusCode: number;\n\theaders: Record<string, string>;\n\tbody: AsyncIterable<Uint8Array>;\n}\n\nexport type LowLevelRequestFn = (\n\turl: string,\n\tinit: { headers: Record<string, string>; signal: AbortSignal },\n) => Promise<GuardedBody>;\n\nasync function defaultLowLevelRequest(\n\turl: string,\n\tinit: { headers: Record<string, string>; signal: AbortSignal },\n): Promise<GuardedBody> {\n\tconst response = await undiciRequest(url, { method: \"GET\", headers: init.headers, signal: init.signal });\n\tconst headers: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(response.headers)) {\n\t\tif (value === undefined) continue;\n\t\theaders[key.toLowerCase()] = Array.isArray(value) ? value.join(\", \") : String(value);\n\t}\n\treturn { statusCode: response.statusCode, headers, body: response.body as AsyncIterable<Uint8Array> };\n}\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\nexport interface GuardedRequestOptions {\n\theaders?: Record<string, string>;\n\ttimeoutMs?: number;\n\tmaxBytes?: number;\n\tmaxRedirects?: number;\n\tsignal?: AbortSignal;\n\tlookup?: DnsLookup;\n\trequest?: LowLevelRequestFn;\n}\n\nexport interface GuardedResponse extends GuardedBody {\n\tfinalUrl: string;\n\tredirectCount: number;\n}\n\n/**\n * GET a URL under the shared guardrails: scheme allowlist, literal-IP and DNS\n * checks on the initial URL and every redirect hop, redirect cap,\n * `Content-Length` pre-check, and per-hop timeout. Streaming byte cutoff is\n * the caller's job via `assertBytesWithinBudget`.\n */\nexport async function guardedRequest(rawUrl: string, options: GuardedRequestOptions = {}): Promise<GuardedResponse> {\n\tconst timeoutMs = options.timeoutMs ?? WEBFETCH_REQUEST_TIMEOUT_MS;\n\tconst maxBytes = options.maxBytes ?? WEBFETCH_MAX_BYTES;\n\tconst maxRedirects = options.maxRedirects ?? WEBFETCH_MAX_REDIRECTS;\n\tconst lookup = options.lookup ?? defaultLookup;\n\tconst request = options.request ?? defaultLowLevelRequest;\n\tconst headers = options.headers ?? {};\n\n\tlet current = normalizeWebUrl(rawUrl);\n\tassertLiteralTargetAllowed(current);\n\n\tfor (let redirectCount = 0; ; redirectCount++) {\n\t\tawait assertHostAllowed(current.hostname, lookup);\n\n\t\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\t\tconst signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;\n\t\tlet response: GuardedBody;\n\t\ttry {\n\t\t\tresponse = await request(current.href, { headers, signal });\n\t\t} catch (error) {\n\t\t\tif (timeoutSignal.aborted && !options.signal?.aborted) {\n\t\t\t\tthrow new WebfetchError(`Request to ${current.href} timed out after ${timeoutMs}ms`, \"timeout\");\n\t\t\t}\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Operation aborted\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst location = response.headers.location ?? response.headers.Location;\n\t\tif (location !== undefined && REDIRECT_STATUSES.has(response.statusCode)) {\n\t\t\tif (redirectCount >= maxRedirects) {\n\t\t\t\tthrow new WebfetchError(`Redirect chain exceeds ${maxRedirects} hops`, \"redirect-limit\");\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tcurrent = new URL(location, current.href);\n\t\t\t} catch {\n\t\t\t\tthrow new WebfetchError(`Invalid redirect target: ${location}`, \"invalid-url\");\n\t\t\t}\n\t\t\tif (current.protocol !== \"http:\" && current.protocol !== \"https:\") {\n\t\t\t\tthrow new WebfetchError(\n\t\t\t\t\t`Blocked redirect to scheme \"${current.protocol}\": only http and https are allowed`,\n\t\t\t\t\t\"blocked-host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tassertLiteralTargetAllowed(current);\n\t\t\tcontinue;\n\t\t}\n\n\t\tassertContentLengthAllowed(response.headers[\"content-length\"], maxBytes);\n\t\treturn { ...response, finalUrl: current.href, redirectCount };\n\t}\n}\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * robots.txt parsing for the polite crawler.
3
+ *
4
+ * Follows RFC 9309 where it matters: the group whose user-agent matches ours
5
+ * (or `*` when none does) supplies the rules, the longest matching pattern wins,
6
+ * and an Allow beats a Disallow of the same length. A missing or unreadable
7
+ * robots.txt means "allowed", which is what the RFC requires and what a crawler
8
+ * must assume when the file is absent.
9
+ *
10
+ * The file is fetched through the shared guardrails, so a hostile robots.txt
11
+ * cannot redirect the crawler somewhere it was already barred from going.
12
+ */
13
+ import { type DnsLookup, type LowLevelRequestFn } from "./guardrails.ts";
14
+ export declare const ROBOTS_USER_AGENT = "ion";
15
+ export interface RobotsRule {
16
+ allow: boolean;
17
+ pattern: string;
18
+ regex: RegExp;
19
+ length: number;
20
+ }
21
+ export interface RobotsPolicy {
22
+ rules: RobotsRule[];
23
+ /** Seconds requested by Crawl-delay, when the file declares one. */
24
+ crawlDelaySeconds?: number;
25
+ sitemaps: string[];
26
+ }
27
+ /** Parse a robots.txt body into a policy for {@link ROBOTS_USER_AGENT}. */
28
+ export declare function parseRobotsTxt(text: string, userAgent?: string): RobotsPolicy;
29
+ /** Longest matching pattern wins; an Allow wins a tie. No rules means allowed. */
30
+ export declare function isPathAllowed(policy: RobotsPolicy, pathWithQuery: string): boolean;
31
+ export declare function isUrlAllowed(policy: RobotsPolicy, url: URL): boolean;
32
+ export interface RobotsFetchOptions {
33
+ userAgent?: string;
34
+ signal?: AbortSignal;
35
+ lookup?: DnsLookup;
36
+ request?: LowLevelRequestFn;
37
+ maxBytes?: number;
38
+ }
39
+ /**
40
+ * Fetch and parse a site's robots.txt. Returns an allow-everything policy when
41
+ * the file is missing, unreadable, or not text: a crawler must not refuse to
42
+ * read a site merely because the site failed to describe its own rules, and it
43
+ * must not guess rules it was not given.
44
+ */
45
+ export declare function fetchRobotsPolicy(originUrl: URL, options?: RobotsFetchOptions): Promise<RobotsPolicy>;
46
+ //# sourceMappingURL=robots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../../src/core/webfetch/robots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAEN,KAAK,SAAS,EAEd,KAAK,iBAAiB,EAGtB,MAAM,iBAAiB,CAAC;AAEzB,eAAO,MAAM,iBAAiB,QAAQ,CAAC;AAEvC,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAiBD,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAA0B,GAAG,YAAY,CAgEhG;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CASlF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAEpE;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC,CA+B/G","sourcesContent":["/**\n * robots.txt parsing for the polite crawler.\n *\n * Follows RFC 9309 where it matters: the group whose user-agent matches ours\n * (or `*` when none does) supplies the rules, the longest matching pattern wins,\n * and an Allow beats a Disallow of the same length. A missing or unreadable\n * robots.txt means \"allowed\", which is what the RFC requires and what a crawler\n * must assume when the file is absent.\n *\n * The file is fetched through the shared guardrails, so a hostile robots.txt\n * cannot redirect the crawler somewhere it was already barred from going.\n */\n\nimport {\n\tassertBytesWithinBudget,\n\ttype DnsLookup,\n\tguardedRequest,\n\ttype LowLevelRequestFn,\n\tWEBFETCH_MAX_BYTES,\n\tWEBFETCH_REQUEST_TIMEOUT_MS,\n} from \"./guardrails.ts\";\n\nexport const ROBOTS_USER_AGENT = \"ion\";\n\nexport interface RobotsRule {\n\tallow: boolean;\n\tpattern: string;\n\tregex: RegExp;\n\tlength: number;\n}\n\nexport interface RobotsPolicy {\n\trules: RobotsRule[];\n\t/** Seconds requested by Crawl-delay, when the file declares one. */\n\tcrawlDelaySeconds?: number;\n\tsitemaps: string[];\n}\n\nfunction patternToRegex(pattern: string): { regex: RegExp; anchored: boolean } | undefined {\n\tif (pattern.length === 0) return undefined;\n\tconst anchored = pattern.endsWith(\"$\");\n\tconst body = anchored ? pattern.slice(0, -1) : pattern;\n\tlet source = \"\";\n\tfor (const character of body) {\n\t\tif (character === \"*\") {\n\t\t\tsource += \".*\";\n\t\t} else {\n\t\t\tsource += character.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\t\t}\n\t}\n\treturn { regex: new RegExp(`^${source}${anchored ? \"$\" : \"\"}`), anchored };\n}\n\n/** Parse a robots.txt body into a policy for {@link ROBOTS_USER_AGENT}. */\nexport function parseRobotsTxt(text: string, userAgent: string = ROBOTS_USER_AGENT): RobotsPolicy {\n\tconst agent = userAgent.toLowerCase();\n\tconst groups: { agents: string[]; lines: string[] }[] = [];\n\tlet current: { agents: string[]; lines: string[] } | undefined;\n\tlet expectingAgents = false;\n\n\tfor (const rawLine of text.split(/\\r?\\n/)) {\n\t\tconst line = rawLine.replace(/#.*$/, \"\").trim();\n\t\tif (line.length === 0) continue;\n\t\tconst separator = line.indexOf(\":\");\n\t\tif (separator === -1) continue;\n\t\tconst field = line.slice(0, separator).trim().toLowerCase();\n\t\tconst value = line.slice(separator + 1).trim();\n\n\t\tif (field === \"user-agent\") {\n\t\t\tif (!current || !expectingAgents) {\n\t\t\t\tcurrent = { agents: [], lines: [] };\n\t\t\t\tgroups.push(current);\n\t\t\t\texpectingAgents = true;\n\t\t\t}\n\t\t\tcurrent.agents.push(value.toLowerCase());\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Any non-user-agent field ends the agent block, per RFC 9309.\n\t\texpectingAgents = false;\n\t\tif (!current) continue;\n\t\tcurrent.lines.push(`${field}:${value}`);\n\t}\n\n\tconst matches = (group: { agents: string[] }) =>\n\t\tgroup.agents.some((candidate) => candidate !== \"*\" && agent.includes(candidate));\n\tconst specific = groups.find(matches);\n\tconst wildcard = groups.find((group) => group.agents.includes(\"*\"));\n\tconst selected = specific ?? wildcard;\n\n\tconst policy: RobotsPolicy = { rules: [], sitemaps: [] };\n\tif (!selected) return policy;\n\n\tfor (const entry of selected.lines) {\n\t\tconst separator = entry.indexOf(\":\");\n\t\tconst field = entry.slice(0, separator);\n\t\tconst value = entry.slice(separator + 1);\n\t\tif (field === \"sitemap\") {\n\t\t\tif (value.length > 0) policy.sitemaps.push(value);\n\t\t\tcontinue;\n\t\t}\n\t\tif (field === \"crawl-delay\") {\n\t\t\tconst seconds = Number.parseFloat(value);\n\t\t\tif (Number.isFinite(seconds) && seconds >= 0) policy.crawlDelaySeconds = seconds;\n\t\t\tcontinue;\n\t\t}\n\t\tif (field !== \"allow\" && field !== \"disallow\") continue;\n\t\tconst compiled = patternToRegex(value);\n\t\t// `Disallow:` with an empty value means allow everything, so it adds no rule.\n\t\tif (!compiled) continue;\n\t\tpolicy.rules.push({\n\t\t\tallow: field === \"allow\",\n\t\t\tpattern: value,\n\t\t\tregex: compiled.regex,\n\t\t\tlength: value.length,\n\t\t});\n\t}\n\treturn policy;\n}\n\n/** Longest matching pattern wins; an Allow wins a tie. No rules means allowed. */\nexport function isPathAllowed(policy: RobotsPolicy, pathWithQuery: string): boolean {\n\tlet best: RobotsRule | undefined;\n\tfor (const rule of policy.rules) {\n\t\tif (!rule.regex.test(pathWithQuery)) continue;\n\t\tif (!best || rule.length > best.length || (rule.length === best.length && rule.allow && !best.allow)) {\n\t\t\tbest = rule;\n\t\t}\n\t}\n\treturn best ? best.allow : true;\n}\n\nexport function isUrlAllowed(policy: RobotsPolicy, url: URL): boolean {\n\treturn isPathAllowed(policy, `${url.pathname}${url.search}`);\n}\n\nexport interface RobotsFetchOptions {\n\tuserAgent?: string;\n\tsignal?: AbortSignal;\n\tlookup?: DnsLookup;\n\trequest?: LowLevelRequestFn;\n\tmaxBytes?: number;\n}\n\n/**\n * Fetch and parse a site's robots.txt. Returns an allow-everything policy when\n * the file is missing, unreadable, or not text: a crawler must not refuse to\n * read a site merely because the site failed to describe its own rules, and it\n * must not guess rules it was not given.\n */\nexport async function fetchRobotsPolicy(originUrl: URL, options: RobotsFetchOptions = {}): Promise<RobotsPolicy> {\n\tconst allowAll: RobotsPolicy = { rules: [], sitemaps: [] };\n\tconst robotsUrl = new URL(\"/robots.txt\", originUrl.origin);\n\ttry {\n\t\tconst response = await guardedRequest(robotsUrl.href, {\n\t\t\theaders: { \"User-Agent\": options.userAgent ?? ROBOTS_USER_AGENT },\n\t\t\tsignal: options.signal,\n\t\t\tlookup: options.lookup,\n\t\t\trequest: options.request,\n\t\t\tmaxBytes: options.maxBytes ?? WEBFETCH_MAX_BYTES,\n\t\t\ttimeoutMs: WEBFETCH_REQUEST_TIMEOUT_MS,\n\t\t});\n\t\t// 4xx means no published rules; only a served body is authoritative.\n\t\tif (response.statusCode >= 400) return allowAll;\n\t\tconst chunks: Uint8Array[] = [];\n\t\tlet totalBytes = 0;\n\t\tfor await (const chunk of response.body) {\n\t\t\ttotalBytes += chunk.length;\n\t\t\tassertBytesWithinBudget(totalBytes, options.maxBytes ?? WEBFETCH_MAX_BYTES);\n\t\t\tchunks.push(chunk);\n\t\t}\n\t\tconst merged = new Uint8Array(totalBytes);\n\t\tlet offset = 0;\n\t\tfor (const chunk of chunks) {\n\t\t\tmerged.set(chunk, offset);\n\t\t\toffset += chunk.length;\n\t\t}\n\t\treturn parseRobotsTxt(new TextDecoder().decode(merged), options.userAgent ?? ROBOTS_USER_AGENT);\n\t} catch {\n\t\treturn allowAll;\n\t}\n}\n"]}