pim-agent 0.13.0 → 0.14.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 (253) hide show
  1. package/package.json +3 -3
  2. package/packages/core/src/attachments/AttachmentStore.ts +8 -13
  3. package/packages/core/src/attachments/Attachments.ts +2 -4
  4. package/packages/core/src/extensions/CoreExtensions.ts +1 -1
  5. package/packages/core/src/extensions/apply-patch/coordinator.ts +1 -1
  6. package/packages/core/src/extensions/apply-patch/executor.ts +21 -25
  7. package/packages/core/src/extensions/apply-patch/matcher.ts +1 -1
  8. package/packages/core/src/extensions/apply-patch/model.ts +2 -6
  9. package/packages/core/src/extensions/apply-patch/parser.ts +60 -162
  10. package/packages/core/src/extensions/apply-patch/schema.ts +0 -1
  11. package/packages/core/src/extensions/bash/MemoryCap.ts +5 -4
  12. package/packages/core/src/extensions/bash/capture.ts +16 -23
  13. package/packages/core/src/extensions/bash/format.ts +2 -2
  14. package/packages/core/src/extensions/bash/image.ts +4 -8
  15. package/packages/core/src/extensions/bash/index.ts +1 -1
  16. package/packages/core/src/extensions/bash/render.ts +1 -1
  17. package/packages/core/src/extensions/bash/run.ts +9 -15
  18. package/packages/core/src/extensions/bash/schema.ts +4 -4
  19. package/packages/core/src/extensions/edit/edit.ts +14 -33
  20. package/packages/core/src/extensions/glob/glob.ts +1 -3
  21. package/packages/core/src/extensions/glob/index.ts +7 -9
  22. package/packages/core/src/extensions/glob/render.ts +2 -4
  23. package/packages/core/src/extensions/glob/schema.ts +1 -1
  24. package/packages/core/src/extensions/grep/grep.ts +7 -7
  25. package/packages/core/src/extensions/grep/render.ts +5 -6
  26. package/packages/core/src/extensions/grep/schema.ts +3 -7
  27. package/packages/core/src/extensions/read/ImageMemory.ts +2 -8
  28. package/packages/core/src/extensions/read/image.ts +3 -3
  29. package/packages/core/src/extensions/read/index.ts +2 -14
  30. package/packages/core/src/extensions/read/read.ts +5 -6
  31. package/packages/core/src/extensions/read/render.ts +1 -1
  32. package/packages/core/src/extensions/read/schema.ts +2 -2
  33. package/packages/core/src/extensions/subagent/render.ts +2 -2
  34. package/packages/core/src/extensions/subagent/subagent.ts +10 -21
  35. package/packages/core/src/extensions/system-prompt/index.ts +1 -2
  36. package/packages/core/src/extensions/system-prompt/prompt.ts +2 -4
  37. package/packages/core/src/extensions/todo/render.ts +1 -4
  38. package/packages/core/src/extensions/todo/todo.ts +16 -23
  39. package/packages/core/src/extensions/web-fetch/JinaReaderClient.ts +3 -11
  40. package/packages/core/src/extensions/web-fetch/WebViewFetchClient.ts +1 -3
  41. package/packages/core/src/extensions/web-fetch/fetch.ts +4 -12
  42. package/packages/core/src/extensions/web-fetch/image.ts +3 -4
  43. package/packages/core/src/extensions/web-fetch/index.ts +2 -13
  44. package/packages/core/src/extensions/web-fetch/render.ts +3 -4
  45. package/packages/core/src/extensions/web-fetch/schema.ts +3 -4
  46. package/packages/core/src/extensions/web-search/ExaMcpClient.ts +23 -31
  47. package/packages/core/src/extensions/web-search/SearchBreaker.ts +1 -1
  48. package/packages/core/src/extensions/web-search/SearchChain.ts +6 -5
  49. package/packages/core/src/extensions/web-search/providers/DuckDuckGoProvider.ts +2 -2
  50. package/packages/core/src/extensions/web-search/providers/FirecrawlProvider.ts +1 -2
  51. package/packages/core/src/extensions/web-search/providers/SearchProvider.ts +3 -3
  52. package/packages/core/src/extensions/write/write.ts +1 -1
  53. package/packages/core/src/picker/InProcessFilePickerSuggestionEngine.ts +1 -3
  54. package/packages/core/src/picker/PickerItem.ts +1 -1
  55. package/packages/core/src/picker/PickerService.ts +3 -7
  56. package/packages/core/src/picker/RemoteFilePickerSuggestionEngine.ts +1 -2
  57. package/packages/core/src/picker/catalog.ts +7 -15
  58. package/packages/core/src/picker/filePickerWorker.ts +1 -3
  59. package/packages/core/src/picker/ranker.ts +1 -1
  60. package/packages/core/src/picker/token.ts +3 -4
  61. package/packages/core/src/session/AgentRuntime.ts +5 -8
  62. package/packages/core/src/session/EventLog.ts +6 -12
  63. package/packages/core/src/session/ReadCursors.ts +3 -4
  64. package/packages/core/src/session/SearchIndex.ts +49 -86
  65. package/packages/core/src/session/SearchTokens.ts +4 -7
  66. package/packages/core/src/session/SessionCache.ts +8 -6
  67. package/packages/core/src/session/SessionDigest.ts +10 -19
  68. package/packages/core/src/session/SessionHost.ts +53 -83
  69. package/packages/core/src/session/SessionLease.ts +12 -15
  70. package/packages/core/src/session/SessionMeta.ts +16 -32
  71. package/packages/core/src/session/SessionName.ts +3 -7
  72. package/packages/core/src/session/SessionRegistry.ts +13 -29
  73. package/packages/core/src/session/SessionUi.ts +12 -16
  74. package/packages/core/src/session/WriteMark.ts +7 -16
  75. package/packages/core/src/shared/Cli.ts +1 -1
  76. package/packages/core/src/shared/DaemonUnit.ts +1 -2
  77. package/packages/core/src/shared/DiffLines.ts +16 -34
  78. package/packages/core/src/shared/DiffRenderer.ts +8 -27
  79. package/packages/core/src/shared/Directories.ts +4 -4
  80. package/packages/core/src/shared/EditMatcher.ts +18 -50
  81. package/packages/core/src/shared/ExtensionToggles.ts +3 -6
  82. package/packages/core/src/shared/FileEnumerator.ts +73 -57
  83. package/packages/core/src/shared/FileScanner.ts +5 -13
  84. package/packages/core/src/shared/FileWatch.ts +13 -17
  85. package/packages/core/src/shared/Format.ts +2 -3
  86. package/packages/core/src/shared/FuzzyMatcher.ts +18 -19
  87. package/packages/core/src/shared/Git.ts +22 -47
  88. package/packages/core/src/shared/GitMonitor.ts +12 -23
  89. package/packages/core/src/shared/GlobExclusions.ts +0 -4
  90. package/packages/core/src/shared/Http.ts +1 -1
  91. package/packages/core/src/shared/ImageMime.ts +3 -5
  92. package/packages/core/src/shared/Images.ts +17 -27
  93. package/packages/core/src/shared/Languages.ts +2 -2
  94. package/packages/core/src/shared/Levenshtein.ts +1 -6
  95. package/packages/core/src/shared/Lines.ts +1 -1
  96. package/packages/core/src/shared/McpClient.ts +2 -2
  97. package/packages/core/src/shared/PatchSummary.ts +1 -1
  98. package/packages/core/src/shared/Paths.ts +4 -1
  99. package/packages/core/src/shared/PiExtensions.ts +5 -12
  100. package/packages/core/src/shared/PimSettings.ts +14 -15
  101. package/packages/core/src/shared/Proc.ts +2 -3
  102. package/packages/core/src/shared/RateLimiter.ts +1 -1
  103. package/packages/core/src/shared/Renderer.ts +1 -3
  104. package/packages/core/src/shared/RepoDiff.ts +24 -46
  105. package/packages/core/src/shared/SearchRender.ts +3 -4
  106. package/packages/core/src/shared/SpillCache.ts +2 -3
  107. package/packages/core/src/shared/SubagentLogs.ts +4 -6
  108. package/packages/core/src/shared/Supervisor.ts +19 -32
  109. package/packages/core/src/shared/Surface.ts +1 -1
  110. package/packages/core/src/shared/Sweeper.ts +1 -1
  111. package/packages/core/src/shared/Tools.ts +17 -30
  112. package/packages/core/src/shared/Updater.ts +15 -15
  113. package/packages/core/src/view/BodyRenderer.ts +1 -1
  114. package/packages/core/src/view/DiffBlocks.ts +0 -1
  115. package/packages/core/src/view/DiffExpand.ts +10 -25
  116. package/packages/core/src/view/DiffLayout.ts +2 -2
  117. package/packages/core/src/view/DiffPairs.ts +2 -2
  118. package/packages/core/src/view/MarkdownPainter.ts +2 -19
  119. package/packages/core/src/view/MovePath.ts +4 -17
  120. package/packages/core/src/view/Painting.ts +4 -4
  121. package/packages/core/src/view/ViewBlock.ts +11 -12
  122. package/packages/daemon/src/Daemon.ts +2 -7
  123. package/packages/daemon/src/DaemonInstall.ts +5 -12
  124. package/packages/daemon/src/Surfaces.ts +3 -12
  125. package/packages/daemon/src/TelegramSurface.ts +0 -1
  126. package/packages/daemon/src/index.ts +0 -1
  127. package/packages/protocol/src/Command.ts +33 -41
  128. package/packages/protocol/src/Diff.ts +0 -5
  129. package/packages/protocol/src/ImageRoute.ts +2 -5
  130. package/packages/protocol/src/ServerEvent.ts +68 -105
  131. package/packages/server/src/AttachmentEndpoint.ts +45 -19
  132. package/packages/server/src/ClientConnection.ts +11 -12
  133. package/packages/server/src/ImageEndpoint.ts +3 -4
  134. package/packages/server/src/ProbeClient.ts +26 -59
  135. package/packages/server/src/Reloader.ts +4 -7
  136. package/packages/server/src/SendFileTool.ts +1 -1
  137. package/packages/server/src/SessionCatalogue.ts +35 -47
  138. package/packages/server/src/SessionProjection.ts +7 -12
  139. package/packages/server/src/SessionStream.ts +33 -80
  140. package/packages/server/src/StaticClient.ts +7 -8
  141. package/packages/server/src/WebOptions.ts +2 -6
  142. package/packages/server/src/WsGateway.ts +35 -96
  143. package/packages/server/src/probe.ts +6 -18
  144. package/packages/telegram/src/Bot.ts +2 -2
  145. package/packages/telegram/src/Commands.ts +108 -65
  146. package/packages/telegram/src/Config.ts +1 -6
  147. package/packages/telegram/src/Markdown.ts +4 -13
  148. package/packages/telegram/src/Renderer.ts +1 -1
  149. package/packages/telegram/src/Session.ts +3 -10
  150. package/packages/telegram/src/TaskScheduler.ts +31 -10
  151. package/packages/telegram/src/TaskStore.ts +11 -1
  152. package/packages/telegram/src/TaskTool.ts +1 -1
  153. package/packages/telegram/src/UpdateConfirm.ts +2 -2
  154. package/packages/tui/src/extensions/_init/index.ts +2 -5
  155. package/packages/tui/src/extensions/file-picker/index.ts +2 -6
  156. package/packages/tui/src/extensions/footer/index.ts +0 -1
  157. package/packages/tui/src/extensions/footer/powerline.ts +16 -28
  158. package/packages/tui/src/extensions/pim/index.ts +1 -1
  159. package/packages/tui/src/extensions/session-lease/index.ts +5 -6
  160. package/packages/tui/src/extensions/working-indicator/index.ts +1 -2
  161. package/packages/tui/src/themes/themeCliArgs.ts +1 -1
  162. package/packages/web/dist/client/assets/{abnfDiagram-O67JEVCF-CZ7V84ot.js → abnfDiagram-O67JEVCF-WweOU5DK.js} +1 -1
  163. package/packages/web/dist/client/assets/{arc-DiHGkUvc.js → arc-O2PmZXWt.js} +1 -1
  164. package/packages/web/dist/client/assets/architecture-7GRP2DOG-COBxVilU.js +1 -0
  165. package/packages/web/dist/client/assets/{architectureDiagram-NJMV4G6O-XS5DhfJB.js → architectureDiagram-NJMV4G6O-DwYq1YaM.js} +1 -1
  166. package/packages/web/dist/client/assets/{blockDiagram-BEXU5L5S-BCsgLvy1.js → blockDiagram-BEXU5L5S-CVab041n.js} +1 -1
  167. package/packages/web/dist/client/assets/{c4Diagram-YGBWAQC7-Bj9LcWNm.js → c4Diagram-YGBWAQC7-BmotHez3.js} +1 -1
  168. package/packages/web/dist/client/assets/channel-BKV-IcTA.js +1 -0
  169. package/packages/web/dist/client/assets/{chunk-3FUC2YCW-BmDurFxp.js → chunk-3FUC2YCW-CWNS7-n4.js} +1 -1
  170. package/packages/web/dist/client/assets/{chunk-5DYCD2WN-DAjG-pqn.js → chunk-5DYCD2WN-DflvXohu.js} +1 -1
  171. package/packages/web/dist/client/assets/{chunk-742MDFTN-Bmxs5puY.js → chunk-742MDFTN-B_0t6_RE.js} +1 -1
  172. package/packages/web/dist/client/assets/{chunk-7INBJB4K-Di7kIxrQ.js → chunk-7INBJB4K-wKj0Q3Kv.js} +1 -1
  173. package/packages/web/dist/client/assets/{chunk-7M6MHVWA-CSc8sR0b.js → chunk-7M6MHVWA-BMvUghc8.js} +1 -1
  174. package/packages/web/dist/client/assets/{chunk-7PRAP22T-C8kd5QvY.js → chunk-7PRAP22T-BY41wkcT.js} +1 -1
  175. package/packages/web/dist/client/assets/{chunk-GTNCS2PH-DG2b2LYE.js → chunk-GTNCS2PH-PqY_YoS0.js} +1 -1
  176. package/packages/web/dist/client/assets/{chunk-GWA4HPMP-DdLaLQCu.js → chunk-GWA4HPMP-fozSU5ty.js} +1 -1
  177. package/packages/web/dist/client/assets/{chunk-MBY4JIJT-C1j0yQlk.js → chunk-MBY4JIJT-CrHrC3jw.js} +1 -1
  178. package/packages/web/dist/client/assets/{chunk-NETBCI7D-Bfq9H74p.js → chunk-NETBCI7D-DWdAxieG.js} +1 -1
  179. package/packages/web/dist/client/assets/{chunk-O7XYJQB3-ZHvBmBO-.js → chunk-O7XYJQB3-B6uOn9iS.js} +1 -1
  180. package/packages/web/dist/client/assets/{chunk-UA2S7LBM-ku1JeHSK.js → chunk-UA2S7LBM-BxYSHqyy.js} +1 -1
  181. package/packages/web/dist/client/assets/{chunk-WEXAMYUT-BP1iga_7.js → chunk-WEXAMYUT-CtwIaQDa.js} +1 -1
  182. package/packages/web/dist/client/assets/{chunk-XXDRQBXY-BBeccPcX.js → chunk-XXDRQBXY-fgBFe-PX.js} +1 -1
  183. package/packages/web/dist/client/assets/{chunk-Z7XXMR3K-SMHZugaR.js → chunk-Z7XXMR3K-CPonoV3p.js} +1 -1
  184. package/packages/web/dist/client/assets/{chunk-ZIGJFQKS-CFU_JLG4.js → chunk-ZIGJFQKS-Cdu87cTj.js} +1 -1
  185. package/packages/web/dist/client/assets/{classDiagram-v2-NBCMYWYE-CYviuQzJ.js → classDiagram-v2-NBCMYWYE-DSWsPaa7.js} +1 -1
  186. package/packages/web/dist/client/assets/{core-DyHsgs5k.js → core-CBoS7AST.js} +1 -1
  187. package/packages/web/dist/client/assets/{cose-bilkent-JH36ORCC-9v2ZkJzo.js → cose-bilkent-JH36ORCC-CTwlldtJ.js} +1 -1
  188. package/packages/web/dist/client/assets/{cynefin-OW5HDTMX-Bx5xRadi.js → cynefin-OW5HDTMX-CZQ4EPNJ.js} +1 -1
  189. package/packages/web/dist/client/assets/{cynefinDiagram-VND7K2PF-BRfGDKqa.js → cynefinDiagram-VND7K2PF-C2gp6H_Q.js} +1 -1
  190. package/packages/web/dist/client/assets/{dagre-6A5THRUB-C4l-2L2e.js → dagre-6A5THRUB-CDxTP47t.js} +1 -1
  191. package/packages/web/dist/client/assets/{diagram-22UHCM2B-d_hQ3kyi.js → diagram-22UHCM2B-BIohE1lI.js} +1 -1
  192. package/packages/web/dist/client/assets/{diagram-3UASUU5V-DrEeguPI.js → diagram-3UASUU5V-TwAUir-w.js} +1 -1
  193. package/packages/web/dist/client/assets/{diagram-ATOU4E4O-BmfQ22pD.js → diagram-ATOU4E4O-BM1JQrIu.js} +1 -1
  194. package/packages/web/dist/client/assets/{diagram-CDSNMT55-BjVWjuPF.js → diagram-CDSNMT55-BKIqhxSI.js} +1 -1
  195. package/packages/web/dist/client/assets/{diagram-MLGK6HIB-wDjk-O8i.js → diagram-MLGK6HIB-CVe3QDHr.js} +1 -1
  196. package/packages/web/dist/client/assets/{diagram-MPIPVDR6-DqXQFE1s.js → diagram-MPIPVDR6-Bj-MQIFI.js} +1 -1
  197. package/packages/web/dist/client/assets/{dist-BddGOpie.js → dist-DlZpcyc2.js} +1 -1
  198. package/packages/web/dist/client/assets/{ebnfDiagram-ZINNZB2B-UB8kOITM.js → ebnfDiagram-ZINNZB2B-C06mmvmz.js} +1 -1
  199. package/packages/web/dist/client/assets/{elk-276RUBZZ-D4miYQnD.js → elk-276RUBZZ-CizJSNEj.js} +1 -1
  200. package/packages/web/dist/client/assets/{erDiagram-OPXOYQCR--RXKv7KH.js → erDiagram-OPXOYQCR-M3FQkKI1.js} +1 -1
  201. package/packages/web/dist/client/assets/eventmodeling-NTZA5JFV-D_UXLpIu.js +1 -0
  202. package/packages/web/dist/client/assets/flowDiagram-KWPJA3E3-BT4eEEVm.js +1 -0
  203. package/packages/web/dist/client/assets/{ganttDiagram-FUAMR5RP-C0CFpE5x.js → ganttDiagram-FUAMR5RP-CojF9Q16.js} +1 -1
  204. package/packages/web/dist/client/assets/{gitGraph-4MIJSDKK-VPL7nv2c.js → gitGraph-4MIJSDKK-YvKqGEPk.js} +1 -1
  205. package/packages/web/dist/client/assets/{gitGraphDiagram-X574FWY7-CgxJA-T8.js → gitGraphDiagram-X574FWY7-XqNqIFo9.js} +1 -1
  206. package/packages/web/dist/client/assets/index--2CDtzvY.css +1 -0
  207. package/packages/web/dist/client/assets/{index-XTlTnQmx.js → index-bT6QPJZs.js} +7 -7
  208. package/packages/web/dist/client/assets/{info-A6RAGUB7-P0-o68pj.js → info-A6RAGUB7-B_1BCzM2.js} +1 -1
  209. package/packages/web/dist/client/assets/{infoDiagram-VRGFBTTK-DFJZNRUP.js → infoDiagram-VRGFBTTK-zFX8B-dP.js} +1 -1
  210. package/packages/web/dist/client/assets/{ishikawaDiagram-OU5B5YK6-ZkyhNd1T.js → ishikawaDiagram-OU5B5YK6-DLzQ_Uyf.js} +1 -1
  211. package/packages/web/dist/client/assets/{journeyDiagram-ZHPQQLJL-DFevH8my.js → journeyDiagram-ZHPQQLJL-S3WRMmoa.js} +1 -1
  212. package/packages/web/dist/client/assets/{kanban-definition-PNTS6WVX-l7e7ZZDC.js → kanban-definition-PNTS6WVX-B5Z8I-kM.js} +1 -1
  213. package/packages/web/dist/client/assets/{line-DO_s6Ujd.js → line-BGMH-i2X.js} +1 -1
  214. package/packages/web/dist/client/assets/{linear-C4xH5PPc.js → linear-KsrestXG.js} +1 -1
  215. package/packages/web/dist/client/assets/{mermaid-parser.core-nQaTP3VY.js → mermaid-parser.core-DNffyJJA.js} +3 -3
  216. package/packages/web/dist/client/assets/{mermaid.core-Cz05yTZh.js → mermaid.core-Cz3vJeQG.js} +4 -4
  217. package/packages/web/dist/client/assets/{mindmap-definition-NLK3R4M7-CHOEuHm2.js → mindmap-definition-NLK3R4M7-CzA61XUf.js} +1 -1
  218. package/packages/web/dist/client/assets/{packet-AYTQ26CC-BH3ehPMo.js → packet-AYTQ26CC-BO55e7cR.js} +1 -1
  219. package/packages/web/dist/client/assets/{pegDiagram-GJSIUBJH-CkWBLtad.js → pegDiagram-GJSIUBJH-DeRiXYNd.js} +1 -1
  220. package/packages/web/dist/client/assets/{pie-WAS4IAKB-nNVEq3dx.js → pie-WAS4IAKB-D9ibrQRe.js} +1 -1
  221. package/packages/web/dist/client/assets/{pieDiagram-5QR66LMP-DimUBAgN.js → pieDiagram-5QR66LMP-BaBpPP33.js} +1 -1
  222. package/packages/web/dist/client/assets/{quadrantDiagram-O4NWA36T-BR0XpRGQ.js → quadrantDiagram-O4NWA36T-DIfn4GjM.js} +1 -1
  223. package/packages/web/dist/client/assets/{radar-RG4KPBEZ-paA-H3mb.js → radar-RG4KPBEZ-Dmn5-nJq.js} +1 -1
  224. package/packages/web/dist/client/assets/{railroad-74A4TZTK-yEiKB3rz.js → railroad-74A4TZTK-ZCWNEd2Z.js} +1 -1
  225. package/packages/web/dist/client/assets/railroad-abnf-HS5TGJTU-_swqhy0y.js +1 -0
  226. package/packages/web/dist/client/assets/railroad-ebnf-LZEXJU2U-CytbazPx.js +1 -0
  227. package/packages/web/dist/client/assets/railroad-peg-WCYAUIDC-Bg8QW17T.js +1 -0
  228. package/packages/web/dist/client/assets/{railroadDiagram-XR7U4H2S--TXe6rdU.js → railroadDiagram-XR7U4H2S-CDPZ39sy.js} +1 -1
  229. package/packages/web/dist/client/assets/{requirementDiagram-PLB6GJNP-DyqH36Za.js → requirementDiagram-PLB6GJNP-CyCI8Yul.js} +1 -1
  230. package/packages/web/dist/client/assets/{sankeyDiagram-IPEJSGJF-Bg6e3BlM.js → sankeyDiagram-IPEJSGJF-p_XAPv72.js} +1 -1
  231. package/packages/web/dist/client/assets/{sequenceDiagram-PO4LG4MO-ClGf85My.js → sequenceDiagram-PO4LG4MO-DmR6IP_o.js} +1 -1
  232. package/packages/web/dist/client/assets/{src-DF7hQfMh.js → src-gnv7pJ1z.js} +1 -1
  233. package/packages/web/dist/client/assets/{stateDiagram-v2-GCMORJYK-BK8TpxNo.js → stateDiagram-v2-GCMORJYK-7ZTHl6ih.js} +1 -1
  234. package/packages/web/dist/client/assets/{swimlanes-2SLR337P-DDnTIT9M.js → swimlanes-2SLR337P-N6bj71pw.js} +1 -1
  235. package/packages/web/dist/client/assets/swimlanesDiagram-TC7HE7FX-BJQ2CBsp.js +8 -0
  236. package/packages/web/dist/client/assets/{timeline-definition-EJHVYXUP-mBBbH3bk.js → timeline-definition-EJHVYXUP-GNez0kW8.js} +1 -1
  237. package/packages/web/dist/client/assets/{treeView-Q6P3EWNA-CTK7tRwR.js → treeView-Q6P3EWNA-DyQZkboR.js} +1 -1
  238. package/packages/web/dist/client/assets/{treemap-WGGIJYW6-vOI-Ef_m.js → treemap-WGGIJYW6-_J8Pw2TM.js} +1 -1
  239. package/packages/web/dist/client/assets/{usecaseDiagram-POWQR4AR-COcii8x-.js → usecaseDiagram-POWQR4AR-Bg-CzKjl.js} +1 -1
  240. package/packages/web/dist/client/assets/{vennDiagram-UO4OBE2U-D6kmDGpM.js → vennDiagram-UO4OBE2U-DBQKHXhK.js} +1 -1
  241. package/packages/web/dist/client/assets/{wardley-WFR3VGLG-CtE2KI9r.js → wardley-WFR3VGLG-B5aAsQ3F.js} +1 -1
  242. package/packages/web/dist/client/assets/{wardleyDiagram-VNRHLVJA-ncxNGWnW.js → wardleyDiagram-VNRHLVJA-BKUQ1LK6.js} +1 -1
  243. package/packages/web/dist/client/assets/{xychartDiagram-PMCCYNJV-DUvd2Qze.js → xychartDiagram-PMCCYNJV-BI2sVbks.js} +1 -1
  244. package/packages/web/dist/client/index.html +2 -2
  245. package/packages/web/dist/client/assets/architecture-7GRP2DOG-HIzEIkwQ.js +0 -1
  246. package/packages/web/dist/client/assets/channel-BCA6qe9I.js +0 -1
  247. package/packages/web/dist/client/assets/eventmodeling-NTZA5JFV-l6SYFw1s.js +0 -1
  248. package/packages/web/dist/client/assets/flowDiagram-KWPJA3E3-CWW9qnqm.js +0 -1
  249. package/packages/web/dist/client/assets/index-D9_XJLSc.css +0 -1
  250. package/packages/web/dist/client/assets/railroad-abnf-HS5TGJTU-mVQx9aVM.js +0 -1
  251. package/packages/web/dist/client/assets/railroad-ebnf-LZEXJU2U-CllXx1OJ.js +0 -1
  252. package/packages/web/dist/client/assets/railroad-peg-WCYAUIDC-BBD2Q5W_.js +0 -1
  253. package/packages/web/dist/client/assets/swimlanesDiagram-TC7HE7FX-CM8UnP5t.js +0 -8
