@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.
- package/README.md +7 -4
- 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.js +1 -1
- 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 +21 -7
- 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 +11 -4
- 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/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 +2 -1
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +26 -13
- 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 +8 -2
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +12 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +18 -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 +143 -1
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +191 -1
- package/dist/app/builder/builder-model.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/use-builder-catalogue.d.ts +4 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +44 -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/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 +13 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +75 -81
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +12 -3
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +21 -5
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +11 -3
- package/dist/app/mcp-app-view-states.d.ts.map +1 -1
- package/dist/app/mcp-app-view-states.js +29 -8
- package/dist/app/mcp-app-view-states.js.map +1 -1
- package/dist/app/mcp-app-view.d.ts +33 -1
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +181 -127
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +6 -1
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +8 -1
- 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 +4 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -1
- package/dist/app/use-view-lifecycle.js +2 -0
- package/dist/app/use-view-lifecycle.js.map +1 -1
- package/dist/app/view-lifecycle.d.ts +80 -4
- package/dist/app/view-lifecycle.d.ts.map +1 -1
- package/dist/app/view-lifecycle.js +90 -3
- package/dist/app/view-lifecycle.js.map +1 -1
- 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 +3 -1
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +22 -10
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.js +1 -1
- 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 +8 -6
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/EmptyState.js +4 -2
- package/dist/components/EmptyState.js.map +1 -1
- package/dist/components/ErrorState.d.ts +5 -2
- package/dist/components/ErrorState.d.ts.map +1 -1
- package/dist/components/ErrorState.js +25 -8
- package/dist/components/ErrorState.js.map +1 -1
- package/dist/components/FilterBar.d.ts +15 -4
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +11 -6
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +66 -21
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +101 -34
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +31 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +30 -11
- 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 +27 -7
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +21 -6
- 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 +9 -3
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +31 -16
- package/dist/components/Toast.js.map +1 -1
- 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 +47 -52
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +58 -120
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +52 -10
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -16
- 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 +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -6
- 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/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 +41 -1
- package/dist/lib/toast-model.d.ts.map +1 -1
- package/dist/lib/toast-model.js +67 -1
- package/dist/lib/toast-model.js.map +1 -1
- package/dist/lib/tone-utils.d.ts +58 -6
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +66 -4
- 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 +1 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/message-types.d.ts +117 -4
- package/dist/locale/message-types.d.ts.map +1 -1
- package/dist/locale/messages-de.d.ts.map +1 -1
- package/dist/locale/messages-de.js +44 -10
- package/dist/locale/messages-de.js.map +1 -1
- package/dist/locale/messages-en.d.ts.map +1 -1
- package/dist/locale/messages-en.js +44 -10
- package/dist/locale/messages-en.js.map +1 -1
- package/dist/locale/toolkit-messages.d.ts +19 -1
- package/dist/locale/toolkit-messages.d.ts.map +1 -1
- package/dist/locale/toolkit-messages.js +54 -1
- package/dist/locale/toolkit-messages.js.map +1 -1
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +2 -0
- 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 +9 -4
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/dialog.d.ts +1 -1
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +10 -3
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +1 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +6 -2
- package/dist/primitives/sheet.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 +30 -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/theme/create-theme.d.ts +19 -1
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +15 -0
- package/dist/theme/create-theme.js.map +1 -1
- package/package.json +5 -4
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +1 -1
- package/src/app/builder/CanvasRow.tsx +63 -17
- package/src/app/builder/CatalogueSheet.tsx +50 -29
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/LayoutSurface.tsx +206 -66
- package/src/app/builder/PipelineStrip.tsx +253 -153
- package/src/app/builder/SaveDialog.tsx +14 -2
- package/src/app/builder/Toolbar.tsx +144 -59
- package/src/app/builder/Workspace.tsx +226 -58
- package/src/app/builder/builder-model.ts +341 -2
- 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/reveal.ts +10 -0
- package/src/app/builder/use-builder-catalogue.ts +56 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/index.ts +12 -2
- package/src/app/layout-builder.tsx +178 -191
- package/src/app/mcp-app-view-chrome.test.tsx +141 -1
- package/src/app/mcp-app-view-chrome.tsx +56 -6
- package/src/app/mcp-app-view-states.tsx +51 -11
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +222 -2
- package/src/app/mcp-app-view.tsx +267 -117
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +8 -1
- 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 +6 -0
- package/src/app/view-lifecycle.test.ts +216 -0
- package/src/app/view-lifecycle.ts +165 -5
- 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 +57 -16
- package/src/app/widget-renderer.tsx +1 -1
- package/src/components/DrillButton.tsx +23 -10
- package/src/components/EmptyState.tsx +6 -4
- package/src/components/ErrorState.tsx +31 -9
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +52 -26
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +297 -90
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +102 -15
- 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 +63 -10
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +37 -19
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +98 -9
- package/src/components/tone-figures.test.tsx +8 -4
- 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 +3 -4
- package/src/hooks/use-tool-result-recovery.ts +84 -142
- package/src/hooks/use-view-data.test.tsx +118 -9
- package/src/hooks/use-view-data.ts +128 -18
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +104 -2
- package/src/index.ts +48 -11
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -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 +166 -1
- package/src/lib/toast-model.ts +104 -2
- package/src/lib/tone-utils.test.ts +86 -10
- package/src/lib/tone-utils.ts +89 -8
- 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 +1 -0
- package/src/locale/message-types.ts +118 -2
- package/src/locale/messages-de.ts +49 -10
- package/src/locale/messages-en.ts +49 -10
- package/src/locale/toolkit-messages.test.ts +133 -0
- package/src/locale/toolkit-messages.ts +63 -2
- package/src/primitives/alert.tsx +3 -0
- package/src/primitives/badge.tsx +9 -4
- package/src/primitives/button.tsx +1 -1
- package/src/primitives/dialog.tsx +10 -1
- package/src/primitives/select.tsx +1 -1
- package/src/primitives/sheet.tsx +7 -0
- 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 +38 -6
- package/src/render-effects.tsx +96 -0
- package/src/theme/cd-tokens.test.ts +3 -1
- package/src/theme/create-theme.test.ts +10 -0
- package/src/theme/create-theme.ts +28 -0
- package/src/theme/theme-css.test.ts +51 -0
- package/src/theme.css +31 -1
- package/ui-catalog.json +448 -41
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import type { ReactNode } from "react"
|
|
2
2
|
import { renderToStaticMarkup } from "react-dom/server"
|
|
3
|
+
import { QueryClient, useQueryClient } from "@tanstack/react-query"
|
|
3
4
|
import { ToolCancelledError, ToolError } from "mcp-use/react"
|
|
4
5
|
import { beforeEach, describe, expect, it, vi } from "vitest"
|
|
6
|
+
import { useToolQueryKey } from "../hooks/use-tool-query.js"
|
|
7
|
+
import { AppQueryProvider, queryClient } from "../providers/query-provider.js"
|
|
8
|
+
import type {
|
|
9
|
+
ToolResultRecoveryOptions,
|
|
10
|
+
ToolResultRecoveryState,
|
|
11
|
+
} from "../hooks/use-tool-result-recovery.js"
|
|
5
12
|
import { LocaleProvider, useLocale } from "../locale/locale-provider.js"
|
|
6
13
|
import { TOOLKIT_MESSAGES, type ToolkitMessages } from "../locale/toolkit-messages.js"
|
|
7
14
|
import { attribute, decodeEntities, openingTags, userFacingTexts } from "../render-scan.js"
|
|
8
15
|
import { createStandaloneHostBridge, HostBridgeProvider } from "./host-bridge.js"
|
|
9
16
|
import { McpAppView } from "./mcp-app-view.js"
|
|
10
17
|
import type { ViewData } from "./mcp-app-view-chrome.js"
|
|
18
|
+
import { McpUseViewContext } from "./model-context.js"
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* McpAppView's wiring, rendered through its real hooks (SSR, the house path):
|
|
@@ -23,9 +31,29 @@ interface HostState {
|
|
|
23
31
|
tool: Record<string, unknown>
|
|
24
32
|
locale: string
|
|
25
33
|
hostContext: Record<string, unknown> | undefined
|
|
34
|
+
/** Replaces the recovery's state (it settles in effects, which SSR never runs). */
|
|
35
|
+
recovery: ToolResultRecoveryState<unknown> | null
|
|
26
36
|
}
|
|
27
37
|
|
|
28
|
-
const host: HostState = vi.hoisted(() => ({
|
|
38
|
+
const host: HostState = vi.hoisted(() => ({
|
|
39
|
+
tool: {},
|
|
40
|
+
locale: "en-US",
|
|
41
|
+
hostContext: undefined,
|
|
42
|
+
recovery: null,
|
|
43
|
+
}))
|
|
44
|
+
|
|
45
|
+
// The real hook always runs (hook order stays fixed); a fixture state stands
|
|
46
|
+
// in for what its controller decides once the stripped result arrived.
|
|
47
|
+
vi.mock(import("../hooks/use-tool-result-recovery.js"), async (importOriginal) => {
|
|
48
|
+
const actual = await importOriginal()
|
|
49
|
+
return {
|
|
50
|
+
...actual,
|
|
51
|
+
useToolResultRecovery: <T,>(options: ToolResultRecoveryOptions) => {
|
|
52
|
+
const state = actual.useToolResultRecovery<T>(options)
|
|
53
|
+
return (host.recovery as ToolResultRecoveryState<T> | null) ?? state
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
})
|
|
29
57
|
|
|
30
58
|
// Only the fields McpAppView reads; the casts narrow the fixtures to the hook types.
|
|
31
59
|
vi.mock(import("mcp-use/react"), async (importOriginal) => {
|
|
@@ -33,11 +61,18 @@ vi.mock(import("mcp-use/react"), async (importOriginal) => {
|
|
|
33
61
|
const useToolContext = () => host.tool
|
|
34
62
|
const useHostContext = () => ({
|
|
35
63
|
locale: host.locale,
|
|
64
|
+
timeZone: "UTC",
|
|
36
65
|
safeArea: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
37
66
|
hostContext: host.hostContext,
|
|
38
67
|
})
|
|
68
|
+
// The view's model-context node, made visible: a <meta> whose `content`
|
|
69
|
+
// the scans below never read as user-facing text.
|
|
70
|
+
const { createElement } = await import("react")
|
|
71
|
+
const ModelContext = ({ content }: { content: string }) =>
|
|
72
|
+
createElement("meta", { "data-model-context": content })
|
|
39
73
|
return {
|
|
40
74
|
...actual,
|
|
75
|
+
ModelContext: ModelContext as unknown as typeof actual.ModelContext,
|
|
41
76
|
useToolContext: useToolContext as unknown as typeof actual.useToolContext,
|
|
42
77
|
useHostContext: useHostContext as unknown as typeof actual.useHostContext,
|
|
43
78
|
useDisplayMode: () => ({
|
|
@@ -113,6 +148,21 @@ beforeEach(() => {
|
|
|
113
148
|
host.tool = { status: "pending", toolInput: undefined, toolOutput: undefined }
|
|
114
149
|
host.locale = "en-US"
|
|
115
150
|
host.hostContext = KNOWN_TOOL
|
|
151
|
+
host.recovery = null
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
/** A tool the host names, with its annotations (SEP-1865 `toolInfo.tool`). */
|
|
155
|
+
const toolInfo = (name: string, annotations: Record<string, unknown>) => ({
|
|
156
|
+
toolInfo: { tool: { name, annotations } },
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
/** The recovery's state when a needed recovery did not run. */
|
|
160
|
+
const blockedBy = (reason: "policy" | "no-tool"): ToolResultRecoveryState<unknown> => ({
|
|
161
|
+
data: null,
|
|
162
|
+
failed: false,
|
|
163
|
+
blocked: reason,
|
|
164
|
+
recoveredAt: null,
|
|
165
|
+
args: null,
|
|
116
166
|
})
|
|
117
167
|
|
|
118
168
|
describe("McpAppView lifecycle wiring (toolkit#176)", () => {
|
|
@@ -148,6 +198,77 @@ describe("McpAppView lifecycle wiring (toolkit#176)", () => {
|
|
|
148
198
|
expect(view).toContain(en.errorHintNoRetry)
|
|
149
199
|
})
|
|
150
200
|
|
|
201
|
+
it("a stripped result of a writing tool the policy kept: the notice, never a button that writes again", () => {
|
|
202
|
+
// claude.ai strips the result of a "start and show" tool; "auto" never
|
|
203
|
+
// re-runs a tool reported as writing (readOnlyHint: false).
|
|
204
|
+
host.hostContext = toolInfo("start_and_show", { readOnlyHint: false })
|
|
205
|
+
host.recovery = blockedBy("policy")
|
|
206
|
+
const view = decodeEntities(render().view)
|
|
207
|
+
expect(view).not.toContain('data-slot="skeleton"')
|
|
208
|
+
expect(view).toContain('data-tone="info"')
|
|
209
|
+
expect(view).toContain(en.blockedTitle)
|
|
210
|
+
expect(view).toContain(en.blockedHintNoRetry)
|
|
211
|
+
expect(view).not.toContain(en.errorTitle)
|
|
212
|
+
expect(view).not.toContain("<button")
|
|
213
|
+
// The same for destructiveHint: true.
|
|
214
|
+
host.hostContext = toolInfo("start_and_show", { readOnlyHint: true, destructiveHint: true })
|
|
215
|
+
expect(render().view).not.toContain("<button")
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it("a tool not reported as writing that a stricter policy kept: the notice offers to load the view", () => {
|
|
219
|
+
host.hostContext = toolInfo("show_list", {})
|
|
220
|
+
host.recovery = blockedBy("policy")
|
|
221
|
+
const view = decodeEntities(render().view)
|
|
222
|
+
expect(view).toContain(en.blockedTitle)
|
|
223
|
+
expect(view).toContain(en.blockedHint)
|
|
224
|
+
expect(view).toContain(`${en.blockedRetry}</button>`)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it("a recovery blocked for want of a tool name stays the plain error without retry", () => {
|
|
228
|
+
host.hostContext = undefined
|
|
229
|
+
host.recovery = blockedBy("no-tool")
|
|
230
|
+
const view = decodeEntities(render().view)
|
|
231
|
+
expect(view).toContain(en.errorTitle)
|
|
232
|
+
expect(view).toContain(en.errorHintNoRetry)
|
|
233
|
+
expect(view).not.toContain(en.blockedTitle)
|
|
234
|
+
expect(view).not.toContain("<button")
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it("a failed recovery stays the plain error with its retry", () => {
|
|
238
|
+
host.recovery = { ...blockedBy("policy"), blocked: null, failed: true }
|
|
239
|
+
const view = decodeEntities(render().view)
|
|
240
|
+
expect(view).toContain(en.errorTitle)
|
|
241
|
+
expect(view).toContain(`${en.retry}</button>`)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it("a payload the view re-loaded itself carries the stamp under its title, in the host's words (N23)", () => {
|
|
245
|
+
const recoveredAt = Date.UTC(2026, 9, 11, 14, 32)
|
|
246
|
+
host.recovery = { data: VIEW, failed: false, blocked: null, recoveredAt, args: {} }
|
|
247
|
+
const view = decodeEntities(render().view)
|
|
248
|
+
expect(view).toContain(
|
|
249
|
+
`<p data-slot="view-data-as-of" class="text-muted-foreground truncate text-sm">Reloaded at 2:32 PM</p>`,
|
|
250
|
+
)
|
|
251
|
+
host.locale = "de-DE"
|
|
252
|
+
expect(decodeEntities(render().view)).toContain(">Neu geladen um 14:32 Uhr</p>")
|
|
253
|
+
// A host-delivered payload carries none.
|
|
254
|
+
host.recovery = null
|
|
255
|
+
host.tool = { status: "ready", toolOutput: VIEW, toolInput: {} }
|
|
256
|
+
expect(render().view).not.toContain('data-slot="view-data-as-of"')
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
it("the stamp's time speaks the language of its words, not the host's other one", () => {
|
|
260
|
+
const recoveredAt = Date.UTC(2026, 9, 11, 14, 32)
|
|
261
|
+
host.recovery = { data: VIEW, failed: false, blocked: null, recoveredAt, args: {} }
|
|
262
|
+
// A German profile (LocaleProvider) on an en-US host: never "4:32 PM Uhr".
|
|
263
|
+
host.locale = "en-US"
|
|
264
|
+
const german = render((node) => <LocaleProvider locale="de">{node}</LocaleProvider>)
|
|
265
|
+
expect(decodeEntities(german.view)).toContain(">Neu geladen um 14:32 Uhr</p>")
|
|
266
|
+
// The host's region of the same language stays: en-GB keeps its 24-hour clock.
|
|
267
|
+
host.locale = "en-GB"
|
|
268
|
+
const british = render((node) => <LocaleProvider locale="en">{node}</LocaleProvider>)
|
|
269
|
+
expect(decodeEntities(british.view)).toContain(">Reloaded at 14:32</p>")
|
|
270
|
+
})
|
|
271
|
+
|
|
151
272
|
it("a host cancellation shows the cancelled notice, no skeleton and no retry", () => {
|
|
152
273
|
host.tool = { status: "error", error: new ToolCancelledError("user"), toolInput: {} }
|
|
153
274
|
const { view } = render()
|
|
@@ -179,6 +300,104 @@ describe("McpAppView lifecycle wiring (toolkit#176)", () => {
|
|
|
179
300
|
})
|
|
180
301
|
})
|
|
181
302
|
|
|
303
|
+
describe("McpAppView toolNameInQueryKey (toolkit#176 K18)", () => {
|
|
304
|
+
/** A widget that prints the cache key its data hooks would use. */
|
|
305
|
+
function KeyProbe() {
|
|
306
|
+
return <output>{JSON.stringify(useToolQueryKey(["feed"], "feed_data", { id: 1 }))}</output>
|
|
307
|
+
}
|
|
308
|
+
const keyIn = (props: { toolNameInQueryKey?: boolean }) =>
|
|
309
|
+
decodeEntities(
|
|
310
|
+
renderToStaticMarkup(
|
|
311
|
+
<HostBridgeProvider bridge={bridge}>
|
|
312
|
+
<McpAppView widgets={{ "demo:probe": KeyProbe }} {...props} />
|
|
313
|
+
</HostBridgeProvider>,
|
|
314
|
+
),
|
|
315
|
+
).match(/<output>(.*?)<\/output>/)?.[1]
|
|
316
|
+
|
|
317
|
+
it("hands the setting to the widgets' data hooks; omitted, the 2.x key stays", () => {
|
|
318
|
+
host.tool = { status: "ready", toolOutput: VIEW, toolInput: {} }
|
|
319
|
+
expect(keyIn({ toolNameInQueryKey: true })).toBe('["feed","feed_data",{"id":1}]')
|
|
320
|
+
expect(keyIn({})).toBe('["feed",{"id":1}]')
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
describe("McpAppView query client", () => {
|
|
325
|
+
/** A widget that tells which client its data hooks use. */
|
|
326
|
+
function clientIn(wrap: (node: ReactNode) => ReactNode) {
|
|
327
|
+
const clients: QueryClient[] = []
|
|
328
|
+
function ClientProbe() {
|
|
329
|
+
clients.push(useQueryClient())
|
|
330
|
+
return null
|
|
331
|
+
}
|
|
332
|
+
renderToStaticMarkup(
|
|
333
|
+
<HostBridgeProvider bridge={bridge}>
|
|
334
|
+
{wrap(<McpAppView widgets={{ "demo:probe": ClientProbe }} />)}
|
|
335
|
+
</HostBridgeProvider>,
|
|
336
|
+
)
|
|
337
|
+
expect(clients.length, "the widget rendered").toBeGreaterThan(0)
|
|
338
|
+
return clients[0]
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
it("its widgets fetch through an enclosing AppQueryProvider's client", () => {
|
|
342
|
+
host.tool = { status: "ready", toolOutput: VIEW, toolInput: {} }
|
|
343
|
+
const perMount = new QueryClient()
|
|
344
|
+
expect(clientIn((node) => <AppQueryProvider client={perMount}>{node}</AppQueryProvider>)).toBe(
|
|
345
|
+
perMount,
|
|
346
|
+
)
|
|
347
|
+
expect(
|
|
348
|
+
clientIn((node) => node),
|
|
349
|
+
"else the toolkit's shared client",
|
|
350
|
+
).toBe(queryClient)
|
|
351
|
+
})
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
describe("McpAppView model context (toolkit#176 K20)", () => {
|
|
355
|
+
/** Inside an mcp-use view, where the view's line joins the native tree. */
|
|
356
|
+
const inView = (node: ReactNode) => (
|
|
357
|
+
<McpUseViewContext.Provider value={true}>{node}</McpUseViewContext.Provider>
|
|
358
|
+
)
|
|
359
|
+
const contexts = (html: string) =>
|
|
360
|
+
openingTags(html, "meta").map((tag) =>
|
|
361
|
+
decodeEntities(attribute(tag, "data-model-context") ?? ""),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
it("an error the user sees instead of the view reaches the model: what failed, and that it is an error", () => {
|
|
365
|
+
host.tool = { status: "error", error: toolError(REASON), toolInput: {} }
|
|
366
|
+
const { view } = render(inView)
|
|
367
|
+
expect(contexts(view)).toEqual([
|
|
368
|
+
`The view of render-view could not be shown (reason: ${REASON}). ` +
|
|
369
|
+
"The user sees an error message with a retry button instead of the view.",
|
|
370
|
+
])
|
|
371
|
+
})
|
|
372
|
+
|
|
373
|
+
it("a blocked recovery tells the model the tool ran and must not be re-run to show the view", () => {
|
|
374
|
+
host.hostContext = toolInfo("start_and_show", { readOnlyHint: false })
|
|
375
|
+
host.recovery = blockedBy("policy")
|
|
376
|
+
expect(contexts(render(inView).view)).toEqual([
|
|
377
|
+
"The view of start_and_show is not shown: start_and_show ran, but the host did not pass its " +
|
|
378
|
+
"result to the view, and the view did not re-run it. The user sees a note to ask in the chat " +
|
|
379
|
+
"for the current state instead of the view. Do not re-run start_and_show just to show the view.",
|
|
380
|
+
])
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it("a cancelled call says so", () => {
|
|
384
|
+
host.tool = { status: "error", error: new ToolCancelledError("user"), toolInput: {} }
|
|
385
|
+
expect(contexts(render(inView).view)).toEqual([
|
|
386
|
+
"The view of render-view was cancelled before it rendered. The user sees a note that the call was cancelled.",
|
|
387
|
+
])
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
it("failed data steps of a shown view are reported; a waiting view reports nothing", () => {
|
|
391
|
+
host.tool = { status: "ready", toolOutput: VIEW, toolInput: {} }
|
|
392
|
+
expect(contexts(render(inView).view)).toEqual([
|
|
393
|
+
"The view of render-view is shown, but some of its data could not be loaded (kpi: timeout). " +
|
|
394
|
+
"The user sees an alert with a retry button.",
|
|
395
|
+
])
|
|
396
|
+
host.tool = { status: "pending", toolInput: undefined, toolOutput: undefined }
|
|
397
|
+
expect(contexts(render(inView).view)).toEqual([])
|
|
398
|
+
})
|
|
399
|
+
})
|
|
400
|
+
|
|
182
401
|
describe("McpAppView locale", () => {
|
|
183
402
|
it("speaks the host's language in its own chrome", () => {
|
|
184
403
|
host.locale = "de-DE"
|
|
@@ -186,7 +405,8 @@ describe("McpAppView locale", () => {
|
|
|
186
405
|
const { view, toasts } = render()
|
|
187
406
|
expect(decodeEntities(view)).toContain(de.errorTitle)
|
|
188
407
|
expect(view).toContain(`${de.retry}</button>`)
|
|
189
|
-
|
|
408
|
+
// The toast stack below the view speaks it too (its close buttons).
|
|
409
|
+
expect(toasts).toContain(`aria-label="${TOOLKIT_MESSAGES.de.common.dismiss}"`)
|
|
190
410
|
})
|
|
191
411
|
|
|
192
412
|
it("leaves useLocale() of consumer widgets alone (no LocaleProvider of its own)", () => {
|