@miragon/mcp-toolkit-ui 2.7.0 → 2.8.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 (387) hide show
  1. package/README.md +7 -4
  2. package/dist/app/adapt-data-widget.d.ts +1 -22
  3. package/dist/app/adapt-data-widget.d.ts.map +1 -1
  4. package/dist/app/adapt-data-widget.js +1 -35
  5. package/dist/app/adapt-data-widget.js.map +1 -1
  6. package/dist/app/builder/BuilderBanners.js +1 -1
  7. package/dist/app/builder/BuilderBanners.js.map +1 -1
  8. package/dist/app/builder/CanvasRow.d.ts +4 -2
  9. package/dist/app/builder/CanvasRow.d.ts.map +1 -1
  10. package/dist/app/builder/CanvasRow.js +21 -7
  11. package/dist/app/builder/CanvasRow.js.map +1 -1
  12. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
  13. package/dist/app/builder/CatalogueSheet.js +11 -4
  14. package/dist/app/builder/CatalogueSheet.js.map +1 -1
  15. package/dist/app/builder/CellPropsSheet.d.ts +7 -3
  16. package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
  17. package/dist/app/builder/CellPropsSheet.js +10 -3
  18. package/dist/app/builder/CellPropsSheet.js.map +1 -1
  19. package/dist/app/builder/DiscardDialog.d.ts +18 -0
  20. package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
  21. package/dist/app/builder/DiscardDialog.js +18 -0
  22. package/dist/app/builder/DiscardDialog.js.map +1 -0
  23. package/dist/app/builder/LayoutSurface.d.ts +33 -9
  24. package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
  25. package/dist/app/builder/LayoutSurface.js +74 -23
  26. package/dist/app/builder/LayoutSurface.js.map +1 -1
  27. package/dist/app/builder/PipelineStrip.d.ts +2 -1
  28. package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
  29. package/dist/app/builder/PipelineStrip.js +26 -13
  30. package/dist/app/builder/PipelineStrip.js.map +1 -1
  31. package/dist/app/builder/SaveDialog.d.ts +9 -1
  32. package/dist/app/builder/SaveDialog.d.ts.map +1 -1
  33. package/dist/app/builder/SaveDialog.js +8 -2
  34. package/dist/app/builder/SaveDialog.js.map +1 -1
  35. package/dist/app/builder/Toolbar.d.ts +12 -4
  36. package/dist/app/builder/Toolbar.d.ts.map +1 -1
  37. package/dist/app/builder/Toolbar.js +18 -7
  38. package/dist/app/builder/Toolbar.js.map +1 -1
  39. package/dist/app/builder/Workspace.d.ts +23 -3
  40. package/dist/app/builder/Workspace.d.ts.map +1 -1
  41. package/dist/app/builder/Workspace.js +58 -8
  42. package/dist/app/builder/Workspace.js.map +1 -1
  43. package/dist/app/builder/builder-model.d.ts +143 -1
  44. package/dist/app/builder/builder-model.d.ts.map +1 -1
  45. package/dist/app/builder/builder-model.js +191 -1
  46. package/dist/app/builder/builder-model.js.map +1 -1
  47. package/dist/app/builder/reveal.d.ts +10 -0
  48. package/dist/app/builder/reveal.d.ts.map +1 -0
  49. package/dist/app/builder/reveal.js +10 -0
  50. package/dist/app/builder/reveal.js.map +1 -0
  51. package/dist/app/builder/use-builder-catalogue.d.ts +4 -1
  52. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
  53. package/dist/app/builder/use-builder-catalogue.js +44 -17
  54. package/dist/app/builder/use-builder-catalogue.js.map +1 -1
  55. package/dist/app/builder/use-builder-session.d.ts +30 -0
  56. package/dist/app/builder/use-builder-session.d.ts.map +1 -0
  57. package/dist/app/builder/use-builder-session.js +58 -0
  58. package/dist/app/builder/use-builder-session.js.map +1 -0
  59. package/dist/app/builder/use-display-resolver.d.ts +17 -0
  60. package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
  61. package/dist/app/builder/use-display-resolver.js +16 -0
  62. package/dist/app/builder/use-display-resolver.js.map +1 -0
  63. package/dist/app/index.d.ts +8 -3
  64. package/dist/app/index.d.ts.map +1 -1
  65. package/dist/app/index.js +8 -2
  66. package/dist/app/index.js.map +1 -1
  67. package/dist/app/layout-builder.d.ts +13 -25
  68. package/dist/app/layout-builder.d.ts.map +1 -1
  69. package/dist/app/layout-builder.js +75 -81
  70. package/dist/app/layout-builder.js.map +1 -1
  71. package/dist/app/mcp-app-view-chrome.d.ts +12 -3
  72. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
  73. package/dist/app/mcp-app-view-chrome.js +21 -5
  74. package/dist/app/mcp-app-view-chrome.js.map +1 -1
  75. package/dist/app/mcp-app-view-states.d.ts +11 -3
  76. package/dist/app/mcp-app-view-states.d.ts.map +1 -1
  77. package/dist/app/mcp-app-view-states.js +29 -8
  78. package/dist/app/mcp-app-view-states.js.map +1 -1
  79. package/dist/app/mcp-app-view.d.ts +33 -1
  80. package/dist/app/mcp-app-view.d.ts.map +1 -1
  81. package/dist/app/mcp-app-view.js +181 -127
  82. package/dist/app/mcp-app-view.js.map +1 -1
  83. package/dist/app/mcp-toolkit-app.d.ts +6 -1
  84. package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
  85. package/dist/app/mcp-toolkit-app.js +8 -1
  86. package/dist/app/mcp-toolkit-app.js.map +1 -1
  87. package/dist/app/mcp-use-host-bridge.d.ts +15 -6
  88. package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
  89. package/dist/app/mcp-use-host-bridge.js +51 -22
  90. package/dist/app/mcp-use-host-bridge.js.map +1 -1
  91. package/dist/app/model-context.d.ts +71 -0
  92. package/dist/app/model-context.d.ts.map +1 -0
  93. package/dist/app/model-context.js +101 -0
  94. package/dist/app/model-context.js.map +1 -0
  95. package/dist/app/use-build-mode-focus.d.ts +33 -0
  96. package/dist/app/use-build-mode-focus.d.ts.map +1 -0
  97. package/dist/app/use-build-mode-focus.js +59 -0
  98. package/dist/app/use-build-mode-focus.js.map +1 -0
  99. package/dist/app/use-view-actions.d.ts +31 -0
  100. package/dist/app/use-view-actions.d.ts.map +1 -0
  101. package/dist/app/use-view-actions.js +81 -0
  102. package/dist/app/use-view-actions.js.map +1 -0
  103. package/dist/app/use-view-lifecycle.d.ts +4 -0
  104. package/dist/app/use-view-lifecycle.d.ts.map +1 -1
  105. package/dist/app/use-view-lifecycle.js +2 -0
  106. package/dist/app/use-view-lifecycle.js.map +1 -1
  107. package/dist/app/view-lifecycle.d.ts +80 -4
  108. package/dist/app/view-lifecycle.d.ts.map +1 -1
  109. package/dist/app/view-lifecycle.js +90 -3
  110. package/dist/app/view-lifecycle.js.map +1 -1
  111. package/dist/app/widget-fixture.d.ts +10 -3
  112. package/dist/app/widget-fixture.d.ts.map +1 -1
  113. package/dist/app/widget-fixture.js +21 -8
  114. package/dist/app/widget-fixture.js.map +1 -1
  115. package/dist/app/widget-props-sheet.d.ts +3 -1
  116. package/dist/app/widget-props-sheet.d.ts.map +1 -1
  117. package/dist/app/widget-props-sheet.js +22 -10
  118. package/dist/app/widget-props-sheet.js.map +1 -1
  119. package/dist/app/widget-renderer.js +1 -1
  120. package/dist/app/widget-renderer.js.map +1 -1
  121. package/dist/components/DrillButton.d.ts +9 -6
  122. package/dist/components/DrillButton.d.ts.map +1 -1
  123. package/dist/components/DrillButton.js +8 -6
  124. package/dist/components/DrillButton.js.map +1 -1
  125. package/dist/components/EmptyState.d.ts.map +1 -1
  126. package/dist/components/EmptyState.js +4 -2
  127. package/dist/components/EmptyState.js.map +1 -1
  128. package/dist/components/ErrorState.d.ts +5 -2
  129. package/dist/components/ErrorState.d.ts.map +1 -1
  130. package/dist/components/ErrorState.js +25 -8
  131. package/dist/components/ErrorState.js.map +1 -1
  132. package/dist/components/FilterBar.d.ts +15 -4
  133. package/dist/components/FilterBar.d.ts.map +1 -1
  134. package/dist/components/FilterBar.js +11 -6
  135. package/dist/components/FilterBar.js.map +1 -1
  136. package/dist/components/KpiGrid.d.ts +66 -21
  137. package/dist/components/KpiGrid.d.ts.map +1 -1
  138. package/dist/components/KpiGrid.js +101 -34
  139. package/dist/components/KpiGrid.js.map +1 -1
  140. package/dist/components/ListFooter.d.ts +31 -4
  141. package/dist/components/ListFooter.d.ts.map +1 -1
  142. package/dist/components/ListFooter.js +30 -11
  143. package/dist/components/ListFooter.js.map +1 -1
  144. package/dist/components/PagedListFooter.d.ts +57 -0
  145. package/dist/components/PagedListFooter.d.ts.map +1 -0
  146. package/dist/components/PagedListFooter.js +27 -0
  147. package/dist/components/PagedListFooter.js.map +1 -0
  148. package/dist/components/Pills.d.ts +27 -7
  149. package/dist/components/Pills.d.ts.map +1 -1
  150. package/dist/components/Pills.js +21 -6
  151. package/dist/components/Pills.js.map +1 -1
  152. package/dist/components/SectionHeading.d.ts +3 -1
  153. package/dist/components/SectionHeading.d.ts.map +1 -1
  154. package/dist/components/SectionHeading.js +6 -2
  155. package/dist/components/SectionHeading.js.map +1 -1
  156. package/dist/components/Toast.d.ts +9 -3
  157. package/dist/components/Toast.d.ts.map +1 -1
  158. package/dist/components/Toast.js +31 -16
  159. package/dist/components/Toast.js.map +1 -1
  160. package/dist/components/WidgetHeader.d.ts +34 -10
  161. package/dist/components/WidgetHeader.d.ts.map +1 -1
  162. package/dist/components/WidgetHeader.js +11 -6
  163. package/dist/components/WidgetHeader.js.map +1 -1
  164. package/dist/hooks/index.d.ts +4 -4
  165. package/dist/hooks/index.d.ts.map +1 -1
  166. package/dist/hooks/index.js +1 -1
  167. package/dist/hooks/index.js.map +1 -1
  168. package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
  169. package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
  170. package/dist/hooks/tool-result-recovery-model.js +273 -0
  171. package/dist/hooks/tool-result-recovery-model.js.map +1 -0
  172. package/dist/hooks/use-tool-query.d.ts +56 -14
  173. package/dist/hooks/use-tool-query.d.ts.map +1 -1
  174. package/dist/hooks/use-tool-query.js +102 -25
  175. package/dist/hooks/use-tool-query.js.map +1 -1
  176. package/dist/hooks/use-tool-result-recovery.d.ts +47 -52
  177. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
  178. package/dist/hooks/use-tool-result-recovery.js +58 -120
  179. package/dist/hooks/use-tool-result-recovery.js.map +1 -1
  180. package/dist/hooks/use-view-data.d.ts +52 -10
  181. package/dist/hooks/use-view-data.d.ts.map +1 -1
  182. package/dist/hooks/use-view-data.js +81 -16
  183. package/dist/hooks/use-view-data.js.map +1 -1
  184. package/dist/hooks/use-view-tool-query.d.ts +12 -7
  185. package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
  186. package/dist/hooks/use-view-tool-query.js +15 -14
  187. package/dist/hooks/use-view-tool-query.js.map +1 -1
  188. package/dist/index.d.ts +17 -10
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +18 -6
  191. package/dist/index.js.map +1 -1
  192. package/dist/lib/focus-return.d.ts +61 -0
  193. package/dist/lib/focus-return.d.ts.map +1 -0
  194. package/dist/lib/focus-return.js +46 -0
  195. package/dist/lib/focus-return.js.map +1 -0
  196. package/dist/lib/parse-tool-result.d.ts +23 -1
  197. package/dist/lib/parse-tool-result.d.ts.map +1 -1
  198. package/dist/lib/parse-tool-result.js +38 -2
  199. package/dist/lib/parse-tool-result.js.map +1 -1
  200. package/dist/lib/toast-model.d.ts +41 -1
  201. package/dist/lib/toast-model.d.ts.map +1 -1
  202. package/dist/lib/toast-model.js +67 -1
  203. package/dist/lib/toast-model.js.map +1 -1
  204. package/dist/lib/tone-utils.d.ts +58 -6
  205. package/dist/lib/tone-utils.d.ts.map +1 -1
  206. package/dist/lib/tone-utils.js +66 -4
  207. package/dist/lib/tone-utils.js.map +1 -1
  208. package/dist/lib/tool-query.d.ts +107 -0
  209. package/dist/lib/tool-query.d.ts.map +1 -0
  210. package/dist/lib/tool-query.js +182 -0
  211. package/dist/lib/tool-query.js.map +1 -0
  212. package/dist/lib/tool-result-observer.d.ts +108 -0
  213. package/dist/lib/tool-result-observer.d.ts.map +1 -0
  214. package/dist/lib/tool-result-observer.js +158 -0
  215. package/dist/lib/tool-result-observer.js.map +1 -0
  216. package/dist/lib/typography.d.ts +37 -0
  217. package/dist/lib/typography.d.ts.map +1 -0
  218. package/dist/lib/typography.js +41 -0
  219. package/dist/lib/typography.js.map +1 -0
  220. package/dist/lib/utils.d.ts.map +1 -1
  221. package/dist/lib/utils.js +11 -1
  222. package/dist/lib/utils.js.map +1 -1
  223. package/dist/locale/index.d.ts +1 -1
  224. package/dist/locale/index.d.ts.map +1 -1
  225. package/dist/locale/message-types.d.ts +117 -4
  226. package/dist/locale/message-types.d.ts.map +1 -1
  227. package/dist/locale/messages-de.d.ts.map +1 -1
  228. package/dist/locale/messages-de.js +44 -10
  229. package/dist/locale/messages-de.js.map +1 -1
  230. package/dist/locale/messages-en.d.ts.map +1 -1
  231. package/dist/locale/messages-en.js +44 -10
  232. package/dist/locale/messages-en.js.map +1 -1
  233. package/dist/locale/toolkit-messages.d.ts +19 -1
  234. package/dist/locale/toolkit-messages.d.ts.map +1 -1
  235. package/dist/locale/toolkit-messages.js +54 -1
  236. package/dist/locale/toolkit-messages.js.map +1 -1
  237. package/dist/primitives/alert.d.ts +1 -1
  238. package/dist/primitives/alert.d.ts.map +1 -1
  239. package/dist/primitives/alert.js +2 -0
  240. package/dist/primitives/alert.js.map +1 -1
  241. package/dist/primitives/badge.d.ts +1 -1
  242. package/dist/primitives/badge.d.ts.map +1 -1
  243. package/dist/primitives/badge.js +9 -4
  244. package/dist/primitives/badge.js.map +1 -1
  245. package/dist/primitives/button.d.ts +1 -1
  246. package/dist/primitives/button.js +1 -1
  247. package/dist/primitives/button.js.map +1 -1
  248. package/dist/primitives/dialog.d.ts +1 -1
  249. package/dist/primitives/dialog.d.ts.map +1 -1
  250. package/dist/primitives/dialog.js +10 -3
  251. package/dist/primitives/dialog.js.map +1 -1
  252. package/dist/primitives/select.js +1 -1
  253. package/dist/primitives/select.js.map +1 -1
  254. package/dist/primitives/sheet.d.ts +1 -1
  255. package/dist/primitives/sheet.d.ts.map +1 -1
  256. package/dist/primitives/sheet.js +6 -2
  257. package/dist/primitives/sheet.js.map +1 -1
  258. package/dist/providers/query-provider.d.ts +32 -1
  259. package/dist/providers/query-provider.d.ts.map +1 -1
  260. package/dist/providers/query-provider.js +53 -4
  261. package/dist/providers/query-provider.js.map +1 -1
  262. package/dist/render-cases-primitives.js +1 -1
  263. package/dist/render-cases-primitives.js.map +1 -1
  264. package/dist/render-cases.d.ts.map +1 -1
  265. package/dist/render-cases.js +30 -6
  266. package/dist/render-cases.js.map +1 -1
  267. package/dist/render-effects.d.ts +42 -0
  268. package/dist/render-effects.d.ts.map +1 -0
  269. package/dist/render-effects.js +81 -0
  270. package/dist/render-effects.js.map +1 -0
  271. package/dist/theme/create-theme.d.ts +19 -1
  272. package/dist/theme/create-theme.d.ts.map +1 -1
  273. package/dist/theme/create-theme.js +15 -0
  274. package/dist/theme/create-theme.js.map +1 -1
  275. package/package.json +5 -4
  276. package/src/app/adapt-data-widget.tsx +2 -42
  277. package/src/app/builder/BuilderBanners.tsx +1 -1
  278. package/src/app/builder/CanvasRow.tsx +63 -17
  279. package/src/app/builder/CatalogueSheet.tsx +50 -29
  280. package/src/app/builder/CellPropsSheet.tsx +17 -2
  281. package/src/app/builder/DiscardDialog.tsx +59 -0
  282. package/src/app/builder/LayoutSurface.tsx +206 -66
  283. package/src/app/builder/PipelineStrip.tsx +253 -153
  284. package/src/app/builder/SaveDialog.tsx +14 -2
  285. package/src/app/builder/Toolbar.tsx +144 -59
  286. package/src/app/builder/Workspace.tsx +226 -58
  287. package/src/app/builder/builder-model.ts +341 -2
  288. package/src/app/builder/builder-model.ux.test.ts +456 -0
  289. package/src/app/builder/builder-ux.test.tsx +844 -0
  290. package/src/app/builder/reveal.ts +10 -0
  291. package/src/app/builder/use-builder-catalogue.ts +56 -19
  292. package/src/app/builder/use-builder-session.ts +68 -0
  293. package/src/app/builder/use-display-resolver.ts +24 -0
  294. package/src/app/index.ts +12 -2
  295. package/src/app/layout-builder.tsx +178 -191
  296. package/src/app/mcp-app-view-chrome.test.tsx +141 -1
  297. package/src/app/mcp-app-view-chrome.tsx +56 -6
  298. package/src/app/mcp-app-view-states.tsx +51 -11
  299. package/src/app/mcp-app-view.effects.test.tsx +292 -0
  300. package/src/app/mcp-app-view.test.tsx +222 -2
  301. package/src/app/mcp-app-view.tsx +267 -117
  302. package/src/app/mcp-toolkit-app.test.tsx +40 -0
  303. package/src/app/mcp-toolkit-app.tsx +8 -1
  304. package/src/app/mcp-use-host-bridge.test.tsx +180 -0
  305. package/src/app/mcp-use-host-bridge.tsx +67 -24
  306. package/src/app/model-context.test.tsx +116 -0
  307. package/src/app/model-context.tsx +125 -0
  308. package/src/app/use-build-mode-focus.ts +62 -0
  309. package/src/app/use-view-actions.ts +89 -0
  310. package/src/app/use-view-lifecycle.ts +6 -0
  311. package/src/app/view-lifecycle.test.ts +216 -0
  312. package/src/app/view-lifecycle.ts +165 -5
  313. package/src/app/widget-fixture.effects.test.tsx +51 -0
  314. package/src/app/widget-fixture.render.test.tsx +81 -0
  315. package/src/app/widget-fixture.tsx +34 -11
  316. package/src/app/widget-props-sheet.tsx +57 -16
  317. package/src/app/widget-renderer.tsx +1 -1
  318. package/src/components/DrillButton.tsx +23 -10
  319. package/src/components/EmptyState.tsx +6 -4
  320. package/src/components/ErrorState.tsx +31 -9
  321. package/src/components/FilterBar.test.tsx +82 -0
  322. package/src/components/FilterBar.tsx +52 -26
  323. package/src/components/KpiGrid.test.tsx +279 -0
  324. package/src/components/KpiGrid.tsx +297 -90
  325. package/src/components/ListFooter.test.tsx +116 -0
  326. package/src/components/ListFooter.tsx +102 -15
  327. package/src/components/PagedListFooter.test.tsx +140 -0
  328. package/src/components/PagedListFooter.tsx +107 -0
  329. package/src/components/Pills.test.tsx +77 -0
  330. package/src/components/Pills.tsx +63 -10
  331. package/src/components/SectionHeading.tsx +9 -3
  332. package/src/components/Toast.tsx +37 -19
  333. package/src/components/WidgetHeader.test.tsx +78 -0
  334. package/src/components/WidgetHeader.tsx +63 -16
  335. package/src/components/feedback-states.test.tsx +98 -9
  336. package/src/components/tone-figures.test.tsx +8 -4
  337. package/src/hooks/index.ts +6 -3
  338. package/src/hooks/tool-result-recovery-model.test.ts +744 -0
  339. package/src/hooks/tool-result-recovery-model.ts +418 -0
  340. package/src/hooks/use-tool-query.effects.test.tsx +205 -0
  341. package/src/hooks/use-tool-query.ts +156 -33
  342. package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
  343. package/src/hooks/use-tool-result-recovery.test.ts +3 -4
  344. package/src/hooks/use-tool-result-recovery.ts +84 -142
  345. package/src/hooks/use-view-data.test.tsx +118 -9
  346. package/src/hooks/use-view-data.ts +128 -18
  347. package/src/hooks/use-view-tool-query.ts +25 -19
  348. package/src/i18n-coverage.test.tsx +104 -2
  349. package/src/index.ts +48 -11
  350. package/src/lib/focus-return.test.ts +288 -0
  351. package/src/lib/focus-return.ts +96 -0
  352. package/src/lib/parse-tool-result.test.ts +46 -1
  353. package/src/lib/parse-tool-result.ts +40 -2
  354. package/src/lib/toast-model.test.ts +166 -1
  355. package/src/lib/toast-model.ts +104 -2
  356. package/src/lib/tone-utils.test.ts +86 -10
  357. package/src/lib/tone-utils.ts +89 -8
  358. package/src/lib/tool-query.test.ts +569 -0
  359. package/src/lib/tool-query.ts +253 -0
  360. package/src/lib/tool-result-observer.test.ts +296 -0
  361. package/src/lib/tool-result-observer.ts +211 -0
  362. package/src/lib/typography.test.ts +45 -0
  363. package/src/lib/typography.ts +47 -0
  364. package/src/lib/utils.ts +12 -1
  365. package/src/locale/index.ts +1 -0
  366. package/src/locale/message-types.ts +118 -2
  367. package/src/locale/messages-de.ts +49 -10
  368. package/src/locale/messages-en.ts +49 -10
  369. package/src/locale/toolkit-messages.test.ts +133 -0
  370. package/src/locale/toolkit-messages.ts +63 -2
  371. package/src/primitives/alert.tsx +3 -0
  372. package/src/primitives/badge.tsx +9 -4
  373. package/src/primitives/button.tsx +1 -1
  374. package/src/primitives/dialog.tsx +10 -1
  375. package/src/primitives/select.tsx +1 -1
  376. package/src/primitives/sheet.tsx +7 -0
  377. package/src/providers/query-provider.test.tsx +154 -0
  378. package/src/providers/query-provider.tsx +66 -5
  379. package/src/render-cases-primitives.tsx +1 -1
  380. package/src/render-cases.tsx +38 -6
  381. package/src/render-effects.tsx +96 -0
  382. package/src/theme/cd-tokens.test.ts +3 -1
  383. package/src/theme/create-theme.test.ts +10 -0
  384. package/src/theme/create-theme.ts +28 -0
  385. package/src/theme/theme-css.test.ts +51 -0
  386. package/src/theme.css +31 -1
  387. package/ui-catalog.json +448 -41