@@ -27,7 +27,7 @@ export type ReadRange = {
27
27
  readonly end?: number;
28
28
  };
29
29
 
30
- export type ReadTextDetails = {
30
+ type ReadTextDetails = {
31
31
  readonly kind: "text";
32
32
  readonly absolutePath: string;
33
33
  readonly totalLines: number;
@@ -42,7 +42,7 @@ export type ReadTextDetails = {
42
42
  export type ReadImageDetails = ImageDetails & {
43
43
  readonly kind: "image";
44
44
  readonly absolutePath: string;
45
- /** Sent earlier in this conversation and unchanged since, so only the note went to the model. */
45
+ /** Only a note was sent; the image went out earlier. */
46
46
  readonly deduped?: boolean;
47
47
  };
48
48
 
@@ -28,7 +28,7 @@ export function formatCallTitle(prompt: string | undefined): string {
28
28
  return (prompt ?? "...").split(/\r?\n/u)[0]?.trim() || "...";
29
29
  }
30
30
 
31
- /** The status line the parent model reads while the call streams: the summary flattened. */
31
+ /** The summary as plain text, for streaming updates. */
32
32
  export function formatTopLine(details: SubagentDetails): string {
33
33
  return summarySpans(details, details.stopReason === undefined)
34
34
  .map((span) => span.text)
@@ -57,7 +57,7 @@ function summarySpans(
57
57
  details: SubagentDetails,
58
58
  isPartial: boolean
59
59
  ): readonly Span[] {
60
- // `details` is typed whole but may not be: pi empties it on failure, and old sessions lack usage.
60
+ // pi empties `details` on failure, and old sessions lack usage.
61
61
  if (details.usage === undefined) {
62
62
  return [];
63
63
  }
@@ -20,9 +20,8 @@ import { MessageText } from "../../session/MessageText";
20
20
  import { CoreExtensions } from "../CoreExtensions";
21
21
  import { formatTopLine } from "./render";
22
22
 
23
- export const PER_TASK_OUTPUT_CAP = 32 * 1024;
24
- export const SUBAGENT_TOOL_NAME = "subagent";
25
-
23
+ const PER_TASK_OUTPUT_CAP = 32 * 1024;
24
+ const SUBAGENT_TOOL_NAME = "subagent";
26
25
  export const UPDATE_INTERVAL_MS = 100;
27
26
 
28
27
  const inSubagent = new AsyncLocalStorage<true>();
@@ -38,7 +37,6 @@ export type SubagentUsage = {
38
37
  };
39
38
 
40
39
  export type SubagentSnapshot = {
41
- /** The child's session id, for a log reader; a transcript is found from the call id, not this. */
42
40
  readonly sessionId: string | undefined;
43
41
  readonly usage: SubagentUsage;
44
42
  readonly stopReason: string | undefined;
@@ -47,7 +45,7 @@ export type SubagentSnapshot = {
47
45
  readonly contextWindow: number | undefined;
48
46
  };
49
47
 
50
- /** `returnedOutput` is the capped answer for the parent model; `fullOutput` is every word written. */
48
+ /** `returnedOutput` is the capped last message; `fullOutput` is every message. */
51
49
  export type SubagentDetails = SubagentSnapshot & {
52
50
  readonly returnedOutput: string;
53
51
  readonly fullOutput: string;
@@ -67,9 +65,9 @@ export type SubagentSession = {
67
65
 
68
66
  export type SubagentSessionSpec = {
69
67
  readonly activeToolNames?: readonly string[];
70
- /** The parent's live level; left unset, pi falls back to settings, not to the parent. */
68
+ /** Unset falls back to pi's settings, not the parent's level. */
71
69
  readonly thinkingLevel?: ThinkingLevel;
72
- /** The parent's tool call id, which names the child's log on disk. */
70
+ /** Names the child's log file. */
73
71
  readonly callId?: string;
74
72
  };
75
73
 
@@ -90,7 +88,7 @@ export function childToolNames(
90
88
  return activeToolNames.filter((name) => name !== SUBAGENT_TOOL_NAME);
91
89
  }
92
90
 
93
- // The child inherits no registrations: without this roster its `tools` allowlist loses every pim tool.
91
+ // The child inherits no registrations; without these its `tools` allowlist drops every pim tool.
94
92
  export function childLoaderOptions(cwd: string): {
95
93
  readonly cwd: string;
96
94
  readonly agentDir: string;
@@ -103,7 +101,7 @@ export function childLoaderOptions(cwd: string): {
103
101
  };
104
102
  }
105
103
 
106
- export async function createSdkSubagentSession(
104
+ async function createSdkSubagentSession(
107
105
  parentCtx: ExtensionContext,
108
106
  spec: SubagentSessionSpec = {}
109
107
  ): Promise<SubagentSession> {
@@ -125,7 +123,7 @@ export async function createSdkSubagentSession(
125
123
  return session;
126
124
  }
127
125
 
128
- // `open`, not `create`: the log path must be derivable from the parent session id and call id.
126
+ // `open`, not `create`, so the log path is derived from the parent session id and call id.
129
127
  async function childSessionManager(
130
128
  parentCtx: ExtensionContext,
131
129
  callId: string | undefined
@@ -279,7 +277,6 @@ export class SubagentEventCapture {
279
277
  this.emitUpdate();
280
278
  }
281
279
 
282
- /** Drops a throttled update still in flight once the run is over. */
283
280
  public dispose(): void {
284
281
  this.cancelPending();
285
282
  }
@@ -295,7 +292,7 @@ export class SubagentEventCapture {
295
292
  };
296
293
  }
297
294
 
298
- /** Everything the child wrote, one paragraph per assistant message, including a streaming one. */
295
+ /** All assistant messages so far, including one still streaming. */
299
296
  public narration(): string {
300
297
  const said =
301
298
  this.pendingText === ""
@@ -358,15 +355,7 @@ export class SubagentEventCapture {
358
355
  }
359
356
  }
360
357
 
361
- type MutableUsage = {
362
- input: number;
363
- output: number;
364
- cacheRead: number;
365
- cacheWrite: number;
366
- cost: number;
367
- turns: number;
368
- contextTokens: number | undefined;
369
- };
358
+ type MutableUsage = { -readonly [K in keyof SubagentUsage]: SubagentUsage[K] };
370
359
 
371
360
  export type OutputCapResult = {
372
361
  readonly text: string;
@@ -15,8 +15,7 @@ const DATETIME_MESSAGE_TYPE = "pim-datetime";
15
15
 
16
16
  export default function (surface?: Surface): ExtensionFactory {
17
17
  return (pi: ExtensionAPI): void => {
18
- // On submit rather than in `before_agent_start`, which can only append
19
- // behind the user's message.
18
+ // `before_agent_start` could only append after the user's message.
20
19
  pi.on("input", () => {
21
20
  pi.sendMessage(
22
21
  {
@@ -78,7 +78,7 @@ export function buildEnvironment(opts: EnvironmentOptions): string {
78
78
  ].join("\n");
79
79
  }
80
80
 
81
- /** What the surface renders beyond plain text; empty, so pi omits the section, where that is nothing. */
81
+ /** Empty makes pi omit the section. */
82
82
  export function buildFormatting(surface: Surface | undefined): string {
83
83
  return surface === undefined ? "" : FORMATTING[surface];
84
84
  }
@@ -110,8 +110,6 @@ function computeOs(options: OsDescriptionOptions): string {
110
110
  return undefined;
111
111
  }
112
112
  });
113
- const unixName = (): string | undefined => runCommand(["uname", "-sr"]);
114
-
115
113
  if (platform === "linux") {
116
114
  const osRelease = runCommand(["cat", "/etc/os-release"]);
117
115
  if (osRelease) {
@@ -147,7 +145,7 @@ function computeOs(options: OsDescriptionOptions): string {
147
145
  return ver?.replace(/\s+/g, " ").trim() || platform;
148
146
  }
149
147
 
150
- return unixName() ?? platform;
148
+ return runCommand(["uname", "-sr"]) ?? platform;
151
149
  }
152
150
 
153
151
  type FieldParser = (line: string) => readonly [string, string] | undefined;
@@ -47,10 +47,7 @@ function inProgressSection(items: readonly TodoItem[]): readonly ViewBlock[] {
47
47
  ];
48
48
  }
49
49
 
50
- export function formatWidgetTitle(
51
- items: readonly TodoItem[],
52
- theme: Theme
53
- ): string {
50
+ function formatWidgetTitle(items: readonly TodoItem[], theme: Theme): string {
54
51
  const total = theme.bold(Format.count(items.length, "todo"));
55
52
  const summary = formatStatusSummary(items);
56
53
  return summary ? `${total} (${summary})` : total;
@@ -14,7 +14,6 @@ export type FormatChecklistOptions = {
14
14
  readonly activeOnly?: boolean;
15
15
  };
16
16
 
17
- /** Identity key for the per-session state slot. */
18
17
  export type TodoSessionKey = ExtensionContext["sessionManager"];
19
18
 
20
19
  const itemsBySession = new WeakMap<TodoSessionKey, TodoItem[]>();
@@ -67,7 +66,7 @@ export function hasActiveItems(items: readonly TodoItem[]): boolean {
67
66
  return items.some(isActive);
68
67
  }
69
68
 
70
- export function summarizeItems(items: readonly TodoItem[]): TodoSummary {
69
+ function summarizeItems(items: readonly TodoItem[]): TodoSummary {
71
70
  const summary: TodoSummary = {
72
71
  pending: 0,
73
72
  in_progress: 0,
@@ -129,32 +128,26 @@ function findLatestTodoItems(branch: readonly unknown[]): TodoItem[] {
129
128
  }
130
129
 
131
130
  function extractTodoItems(entry: unknown): TodoItem[] | undefined {
131
+ const holder = todoHolder(entry);
132
+ return isRecord(holder) && Array.isArray(holder.todos)
133
+ ? normalizeUnknownItems(holder.todos)
134
+ : undefined;
135
+ }
136
+
137
+ /** The todo tool result's details, or a compaction checkpoint's data. */
138
+ function todoHolder(entry: unknown): unknown {
132
139
  if (!isRecord(entry)) {
133
140
  return undefined;
134
141
  }
135
- if (entry.type === "message") {
136
- const message = entry.message;
137
- if (
138
- !isRecord(message) ||
139
- message.role !== "toolResult" ||
140
- message.toolName !== "todo"
141
- ) {
142
- return undefined;
143
- }
144
- const details = message.details;
145
- if (!isRecord(details) || !Array.isArray(details.todos)) {
146
- return undefined;
147
- }
148
- return normalizeUnknownItems(details.todos);
149
- }
150
142
  if (entry.type === "custom" && entry.customType === TODO_STATE_CUSTOM_TYPE) {
151
- const data = entry.data;
152
- if (!isRecord(data) || !Array.isArray(data.todos)) {
153
- return undefined;
154
- }
155
- return normalizeUnknownItems(data.todos);
143
+ return entry.data;
156
144
  }
157
- return undefined;
145
+ const message = entry.type === "message" ? entry.message : undefined;
146
+ return isRecord(message) &&
147
+ message.role === "toolResult" &&
148
+ message.toolName === "todo"
149
+ ? message.details
150
+ : undefined;
158
151
  }
159
152
 
160
153
  function normalizeUnknownItems(items: readonly unknown[]): TodoItem[] {
@@ -155,17 +155,9 @@ function requiredString(value: unknown, name: string): string {
155
155
  }
156
156
 
157
157
  function optionalString(value: unknown, name: string): string | undefined {
158
- if (value === undefined || value === null) {
159
- return undefined;
160
- }
161
-
162
- if (typeof value !== "string") {
163
- throw new JinaReaderClientError(
164
- `Response contained invalid payload: expected string ${name}.`
165
- );
166
- }
167
-
168
- return value;
158
+ return value === undefined || value === null
159
+ ? undefined
160
+ : requiredString(value, name);
169
161
  }
170
162
 
171
163
  function stringifyErrorData(data: unknown): string {
@@ -171,9 +171,7 @@ function readSnapshot(value: unknown): WebViewSnapshot {
171
171
  function safeClose(view: WebViewLike): void {
172
172
  try {
173
173
  view.close();
174
- } catch {
175
- // close() throws if already closed.
176
- }
174
+ } catch {}
177
175
  }
178
176
 
179
177
  function defaultFactory(): WebViewLike {
@@ -9,7 +9,7 @@ import type { JinaReaderClient } from "./JinaReaderClient";
9
9
  import {
10
10
  WEB_FETCH_INLINE_BYTES,
11
11
  type WebFetchFormat,
12
- type WebFetchResolvedFormat,
12
+ type WebFetchPageDetails,
13
13
  } from "./schema";
14
14
  import type { WebViewFetchClient } from "./WebViewFetchClient";
15
15
 
@@ -19,16 +19,8 @@ export type WebFetchPage = {
19
19
  readonly content: string;
20
20
  };
21
21
 
22
- export type WebFetchPageOutcome = {
23
- readonly kind: "page";
22
+ export type WebFetchPageOutcome = WebFetchPageDetails & {
24
23
  readonly text: string;
25
- readonly title: string;
26
- readonly url: string;
27
- readonly format: WebFetchResolvedFormat;
28
- readonly returnedBytes: number;
29
- readonly totalBytes: number;
30
- readonly truncated: boolean;
31
- readonly path: string | null;
32
24
  };
33
25
 
34
26
  export type WebFetchOutcome = WebFetchPageOutcome | WebFetchImageOutcome;
@@ -73,7 +65,7 @@ export function validatePublicUrl(value: string): string {
73
65
 
74
66
  export async function formatOutcome(
75
67
  page: WebFetchPage,
76
- format: WebFetchResolvedFormat
68
+ format: WebFetchFormat
77
69
  ): Promise<WebFetchPageOutcome> {
78
70
  const { body, returnedBytes, totalBytes, truncated } =
79
71
  OutputBudget.truncateUtf8(page.content, WEB_FETCH_INLINE_BYTES);
@@ -120,7 +112,7 @@ export type ExecuteFetchInput = {
120
112
  readonly url: string;
121
113
  readonly format: WebFetchFormat;
122
114
  readonly signal?: AbortSignal;
123
- /** Only the image probe takes it; the readers own their own transports. */
115
+ /** Used only by the image probe. */
124
116
  readonly fetch?: HttpFetch;
125
117
  };
126
118
 
@@ -20,7 +20,7 @@ const TIMEOUT_MS = 20_000;
20
20
 
21
21
  const IMAGE_CONTENT_TYPE = /^image\//iu;
22
22
 
23
- /** The picture the URL really serves, or null for anything the page path should handle. */
23
+ /** Null when the URL does not serve an image. */
24
24
  export async function fetchImage(
25
25
  input: ImageFetchInput
26
26
  ): Promise<NormalisedImage | null> {
@@ -49,7 +49,6 @@ export function imageContent(
49
49
  return [...Images.contentOf(image, Images.noteOf(image)), ...footer];
50
50
  }
51
51
 
52
- /** The fetch succeeded and the intent was ambiguous, so the model is told what it got, not refused. */
53
52
  export function noVisionNote(url: string, image: NormalisedImage): string {
54
53
  const saved = image.cachePath === null ? "" : `, saved to ${image.cachePath}`;
55
54
  return Images.noVisionNote(
@@ -72,7 +71,7 @@ export function imageDetails(
72
71
  };
73
72
  }
74
73
 
75
- /** A response whose own headers claim a picture; the bytes still have to agree. */
74
+ /** A response whose headers claim an image; the bytes are sniffed later. */
76
75
  async function declaredImage(input: ImageFetchInput): Promise<Response | null> {
77
76
  let response: Response;
78
77
 
@@ -105,7 +104,7 @@ async function declaredImage(input: ImageFetchInput): Promise<Response | null> {
105
104
  return response;
106
105
  }
107
106
 
108
- /** Stops at the cap and at the first chunk that is not a picture, so neither is ever buffered whole. */
107
+ /** Stops early on oversize or on bytes that don't sniff as an image. */
109
108
  async function readCapped(
110
109
  response: Response,
111
110
  url: string
@@ -64,19 +64,8 @@ export default function (pi: ExtensionAPI): void {
64
64
  };
65
65
  }
66
66
 
67
- return {
68
- content: [{ type: "text", text: outcome.text }],
69
- details: {
70
- kind: "page",
71
- url: outcome.url,
72
- title: outcome.title,
73
- format: outcome.format,
74
- returnedBytes: outcome.returnedBytes,
75
- totalBytes: outcome.totalBytes,
76
- truncated: outcome.truncated,
77
- path: outcome.path,
78
- },
79
- };
67
+ const { text, ...details } = outcome;
68
+ return { content: [{ type: "text", text }], details };
80
69
  },
81
70
  toViewModel: webFetchView,
82
71
  });
@@ -9,14 +9,13 @@ import type {
9
9
  WebFetchFormat,
10
10
  WebFetchImageDetails,
11
11
  WebFetchInput,
12
- WebFetchResolvedFormat,
13
12
  webFetchSchema,
14
13
  } from "./schema";
15
14
 
16
15
  type WebFetchViewInput = ToolViewInput<typeof webFetchSchema, WebFetchDetails>;
17
16
 
18
17
  type TitleOutcome = {
19
- readonly format: WebFetchResolvedFormat;
18
+ readonly format: WebFetchFormat;
20
19
  readonly totalBytes: number;
21
20
  };
22
21
 
@@ -41,7 +40,7 @@ export function webFetchView({ args, result }: WebFetchViewInput): ToolView {
41
40
  };
42
41
  }
43
42
 
44
- /** Legacy sessions predate the tag, so anything untagged reads as a page. */
43
+ /** Untagged (legacy) details are pages. */
45
44
  function imageDetailsOf(
46
45
  details: WebFetchDetails | undefined
47
46
  ): WebFetchImageDetails | undefined {
@@ -95,6 +94,6 @@ function formatDetail(
95
94
  : `${Format.bytesCompact(outcome.totalBytes)} ${label}`;
96
95
  }
97
96
 
98
- function formatLabel(format: WebFetchResolvedFormat): string {
97
+ function formatLabel(format: WebFetchFormat): string {
99
98
  return format === "html" ? "HTML" : "Markdown";
100
99
  }
@@ -6,7 +6,6 @@ export const WEB_FETCH_INLINE_BYTES = 32 * 1024;
6
6
 
7
7
  export const FETCH_FORMATS = ["markdown", "html"] as const;
8
8
  export type WebFetchFormat = (typeof FETCH_FORMATS)[number];
9
- export type WebFetchResolvedFormat = WebFetchFormat;
10
9
 
11
10
  export const webFetchSchema = Type.Object({
12
11
  url: Type.String({
@@ -27,7 +26,7 @@ export type WebFetchPageDetails = {
27
26
  readonly kind: "page";
28
27
  readonly url: string;
29
28
  readonly title: string;
30
- readonly format: WebFetchResolvedFormat;
29
+ readonly format: WebFetchFormat;
31
30
  readonly returnedBytes: number;
32
31
  readonly totalBytes: number;
33
32
  readonly truncated: boolean;
@@ -37,9 +36,9 @@ export type WebFetchPageDetails = {
37
36
  export type WebFetchImageDetails = ImageDetails & {
38
37
  readonly kind: "image";
39
38
  readonly url: string;
40
- /** `~/.pim/cache/img-<sha256>.<ext>`, or null when the cache write failed. */
39
+ /** Null when the cache write failed. */
41
40
  readonly path: string | null;
42
- /** Cached and shown here, but never sent: the current model has no vision input. */
41
+ /** Not sent because the model has no vision input. */
43
42
  readonly withheld: boolean;
44
43
  };
45
44
 
@@ -19,6 +19,8 @@ type ExaSearchInput = {
19
19
  readonly signal?: AbortSignal;
20
20
  };
21
21
 
22
+ type ResultObject = Readonly<Record<string, unknown>>;
23
+
22
24
  class ExaSearchError extends Error {
23
25
  public constructor(message: string) {
24
26
  super(message);
@@ -28,7 +30,7 @@ class ExaSearchError extends Error {
28
30
 
29
31
  const defaultEndpoint = "https://mcp.exa.ai/mcp";
30
32
  const toolName = "web_search_exa";
31
- // Stay under the keyless endpoint's 2 req/s window, or a 429 no longer means the daily cap.
33
+ // Stay under the keyless 2 req/s limit so a 429 means the daily cap.
32
34
  const maxRequestsPerWindow = 2;
33
35
  const windowMs = 1100;
34
36
 
@@ -40,7 +42,7 @@ export class ExaMcpClient {
40
42
  options.apiKey === undefined || options.apiKey.length === 0
41
43
  ? undefined
42
44
  : options.apiKey;
43
- // Throttle only on the free tier; an API key lifts the rate limit.
45
+ // An API key lifts the rate limit.
44
46
  const rateLimiter =
45
47
  apiKey !== undefined
46
48
  ? undefined
@@ -181,37 +183,30 @@ function readPlainTextSnippet(lines: readonly string[]): string {
181
183
 
182
184
  function findFirstObjectArray(
183
185
  values: readonly unknown[]
184
- ): readonly Readonly<Record<string, unknown>>[] | undefined {
186
+ ): readonly ResultObject[] | undefined {
185
187
  for (const value of values) {
186
- if (
187
- Array.isArray(value) &&
188
- value.every((item) => Json.asRecord(item) !== undefined)
189
- ) {
190
- return value as readonly Readonly<Record<string, unknown>>[];
191
- }
192
-
193
- const record = Json.asRecord(value);
194
-
195
- if (record === undefined) {
196
- continue;
188
+ if (isObjectArray(value)) {
189
+ return value;
197
190
  }
198
-
199
- for (const nestedValue of Object.values(record)) {
200
- if (
201
- Array.isArray(nestedValue) &&
202
- nestedValue.every((item) => Json.asRecord(item) !== undefined)
203
- ) {
204
- return nestedValue as readonly Readonly<Record<string, unknown>>[];
205
- }
191
+ const nested = Object.values(Json.asRecord(value) ?? {}).find(
192
+ isObjectArray
193
+ );
194
+ if (nested !== undefined) {
195
+ return nested;
206
196
  }
207
197
  }
208
198
 
209
199
  return undefined;
210
200
  }
211
201
 
212
- function projectResult(
213
- result: Readonly<Record<string, unknown>>
214
- ): SearchResult {
202
+ function isObjectArray(value: unknown): value is readonly ResultObject[] {
203
+ return (
204
+ Array.isArray(value) &&
205
+ value.every((item) => Json.asRecord(item) !== undefined)
206
+ );
207
+ }
208
+
209
+ function projectResult(result: ResultObject): SearchResult {
215
210
  return {
216
211
  title: readResultString(result, "title"),
217
212
  url: readResultString(result, "url"),
@@ -219,7 +214,7 @@ function projectResult(
219
214
  };
220
215
  }
221
216
 
222
- function readSnippet(result: Readonly<Record<string, unknown>>): string {
217
+ function readSnippet(result: ResultObject): string {
223
218
  return (
224
219
  readOptionalResultString(result, "snippet") ??
225
220
  readOptionalResultString(result, "text") ??
@@ -228,10 +223,7 @@ function readSnippet(result: Readonly<Record<string, unknown>>): string {
228
223
  );
229
224
  }
230
225
 
231
- function readResultString(
232
- result: Readonly<Record<string, unknown>>,
233
- name: string
234
- ): string {
226
+ function readResultString(result: ResultObject, name: string): string {
235
227
  const value = readOptionalResultString(result, name);
236
228
 
237
229
  if (value === undefined) {
@@ -242,7 +234,7 @@ function readResultString(
242
234
  }
243
235
 
244
236
  function readOptionalResultString(
245
- result: Readonly<Record<string, unknown>>,
237
+ result: ResultObject,
246
238
  name: string
247
239
  ): string | undefined {
248
240
  const value = result[name];
@@ -27,7 +27,7 @@ const DAY_MS = 86_400_000;
27
27
 
28
28
  const defaultProbeIntervalMs = 1_800_000;
29
29
 
30
- /** Which providers are quota-exhausted, on disk; quota is per-IP-per-day, so trips expire at UTC midnight. */
30
+ /** Persists quota-exhausted providers. Trips expire at UTC midnight unless a retry-after is given. */
31
31
  export class SearchBreaker {
32
32
  private readonly filePath: string;
33
33
  private readonly now: () => number;
@@ -18,7 +18,7 @@ export type SearchChainOptions = {
18
18
  readonly breaker: SearchBreaker;
19
19
  };
20
20
 
21
- /** Tries providers in order until one answers; an empty result set is an answer and ends the chain. */
21
+ /** Tries providers in order; the first answer wins, even an empty one. */
22
22
  export class SearchChain {
23
23
  private readonly providers: readonly SearchProvider[];
24
24
  private readonly breaker: SearchBreaker;
@@ -30,7 +30,6 @@ export class SearchChain {
30
30
 
31
31
  public async search(input: ProviderSearchInput): Promise<ChainSearchOutcome> {
32
32
  const failures: string[] = [];
33
- let attempted = false;
34
33
 
35
34
  for (const provider of this.providers) {
36
35
  if (await this.breaker.isOpen(provider.name)) {
@@ -46,14 +45,16 @@ export class SearchChain {
46
45
  const results = await provider.search(input);
47
46
  await this.breaker.reset(provider.name);
48
47
 
49
- return { provider: provider.name, results, fellBack: attempted };
48
+ return {
49
+ provider: provider.name,
50
+ results,
51
+ fellBack: failures.length > 0,
52
+ };
50
53
  } catch (error) {
51
54
  if (input.signal?.aborted || Errors.isAbort(error)) {
52
55
  throw error;
53
56
  }
54
57
 
55
- attempted = true;
56
-
57
58
  if (error instanceof ProviderQuotaError) {
58
59
  await this.breaker.trip({
59
60
  provider: provider.name,
@@ -25,7 +25,7 @@ const defaultReaderEndpoint = "https://r.jina.ai";
25
25
  const defaultSearchEndpoint = "https://lite.duckduckgo.com/lite/";
26
26
  const defaultTimeoutMs = 30_000;
27
27
 
28
- /** Reads the Lite SERP through Jina: DuckDuckGo answers direct API calls with a 202 anti-bot challenge. */
28
+ /** Reads the Lite SERP through Jina; direct requests get a 202 anti-bot challenge. */
29
29
  export class DuckDuckGoProvider implements SearchProvider {
30
30
  public readonly name = "duckduckgo";
31
31
 
@@ -43,7 +43,7 @@ export class DuckDuckGoProvider implements SearchProvider {
43
43
  this.timeoutMs = options.timeoutMs ?? defaultTimeoutMs;
44
44
  this.headers = {
45
45
  Accept: "application/json",
46
- // The reader caches aggressively and would serve a stale SERP.
46
+ // Otherwise the reader may serve a stale SERP.
47
47
  "x-no-cache": "true",
48
48
  ...(options.apiKey === undefined || options.apiKey.length === 0
49
49
  ? {}
@@ -20,7 +20,6 @@ export type FirecrawlProviderOptions = {
20
20
  const defaultEndpoint = "https://api.firecrawl.dev/v2/search";
21
21
  const defaultTimeoutMs = 20_000;
22
22
 
23
- /** Firecrawl search; omitting `Authorization` is the keyless tier, whose exhaustion shows only as a 429. */
24
23
  export class FirecrawlProvider implements SearchProvider {
25
24
  public readonly name = "firecrawl";
26
25
 
@@ -73,7 +72,7 @@ export class FirecrawlProvider implements SearchProvider {
73
72
  quotaStatuses: [429],
74
73
  quotaMessage:
75
74
  "Firecrawl rejected the request: keyless daily limit reached.",
76
- // Firecrawl meters a rolling 24h window and reports the remainder in the body, not Retry-After.
75
+ // Firecrawl reports the wait in the body, not Retry-After.
77
76
  readRetryAfterMs,
78
77
  });
79
78
  }