@miragon/mcp-toolkit-ui 2.6.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.
- package/README.md +14 -5
- package/dist/app/adapt-data-widget.d.ts +1 -22
- package/dist/app/adapt-data-widget.d.ts.map +1 -1
- package/dist/app/adapt-data-widget.js +1 -35
- package/dist/app/adapt-data-widget.js.map +1 -1
- package/dist/app/builder/BuilderBanners.d.ts +7 -2
- package/dist/app/builder/BuilderBanners.d.ts.map +1 -1
- package/dist/app/builder/BuilderBanners.js +8 -3
- package/dist/app/builder/BuilderBanners.js.map +1 -1
- package/dist/app/builder/CanvasRow.d.ts +4 -2
- package/dist/app/builder/CanvasRow.d.ts.map +1 -1
- package/dist/app/builder/CanvasRow.js +29 -17
- package/dist/app/builder/CanvasRow.js.map +1 -1
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
- package/dist/app/builder/CatalogueSheet.js +14 -6
- package/dist/app/builder/CatalogueSheet.js.map +1 -1
- package/dist/app/builder/CellPropsSheet.d.ts +7 -3
- package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
- package/dist/app/builder/CellPropsSheet.js +10 -3
- package/dist/app/builder/CellPropsSheet.js.map +1 -1
- package/dist/app/builder/DiscardDialog.d.ts +18 -0
- package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
- package/dist/app/builder/DiscardDialog.js +18 -0
- package/dist/app/builder/DiscardDialog.js.map +1 -0
- package/dist/app/builder/EmptyHint.d.ts +4 -0
- package/dist/app/builder/EmptyHint.d.ts.map +1 -1
- package/dist/app/builder/EmptyHint.js +6 -1
- package/dist/app/builder/EmptyHint.js.map +1 -1
- package/dist/app/builder/LayoutSurface.d.ts +33 -9
- package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
- package/dist/app/builder/LayoutSurface.js +74 -23
- package/dist/app/builder/LayoutSurface.js.map +1 -1
- package/dist/app/builder/PipelineStrip.d.ts +5 -2
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +33 -15
- package/dist/app/builder/PipelineStrip.js.map +1 -1
- package/dist/app/builder/SaveDialog.d.ts +9 -1
- package/dist/app/builder/SaveDialog.d.ts.map +1 -1
- package/dist/app/builder/SaveDialog.js +9 -3
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +14 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +24 -7
- package/dist/app/builder/Toolbar.js.map +1 -1
- package/dist/app/builder/Workspace.d.ts +23 -3
- package/dist/app/builder/Workspace.d.ts.map +1 -1
- package/dist/app/builder/Workspace.js +58 -8
- package/dist/app/builder/Workspace.js.map +1 -1
- package/dist/app/builder/builder-model.d.ts +146 -3
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +196 -5
- package/dist/app/builder/builder-model.js.map +1 -1
- package/dist/app/builder/labels.d.ts +13 -62
- package/dist/app/builder/labels.d.ts.map +1 -1
- package/dist/app/builder/labels.js +9 -58
- package/dist/app/builder/labels.js.map +1 -1
- package/dist/app/builder/reveal.d.ts +10 -0
- package/dist/app/builder/reveal.d.ts.map +1 -0
- package/dist/app/builder/reveal.js +10 -0
- package/dist/app/builder/reveal.js.map +1 -0
- package/dist/app/builder/status-chip.d.ts.map +1 -1
- package/dist/app/builder/status-chip.js +3 -2
- package/dist/app/builder/status-chip.js.map +1 -1
- package/dist/app/builder/use-builder-catalogue.d.ts +5 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +50 -17
- package/dist/app/builder/use-builder-catalogue.js.map +1 -1
- package/dist/app/builder/use-builder-session.d.ts +30 -0
- package/dist/app/builder/use-builder-session.d.ts.map +1 -0
- package/dist/app/builder/use-builder-session.js +58 -0
- package/dist/app/builder/use-builder-session.js.map +1 -0
- package/dist/app/builder/use-display-resolver.d.ts +17 -0
- package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
- package/dist/app/builder/use-display-resolver.js +16 -0
- package/dist/app/builder/use-display-resolver.js.map +1 -0
- package/dist/app/builder/use-save-dashboard.d.ts +3 -1
- package/dist/app/builder/use-save-dashboard.d.ts.map +1 -1
- package/dist/app/builder/use-save-dashboard.js +3 -1
- package/dist/app/builder/use-save-dashboard.js.map +1 -1
- package/dist/app/index.d.ts +8 -3
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +8 -2
- package/dist/app/index.js.map +1 -1
- package/dist/app/layout-builder.d.ts +18 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +84 -78
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +103 -20
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +125 -40
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +23 -0
- package/dist/app/mcp-app-view-states.d.ts.map +1 -0
- package/dist/app/mcp-app-view-states.js +55 -0
- package/dist/app/mcp-app-view-states.js.map +1 -0
- package/dist/app/mcp-app-view.d.ts +72 -5
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +241 -141
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +8 -2
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +33 -4
- package/dist/app/mcp-toolkit-app.js.map +1 -1
- package/dist/app/mcp-use-host-bridge.d.ts +15 -6
- package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
- package/dist/app/mcp-use-host-bridge.js +51 -22
- package/dist/app/mcp-use-host-bridge.js.map +1 -1
- package/dist/app/model-context.d.ts +71 -0
- package/dist/app/model-context.d.ts.map +1 -0
- package/dist/app/model-context.js +101 -0
- package/dist/app/model-context.js.map +1 -0
- package/dist/app/use-build-mode-focus.d.ts +33 -0
- package/dist/app/use-build-mode-focus.d.ts.map +1 -0
- package/dist/app/use-build-mode-focus.js +59 -0
- package/dist/app/use-build-mode-focus.js.map +1 -0
- package/dist/app/use-view-actions.d.ts +31 -0
- package/dist/app/use-view-actions.d.ts.map +1 -0
- package/dist/app/use-view-actions.js +81 -0
- package/dist/app/use-view-actions.js.map +1 -0
- package/dist/app/use-view-lifecycle.d.ts +42 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -0
- package/dist/app/use-view-lifecycle.js +81 -0
- package/dist/app/use-view-lifecycle.js.map +1 -0
- package/dist/app/view-lifecycle.d.ts +185 -0
- package/dist/app/view-lifecycle.d.ts.map +1 -0
- package/dist/app/view-lifecycle.js +207 -0
- package/dist/app/view-lifecycle.js.map +1 -0
- package/dist/app/widget-fixture.d.ts +10 -3
- package/dist/app/widget-fixture.d.ts.map +1 -1
- package/dist/app/widget-fixture.js +21 -8
- package/dist/app/widget-fixture.js.map +1 -1
- package/dist/app/widget-props-sheet.d.ts +6 -10
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +25 -20
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.d.ts +41 -1
- package/dist/app/widget-renderer.d.ts.map +1 -1
- package/dist/app/widget-renderer.js +82 -31
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +9 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +9 -6
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts +33 -0
- package/dist/components/EmptyState.d.ts.map +1 -0
- package/dist/components/EmptyState.js +19 -0
- package/dist/components/EmptyState.js.map +1 -0
- package/dist/components/ErrorState.d.ts +53 -0
- package/dist/components/ErrorState.d.ts.map +1 -0
- package/dist/components/ErrorState.js +77 -0
- package/dist/components/ErrorState.js.map +1 -0
- package/dist/components/FilterBar.d.ts +16 -5
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +13 -5
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/GroupCard.d.ts.map +1 -1
- package/dist/components/GroupCard.js +2 -1
- package/dist/components/GroupCard.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +70 -18
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +112 -23
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +32 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +35 -6
- package/dist/components/ListFooter.js.map +1 -1
- package/dist/components/PagedListFooter.d.ts +57 -0
- package/dist/components/PagedListFooter.d.ts.map +1 -0
- package/dist/components/PagedListFooter.js +27 -0
- package/dist/components/PagedListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +36 -12
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +29 -8
- package/dist/components/Pills.js.map +1 -1
- package/dist/components/SectionHeading.d.ts +3 -1
- package/dist/components/SectionHeading.d.ts.map +1 -1
- package/dist/components/SectionHeading.js +6 -2
- package/dist/components/SectionHeading.js.map +1 -1
- package/dist/components/Toast.d.ts +43 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/Toast.js +106 -0
- package/dist/components/Toast.js.map +1 -0
- package/dist/components/WidgetHeader.d.ts +34 -10
- package/dist/components/WidgetHeader.d.ts.map +1 -1
- package/dist/components/WidgetHeader.js +11 -6
- package/dist/components/WidgetHeader.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -4
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
- package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
- package/dist/hooks/tool-result-recovery-model.js +273 -0
- package/dist/hooks/tool-result-recovery-model.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +56 -14
- package/dist/hooks/use-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-tool-query.js +102 -25
- package/dist/hooks/use-tool-query.js.map +1 -1
- package/dist/hooks/use-tool-result-recovery.d.ts +61 -44
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +62 -110
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +55 -7
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -11
- package/dist/hooks/use-view-data.js.map +1 -1
- package/dist/hooks/use-view-tool-query.d.ts +12 -7
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-view-tool-query.js +15 -14
- package/dist/hooks/use-view-tool-query.js.map +1 -1
- package/dist/index.d.ts +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/focus-return.d.ts +61 -0
- package/dist/lib/focus-return.d.ts.map +1 -0
- package/dist/lib/focus-return.js +46 -0
- package/dist/lib/focus-return.js.map +1 -0
- package/dist/lib/focus-ring.d.ts +18 -0
- package/dist/lib/focus-ring.d.ts.map +1 -0
- package/dist/lib/focus-ring.js +18 -0
- package/dist/lib/focus-ring.js.map +1 -0
- package/dist/lib/icon-stroke.d.ts +12 -0
- package/dist/lib/icon-stroke.d.ts.map +1 -0
- package/dist/lib/icon-stroke.js +12 -0
- package/dist/lib/icon-stroke.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +23 -1
- package/dist/lib/parse-tool-result.d.ts.map +1 -1
- package/dist/lib/parse-tool-result.js +38 -2
- package/dist/lib/parse-tool-result.js.map +1 -1
- package/dist/lib/toast-model.d.ts +86 -0
- package/dist/lib/toast-model.d.ts.map +1 -0
- package/dist/lib/toast-model.js +102 -0
- package/dist/lib/toast-model.js.map +1 -0
- package/dist/lib/tone-utils.d.ts +95 -9
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +100 -9
- package/dist/lib/tone-utils.js.map +1 -1
- package/dist/lib/tool-query.d.ts +107 -0
- package/dist/lib/tool-query.d.ts.map +1 -0
- package/dist/lib/tool-query.js +182 -0
- package/dist/lib/tool-query.js.map +1 -0
- package/dist/lib/tool-result-observer.d.ts +108 -0
- package/dist/lib/tool-result-observer.d.ts.map +1 -0
- package/dist/lib/tool-result-observer.js +158 -0
- package/dist/lib/tool-result-observer.js.map +1 -0
- package/dist/lib/typography.d.ts +37 -0
- package/dist/lib/typography.d.ts.map +1 -0
- package/dist/lib/typography.js +41 -0
- package/dist/lib/typography.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +11 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/locale/index.d.ts +3 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/index.js +2 -1
- package/dist/locale/index.js.map +1 -1
- package/dist/locale/locale-provider.d.ts +42 -1
- package/dist/locale/locale-provider.d.ts.map +1 -1
- package/dist/locale/locale-provider.js +44 -3
- package/dist/locale/locale-provider.js.map +1 -1
- package/dist/locale/message-types.d.ts +336 -0
- package/dist/locale/message-types.d.ts.map +1 -0
- package/dist/locale/message-types.js +7 -0
- package/dist/locale/message-types.js.map +1 -0
- package/dist/locale/messages-de.d.ts +9 -0
- package/dist/locale/messages-de.d.ts.map +1 -0
- package/dist/locale/messages-de.js +185 -0
- package/dist/locale/messages-de.js.map +1 -0
- package/dist/locale/messages-en.d.ts +8 -0
- package/dist/locale/messages-en.d.ts.map +1 -0
- package/dist/locale/messages-en.js +184 -0
- package/dist/locale/messages-en.js.map +1 -0
- package/dist/locale/toolkit-messages.d.ts +57 -0
- package/dist/locale/toolkit-messages.d.ts.map +1 -0
- package/dist/locale/toolkit-messages.js +103 -0
- package/dist/locale/toolkit-messages.js.map +1 -0
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +6 -2
- package/dist/primitives/alert.js.map +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/badge.d.ts.map +1 -1
- package/dist/primitives/badge.js +19 -6
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.d.ts.map +1 -1
- package/dist/primitives/button.js +12 -8
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/card.js +4 -4
- package/dist/primitives/card.js.map +1 -1
- package/dist/primitives/dialog.d.ts +7 -3
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +22 -8
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/input.d.ts.map +1 -1
- package/dist/primitives/input.js +4 -1
- package/dist/primitives/input.js.map +1 -1
- package/dist/primitives/scroll-area.js +1 -1
- package/dist/primitives/scroll-area.js.map +1 -1
- package/dist/primitives/select.d.ts.map +1 -1
- package/dist/primitives/select.js +6 -3
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +3 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +17 -7
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/primitives/skeleton.js +1 -1
- package/dist/primitives/skeleton.js.map +1 -1
- package/dist/primitives/switch.d.ts.map +1 -1
- package/dist/primitives/switch.js +2 -1
- package/dist/primitives/switch.js.map +1 -1
- package/dist/primitives/tabs.d.ts.map +1 -1
- package/dist/primitives/tabs.js +5 -3
- package/dist/primitives/tabs.js.map +1 -1
- package/dist/providers/query-provider.d.ts +32 -1
- package/dist/providers/query-provider.d.ts.map +1 -1
- package/dist/providers/query-provider.js +53 -4
- package/dist/providers/query-provider.js.map +1 -1
- package/dist/render-cases-primitives.js +1 -1
- package/dist/render-cases-primitives.js.map +1 -1
- package/dist/render-cases.d.ts.map +1 -1
- package/dist/render-cases.js +48 -6
- package/dist/render-cases.js.map +1 -1
- package/dist/render-effects.d.ts +42 -0
- package/dist/render-effects.d.ts.map +1 -0
- package/dist/render-effects.js +81 -0
- package/dist/render-effects.js.map +1 -0
- package/dist/render-scan.d.ts +25 -0
- package/dist/render-scan.d.ts.map +1 -0
- package/dist/render-scan.js +66 -0
- package/dist/render-scan.js.map +1 -0
- package/dist/theme/cd-tokens.d.ts +66 -0
- package/dist/theme/cd-tokens.d.ts.map +1 -0
- package/dist/theme/cd-tokens.js +64 -0
- package/dist/theme/cd-tokens.js.map +1 -0
- package/dist/theme/create-theme.d.ts +214 -39
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +204 -13
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/fonts.d.ts +38 -0
- package/dist/theme/fonts.d.ts.map +1 -0
- package/dist/theme/fonts.js +56 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/theme/host-fonts.d.ts +39 -0
- package/dist/theme/host-fonts.d.ts.map +1 -0
- package/dist/theme/host-fonts.js +44 -0
- package/dist/theme/host-fonts.js.map +1 -0
- package/dist/theme/index.d.ts +8 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +5 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/portal-container.d.ts +16 -0
- package/dist/theme/portal-container.d.ts.map +1 -0
- package/dist/theme/portal-container.js +19 -0
- package/dist/theme/portal-container.js.map +1 -0
- package/dist/theme/presets.d.ts +24 -9
- package/dist/theme/presets.d.ts.map +1 -1
- package/dist/theme/presets.js +44 -11
- package/dist/theme/presets.js.map +1 -1
- package/dist/theme/theme-provider.d.ts +27 -9
- package/dist/theme/theme-provider.d.ts.map +1 -1
- package/dist/theme/theme-provider.js +42 -20
- package/dist/theme/theme-provider.js.map +1 -1
- package/package.json +11 -5
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +26 -13
- package/src/app/builder/CanvasRow.tsx +79 -32
- package/src/app/builder/CatalogueSheet.tsx +58 -35
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/EmptyHint.tsx +16 -11
- package/src/app/builder/LayoutSurface.tsx +207 -67
- package/src/app/builder/PipelineStrip.tsx +265 -156
- package/src/app/builder/SaveDialog.tsx +25 -14
- package/src/app/builder/Toolbar.tsx +154 -57
- package/src/app/builder/Workspace.tsx +226 -56
- package/src/app/builder/builder-feedback.test.tsx +75 -0
- package/src/app/builder/builder-model.test.ts +5 -0
- package/src/app/builder/builder-model.ts +346 -6
- package/src/app/builder/builder-model.ux.test.ts +456 -0
- package/src/app/builder/builder-ux.test.tsx +844 -0
- package/src/app/builder/labels.ts +15 -121
- package/src/app/builder/reveal.ts +10 -0
- package/src/app/builder/status-chip.tsx +8 -4
- package/src/app/builder/use-builder-catalogue.ts +62 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/builder/use-save-dashboard.ts +5 -0
- package/src/app/index.ts +20 -3
- package/src/app/layout-builder.tsx +193 -186
- package/src/app/mcp-app-view-chrome.test.tsx +487 -14
- package/src/app/mcp-app-view-chrome.tsx +328 -100
- package/src/app/mcp-app-view-states.tsx +140 -0
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +478 -0
- package/src/app/mcp-app-view.tsx +447 -190
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +39 -8
- package/src/app/mcp-use-host-bridge.test.tsx +180 -0
- package/src/app/mcp-use-host-bridge.tsx +67 -24
- package/src/app/model-context.test.tsx +116 -0
- package/src/app/model-context.tsx +125 -0
- package/src/app/use-build-mode-focus.ts +62 -0
- package/src/app/use-view-actions.ts +89 -0
- package/src/app/use-view-lifecycle.ts +122 -0
- package/src/app/view-lifecycle.test.ts +443 -0
- package/src/app/view-lifecycle.ts +334 -0
- package/src/app/widget-fixture.effects.test.tsx +51 -0
- package/src/app/widget-fixture.render.test.tsx +81 -0
- package/src/app/widget-fixture.tsx +34 -11
- package/src/app/widget-props-sheet.tsx +67 -39
- package/src/app/widget-renderer.render.test.tsx +131 -0
- package/src/app/widget-renderer.tsx +136 -38
- package/src/components/DrillButton.tsx +24 -10
- package/src/components/EmptyState.tsx +83 -0
- package/src/components/ErrorState.tsx +204 -0
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +56 -27
- package/src/components/GroupCard.tsx +3 -2
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +329 -91
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +110 -12
- package/src/components/PagedListFooter.test.tsx +140 -0
- package/src/components/PagedListFooter.tsx +107 -0
- package/src/components/Pills.test.tsx +77 -0
- package/src/components/Pills.tsx +78 -16
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +206 -0
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +314 -0
- package/src/components/tone-figures.test.tsx +58 -0
- package/src/fonts.css +19 -0
- package/src/globals.css +9 -165
- package/src/hooks/index.ts +6 -3
- package/src/hooks/tool-result-recovery-model.test.ts +744 -0
- package/src/hooks/tool-result-recovery-model.ts +418 -0
- package/src/hooks/use-tool-query.effects.test.tsx +205 -0
- package/src/hooks/use-tool-query.ts +156 -33
- package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
- package/src/hooks/use-tool-result-recovery.test.ts +28 -5
- package/src/hooks/use-tool-result-recovery.ts +101 -131
- package/src/hooks/use-view-data.test.tsx +169 -0
- package/src/hooks/use-view-data.ts +131 -10
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +425 -0
- package/src/index.ts +102 -13
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -0
- package/src/lib/focus-ring.ts +20 -0
- package/src/lib/icon-stroke.test.ts +59 -0
- package/src/lib/icon-stroke.ts +13 -0
- package/src/lib/parse-tool-result.test.ts +46 -1
- package/src/lib/parse-tool-result.ts +40 -2
- package/src/lib/toast-model.test.ts +233 -0
- package/src/lib/toast-model.ts +165 -0
- package/src/lib/tone-utils.test.ts +125 -16
- package/src/lib/tone-utils.ts +144 -15
- package/src/lib/tool-query.test.ts +569 -0
- package/src/lib/tool-query.ts +253 -0
- package/src/lib/tool-result-observer.test.ts +296 -0
- package/src/lib/tool-result-observer.ts +211 -0
- package/src/lib/typography.test.ts +45 -0
- package/src/lib/typography.ts +47 -0
- package/src/lib/utils.ts +12 -1
- package/src/locale/index.ts +14 -1
- package/src/locale/locale-provider.test.tsx +87 -0
- package/src/locale/locale-provider.tsx +90 -3
- package/src/locale/message-types.ts +337 -0
- package/src/locale/messages-de.ts +198 -0
- package/src/locale/messages-en.ts +196 -0
- package/src/locale/toolkit-messages.test.ts +349 -0
- package/src/locale/toolkit-messages.ts +143 -0
- package/src/no-hardcoded-copy.test.ts +432 -0
- package/src/primitives/alert.tsx +7 -2
- package/src/primitives/badge.tsx +19 -7
- package/src/primitives/button.tsx +13 -8
- package/src/primitives/card.tsx +4 -4
- package/src/primitives/dialog.tsx +42 -8
- package/src/primitives/input.tsx +5 -3
- package/src/primitives/scroll-area.tsx +1 -1
- package/src/primitives/select.tsx +7 -4
- package/src/primitives/sheet.tsx +33 -6
- package/src/primitives/skeleton.tsx +1 -1
- package/src/primitives/switch.tsx +4 -2
- package/src/primitives/tabs.tsx +9 -6
- package/src/providers/query-provider.test.tsx +154 -0
- package/src/providers/query-provider.tsx +66 -5
- package/src/render-cases-primitives.tsx +1 -1
- package/src/render-cases.tsx +82 -6
- package/src/render-effects.tsx +96 -0
- package/src/render-scan.ts +75 -0
- package/src/theme/cd-tokens.generated.css +48 -0
- package/src/theme/cd-tokens.test.ts +109 -0
- package/src/theme/cd-tokens.ts +67 -0
- package/src/theme/create-theme.test.ts +253 -5
- package/src/theme/create-theme.ts +341 -41
- package/src/theme/fonts.test.ts +85 -0
- package/src/theme/fonts.ts +72 -0
- package/src/theme/host-fonts.test.ts +135 -0
- package/src/theme/host-fonts.ts +52 -0
- package/src/theme/index.ts +15 -1
- package/src/theme/portal-container.ts +20 -0
- package/src/theme/presets.ts +44 -11
- package/src/theme/theme-css.test.ts +619 -0
- package/src/theme/theme-provider.test.tsx +82 -0
- package/src/theme/theme-provider.tsx +60 -24
- package/src/theme.css +344 -0
- package/ui-catalog.json +783 -49
|
@@ -1,63 +1,186 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react"
|
|
2
|
+
import {
|
|
3
|
+
hashKey,
|
|
4
|
+
useMutation,
|
|
5
|
+
useQuery,
|
|
6
|
+
useQueryClient,
|
|
7
|
+
type MutationFunctionContext,
|
|
8
|
+
type UseMutationOptions,
|
|
9
|
+
type UseMutationResult,
|
|
10
|
+
type UseQueryResult,
|
|
11
|
+
} from "@tanstack/react-query"
|
|
12
|
+
import { useCallTool, useToolNameInQueryKey } from "../providers/query-provider.js"
|
|
3
13
|
import { parseToolResult } from "../lib/parse-tool-result.js"
|
|
14
|
+
import {
|
|
15
|
+
claimToolQueryKey,
|
|
16
|
+
invalidateToolQueries,
|
|
17
|
+
NoToolTransportError,
|
|
18
|
+
settleEachCall,
|
|
19
|
+
toolKeyCollisionMessage,
|
|
20
|
+
toolQueryKey,
|
|
21
|
+
toolQueryOptions,
|
|
22
|
+
type PerCallCallbacks,
|
|
23
|
+
type UseToolQueryOptions,
|
|
24
|
+
} from "../lib/tool-query.js"
|
|
4
25
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
26
|
+
export type { UseToolQueryOptions } from "../lib/tool-query.js"
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The exact cache key `useToolQuery`, `useViewToolQuery` and `useViewData`
|
|
30
|
+
* use for this tool and args under the nearest `AppQueryProvider`:
|
|
31
|
+
* `toolQueryKey` with the provider's `toolNameInQueryKey` setting. For
|
|
32
|
+
* `getQueryData`, `setQueryData` or `cancelQueries({ exact: true })`; prefix
|
|
33
|
+
* invalidation needs only the caller's `queryKey`. A new array per render.
|
|
34
|
+
*/
|
|
35
|
+
export function useToolQueryKey(
|
|
36
|
+
queryKey: readonly unknown[],
|
|
37
|
+
toolName: string,
|
|
38
|
+
args: object,
|
|
39
|
+
): unknown[] {
|
|
40
|
+
return toolQueryKey(queryKey, toolName, args, useToolNameInQueryKey())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Warns when two tools use one cache key (toolkit#176 K18): their answers
|
|
45
|
+
* would overwrite each other. Only the 2.x key can collide: with the tool
|
|
46
|
+
* name in the key (`toolNameInQueryKey`), two tools never share one.
|
|
47
|
+
*/
|
|
48
|
+
export function useToolKeyGuard(
|
|
49
|
+
queryKey: readonly unknown[],
|
|
50
|
+
toolName: string,
|
|
51
|
+
args: object,
|
|
52
|
+
): void {
|
|
53
|
+
const client = useQueryClient()
|
|
54
|
+
const keyId = hashKey(useToolQueryKey(queryKey, toolName, args))
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const previous = claimToolQueryKey(client, keyId, toolName)
|
|
57
|
+
if (previous !== null) console.warn(toolKeyCollisionMessage(keyId, toolName, previous))
|
|
58
|
+
}, [client, keyId, toolName])
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fetches a query again once a tool transport arrives, when it failed for
|
|
63
|
+
* want of one ({@link NoToolTransportError}): a `callTool` that resolves
|
|
64
|
+
* after the first render. TanStack refetches on a new key or `enabled`,
|
|
65
|
+
* never on a new fetcher, so the query would keep the error until a remount.
|
|
66
|
+
*/
|
|
67
|
+
export function useRefetchOnTransport(
|
|
68
|
+
callTool: unknown,
|
|
69
|
+
query: Pick<UseQueryResult<unknown, Error>, "error" | "refetch">,
|
|
70
|
+
): void {
|
|
71
|
+
const { error, refetch } = query
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (callTool && error instanceof NoToolTransportError) void refetch()
|
|
74
|
+
}, [callTool, error, refetch])
|
|
8
75
|
}
|
|
9
76
|
|
|
10
77
|
/**
|
|
11
78
|
* Loads data from a widget tool via TanStack Query.
|
|
12
79
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* entries
|
|
16
|
-
*
|
|
17
|
-
*
|
|
80
|
+
* The effective cache key is `[...queryKey, args]` (`toolQueryKey`): two
|
|
81
|
+
* callers that share `queryKey` but pass different `args` get separate
|
|
82
|
+
* entries. Two tools must not share a key and args; the hook warns when they
|
|
83
|
+
* do. Under an `AppQueryProvider` with `toolNameInQueryKey` (opt-in in 2.x,
|
|
84
|
+
* the default from the next major) the key is `[...queryKey, toolName,
|
|
85
|
+
* args]` and two tools never collide; `useToolQueryKey` returns the key in
|
|
86
|
+
* force. `opts` passes TanStack's query options through (`retry`,
|
|
87
|
+
* `retryDelay`, `staleTime`, `placeholderData` / `keepPreviousData`,
|
|
88
|
+
* `initialData` + `initialDataUpdatedAt`, `enabled`, `select`, …), and the
|
|
89
|
+
* result exposes `refetch`, `failureCount` and `failureReason`. `retry`
|
|
90
|
+
* defaults to the client's; `retry: shouldRetryToolCall` stops retrying a
|
|
91
|
+
* tool's own `isError` answer.
|
|
92
|
+
*
|
|
93
|
+
* The tool goes through `AppQueryProvider`'s `callTool`, else the nearest
|
|
94
|
+
* `HostBridgeProvider`'s bridge; with neither, the query fails with a
|
|
95
|
+
* "no tool transport" error instead of idling, and fetches once one arrives.
|
|
18
96
|
*/
|
|
19
97
|
export function useToolQuery<TData = unknown, TSelected = TData>(
|
|
20
|
-
queryKey: unknown[],
|
|
98
|
+
queryKey: readonly unknown[],
|
|
21
99
|
toolName: string,
|
|
22
100
|
args: object,
|
|
23
101
|
opts?: UseToolQueryOptions<TData, TSelected>,
|
|
24
|
-
) {
|
|
102
|
+
): UseQueryResult<TSelected, Error> {
|
|
25
103
|
const callTool = useCallTool()
|
|
104
|
+
const toolNameInKey = useToolNameInQueryKey()
|
|
105
|
+
useToolKeyGuard(queryKey, toolName, args)
|
|
106
|
+
const query = useQuery<TData, Error, TSelected>(
|
|
107
|
+
toolQueryOptions<TData, TSelected>(queryKey, toolName, args, callTool, opts, {
|
|
108
|
+
toolNameInKey,
|
|
109
|
+
}),
|
|
110
|
+
)
|
|
111
|
+
useRefetchOnTransport(callTool, query)
|
|
112
|
+
return query
|
|
113
|
+
}
|
|
26
114
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
select: opts?.select,
|
|
35
|
-
enabled: !!callTool && (opts?.enabled ?? true),
|
|
36
|
-
})
|
|
115
|
+
/** Options of {@link useToolMutation}: TanStack's mutation options plus `invalidateKeys`. */
|
|
116
|
+
export type UseToolMutationOptions<TData = unknown> = Omit<
|
|
117
|
+
UseMutationOptions<TData, Error, Record<string, unknown>, unknown>,
|
|
118
|
+
"mutationFn" | "onMutate"
|
|
119
|
+
> & {
|
|
120
|
+
/** Query keys (prefixes) to invalidate after a successful call. */
|
|
121
|
+
invalidateKeys?: unknown[][]
|
|
37
122
|
}
|
|
38
123
|
|
|
39
124
|
/**
|
|
40
|
-
* Executes a mutation via a widget tool and invalidates
|
|
125
|
+
* Executes a mutation via a widget tool and invalidates `invalidateKeys`
|
|
126
|
+
* after each successful call (`invalidateQueries`: active queries refetch,
|
|
127
|
+
* inactive ones are marked stale and refetch when they are next used).
|
|
128
|
+
*
|
|
129
|
+
* `mutate(args, { onSuccess, onError, onSettled })` fires its per-call
|
|
130
|
+
* callbacks for EVERY call while the component is mounted, not only for the
|
|
131
|
+
* latest one (TanStack's own rule), so two quick calls each get their
|
|
132
|
+
* confirmation. The hook-level callbacks in `opts` run first; the
|
|
133
|
+
* invalidation runs before the hook-level `onSuccess`.
|
|
41
134
|
*/
|
|
42
135
|
export function useToolMutation<TData = unknown>(
|
|
43
136
|
toolName: string,
|
|
44
|
-
opts?:
|
|
45
|
-
) {
|
|
137
|
+
opts?: UseToolMutationOptions<TData>,
|
|
138
|
+
): UseMutationResult<TData, Error, Record<string, unknown>> {
|
|
46
139
|
const callTool = useCallTool()
|
|
47
140
|
const queryClient = useQueryClient()
|
|
141
|
+
const { invalidateKeys, onSuccess, ...options } = opts ?? {}
|
|
48
142
|
|
|
49
|
-
|
|
143
|
+
const mutation = useMutation<TData, Error, Record<string, unknown>>({
|
|
144
|
+
...options,
|
|
50
145
|
mutationFn: async (args: Record<string, unknown>) => {
|
|
51
|
-
if (!callTool) throw new
|
|
146
|
+
if (!callTool) throw new NoToolTransportError(toolName)
|
|
52
147
|
const result = await callTool(toolName, args)
|
|
53
148
|
return parseToolResult<TData>(result)
|
|
54
149
|
},
|
|
55
|
-
onSuccess: async () => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
opts.invalidateKeys.map((key) => queryClient.refetchQueries({ queryKey: key })),
|
|
59
|
-
)
|
|
60
|
-
}
|
|
150
|
+
onSuccess: async (data, variables, onMutateResult, context) => {
|
|
151
|
+
await invalidateToolQueries(queryClient, invalidateKeys)
|
|
152
|
+
await onSuccess?.(data, variables, onMutateResult, context)
|
|
61
153
|
},
|
|
62
154
|
})
|
|
155
|
+
|
|
156
|
+
// Per-call callbacks fire only while mounted (TanStack's rule, kept), with
|
|
157
|
+
// the latest meta/mutationKey. Both refs are written in effects and read
|
|
158
|
+
// only when a call settles, so `mutate` stays stable across renders.
|
|
159
|
+
const mounted = useRef(false)
|
|
160
|
+
const scope = useRef<Pick<MutationFunctionContext, "meta" | "mutationKey">>({
|
|
161
|
+
meta: undefined,
|
|
162
|
+
mutationKey: undefined,
|
|
163
|
+
})
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
scope.current = { meta: options.meta, mutationKey: options.mutationKey }
|
|
166
|
+
})
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
mounted.current = true
|
|
169
|
+
return () => {
|
|
170
|
+
mounted.current = false
|
|
171
|
+
}
|
|
172
|
+
}, [])
|
|
173
|
+
const { mutateAsync } = mutation
|
|
174
|
+
const mutate = useCallback(
|
|
175
|
+
(
|
|
176
|
+
variables: Record<string, unknown>,
|
|
177
|
+
callbacks?: PerCallCallbacks<TData, Record<string, unknown>>,
|
|
178
|
+
) => {
|
|
179
|
+
settleEachCall(mutateAsync(variables), variables, callbacks, () =>
|
|
180
|
+
mounted.current ? { client: queryClient, ...scope.current } : null,
|
|
181
|
+
)
|
|
182
|
+
},
|
|
183
|
+
[mutateAsync, queryClient],
|
|
184
|
+
)
|
|
185
|
+
return { ...mutation, mutate }
|
|
63
186
|
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi, type Mock } from "vitest"
|
|
3
|
+
import type { ToolResultObserver } from "../lib/tool-result-observer.js"
|
|
4
|
+
import { createToolResultObserver } from "../lib/tool-result-observer.js"
|
|
5
|
+
import { advanceTimers, hookProbe, inAct, renderWithEffects } from "../render-effects.js"
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_ASSUME_STRIPPED_AFTER_MS,
|
|
8
|
+
useToolResultRecovery,
|
|
9
|
+
type ToolResultRecoveryOptions,
|
|
10
|
+
} from "./use-tool-result-recovery.js"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The hook's wiring with its effects running (toolkit#176 K13): the default
|
|
14
|
+
* observer is the document's (`installToolResultObserver`), the controller
|
|
15
|
+
* subscribes to it on mount, and a stripped result re-runs the tool from the
|
|
16
|
+
* observer's notification alone, while a slow tool on a compliant host is
|
|
17
|
+
* never re-run. The decision itself is pinned in the recovery model's tests.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const installed = vi.hoisted(() => ({ observer: null as ToolResultObserver | null }))
|
|
21
|
+
|
|
22
|
+
// The document's observer, as a framed view would install it; the tests drive
|
|
23
|
+
// a fake host channel instead of window.parent.
|
|
24
|
+
vi.mock(import("../lib/tool-result-observer.js"), async (importOriginal) => {
|
|
25
|
+
const actual = await importOriginal()
|
|
26
|
+
return { ...actual, installToolResultObserver: () => installed.observer }
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
/** A host channel the observer listens on, with the SEP-1865 messages a host sends. */
|
|
30
|
+
function fakeHost() {
|
|
31
|
+
const channel = new EventTarget()
|
|
32
|
+
const observer = createToolResultObserver(channel)
|
|
33
|
+
const send = (data: unknown) =>
|
|
34
|
+
inAct(() => channel.dispatchEvent(new MessageEvent("message", { data })))
|
|
35
|
+
const notify = (method: string, params: Record<string, unknown>) =>
|
|
36
|
+
send({ jsonrpc: "2.0", method, params })
|
|
37
|
+
return {
|
|
38
|
+
observer,
|
|
39
|
+
handshake: () =>
|
|
40
|
+
send({
|
|
41
|
+
jsonrpc: "2.0",
|
|
42
|
+
id: 1,
|
|
43
|
+
result: { protocolVersion: "2026-01-26", hostCapabilities: {} },
|
|
44
|
+
}),
|
|
45
|
+
toolInput: (args: Record<string, unknown>) =>
|
|
46
|
+
notify("ui/notifications/tool-input", { arguments: args }),
|
|
47
|
+
strippedResult: () =>
|
|
48
|
+
notify("ui/notifications/tool-result", { content: [{ type: "text", text: "Rendered." }] }),
|
|
49
|
+
structuredResult: (structuredContent: unknown) =>
|
|
50
|
+
notify("ui/notifications/tool-result", { content: [], structuredContent }),
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type CallTool = ToolResultRecoveryOptions["callTool"]
|
|
55
|
+
|
|
56
|
+
const PAYLOAD = { ok: true, rows: 3 }
|
|
57
|
+
const isValid = (value: unknown) => (value as { ok?: unknown } | null)?.ok === true
|
|
58
|
+
|
|
59
|
+
let callTool: Mock<CallTool>
|
|
60
|
+
|
|
61
|
+
/** Mount the hook with the view's inputs; the probe keeps its latest state. */
|
|
62
|
+
async function mount(over: Partial<ToolResultRecoveryOptions> = {}) {
|
|
63
|
+
const options: ToolResultRecoveryOptions = {
|
|
64
|
+
resultReady: false,
|
|
65
|
+
props: undefined,
|
|
66
|
+
isValid,
|
|
67
|
+
// The view runtime's input: a partial stream may have merged into it.
|
|
68
|
+
toolInput: { id: 7 },
|
|
69
|
+
hostContext: { toolInfo: { tool: { name: "show_list" } } },
|
|
70
|
+
callTool,
|
|
71
|
+
...over,
|
|
72
|
+
}
|
|
73
|
+
const probe = hookProbe(() => useToolResultRecovery<typeof PAYLOAD>(options))
|
|
74
|
+
const view = await renderWithEffects(<probe.Probe />)
|
|
75
|
+
return { ...view, state: probe.current }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
vi.useFakeTimers()
|
|
80
|
+
callTool = vi.fn<CallTool>(() => Promise.resolve({ structuredContent: PAYLOAD }))
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
afterEach(() => {
|
|
84
|
+
vi.useRealTimers()
|
|
85
|
+
installed.observer = null
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe("useToolResultRecovery with its effects (K13)", () => {
|
|
89
|
+
it("keep: a structured result the latch delivered is never re-run", async () => {
|
|
90
|
+
const host = fakeHost()
|
|
91
|
+
installed.observer = host.observer
|
|
92
|
+
await host.handshake()
|
|
93
|
+
await host.toolInput({ id: 7 })
|
|
94
|
+
await host.structuredResult(PAYLOAD)
|
|
95
|
+
const view = await mount({ resultReady: true, props: PAYLOAD })
|
|
96
|
+
await advanceTimers(vi.advanceTimersByTime, DEFAULT_ASSUME_STRIPPED_AFTER_MS * 4)
|
|
97
|
+
expect(callTool).not.toHaveBeenCalled()
|
|
98
|
+
expect(view.state().data).toBeNull()
|
|
99
|
+
await view.unmount()
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it("slow: a compliant host still answering is never re-run, however long it takes", async () => {
|
|
103
|
+
const host = fakeHost()
|
|
104
|
+
installed.observer = host.observer
|
|
105
|
+
await host.handshake()
|
|
106
|
+
await host.toolInput({ id: 7 })
|
|
107
|
+
const view = await mount()
|
|
108
|
+
await advanceTimers(vi.advanceTimersByTime, DEFAULT_ASSUME_STRIPPED_AFTER_MS + 1)
|
|
109
|
+
await advanceTimers(vi.advanceTimersByTime, 10_000)
|
|
110
|
+
expect(callTool).not.toHaveBeenCalled()
|
|
111
|
+
expect(view.state()).toMatchObject({ data: null, failed: false, blocked: null })
|
|
112
|
+
await view.unmount()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it("strip: the observer's notification alone re-runs the tool once, with the complete input", async () => {
|
|
116
|
+
const host = fakeHost()
|
|
117
|
+
installed.observer = host.observer
|
|
118
|
+
await host.handshake()
|
|
119
|
+
const view = await mount()
|
|
120
|
+
await host.toolInput({ id: 7, page: 2 })
|
|
121
|
+
expect(callTool).not.toHaveBeenCalled()
|
|
122
|
+
// Nothing re-renders the view here: only the subscription can react.
|
|
123
|
+
await host.strippedResult()
|
|
124
|
+
expect(callTool).toHaveBeenCalledTimes(1)
|
|
125
|
+
expect(callTool).toHaveBeenCalledWith("show_list", { id: 7, page: 2 })
|
|
126
|
+
expect(view.state()).toMatchObject({ data: PAYLOAD, failed: false, args: { id: 7, page: 2 } })
|
|
127
|
+
await advanceTimers(vi.advanceTimersByTime, 10_000)
|
|
128
|
+
expect(callTool, "a single flight").toHaveBeenCalledTimes(1)
|
|
129
|
+
await view.unmount()
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it("without an observer (observer: null) the 2.x grace timer re-runs a silent call", async () => {
|
|
133
|
+
const view = await mount({ observer: null })
|
|
134
|
+
await advanceTimers(vi.advanceTimersByTime, DEFAULT_ASSUME_STRIPPED_AFTER_MS - 1)
|
|
135
|
+
expect(callTool).not.toHaveBeenCalled()
|
|
136
|
+
await advanceTimers(vi.advanceTimersByTime, 1)
|
|
137
|
+
expect(callTool).toHaveBeenCalledTimes(1)
|
|
138
|
+
expect(callTool).toHaveBeenCalledWith("show_list", { id: 7 })
|
|
139
|
+
await view.unmount()
|
|
140
|
+
})
|
|
141
|
+
})
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
decodeRecoveredResult,
|
|
4
|
+
isRecoveryReady,
|
|
5
|
+
resolveRecoveryToolName,
|
|
6
|
+
} from "./use-tool-result-recovery.js"
|
|
3
7
|
|
|
4
|
-
// The hook's effect wiring (
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// pure decision logic.
|
|
8
|
+
// The hook's effect wiring (default observer, subscription, keep/strip/slow)
|
|
9
|
+
// runs in use-tool-result-recovery.effects.test.tsx and end-to-end in the
|
|
10
|
+
// consumer's Playwright host simulation; these tests pin the pure helpers.
|
|
8
11
|
|
|
9
12
|
describe("resolveRecoveryToolName", () => {
|
|
10
13
|
it("reads the SEP-1865 shape toolInfo.tool.name first", () => {
|
|
@@ -63,3 +66,23 @@ describe("decodeRecoveredResult", () => {
|
|
|
63
66
|
expect(decodeRecoveredResult({ content: [] }, isView)).toBeNull()
|
|
64
67
|
})
|
|
65
68
|
})
|
|
69
|
+
|
|
70
|
+
describe("isRecoveryReady (toolkit#176)", () => {
|
|
71
|
+
const base = { resultReady: false, assumedReady: false, cancelled: false, errored: false }
|
|
72
|
+
|
|
73
|
+
it("fires once a result latched or the stripped-result grace period passed", () => {
|
|
74
|
+
expect(isRecoveryReady(base)).toBe(false)
|
|
75
|
+
expect(isRecoveryReady({ ...base, resultReady: true })).toBe(true)
|
|
76
|
+
expect(isRecoveryReady({ ...base, assumedReady: true })).toBe(true)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("never re-executes a call that failed (K14: isError renders the error instead)", () => {
|
|
80
|
+
expect(isRecoveryReady({ ...base, resultReady: true, errored: true })).toBe(false)
|
|
81
|
+
expect(isRecoveryReady({ ...base, assumedReady: true, errored: true })).toBe(false)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("never re-executes a call the host cancelled", () => {
|
|
85
|
+
expect(isRecoveryReady({ ...base, resultReady: true, cancelled: true })).toBe(false)
|
|
86
|
+
expect(isRecoveryReady({ ...base, assumedReady: true, cancelled: true })).toBe(false)
|
|
87
|
+
})
|
|
88
|
+
})
|