@@ -1,48 +1,49 @@
1
+ import { type ToolResultObserver } from "../lib/tool-result-observer.js";
2
+ import { type RecoveryPolicy, type ToolResultRecoveryState } from "./tool-result-recovery-model.js";
3
+ export { decodeRecoveredResult } from "./tool-result-recovery-model.js";
4
+ export type { RecoveryBlockReason, RecoveryPolicy, ToolResultRecoveryState, ToolSafety, } from "./tool-result-recovery-model.js";
1
5
  /**
2
6
  * Recovery for hosts that deliver the `ui/notifications/tool-result`
3
7
  * notification without `structuredContent` (observed on claude.ai and Claude
4
- * Desktop, which forward only the model-facing `content` blocks). Since
5
- * mcp-use 2.x such a result is not even observable: the `useToolContext`
6
- * latch ignores content-only successes, so the tool status stays `"pending"`
7
- * forever and the shell would idle on its loading skeleton.
8
+ * Desktop, which forward only the model-facing `content` blocks). mcp-use
9
+ * 2.x's `useToolContext` latch ignores such a content-only result, so its
10
+ * status stays `"pending"` forever and the shell would idle on its skeleton.
8
11
  *
9
- * Because the stripped notification is invisible, readiness is inferred two
10
- * ways: the hard `resultReady` signal (the latch fired but the payload is
11
- * invalid), or a grace timer — once the originating tool is known and no
12
- * result has latched within
13
- * {@link ToolResultRecoveryOptions.assumeStrippedAfterMs}, the result is
14
- * assumed delivered-but-stripped. Either way the hook re-executes the
15
- * originating tool once via the host bridge's official `callTool` — tool-call
16
- * RESPONSES carry `structuredContent` intact on those hosts — and exposes the
17
- * decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
18
- * a valid payload up front, so the recovery never fires there.
12
+ * The hook re-executes the originating tool once via the host bridge's
13
+ * `callTool` — tool-call RESPONSES carry `structuredContent` intact on those
14
+ * hosts — and exposes the decoded payload. When it does so (toolkit#176):
19
15
  *
20
- * A call the host cancelled is never recovered: since mcp-use 2.7.1 the
21
- * cancellation latches as `status: "error"` (a `ToolCancelledError`), which
22
- * would otherwise count as a ready-but-invalid result — re-executing it would
23
- * override the user's decision to stop the call. Neither is a call that
24
- * failed (`isError` or a transport error, {@link ToolResultRecoveryOptions.errored}):
25
- * re-running it only repeats the failure, so the shell renders the error and
26
- * offers an explicit retry instead (toolkit#176).
16
+ * - **Only when the host stripped the result.** A passive observer of the
17
+ * host's lifecycle notifications (`installToolResultObserver`) sees the
18
+ * content-only result itself, so the recovery fires as it arrives, and a
19
+ * slow tool on a compliant host is never re-run (K13): no result has
20
+ * arrived because none was sent. Where the observer cannot vouch for that
21
+ * (no browser frame, or installed after the handshake), the 2.x grace timer
22
+ * ({@link ToolResultRecoveryOptions.assumeStrippedAfterMs}) still infers a
23
+ * stripped result, once the call's arguments arrived.
24
+ * - **With the call's complete arguments** (N21): the observer's complete
25
+ * `tool-input`, never a partial stream; an equal re-delivery is the same run.
26
+ * - **Never for a cancelled or failed call:** re-running repeats the failure
27
+ * or overrides the user's stop; the shell renders that state and offers an
28
+ * explicit retry.
29
+ * - **Only for a tool the policy allows** ({@link ToolResultRecoveryOptions.policy}):
30
+ * by default never one the host reports as writing (`readOnlyHint: false`
31
+ * or `destructiveHint: true` in `hostContext.toolInfo.tool.annotations`).
32
+ * A blocked recovery is reported (`blocked`) so the view can show its error.
27
33
  *
28
- * Assumes the originating tool is a read-only render pipeline (true for all
29
- * toolkit `render-view`/`show_*` tools) — the re-execution must be safe to
30
- * repeat, and may rarely run concurrently with the original invocation when
31
- * the grace timer beats a slow but conforming host.
34
+ * The decision and its timer live in `createRecoveryController`; this hook
35
+ * only binds it to React.
32
36
  */
