@grackle-ai/web-components 0.112.2 → 0.113.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 (26) hide show
  1. package/.rush/temp/{1421806d07f6b0c455deca4bf89a6412726ffd8b.tar.log → 05ec67b10f932bdbe295aab3f4465cf0d26cb485.tar.log} +16 -14
  2. package/.rush/temp/{1421806d07f6b0c455deca4bf89a6412726ffd8b.untar.log → 05ec67b10f932bdbe295aab3f4465cf0d26cb485.untar.log} +2 -2
  3. package/.rush/temp/{a0341c0f1c835c664217d8a879aa38d780e62122.tar.log → b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61.tar.log} +2 -2
  4. package/.rush/temp/{a0341c0f1c835c664217d8a879aa38d780e62122.untar.log → b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61.untar.log} +2 -2
  5. package/.rush/temp/chunked-rush-logs/web-components._phase_build.chunks.jsonl +6 -5
  6. package/.rush/temp/chunked-rush-logs/web-components._phase_test.chunks.jsonl +20 -21
  7. package/.rush/temp/operation/_phase_build/all.log +6 -5
  8. package/.rush/temp/operation/_phase_build/log-chunks.jsonl +6 -5
  9. package/.rush/temp/operation/_phase_build/state.json +1 -1
  10. package/.rush/temp/operation/_phase_test/all.log +20 -21
  11. package/.rush/temp/operation/_phase_test/log-chunks.jsonl +20 -21
  12. package/.rush/temp/operation/_phase_test/state.json +1 -1
  13. package/README.md +1 -0
  14. package/dist/McpAppWidget-CSX2W2Vb.js +5774 -0
  15. package/dist/index.js +11976 -17723
  16. package/package.json +2 -2
  17. package/rush-logs/web-components._phase_build.cache.log +1 -1
  18. package/rush-logs/web-components._phase_build.log +6 -5
  19. package/rush-logs/web-components._phase_test.cache.log +1 -1
  20. package/rush-logs/web-components._phase_test.log +20 -21
  21. package/src/components/display/EventRenderer.stories.tsx +22 -0
  22. package/src/components/display/EventRenderer.tsx +44 -2
  23. package/src/components/display/EventStream.tsx +4 -1
  24. package/src/components/display/index.ts +3 -1
  25. package/src/index.ts +1 -1
  26. package/temp/build/lint/_eslint-5eVG3S6w.json +13 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grackle-ai/web-components",
3
- "version": "0.112.2",
3
+ "version": "0.113.0",
4
4
  "description": "Presentational React component library for the Grackle web UI",
5
5
  "license": "MIT",
