@grackle-ai/web-components 0.112.1 → 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 (28) hide show
  1. package/.rush/temp/05ec67b10f932bdbe295aab3f4465cf0d26cb485.tar.log +238 -0
  2. package/.rush/temp/{30718c57404891eb5c6c96c935c4a6879170c963.untar.log → 05ec67b10f932bdbe295aab3f4465cf0d26cb485.untar.log} +2 -2
  3. package/.rush/temp/b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61.tar.log +12 -0
  4. package/.rush/temp/{6ab1fbb7acd3281d7612ffe24dcc9982dd8c9061.untar.log → b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61.untar.log} +2 -2
  5. package/.rush/temp/chunked-rush-logs/web-components._phase_build.chunks.jsonl +19 -0
  6. package/.rush/temp/chunked-rush-logs/web-components._phase_test.chunks.jsonl +124 -0
  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 +19 -0
  19. package/rush-logs/web-components._phase_test.cache.log +1 -1
  20. package/rush-logs/web-components._phase_test.log +124 -0
  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/hooks/types.ts +1 -1
  26. package/src/index.ts +1 -1
  27. package/src/mocks/MockGrackleProvider.tsx +2 -2
  28. package/temp/build/lint/_eslint-5eVG3S6w.json +838 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grackle-ai/web-components",
3
- "version": "0.112.1",
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.1"
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: 30718c57404891eb5c6c96c935c4a6879170c963
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.
@@ -0,0 +1,19 @@
1
+ Invoking: heft run --only build -- --clean
2
+ ---- build started ----
3
+ [build:typescript] Using TypeScript version 5.7.3
4
+ [build:storybook-build] Building Storybook...
5
+ [build:storybook-build] Storybook build completed.
6
+ [build:vite-build] Starting Vite build...
7
+ [build:lint] Using ESLint version 9.39.4
8
+ vite v6.4.2 building for production...
9
+ transforming...
10
+ ✓ 2716 modules transformed.
11
+ rendering chunks...
12
+ computing gzip size...
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
17
+ [build:vite-build] Vite build completed.
18
+ ---- build finished (77.344s) ----
19
+ -------------------- Finished (77.347s) --------------------
@@ -1,4 +1,4 @@
1
1
  Build cache hit.
2
- Cache key: 6ab1fbb7acd3281d7612ffe24dcc9982dd8c9061
2
+ Cache key: b47d67cd3e2d79d0da7f9aef2eb425725d6d2f61
3
3
  Clearing cached folders: .rush/temp/operation/_phase_test
4
4
  Successfully restored output from the build cache.