33
37
  /**
34
- * Default grace period before a silent latch counts as a stripped result.
35
- * Long enough for a conforming host to latch a typical render tool first,
36
- * short enough that users on stripping hosts are not left staring at the
37
- * skeleton noticeably.
38
+ * Default grace period before a silent latch counts as a stripped result —
39
+ * used only where the transport observer cannot vouch that nothing arrived.
38
40
  */
39
41
  export declare const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500;
40
42
  export interface ToolResultRecoveryOptions {
41
43
  /**
42
44
  * The latch fired (`useToolContext().status !== "pending"`) — a structured
43
45
  * result, a tool error, or a host cancellation arrived. On hosts that strip
44
- * `structuredContent` this never turns true; the grace timer below covers
45
- * that case.
46
+ * `structuredContent` this never turns true.
46
47
  */
47
48
  resultReady: boolean;
48
49
  /**
@@ -61,10 +62,7 @@ export interface ToolResultRecoveryOptions {
61
62
  errored?: boolean;
62
63
  /** The payload the host delivered (`useToolContext().toolOutput`). */
63
64
  props: unknown;
64
- /**
65
- * Validates a candidate payload. MUST be referentially stable (module-level
66
- * function or memoised) — it is an effect dependency.
67
- */
65
+ /** Validates a candidate payload. */
68
66
  isValid: (value: unknown) => boolean;
69
67
  /** The tool arguments from `ui/notifications/tool-input` (`useToolContext().toolInput`). */
70
68
  toolInput: Record<string, unknown> | null | undefined;
@@ -74,18 +72,19 @@ export interface ToolResultRecoveryOptions {
74
72
  callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
75
73
  /**
76
74
  * Grace period in ms after which a silent latch counts as a stripped
77
- * result. Armed once the originating tool is known while `resultReady` is
78
- * still false; re-armed on every `toolInput` update, because streaming
79
- * arguments mean the invocation may not have finished yet. Defaults to
75
+ * result. Applies only where the transport observer cannot vouch that no
76
+ * result arrived (see above); restarts for new arguments. Defaults to
80
77
  * {@link DEFAULT_ASSUME_STRIPPED_AFTER_MS}.
81
78
  */
82
79
  assumeStrippedAfterMs?: number;
83
- }
84
- export interface ToolResultRecoveryState<T> {
85
- /** The recovered payload, `null` until the re-execution resolved (or when it failed). */
86
- data: T | null;
87
- /** `true` when the single recovery attempt failed — the shell keeps its skeleton, no retry loop. */
88
- failed: boolean;
80
+ /** Which tools may be re-executed on their own. Default `"auto"`. */
81
+ policy?: RecoveryPolicy;
82
+ /**
83
+ * The transport observer. Defaults to the document's
84
+ * (`installToolResultObserver()`); `null` disables it, leaving the grace
85
+ * timer to decide alone (the 2.x behaviour).
86
+ */
87
+ observer?: ToolResultObserver | null;
89
88
  }
90
89
  /**
91
90
  * Resolves the originating tool name from the host context's `toolInfo`.
@@ -94,14 +93,10 @@ export interface ToolResultRecoveryState<T> {
94
93
  */
95
94
  export declare function resolveRecoveryToolName(hostContext: unknown): string | undefined;
96
95
  /**
97
- * Decodes a re-executed tool result and validates it. Exposed for tests;
98
- * the hook uses it on the `callTool` response.
99
- */
100
- export declare function decodeRecoveredResult<T>(result: unknown, isValid: (value: unknown) => boolean): T | null;
101
- /**
102
- * Whether the recovery may fire: the result latched (or is assumed stripped)
103
- * and the call was neither cancelled nor failed. Exported for tests — this is
104
- * the #176 rule "never recover on an error status".
96
+ * Whether a latched or assumed-stripped result may be recovered at all: the
97
+ * call was neither cancelled nor failed. Kept for existing imports; the full
98
+ * rule (observer, policy, arguments) is `decideRecovery`.
99
+ * @deprecated Use `decideRecovery` from the recovery model.
105
100
  */
106
101
  export declare function isRecoveryReady(state: {
107
102
  resultReady: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,OAAO,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACrD,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACvD,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3E;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,yFAAyF;IACzF,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,oGAAoG;IACpG,MAAM,EAAE,OAAO,CAAA;CAChB;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAehF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GACnC,CAAC,GAAG,IAAI,CAQV;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,GAAG,OAAO,CAGV;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,yBAAyB,GACjC,uBAAuB,CAAC,CAAC,CAAC,CAwF5B"}
1
+ {"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnG,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC7B,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,uBAAuB,EACvB,UAAU,GACX,MAAM,iCAAiC,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;GAGG;AACH,eAAO,MAAM,gCAAgC,OAAO,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACrD,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACvD,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3E;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,qEAAqE;IACrE,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAehF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,EAAE,OAAO,CAAA;IACrB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;CACjB,GAAG,OAAO,CAGV;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,yBAAyB,GACjC,uBAAuB,CAAC,CAAC,CAAC,CAyC5B"}
@@ -1,45 +1,44 @@
1
- import { useEffect, useRef, useState } from "react";
2
- import { parseToolResult } from "../lib/parse-tool-result.js";
1
+ import { useEffect, useState, useSyncExternalStore } from "react";
2
+ import { installToolResultObserver } from "../lib/tool-result-observer.js";
3
+ import { createRecoveryController, } from "./tool-result-recovery-model.js";
4
+ export { decodeRecoveredResult } from "./tool-result-recovery-model.js";
3
5
  /**
4
6
  * Recovery for hosts that deliver the `ui/notifications/tool-result`
5
7
  * notification without `structuredContent` (observed on claude.ai and Claude
6
- * Desktop, which forward only the model-facing `content` blocks). Since
7
- * mcp-use 2.x such a result is not even observable: the `useToolContext`
8
- * latch ignores content-only successes, so the tool status stays `"pending"`
9
- * forever and the shell would idle on its loading skeleton.
8
+ * Desktop, which forward only the model-facing `content` blocks). mcp-use
9
+ * 2.x's `useToolContext` latch ignores such a content-only result, so its
10
+ * status stays `"pending"` forever and the shell would idle on its skeleton.
10
11
  *
11
- * Because the stripped notification is invisible, readiness is inferred two
12
- * ways: the hard `resultReady` signal (the latch fired but the payload is
13
- * invalid), or a grace timer — once the originating tool is known and no
14
- * result has latched within
15
- * {@link ToolResultRecoveryOptions.assumeStrippedAfterMs}, the result is
16
- * assumed delivered-but-stripped. Either way the hook re-executes the
17
- * originating tool once via the host bridge's official `callTool` — tool-call
18
- * RESPONSES carry `structuredContent` intact on those hosts — and exposes the
19
- * decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
20
- * a valid payload up front, so the recovery never fires there.
12
+ * The hook re-executes the originating tool once via the host bridge's
13
+ * `callTool` — tool-call RESPONSES carry `structuredContent` intact on those
14
+ * hosts — and exposes the decoded payload. When it does so (toolkit#176):
21
15
  *
22
- * A call the host cancelled is never recovered: since mcp-use 2.7.1 the
23
- * cancellation latches as `status: "error"` (a `ToolCancelledError`), which
24
- * would otherwise count as a ready-but-invalid result — re-executing it would
25
- * override the user's decision to stop the call. Neither is a call that
26
- * failed (`isError` or a transport error, {@link ToolResultRecoveryOptions.errored}):
27
- * re-running it only repeats the failure, so the shell renders the error and
28
- * offers an explicit retry instead (toolkit#176).
16
+ * - **Only when the host stripped the result.** A passive observer of the
17
+ * host's lifecycle notifications (`installToolResultObserver`) sees the
18
+ * content-only result itself, so the recovery fires as it arrives, and a
19
+ * slow tool on a compliant host is never re-run (K13): no result has
20
+ * arrived because none was sent. Where the observer cannot vouch for that
21
+ * (no browser frame, or installed after the handshake), the 2.x grace timer
22
+ * ({@link ToolResultRecoveryOptions.assumeStrippedAfterMs}) still infers a
23
+ * stripped result, once the call's arguments arrived.
24
+ * - **With the call's complete arguments** (N21): the observer's complete
25
+ * `tool-input`, never a partial stream; an equal re-delivery is the same run.
26
+ * - **Never for a cancelled or failed call:** re-running repeats the failure
27
+ * or overrides the user's stop; the shell renders that state and offers an
28
+ * explicit retry.
29
+ * - **Only for a tool the policy allows** ({@link ToolResultRecoveryOptions.policy}):
30
+ * by default never one the host reports as writing (`readOnlyHint: false`
31
+ * or `destructiveHint: true` in `hostContext.toolInfo.tool.annotations`).
32
+ * A blocked recovery is reported (`blocked`) so the view can show its error.
29
33
  *
30
- * Assumes the originating tool is a read-only render pipeline (true for all
31
- * toolkit `render-view`/`show_*` tools) — the re-execution must be safe to
32
- * repeat, and may rarely run concurrently with the original invocation when
33
- * the grace timer beats a slow but conforming host.
34
+ * The decision and its timer live in `createRecoveryController`; this hook
35
+ * only binds it to React.
34
36
  */
35
37
  /**
36
- * Default grace period before a silent latch counts as a stripped result.
37
- * Long enough for a conforming host to latch a typical render tool first,
38
- * short enough that users on stripping hosts are not left staring at the
39
- * skeleton noticeably.
38
+ * Default grace period before a silent latch counts as a stripped result —
39
+ * used only where the transport observer cannot vouch that nothing arrived.
40
40
  */
41
41
  export const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500;
42
- const IDLE = { data: null, failed: false };
43
42
  /**
44
43
  * Resolves the originating tool name from the host context's `toolInfo`.
45
44
  * Reads the SEP-1865 shape first (`toolInfo.tool.name`), then the flattened
@@ -65,23 +64,10 @@ export function resolveRecoveryToolName(hostContext) {
65
64
  return undefined;
66
65
  }
67
66
  /**
68
- * Decodes a re-executed tool result and validates it. Exposed for tests;
69
- * the hook uses it on the `callTool` response.
70
- */
71
- export function decodeRecoveredResult(result, isValid) {
72
- let decoded;
73
- try {
74
- decoded = parseToolResult(result);
75
- }
76
- catch {
77
- return null;
78
- }
79
- return decoded !== null && isValid(decoded) ? decoded : null;
80
- }
81
- /**
82
- * Whether the recovery may fire: the result latched (or is assumed stripped)
83
- * and the call was neither cancelled nor failed. Exported for tests — this is
84
- * the #176 rule "never recover on an error status".
67
+ * Whether a latched or assumed-stripped result may be recovered at all: the
68
+ * call was neither cancelled nor failed. Kept for existing imports; the full
69
+ * rule (observer, policy, arguments) is `decideRecovery`.
70
+ * @deprecated Use `decideRecovery` from the recovery model.
85
71
  */
86
72
  export function isRecoveryReady(state) {
87
73
  if (state.cancelled || state.errored)
@@ -89,79 +75,31 @@ export function isRecoveryReady(state) {
89
75
  return state.resultReady || state.assumedReady;
90
76
  }
91
77
  export function useToolResultRecovery(options) {
92
- const { resultReady, cancelled = false, errored = false, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, } = options;
93
- const [state, setState] = useState(IDLE);
94
- // Single-flight: the promise ref survives StrictMode's dev-mode
95
- // effect re-run (cleanup + setup on the same instance), so the re-run
96
- // re-subscribes to the SAME in-flight call instead of firing a second one.
97
- const flightRef = useRef(null);
98
- const flightInputRef = useRef(null);
99
- const toolName = resolveRecoveryToolName(hostContext);
100
- // A stripped result is unobservable (the 2.x latch ignores content-only
101
- // results), so infer it: once a recovery could fire but the latch has been
102
- // silent for the grace period, treat the result as delivered-but-stripped.
103
- // Re-armed on every toolInput identity change — streaming arguments mean
104
- // the invocation may still be running, so the grace period starts over.
105
- // The re-arm is a render-phase reset (not an effect) so the cascading-
106
- // render lint stays satisfied; the timer effect below restarts anyway
107
- // because toolInput is one of its dependencies.
108
- const [assumedReady, setAssumedReady] = useState(false);
109
- const [prevTimerInput, setPrevTimerInput] = useState(toolInput);
110
- if (prevTimerInput !== toolInput) {
111
- setPrevTimerInput(toolInput);
112
- if (assumedReady)
113
- setAssumedReady(false);
114
- }
115
- const suppressed = cancelled || errored;
78
+ const { resultReady, cancelled = false, errored = false, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, policy = "auto", observer, } = options;
79
+ // One controller per mount; it survives StrictMode's effect re-run, so an
80
+ // in-flight call is never fired twice.
81
+ const [controller] = useState(() => createRecoveryController({
82
+ observer: observer === undefined ? installToolResultObserver() : observer,
83
+ }));
116
84
  useEffect(() => {
117
- if (resultReady || suppressed || toolName === undefined)
118
- return;
119
- const timer = setTimeout(() => setAssumedReady(true), assumeStrippedAfterMs);
120
- return () => clearTimeout(timer);
121
- }, [resultReady, suppressed, toolName, toolInput, assumeStrippedAfterMs]);
122
- // A cancelled or failed call never counts as ready, so the effect below
123
- // invalidates any in-flight attempt the same way it does for a superseded run.
124
- const ready = isRecoveryReady({ resultReady, assumedReady, cancelled, errored });
85
+ controller.start();
86
+ return () => controller.stop();
87
+ }, [controller]);
125
88
  useEffect(() => {
126
- // A new tool run (result no longer ready, or fresh tool-input identity)
127
- // invalidates any previous recovery attempt and re-arms the single-flight.
128
- if (flightRef.current && (!ready || flightInputRef.current !== toolInput)) {
129
- flightRef.current = null;
130
- setState((prev) => (prev.data === null && !prev.failed ? prev : IDLE));
131
- }
132
- // Never fire on conforming hosts (valid payload) or before the
133
- // originating tool is known.
134
- if (!ready || isValid(props) || toolName === undefined)
135
- return;
136
- if (!flightRef.current) {
137
- flightInputRef.current = toolInput;
138
- flightRef.current = (async () => {
139
- try {
140
- const result = await callTool(toolName, toolInput ?? {});
141
- const data = decodeRecoveredResult(result, isValid);
142
- if (data !== null)
143
- return { data, failed: false };
144
- console.warn(`[mcp-toolkit] tool-result recovery: re-executing "${toolName}" returned no usable payload`);
145
- return { data: null, failed: true };
146
- }
147
- catch (err) {
148
- console.warn(`[mcp-toolkit] tool-result recovery for "${toolName}" failed:`, err);
149
- return { data: null, failed: true };
150
- }
151
- })();
152
- }
153
- const flight = flightRef.current;
154
- let stale = false;
155
- void flight.then((outcome) => {
156
- // Drop the outcome when this subscription was superseded or the flight
157
- // was invalidated by a newer tool run.
158
- if (!stale && flightRef.current === flight)
159
- setState(outcome);
89
+ controller.update({
90
+ resultReady,
91
+ cancelled,
92
+ errored,
93
+ props,
94
+ isValid,
95
+ toolInput,
96
+ hostContext,
97
+ callTool,
98
+ policy,
99
+ graceMs: assumeStrippedAfterMs,
100
+ resolveToolName: resolveRecoveryToolName,
160
101
  });
161
- return () => {
162
- stale = true;
163
- };
164
- }, [ready, props, isValid, toolName, toolInput, callTool]);
165
- return state;
102
+ });
103
+ return useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
166
104
  }
167
105
  //# sourceMappingURL=use-tool-result-recovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,yBAAyB,EAA2B,MAAM,gCAAgC,CAAA;AACnG,OAAO,EACL,wBAAwB,GAGzB,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAQvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,IAAI,CAAA;AAkDpD;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAoB;IAC1D,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACrE,MAAM,IAAI,GAAI,WAAuC,CAAC,QAAQ,CAAA;IAC9D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IACvD,MAAM,GAAG,GAAG,IAA+B,CAAA;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAA;IACrB,MAAM,UAAU,GAAG;QACjB,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACrF,GAAG,CAAC,IAAI;QACR,GAAG,CAAC,QAAQ;KACb,CAAA;IACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAA;IAC7E,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAK/B;IACC,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAClD,OAAO,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,YAAY,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAkC;IAElC,MAAM,EACJ,WAAW,EACX,SAAS,GAAG,KAAK,EACjB,OAAO,GAAG,KAAK,EACf,KAAK,EACL,OAAO,EACP,SAAS,EACT,WAAW,EACX,QAAQ,EACR,qBAAqB,GAAG,gCAAgC,EACxD,MAAM,GAAG,MAAM,EACf,QAAQ,GACT,GAAG,OAAO,CAAA;IACX,0EAA0E;IAC1E,uCAAuC;IACvC,MAAM,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CACjC,wBAAwB,CAAI;QAC1B,QAAQ,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,yBAAyB,EAAE,CAAC,CAAC,CAAC,QAAQ;KAC1E,CAAC,CACH,CAAA;IACD,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,CAAA;IAChC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAChB,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,MAAM,CAAC;YAChB,WAAW;YACX,SAAS;YACT,OAAO;YACP,KAAK;YACL,OAAO;YACP,SAAS;YACT,WAAW;YACX,QAAQ;YACR,MAAM;YACN,OAAO,EAAE,qBAAqB;YAC9B,eAAe,EAAE,uBAAuB;SACzC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,OAAO,oBAAoB,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;AAC7F,CAAC"}
@@ -1,25 +1,67 @@
1
+ import { type UseToolQueryOptions } from "../lib/tool-query.js";
1
2
  export interface ViewDataResult<T> {
2
3
  data: T | null;
3
4
  /** True while self-fetching with no data yet — the first paint of a cockpit cell. */
4
5
  loading: boolean;
5
6
  error: Error | null;
6
7
  /**
7
- * Fetch `tool` again: the retry of an error state
8
- * (`<ErrorState onRetry={refetch} … />`). Host-pushed data, when present,
9
- * stays what `data` returns.
8
+ * Fetch `tool` again now: the retry of an error state
9
+ * (`<ErrorState onRetry={refetch} … />`) or a manual refresh — a new read
10
+ * even while a failed fetch still waits on its retry backoff. In `"static"`
11
+ * mode host-pushed data, when present, stays what `data` returns.
10
12
  */
11
13
  refetch: () => void;
14
+ /** Failed attempts of the current fetch (0 once it succeeds). */
15
+ failureCount: number;
16
+ /**
17
+ * The current fetch's last failed attempt — set from the first failure on,
18
+ * while the query still retries (`error` waits for the last retry).
19
+ */
20
+ failureReason: Error | null;
21
+ /** A fetch is in flight (the first one or a refetch). */
22
+ isFetching: boolean;
23
+ /**
24
+ * `data` is a placeholder (`placeholderData`, e.g. `keepPreviousData`):
25
+ * the previous args' answer while the current args' fetch runs or failed.
26
+ */
27
+ isPlaceholderData: boolean;
12
28
  }
29
+ /**
30
+ * How {@link useViewData} treats host-pushed `initialData`.
31
+ *
32
+ * - `"static"` (default): returned verbatim; the feed query stays off while
33
+ * it is present.
34
+ * - `"seed"`: it becomes the feed query's cached answer, and the query stays
35
+ * live (once `ready`): an invalidation after a write, a `refetch` or a
36
+ * retry re-reads the feed. A fresh seed is not refetched on mount (it is
37
+ * younger than `staleTime`); a payload delivered anew (content not seeded
38
+ * for the key before) replaces the cached answer, while a re-rendered or
39
+ * remounted old one never rolls a refetched answer back.
40
+ */
41
+ export type ViewDataMode = "static" | "seed";
42
+ /**
43
+ * Options of {@link useViewData}: TanStack's query options for the feed
44
+ * (`retry`, `retryDelay`, `staleTime`, `placeholderData` /
45
+ * `keepPreviousData`, `enabled` as an extra gate next to `ready`, …),
46
+ * plus how host data seeds it.
47
+ */
48
+ export type UseViewDataOptions<T> = Omit<UseToolQueryOptions<T>, "initialData" | "select"> & {
49
+ initialDataMode?: ViewDataMode;
50
+ };
13
51
  /**
14
52
  * The seam that lets one widget component serve both modes without a duplicate UI.
15
53
  *
16
54
  * Standalone (a `*_show_*` widget) the agent's tool result is handed in via
17
- * `initialData` (from the view's stepData, e.g. through `adaptDataWidget`) and
18
- * returned verbatim. Embedded in a self-fetching cockpit only scope params are
19
- * passed, so the component fetches `tool` with `args` under `key` — disabled
20
- * unless data is absent AND `ready` (i.e. the required id/key is present).
21
- * Sibling widgets sharing `key` dedupe to a single call, so a composed view of
22
- * N widgets over one data feed fetches once.
55
+ * `initialData` (from the view's stepData, e.g. through `adaptDataWidget`).
56
+ * Embedded in a self-fetching cockpit only scope params are passed, so the
57
+ * component fetches `tool` with `args` under `key`, gated on `ready` (i.e.
58
+ * the required id/key is present). Sibling widgets sharing `key` and `args`
59
+ * dedupe to a single call, so a composed view of N widgets over one data
60
+ * feed fetches once.
61
+ *
62
+ * By default host data is returned verbatim and switches the query off;
63
+ * `initialDataMode: "seed"` keeps the query live over it instead (see
64
+ * {@link ViewDataMode}). `options` passes TanStack's query options through.
23
65
  */
24
- export declare function useViewData<T>(initialData: T | null | undefined, key: ReadonlyArray<unknown>, tool: string, args: Record<string, unknown>, ready: boolean): ViewDataResult<T>;
66
+ export declare function useViewData<T>(initialData: T | null | undefined, key: ReadonlyArray<unknown>, tool: string, args: Record<string, unknown>, ready: boolean, options?: UseViewDataOptions<T>): ViewDataResult<T>;
25
67
  //# sourceMappingURL=use-view-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-view-data.d.ts","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB;;;;OAIG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACjC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,EAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,OAAO,GACb,cAAc,CAAC,CAAC,CAAC,CAQnB"}
1
+ {"version":3,"file":"use-view-data.d.ts","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAG9E,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,aAAa,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,yDAAyD;IACzD,UAAU,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,aAAa,GAAG,QAAQ,CAAC,GAAG;IAC3F,eAAe,CAAC,EAAE,YAAY,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,WAAW,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACjC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,EAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAC9B,cAAc,CAAC,CAAC,CAAC,CA0BnB"}
@@ -1,23 +1,88 @@
1
- import { useCallback } from "react";
2
- import { useToolQuery } from "./use-tool-query.js";
1
+ import { useCallback, useState } from "react";
2
+ import { hashKey, useQueryClient } from "@tanstack/react-query";
3
+ import { seedToolQuery } from "../lib/tool-query.js";
4
+ import { useToolQuery, useToolQueryKey } from "./use-tool-query.js";
3
5
  /**
4
6
  * The seam that lets one widget component serve both modes without a duplicate UI.
5
7
  *
6
8
  * Standalone (a `*_show_*` widget) the agent's tool result is handed in via
7
- * `initialData` (from the view's stepData, e.g. through `adaptDataWidget`) and
8
- * returned verbatim. Embedded in a self-fetching cockpit only scope params are
9
- * passed, so the component fetches `tool` with `args` under `key` — disabled
10
- * unless data is absent AND `ready` (i.e. the required id/key is present).
11
- * Sibling widgets sharing `key` dedupe to a single call, so a composed view of
12
- * N widgets over one data feed fetches once.
9
+ * `initialData` (from the view's stepData, e.g. through `adaptDataWidget`).
10
+ * Embedded in a self-fetching cockpit only scope params are passed, so the
11
+ * component fetches `tool` with `args` under `key`, gated on `ready` (i.e.
12
+ * the required id/key is present). Sibling widgets sharing `key` and `args`
13
+ * dedupe to a single call, so a composed view of N widgets over one data
14
+ * feed fetches once.
15
+ *
16
+ * By default host data is returned verbatim and switches the query off;
17
+ * `initialDataMode: "seed"` keeps the query live over it instead (see
18
+ * {@link ViewDataMode}). `options` passes TanStack's query options through.
19
+ */
20
+ export function useViewData(initialData, key, tool, args, ready, options) {
21
+ const { initialDataMode = "static", enabled, ...queryOptions } = options ?? {};
22
+ const seeding = initialDataMode === "seed";
23
+ const cacheKey = useStableKey(useToolQueryKey(key, tool, args));
24
+ useSeed(seeding ? initialData : null, cacheKey, queryOptions.initialDataUpdatedAt);
25
+ const active = ready && enabled !== false;
26
+ const fetches = active && (seeding || !initialData);
27
+ const query = useToolQuery([...key], tool, args, {
28
+ ...queryOptions,
29
+ enabled: typeof enabled === "function" ? (q) => fetches && enabled(q) : fetches,
30
+ });
31
+ const data = seeding ? (query.data ?? initialData) : (initialData ?? query.data);
32
+ const refetch = useFreshRefetch(cacheKey, query.refetch);
33
+ return {
34
+ data: data ?? null,
35
+ // The query's own verdict: a function `enabled` that returns false idles
36
+ // like `enabled: false`, never an endless skeleton.
37
+ loading: !data && query.isEnabled && !query.isError,
38
+ error: query.error,
39
+ refetch,
40
+ failureCount: query.failureCount,
41
+ failureReason: query.failureReason,
42
+ isFetching: query.isFetching,
43
+ isPlaceholderData: query.isPlaceholderData,
44
+ };
45
+ }
46
+ /** `key`, kept by content: callers build `key`/`args` anew every render. */
47
+ function useStableKey(key) {
48
+ const id = hashKey(key);
49
+ const [stable, setStable] = useState({ id, key });
50
+ if (stable.id !== id)
51
+ setStable({ id, key });
52
+ return stable.id === id ? stable.key : key;
53
+ }
54
+ /**
55
+ * `"seed"` mode: write the host's payload into the feed's cache entry in the
56
+ * render phase, before the query's observer reads the cache — what TanStack's
57
+ * own `initialData` does (see {@link seedToolQuery} for when it wins over a
58
+ * cached answer). The last processed seed skips the content check while the
59
+ * same object comes in render after render.
60
+ */
61
+ function useSeed(seed, cacheKey, updatedAt) {
62
+ const client = useQueryClient();
63
+ const keyId = hashKey(cacheKey);
64
+ const [seen, setSeen] = useState(null);
65
+ if (seed == null || (seen?.seed === seed && seen.keyId === keyId))
66
+ return;
67
+ const at = typeof updatedAt === "function" ? updatedAt() : updatedAt;
68
+ const written = seedToolQuery(client, cacheKey, seed, at);
69
+ // Only a real change re-renders: an equal new object per render must not loop.
70
+ if (written || seen?.keyId !== keyId)
71
+ setSeen({ seed, keyId });
72
+ }
73
+ /**
74
+ * A refetch that reads anew at once. TanStack restarts an in-flight fetch only
75
+ * over data (`cancelRefetch`); a key without data joins the running retry
76
+ * chain and waits out its backoff. So cancel that chain first, then read.
13
77
  */
14
- export function useViewData(initialData, key, tool, args, ready) {
15
- const query = useToolQuery([...key], tool, args, { enabled: !initialData && ready });
16
- const data = initialData ?? query.data ?? null;
17
- const { refetch: refetchQuery } = query;
18
- const refetch = useCallback(() => {
19
- void refetchQuery();
20
- }, [refetchQuery]);
21
- return { data, loading: !data && ready && !query.isError, error: query.error ?? null, refetch };
78
+ function useFreshRefetch(cacheKey, refetchQuery) {
79
+ const client = useQueryClient();
80
+ return useCallback(() => {
81
+ if (client.getQueryData(cacheKey) !== undefined) {
82
+ void refetchQuery();
83
+ return;
84
+ }
85
+ void client.cancelQueries({ queryKey: cacheKey, exact: true }).then(() => refetchQuery());
86
+ }, [client, cacheKey, refetchQuery]);
22
87
  }
23
88
  //# sourceMappingURL=use-view-data.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-view-data.js","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAelD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,WAAiC,EACjC,GAA2B,EAC3B,IAAY,EACZ,IAA6B,EAC7B,KAAc;IAEd,MAAM,KAAK,GAAG,YAAY,CAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC,CAAA;IACvF,MAAM,IAAI,GAAG,WAAW,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,CAAA;IAC9C,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,KAAK,CAAA;IACvC,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,KAAK,YAAY,EAAE,CAAA;IACrB,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAA;IAClB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,EAAE,OAAO,EAAE,CAAA;AACjG,CAAC"}
1
+ {"version":3,"file":"use-view-data.js","sourceRoot":"","sources":["../../src/hooks/use-view-data.ts"],"names":[],"mappings":"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"}