6
6
  "sideEffects": [
@@ -46,7 +46,7 @@
46
46
  "remark-gfm": "^4.0.0",
47
47
  "lucide-react": "~0.474.0",
48
48
  "react-router": "^7.0.0",
49
- "@grackle-ai/common": "0.112.2"
49
+ "@grackle-ai/common": "0.113.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@rushstack/heft": "1.2.7",
@@ -1,4 +1,4 @@
1
1
  Build cache hit.
2
- Cache key: 1421806d07f6b0c455deca4bf89a6412726ffd8b
2
+ Cache key: 05ec67b10f932bdbe295aab3f4465cf0d26cb485
3
3
  Clearing cached folders: dist, storybook-static, .rush/temp/operation/_phase_build
4
4
  Successfully restored output from the build cache.
@@ -10,9 +10,10 @@ transforming...
10
10
  ✓ 2716 modules transformed.
11
11
  rendering chunks...
12
12
  computing gzip size...
13
- dist/index.css 158.47 kB │ gzip: 20.60 kB
14
- dist/index.js 1,591.31 kB │ gzip: 401.72 kB
15
- built in 5.69s
13
+ dist/index.css 158.47 kB │ gzip: 20.60 kB
14
+ dist/McpAppWidget-CSX2W2Vb.js 205.28 kB │ gzip: 47.19 kB
15
+ dist/index.js 1,385.24 kB gzip: 354.56 kB
16
+ ✓ built in 5.92s
16
17
  [build:vite-build] Vite build completed.
17
- ---- build finished (72.731s) ----
18
- -------------------- Finished (72.734s) --------------------
18
+ ---- build finished (77.344s) ----
19
+ -------------------- Finished (77.347s) --------------------
@@ -1,4 +1,4 @@
1
1
  Build cache hit.
2
- Cache key: a0341c0f1c835c664217d8a879aa38d780e62122
2
+ Cache key: b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61
3
3
  Clearing cached folders: .rush/temp/operation/_phase_test
4
4
  Successfully restored output from the build cache.
@@ -5,30 +5,29 @@ The provided list of phases does not contain all phase dependencies. You may nee
5
5
 
6
6
  RUN v3.2.4 /home/runner/work/grackle/grackle/packages/web-components
7
7
 
8
- ✓ src/utils/sessionEvents.test.ts (14 tests) 60ms
9
- ✓ src/utils/eventContent.test.ts (38 tests) 155ms
10
- ✓ src/utils/dashboard.test.ts (4 tests) 37ms
11
- ✓ src/utils/route-config.test.ts (23 tests) 50ms
12
- ✓ src/utils/scrollUtils.test.ts (11 tests) 20ms
13
- ✓ src/utils/breadcrumbs.test.ts (18 tests) 65ms
14
- ✓ src/components/tools/classifyTool.test.ts (6 tests) 22ms
15
- ✓ src/components/tools/toolCardHelpers.test.ts (10 tests) 28ms
16
- ✓ src/utils/assetUrl.test.ts (3 tests) 18ms
17
- ✓ src/components/display/extractText.test.tsx (8 tests) 17ms
18
- ✓ src/components/editable/useEditableField.test.tsx (17 tests) 206ms
19
- ✓ src/hooks/useEventSelection.test.ts (13 tests) 146ms
20
- ✓ src/components/notifications/UpdateBanner.test.tsx (4 tests) 199ms
21
- ✓ src/utils/grackleHostStyleVariables.test.ts (2 tests) 445ms
22
- grackleHostStyleVariables > always returns the MCP-standard fallback variables 416ms
23
- ✓ src/components/display/McpAppWidget.test.tsx (3 tests) 258ms
8
+ ✓ src/utils/sessionEvents.test.ts (14 tests) 36ms
9
+ ✓ src/utils/eventContent.test.ts (38 tests) 110ms
10
+ ✓ src/utils/dashboard.test.ts (4 tests) 7ms
11
+ ✓ src/utils/route-config.test.ts (23 tests) 21ms
12
+ ✓ src/utils/scrollUtils.test.ts (11 tests) 49ms
13
+ ✓ src/utils/breadcrumbs.test.ts (18 tests) 88ms
14
+ ✓ src/components/tools/classifyTool.test.ts (6 tests) 17ms
15
+ ✓ src/utils/assetUrl.test.ts (3 tests) 33ms
16
+ ✓ src/components/tools/toolCardHelpers.test.ts (10 tests) 29ms
17
+ ✓ src/components/display/extractText.test.tsx (8 tests) 31ms
18
+ ✓ src/components/editable/useEditableField.test.tsx (17 tests) 273ms
19
+ ✓ src/hooks/useEventSelection.test.ts (13 tests) 121ms
20
+ ✓ src/components/notifications/UpdateBanner.test.tsx (4 tests) 155ms
21
+ ✓ src/utils/grackleHostStyleVariables.test.ts (2 tests) 306ms
22
+ src/components/display/McpAppWidget.test.tsx (3 tests) 383ms
24
23
 
25
24
  Test Files 15 passed (15)
26
25
  Tests 174 passed (174)
27
- Start at 23:48:14
28
- Duration 16.41s (transform 2.75s, setup 0ms, collect 18.15s, tests 1.73s, environment 14.38s, prepare 5.42s)
26
+ Start at 03:06:05
27
+ Duration 16.86s (transform 3.49s, setup 0ms, collect 18.02s, tests 1.66s, environment 13.18s, prepare 5.11s)
29
28
 
30
29
  [test:vitest] Vitest completed.
31
- [test:storybook-test] Starting Storybook static server on port 36655...
30
+ [test:storybook-test] Starting Storybook static server on port 33461...
32
31
  [test:storybook-test] Storybook server ready. Running interaction tests...
33
32
  jest-haste-map: duplicate manual mock found: adapter-manager
34
33
  The following files share their name; please delete one of them:
@@ -121,5 +120,5 @@ jest-haste-map: duplicate manual mock found: utils/network
121
120
  * <rootDir>/packages/server/src/__mocks__/utils/network.ts
122
121
 
123
122
  [test:storybook-test] Storybook interaction tests completed.
124
- ---- test finished (113.186s) ----
125
- -------------------- Finished (113.19s) --------------------
123
+ ---- test finished (118.259s) ----
124
+ -------------------- Finished (118.269s) --------------------
@@ -170,6 +170,28 @@ export const MarkdownParagraphWrapping: Story = {
170
170
  },
171
171
  };