@@ -0,0 +1,124 @@
1
+ Invoking: heft run --only test
2
+ The provided list of phases does not contain all phase dependencies. You may need to run the excluded phases manually.
3
+ ---- test started ----
4
+ [test:vitest] Running vitest...
5
+
6
+ RUN v3.2.4 /home/runner/work/grackle/grackle/packages/web-components
7
+
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
23
+
24
+ Test Files 15 passed (15)
25
+ Tests 174 passed (174)
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)
28
+
29
+ [test:vitest] Vitest completed.
30
+ [test:storybook-test] Starting Storybook static server on port 33461...
31
+ [test:storybook-test] Storybook server ready. Running interaction tests...
32
+ jest-haste-map: duplicate manual mock found: adapter-manager
33
+ The following files share their name; please delete one of them:
34
+ * <rootDir>/packages/server/dist/__mocks__/adapter-manager.js
35
+ * <rootDir>/packages/server/src/__mocks__/adapter-manager.ts
36
+
37
+ jest-haste-map: duplicate manual mock found: auto-reconnect
38
+ The following files share their name; please delete one of them:
39
+ * <rootDir>/packages/server/dist/__mocks__/auto-reconnect.js
40
+ * <rootDir>/packages/server/src/__mocks__/auto-reconnect.ts
41
+
42
+ jest-haste-map: duplicate manual mock found: event-bus
43
+ The following files share their name; please delete one of them:
44
+ * <rootDir>/packages/server/dist/__mocks__/event-bus.js
45
+ * <rootDir>/packages/server/src/__mocks__/event-bus.ts
46
+
47
+ jest-haste-map: duplicate manual mock found: event-processor
48
+ The following files share their name; please delete one of them:
49
+ * <rootDir>/packages/server/dist/__mocks__/event-processor.js
50
+ * <rootDir>/packages/server/src/__mocks__/event-processor.ts
51
+
52
+ jest-haste-map: duplicate manual mock found: github-import
53
+ The following files share their name; please delete one of them:
54
+ * <rootDir>/packages/server/dist/__mocks__/github-import.js
55
+ * <rootDir>/packages/server/src/__mocks__/github-import.ts
56
+
57
+ jest-haste-map: duplicate manual mock found: lifecycle
58
+ The following files share their name; please delete one of them:
59
+ * <rootDir>/packages/server/dist/__mocks__/lifecycle.js
60
+ * <rootDir>/packages/server/src/__mocks__/lifecycle.ts
61
+
62
+ jest-haste-map: duplicate manual mock found: log-writer
63
+ The following files share their name; please delete one of them:
64
+ * <rootDir>/packages/server/dist/__mocks__/log-writer.js
65
+ * <rootDir>/packages/server/src/__mocks__/log-writer.ts
66
+
67
+ jest-haste-map: duplicate manual mock found: logger
68
+ The following files share their name; please delete one of them:
69
+ * <rootDir>/packages/server/dist/__mocks__/logger.js
70
+ * <rootDir>/packages/server/src/__mocks__/logger.ts
71
+
72
+ jest-haste-map: duplicate manual mock found: pipe-delivery
73
+ The following files share their name; please delete one of them:
74
+ * <rootDir>/packages/server/dist/__mocks__/pipe-delivery.js
75
+ * <rootDir>/packages/server/src/__mocks__/pipe-delivery.ts
76
+
77
+ jest-haste-map: duplicate manual mock found: processor-registry
78
+ The following files share their name; please delete one of them:
79
+ * <rootDir>/packages/server/dist/__mocks__/processor-registry.js
80
+ * <rootDir>/packages/server/src/__mocks__/processor-registry.ts
81
+
82
+ jest-haste-map: duplicate manual mock found: reanimate-agent
83
+ The following files share their name; please delete one of them:
84
+ * <rootDir>/packages/server/dist/__mocks__/reanimate-agent.js
85
+ * <rootDir>/packages/server/src/__mocks__/reanimate-agent.ts
86
+
87
+ jest-haste-map: duplicate manual mock found: session-recovery
88
+ The following files share their name; please delete one of them:
89
+ * <rootDir>/packages/server/dist/__mocks__/session-recovery.js
90
+ * <rootDir>/packages/server/src/__mocks__/session-recovery.ts
91
+
92
+ jest-haste-map: duplicate manual mock found: stream-hub
93
+ The following files share their name; please delete one of them:
94
+ * <rootDir>/packages/server/dist/__mocks__/stream-hub.js
95
+ * <rootDir>/packages/server/src/__mocks__/stream-hub.ts
96
+
97
+ jest-haste-map: duplicate manual mock found: stream-registry
98
+ The following files share their name; please delete one of them:
99
+ * <rootDir>/packages/server/dist/__mocks__/stream-registry.js
100
+ * <rootDir>/packages/server/src/__mocks__/stream-registry.ts
101
+
102
+ jest-haste-map: duplicate manual mock found: token-push
103
+ The following files share their name; please delete one of them:
104
+ * <rootDir>/packages/server/dist/__mocks__/token-push.js
105
+ * <rootDir>/packages/server/src/__mocks__/token-push.ts
106
+
107
+ jest-haste-map: duplicate manual mock found: utils/exec
108
+ The following files share their name; please delete one of them:
109
+ * <rootDir>/packages/server/dist/__mocks__/utils/exec.js
110
+ * <rootDir>/packages/server/src/__mocks__/utils/exec.ts
111
+
112
+ jest-haste-map: duplicate manual mock found: utils/format-gh-error
113
+ The following files share their name; please delete one of them:
114
+ * <rootDir>/packages/server/dist/__mocks__/utils/format-gh-error.js
115
+ * <rootDir>/packages/server/src/__mocks__/utils/format-gh-error.ts
116
+
117
+ jest-haste-map: duplicate manual mock found: utils/network
118
+ The following files share their name; please delete one of them:
119
+ * <rootDir>/packages/server/dist/__mocks__/utils/network.js
120
+ * <rootDir>/packages/server/src/__mocks__/utils/network.ts
121
+
122
+ [test:storybook-test] Storybook interaction tests completed.
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";
@@ -327,7 +327,7 @@ export interface UseWorkspacesResult {
327
327
  defaultPersonaId?: string,
328
328
  useWorktrees?: boolean,
329
329
  workingDirectory?: string,
330
- onSuccess?: () => void,
330
+ onSuccess?: (workspace: Workspace) => void,
331
331
  onError?: (message: string) => void,
332
332
  ) => Promise<void>;
333
333
  /** Archive a workspace by ID. */
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";
@@ -382,7 +382,7 @@ export function MockGrackleProvider({ children }: MockGrackleProviderProps): JSX
382
382
  defaultPersonaId?: string,
383
383
  useWorktrees?: boolean,
384
384
  workingDirectory?: string,
385
- onSuccess?: () => void,
385
+ onSuccess?: (workspace: Workspace) => void,
386
386
  _onError?: (message: string) => void,
387
387
  ) => {
388
388
  console.log("[MockGrackle] createWorkspace", { name, description });
@@ -405,7 +405,7 @@ export function MockGrackleProvider({ children }: MockGrackleProviderProps): JSX
405
405
 
406
406
  setWorkspaces((prev) => [...prev, newWorkspace]);
407
407
  if (onSuccess) {
408
- onSuccess();
408
+ onSuccess(newWorkspace);
409
409
  }
410
410
  },
411
411
  [nextId],