172
172
 
173
+ /** Widget event renders the lazy-loaded MCP App host iframe. */
174
+ export const WidgetEvent: Story = {
175
+ args: {
176
+ event: makeEvent({
177
+ eventType: "widget",
178
+ content: JSON.stringify({
179
+ resourceUri: "ui://grackle/hello-widget",
180
+ toolName: "show_hello_widget",
181
+ html: "<!doctype html><html><body><div class=\"card\">widget</div></body></html>",
182
+ toolInput: { message: "hi" },
183
+ toolResult: { content: [{ type: "text", text: "ok" }] },
184
+ }),
185
+ }),
186
+ // Different origin than Storybook (6006) so McpAppWidget's same-origin guard passes.
187
+ sandboxProxyUrl: "http://localhost:6007/sandbox.html",
188
+ },
189
+ play: async ({ canvas }) => {
190
+ // McpAppWidget is lazy-loaded behind Suspense; findByTestId waits for the chunk.
191
+ await expect(await canvas.findByTestId("mcp-app-widget")).toBeInTheDocument();
192
+ },
193
+ };
194
+
173
195
  /** User input events render as markdown (bold, lists, inline code) inside the bubble. */
174
196
  export const UserMessageMarkdown: Story = {
175
197
  args: {
@@ -1,4 +1,4 @@
1
- import { type ReactNode, useState, type JSX } from "react";
1
+ import { type ReactNode, useState, lazy, Suspense, type LazyExoticComponent, type ComponentType, type JSX } from "react";
2
2
  import { ChevronDown, ChevronRight } from "lucide-react";
3
3
  import Markdown from "react-markdown";
4
4
  import rehypePrismPlus from "rehype-prism-plus/common";
@@ -7,9 +7,19 @@ import type { SessionEvent } from "../../hooks/types.js";
7
7
  import { formatTokens, formatCost } from "../../utils/format.js";
8
8
  import { ICON_SM } from "../../utils/iconSize.js";
9
9
  import { ToolCard } from "../tools/ToolCard.js";
10
+ import type { McpAppWidgetProps } from "./McpAppWidget.js";
11
+ import type { McpUiResourceCsp } from "@modelcontextprotocol/ext-apps/app-bridge";
12
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
10
13
  import { CopyButton } from "./CopyButton.js";
11
14
  import styles from "./EventRenderer.module.scss";
12
15
 
16
+ // Lazy-loaded (and intentionally NOT re-exported from the package barrel) so the
17
+ // heavy ext-apps AppBridge is code-split into an async chunk loaded only when a
18
+ // widget actually renders — keeps the main chat bundle under the chunk-size cap.
19
+ const McpAppWidget: LazyExoticComponent<ComponentType<McpAppWidgetProps>> = lazy(() =>
20
+ import("./McpAppWidget.js").then((m) => ({ default: m.McpAppWidget })),
21
+ );
22
+
13
23
  /** Props for the EventRenderer component. */
14
24
  interface Props {
15
25
  event: SessionEvent;
@@ -17,6 +27,8 @@ interface Props {
17
27
  toolUseCtx?: { tool: string; args: unknown; detailedResult?: string };
18
28
  /** True when a tool_use completed but has no tool_result (e.g. Claude Code text-result pattern). */
19
29
  settled?: boolean;
30
+ /** Sandbox proxy origin URL for rendering MCP Apps widget events (different origin than the app). */
31
+ sandboxProxyUrl?: string;
20
32
  }
21
33
 
22
34
  // --- Individual event type renderers ---
@@ -201,10 +213,40 @@ function DefaultEvent({ content }: { content: string }): JSX.Element {
201
213
  // --- Main component ---
202
214
 
203
215
  /** Renders a single session event, dispatching to the appropriate type-specific renderer. */
204
- export function EventRenderer({ event, toolUseCtx, settled }: Props): JSX.Element {
216
+ export function EventRenderer({ event, toolUseCtx, settled, sandboxProxyUrl }: Props): JSX.Element {
205
217
  const time = new Date(event.timestamp).toLocaleTimeString();
206
218
 
207
219
  switch (event.eventType) {
220
+ case "widget": {
221
+ // MCP Apps widget event (pushed by the broker). Self-contained: HTML +
222
+ // tool input/result. Renders in the cross-origin sandbox via McpAppWidget.
223
+ if (!sandboxProxyUrl) {
224
+ return <DefaultEvent content={event.content} />;
225
+ }
226
+ let payload: {
227
+ html?: string;
228
+ csp?: McpUiResourceCsp;
229
+ toolInput?: Record<string, unknown>;
230
+ toolResult?: CallToolResult;
231
+ } = {};
232
+ try {
233
+ payload = JSON.parse(event.content) as typeof payload;
234
+ } catch { /* malformed widget payload — fall back */ }
235
+ if (!payload.html) {
236
+ return <DefaultEvent content={event.content} />;
237
+ }
238
+ return (
239
+ <Suspense fallback={<DefaultEvent content="Loading widget..." />}>
240
+ <McpAppWidget
241
+ widgetHtml={payload.html}
242
+ sandboxProxyUrl={sandboxProxyUrl}
243
+ csp={payload.csp}
244
+ toolInput={payload.toolInput}
245
+ toolResult={payload.toolResult}
246
+ />
247
+ </Suspense>
248
+ );
249
+ }
208
250
  case "system": {
209
251
  // Detect system context events via the raw metadata marker
210
252
  if (event.raw) {
@@ -88,6 +88,8 @@ interface EventStreamProps {
88
88
  * Receives the target session ID and the formatted envelope text.
89
89
  */
90
90
  onForward?: (sessionId: string, text: string) => Promise<void>;
91
+ /** Sandbox proxy origin URL for rendering MCP Apps widget events. */
92
+ sandboxProxyUrl?: string;
91
93
  }
92
94
 
93
95
  /**
@@ -104,6 +106,7 @@ export function EventStream({
104
106
  environments,
105
107
  personas,
106
108
  onForward,
109
+ sandboxProxyUrl,
107
110
  }: EventStreamProps): JSX.Element {
108
111
  const scrollRef = useRef<HTMLDivElement>(null);
109
112
  const [isReversed, setIsReversed] = useState(readStoredDirection);
@@ -303,7 +306,7 @@ export function EventStream({
303
306
  onToggle={(shiftKey) => { selection.toggleEvent(originalIndex, shiftKey); }}
304
307
  onCopied={() => { onShowToast?.("Copied to clipboard", "success"); }}
305
308
  >
306
- <EventRenderer event={event} toolUseCtx={event.toolUseCtx} settled={event.settled} />
309
+ <EventRenderer event={event} toolUseCtx={event.toolUseCtx} settled={event.settled} sandboxProxyUrl={sandboxProxyUrl} />
307
310
  </EventHoverRow>
308
311
  </motion.div>
309
312
  );
@@ -14,7 +14,9 @@ export { Spinner } from "./Spinner.js";
14
14
  export { SplashScreen } from "./SplashScreen.js";
15
15
  export { Tooltip } from "./Tooltip.js";
16
16
  export { SessionAttemptSelector } from "./SessionAttemptSelector.js";
17
- export { McpAppWidget } from "./McpAppWidget.js";
17
+ // NOTE: McpAppWidget is intentionally NOT re-exported as a value — EventRenderer
18
+ // lazy-imports it directly so the heavy ext-apps AppBridge stays code-split out of
19
+ // the main chat bundle. Its prop types remain exported below for consumers.
18
20
 
19
21
  export type { ButtonProps, ButtonVariant, ButtonSize } from "./Button.js";
20
22
  export type { TooltipProps, TooltipPlacement } from "./Tooltip.js";
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ export { useDagLayout } from "./components/dag/useDagLayout.js";
19
19
  export {
20
20
  Breadcrumbs, Button, CopyButton, DemoBanner, SplitButton,
21
21
  EventRenderer, ConfirmDialog, Skeleton, SkeletonText, SkeletonCard,
22
- Spinner, SplashScreen, Tooltip, McpAppWidget,
22
+ Spinner, SplashScreen, Tooltip,
23
23
  } from "./components/display/index.js";
24
24
  export type { ButtonProps, ButtonVariant, ButtonSize } from "./components/display/index.js";
25
25
  export type { TooltipProps, TooltipPlacement } from "./components/display/index.js";
@@ -145,9 +145,17 @@
145
145
  "components/tools/ToolCard.tsx",
146
146
  "daOT8+qSG8CTNk+//LXtKNBcFfE=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
147
147
  ],
148
+ [
149
+ "utils/grackleHostStyleVariables.ts",
150
+ "4GAn+eMbEHJoOb1z01LPtk6nJ7U=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
151
+ ],
152
+ [
153
+ "components/display/McpAppWidget.tsx",
154
+ "FHPzMKgR6sTY4eFNQv5BPGbIhBI=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
155
+ ],
148
156
  [
149
157
  "components/display/EventRenderer.tsx",
150
- "baXzKtFkiMslyFhdBCwrXQHmfZ8=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
158
+ "PHybhj9WzoyCcHMrbT8OHMiXuQI=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
151
159
  ],
152
160
  [
153
161
  "components/display/ConfirmDialog.tsx",
@@ -177,17 +185,9 @@
177
185
  "components/display/SessionAttemptSelector.tsx",
178
186
  "3P6Dn2a9NBqHlUcL32V4cbFlQnA=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
179
187
  ],
180
- [
181
- "utils/grackleHostStyleVariables.ts",
182
- "4GAn+eMbEHJoOb1z01LPtk6nJ7U=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
183
- ],
184
- [
185
- "components/display/McpAppWidget.tsx",
186
- "FHPzMKgR6sTY4eFNQv5BPGbIhBI=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
187
- ],
188
188
  [
189
189
  "components/display/index.ts",
190
- "RDb8Fh+7051CrG4TyqRFZAV2xes=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
190
+ "u8VYHmtVaFCzY50HZB9BaToo/Uk=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
191
191
  ],
192
192
  [
193
193
  "components/display/EventHoverRow.tsx",
@@ -223,7 +223,7 @@
223
223
  ],
224
224
  [
225
225
  "components/display/EventStream.tsx",
226
- "nUUukNWjhiFGA12f1MdOlE8Y3No=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
226
+ "zU7SmOEHQotfmTvaRF0f7x3kIzo=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
227
227
  ],
228
228
  [
229
229
  "components/editable/useEditableField.ts",
@@ -483,7 +483,7 @@
483
483
  ],
484
484
  [
485
485
  "index.ts",
486
- "Lbo23h9QnwqCWZmf6x/aafniLGY=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
486
+ "ahBkv6xGAgyekHPIzGpNiJ2T2lI=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
487
487
  ],
488
488
  [
489
489
  "components/index.ts",
@@ -527,7 +527,7 @@
527
527
  ],
528
528
  [
529
529
  "components/display/EventRenderer.stories.tsx",
530
- "TJiKZNxPldFn9X6rDkmjlIjwp1k=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
530
+ "vwvW6L580d9RGMBXR6UIB78YLAg=_7W3TvvwZxl0TGST6/dyQa8DKDDc="
531
531
  ],
532
532
  [
533
533
  "components/display/EventStream.stories.tsx",