@mcp-b/react-components 0.38.0 → 0.39.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 (33) hide show
  1. package/dist/{ToggleGroup-_pQMyHGM.d.ts → ToggleGroup-BrQZOQn_.d.ts} +1 -1
  2. package/dist/components/agents-sdk/AgentActivityPreview.js +1 -1
  3. package/dist/components/agents-sdk/AgentChat.js +5 -5
  4. package/dist/components/agents-sdk/BrowserLiveView.d.ts +73 -25
  5. package/dist/components/agents-sdk/BrowserLiveView.js +95 -65
  6. package/dist/components/agents-sdk/BrowserRunPanel.js +1 -1
  7. package/dist/components/agents-sdk/McpPluginCatalog.js +1 -1
  8. package/dist/components/agents-sdk/ModelSelector.js +1 -1
  9. package/dist/components/agents-sdk/ThinkChat.js +1 -1
  10. package/dist/components/agents-sdk/ThinkChatActivity.js +1 -1
  11. package/dist/components/agents-sdk/ThinkExecutionWorkbench.js +1 -1
  12. package/dist/components/agents-sdk/ThinkFullApp.js +11 -10
  13. package/dist/components/agents-sdk/ThinkFullAppViewSwitch.d.ts +1 -1
  14. package/dist/components/agents-sdk/ThinkFullAppViewSwitch.js +1 -1
  15. package/dist/components/agents-sdk/ThinkRoutineDetail.js +1 -1
  16. package/dist/components/agents-sdk/ThinkRoutineLibrary.js +1 -1
  17. package/dist/components/agents-sdk/ThinkThreadPicker.js +1 -1
  18. package/dist/components/agents-sdk/WorkspaceExplorer.js +1 -1
  19. package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
  20. package/dist/components/foundations/EmptyState.d.ts +10 -0
  21. package/dist/components/foundations/EmptyState.js +10 -0
  22. package/dist/components/foundations/ToggleGroup.d.ts +1 -1
  23. package/dist/components/foundations/ToggleGroup.js +1 -1
  24. package/dist/components/general-purpose/PricingBillingToggle.js +1 -1
  25. package/dist/components/general-purpose/PricingUsageCalculator.js +1 -1
  26. package/dist/components/nanites/AgentToolDetail.js +3 -3
  27. package/dist/styles/agent-chat.css +2 -2
  28. package/dist/styles/base.css +4 -0
  29. package/dist/styles/browser-live-view.css +45 -0
  30. package/dist/styles/think-full-app.css +6 -0
  31. package/package.json +2 -2
  32. package/dist/{ThinkChat-DkA4Wr71.js → ThinkChat-BES_3Mb-.js} +1 -1
  33. package/dist/{WorkspaceFileView-DeGzWwhK.js → WorkspaceFileView-D0r7xnq5.js} +1 -1
@@ -1,7 +1,7 @@
1
1
  import { r as ToggleVariantsOptions } from "./Toggle-DLrIf5YH.js";
2
2
  import * as React from "react";
3
- import { Toggle } from "@base-ui/react/toggle";
4
3
  import { ToggleGroup } from "@base-ui/react/toggle-group";
4
+ import { Toggle } from "@base-ui/react/toggle";
5
5
 
6
6
  //#region src/components/foundations/ToggleGroup.d.ts
7
7
  type ToggleGroupSize = ToggleVariantsOptions["size"];
@@ -3,8 +3,8 @@ import { C as FileIcon, J as SpinnerIcon, j as McpIcon, rt as XIcon, tt as Warni
3
3
  import { ActivityHeader } from "../ai-sdk/Activity.js";
4
4
  import { Button } from "../foundations/Button.js";
5
5
  import { t as NavigationLink } from "../../navigation-link-kqMa81v5.js";
6
- import { AppIcon } from "../foundations/AppIcon.js";
7
6
  import { AgentActivityFavicon, AgentActivityIcon } from "./AgentActivity.js";
7
+ import { AppIcon } from "../foundations/AppIcon.js";
8
8
  import "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/components/agents-sdk/AgentActivityPreview.tsx
@@ -666,13 +666,13 @@ function AgentChat({ className, messages, status = "ready", onSubmit, showCompos
666
666
  "aria-atomic": "true",
667
667
  children: copyAnnouncement
668
668
  }),
669
- loading ? /* @__PURE__ */ jsxs("div", {
669
+ loading ? /* @__PURE__ */ jsx("div", {
670
670
  className: "agent-chat__transcript-loading",
671
671
  role: "status",
672
- children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), /* @__PURE__ */ jsx("span", {
673
- className: "sigvelo-visually-hidden",
674
- children: "Loading conversation"
675
- })]
672
+ children: /* @__PURE__ */ jsx(EmptyState, {
673
+ icon: /* @__PURE__ */ jsx(SpinnerIcon, {}),
674
+ description: "Loading conversation"
675
+ })
676
676
  }) : showsStartScreen ? /* @__PURE__ */ jsx(AgentChatStartScreen, {
677
677
  ...startScreenProps,
678
678
  composer
@@ -2,27 +2,85 @@ import * as React from "react";
2
2
  import { BrowserLiveViewUrl } from "agents/browser";
3
3
 
4
4
  //#region src/components/agents-sdk/BrowserLiveView.d.ts
5
- interface BrowserLiveViewProps extends React.HTMLAttributes<HTMLDivElement> {
6
- /** Complete upstream value returned by `cdp.getLiveViewUrl()`. */
7
- source: BrowserLiveViewUrl;
8
- /** Epoch ms when `source` was received. Defaults to its first render. */
9
- receivedAt?: number;
10
- /** The page the session was showing — used for the ended-state text. */
5
+ /** Where a live view is in its lifecycle, however the pixels arrive. */
6
+ type BrowserLiveViewPhase = "connecting" | "streaming" | "reconnecting" | "idle" | "failed";
7
+ interface BrowserLiveViewCommonProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ /** The page being shown names the surface and labels its ended state. */
11
9
  pageTitle?: string;
12
10
  /**
13
- * Shown once the link expires pass the last screenshot the agent took
11
+ * Replaces the built-in text for the current phase e.g. a failure reason.
12
+ * Set it while the view is live and it reads as a notice over the picture,
13
+ * which is where a fault that does not end the session belongs.
14
+ */
15
+ statusLabel?: string;
16
+ /**
17
+ * Shown once the view stops — pass the last screenshot the agent took
14
18
  * (`<img>`) to keep the final frame on screen. Defaults to a quiet
15
19
  * "Live view ended" state.
16
20
  */
17
21
  fallback?: React.ReactNode;
22
+ /** Omits the expand control for a view that already fills its viewport. */
23
+ expandable?: boolean;
24
+ /**
25
+ * Takes the whole container instead of standing in it as a 16/10 card.
26
+ * The card treatment — the aspect box, the hairline, the rounded corners —
27
+ * is there to separate the view from what sits beside it; a view that is
28
+ * the entire surface, as it is on a phone, has nothing to separate from and
29
+ * spends real pixels saying so. Usually paired with `expandable={false}`,
30
+ * since there is nowhere larger to expand into.
31
+ */
32
+ fill?: boolean;
18
33
  }
34
+ type BrowserLiveViewProps = BrowserLiveViewCommonProps & ({
35
+ /** Complete upstream value returned by `cdp.getLiveViewUrl()`. */source: BrowserLiveViewUrl; /** Epoch ms when `source` was received. Defaults to its first render. */
36
+ receivedAt?: number;
37
+ renderMedia?: never;
38
+ phase?: never;
39
+ } | {
40
+ /**
41
+ * The picture, drawn by the host — a `<video>` on its own transport, a
42
+ * canvas, whatever it carries. Called once per placement because
43
+ * neither a video nor an iframe can occupy two places at once.
44
+ *
45
+ * Remote-control surfaces belong in here too: coordinate mapping and
46
+ * key handling are the host's, since only it knows what its input API
47
+ * expects. This component owns the frame around them. An overlay drawn
48
+ * here covers the picture and stays under the frame's own chrome, so a
49
+ * control surface can take every pointer the picture gets without
50
+ * swallowing the Live badge or the expand control.
51
+ *
52
+ * `statusId` names whatever element currently states the phase, for a
53
+ * control surface to point `aria-describedby` at.
54
+ */
55
+ renderMedia: (placement: "inline" | "dialog", statusId: string) => React.ReactNode; /** The host draws, so the host owns the lifecycle. A URL derives its own. */
56
+ phase: BrowserLiveViewPhase;
57
+ source?: never;
58
+ receivedAt?: never;
59
+ });
19
60
  /**
20
- * Embeds a Browser Run Live View — a real-time, interactive view of the
21
- * agent's browser session. Links expire (~5 minutes), so the iframe swaps to
22
- * `fallback` (e.g. the last screenshot) once `source.expiresInMs` passes.
23
- * While the hosted viewer connects, a quiet loading overlay hides the frame; if it
24
- * never loads, the view degrades to `fallback` or an unavailable state. An
25
- * expand button opens the same view in a fullscreen dialog.
61
+ * A live, interactive view of an agent's browser session.
62
+ *
63
+ * It takes the session either way round. Give it `source` — a Browser Run
64
+ * `BrowserLiveViewUrl` — and it embeds the hosted viewer, expiring the frame
65
+ * on its own once `expiresInMs` passes. Give it `renderMedia` and a `phase`
66
+ * instead and the host draws the picture on its own transport while this keeps
67
+ * the frame around it. The Live badge, the connecting overlay, the ended
68
+ * state, and the fullscreen expand are the same either way, because to the
69
+ * person watching it is the same thing.
70
+ *
71
+ * `fill` drops the card treatment for a view that is the whole surface rather
72
+ * than a block on one — the phone's screen, or a panel that already sizes
73
+ * itself. Everything else about the frame is unchanged.
74
+ *
75
+ * A host-drawn view keeps its own input surface, because coordinate mapping
76
+ * and key handling depend on what the host's input API expects — a screencast
77
+ * wants CSS pixels offset by its viewport, and nothing generic here could know
78
+ * that. This component owns the frame; the host owns the picture and control.
79
+ *
80
+ * The two sources differ in what the host must trust. A hosted URL embeds a
81
+ * third-party origin and runs its script; the iframe is unsandboxed by design
82
+ * because the viewer needs scripts and its own origin to stream the session,
83
+ * so only pass trusted Live View URLs. Host-drawn media embeds no origin.
26
84
  *
27
85
  * Where URLs come from (upstream: `agents/browser` in
28
86
  * github.com/cloudflare/agents — `BrowserLiveViewUrl`): the model calls
@@ -32,17 +90,7 @@ interface BrowserLiveViewProps extends React.HTMLAttributes<HTMLDivElement> {
32
90
  *
33
91
  * Styling rides `@mcp-b/react-components/styles` (browser-live-view.css),
34
92
  * which think-chat consumers load anyway.
35
- *
36
- * The iframe is unsandboxed by design: the hosted Live View UI needs scripts
37
- * and its own origin to stream the session. Only pass trusted Live View URLs.
38
93
  */
39
- declare function BrowserLiveView({
40
- source,
41
- receivedAt,
42
- pageTitle,
43
- fallback,
44
- className,
45
- ...props
46
- }: BrowserLiveViewProps): React.JSX.Element;
94
+ declare function BrowserLiveView(props: BrowserLiveViewProps): React.JSX.Element;
47
95
  //#endregion
48
- export { BrowserLiveView, BrowserLiveViewProps };
96
+ export { BrowserLiveView, BrowserLiveViewPhase, BrowserLiveViewProps };
@@ -2,12 +2,19 @@ import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { A as MaximizeIcon, J as SpinnerIcon } from "../../icons-B4mGvCvc.js";
3
3
  import { Button } from "../foundations/Button.js";
4
4
  import { Dialog } from "../foundations/Dialog.js";
5
- import { StatusPill } from "../foundations/StatusPill.js";
6
5
  import { TransitionSurface } from "../foundations/TransitionSurface.js";
6
+ import { StatusPill } from "../foundations/StatusPill.js";
7
7
  import * as React from "react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/components/agents-sdk/BrowserLiveView.tsx
10
10
  const FRAME_LOAD_TIMEOUT_MS = 15e3;
11
+ const PHASE_TEXT = {
12
+ connecting: "Connecting live view…",
13
+ streaming: "Live",
14
+ reconnecting: "Reconnecting live view…",
15
+ idle: "Live view ended",
16
+ failed: "Live view unavailable"
17
+ };
11
18
  function EndedState({ title, detail }) {
12
19
  return /* @__PURE__ */ jsxs("div", {
13
20
  className: "browser-live-view__ended",
@@ -21,12 +28,29 @@ function EndedState({ title, detail }) {
21
28
  });
22
29
  }
23
30
  /**
24
- * Embeds a Browser Run Live View — a real-time, interactive view of the
25
- * agent's browser session. Links expire (~5 minutes), so the iframe swaps to
26
- * `fallback` (e.g. the last screenshot) once `source.expiresInMs` passes.
27
- * While the hosted viewer connects, a quiet loading overlay hides the frame; if it
28
- * never loads, the view degrades to `fallback` or an unavailable state. An
29
- * expand button opens the same view in a fullscreen dialog.
31
+ * A live, interactive view of an agent's browser session.
32
+ *
33
+ * It takes the session either way round. Give it `source` — a Browser Run
34
+ * `BrowserLiveViewUrl` — and it embeds the hosted viewer, expiring the frame
35
+ * on its own once `expiresInMs` passes. Give it `renderMedia` and a `phase`
36
+ * instead and the host draws the picture on its own transport while this keeps
37
+ * the frame around it. The Live badge, the connecting overlay, the ended
38
+ * state, and the fullscreen expand are the same either way, because to the
39
+ * person watching it is the same thing.
40
+ *
41
+ * `fill` drops the card treatment for a view that is the whole surface rather
42
+ * than a block on one — the phone's screen, or a panel that already sizes
43
+ * itself. Everything else about the frame is unchanged.
44
+ *
45
+ * A host-drawn view keeps its own input surface, because coordinate mapping
46
+ * and key handling depend on what the host's input API expects — a screencast
47
+ * wants CSS pixels offset by its viewport, and nothing generic here could know
48
+ * that. This component owns the frame; the host owns the picture and control.
49
+ *
50
+ * The two sources differ in what the host must trust. A hosted URL embeds a
51
+ * third-party origin and runs its script; the iframe is unsandboxed by design
52
+ * because the viewer needs scripts and its own origin to stream the session,
53
+ * so only pass trusted Live View URLs. Host-drawn media embeds no origin.
30
54
  *
31
55
  * Where URLs come from (upstream: `agents/browser` in
32
56
  * github.com/cloudflare/agents — `BrowserLiveViewUrl`): the model calls
@@ -36,22 +60,21 @@ function EndedState({ title, detail }) {
36
60
  *
37
61
  * Styling rides `@mcp-b/react-components/styles` (browser-live-view.css),
38
62
  * which think-chat consumers load anyway.
39
- *
40
- * The iframe is unsandboxed by design: the hosted Live View UI needs scripts
41
- * and its own origin to stream the session. Only pass trusted Live View URLs.
42
63
  */
43
- function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, ...props }) {
44
- const [expired, setExpired] = React.useState(() => receivedAt !== void 0 && receivedAt + source.expiresInMs <= Date.now());
64
+ function BrowserLiveView(props) {
65
+ const { source, receivedAt, renderMedia, phase, pageTitle, statusLabel, fallback, expandable = true, fill, className, ...rest } = props;
66
+ const [expired, setExpired] = React.useState(() => source !== void 0 && receivedAt !== void 0 && receivedAt + source.expiresInMs <= Date.now());
45
67
  const [reportedFrameState, setReportedFrameState] = React.useState(() => ({
46
- url: source.url,
68
+ url: source?.url ?? "",
47
69
  value: "loading"
48
70
  }));
49
- if (reportedFrameState.url !== source.url) setReportedFrameState({
71
+ if (source && reportedFrameState.url !== source.url) setReportedFrameState({
50
72
  url: source.url,
51
73
  value: "loading"
52
74
  });
53
- const frameState = reportedFrameState.url === source.url ? reportedFrameState.value : "loading";
75
+ const frameState = source && reportedFrameState.url === source.url ? reportedFrameState.value : "loading";
54
76
  React.useEffect(() => {
77
+ if (!source) return;
55
78
  const remaining = (receivedAt ?? Date.now()) + source.expiresInMs - Date.now();
56
79
  if (remaining <= 0) {
57
80
  setExpired(true);
@@ -60,57 +83,71 @@ function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, .
60
83
  setExpired(false);
61
84
  const timer = setTimeout(() => setExpired(true), remaining);
62
85
  return () => clearTimeout(timer);
63
- }, [
64
- receivedAt,
65
- source.expiresInMs,
66
- source.targetId,
67
- source.url
68
- ]);
86
+ }, [receivedAt, source]);
69
87
  React.useEffect(() => {
70
- if (frameState !== "loading") return;
88
+ if (!source || frameState !== "loading") return;
71
89
  const url = source.url;
72
90
  const timer = setTimeout(() => setReportedFrameState({
73
91
  url,
74
92
  value: "failed"
75
93
  }), FRAME_LOAD_TIMEOUT_MS);
76
94
  return () => clearTimeout(timer);
77
- }, [frameState, source.url]);
78
- const failed = frameState === "failed";
79
- const live = !expired && !failed;
95
+ }, [frameState, source]);
96
+ const activePhase = source ? expired ? "idle" : frameState === "failed" ? "failed" : frameState === "loading" ? "connecting" : "streaming" : phase ?? "connecting";
97
+ const live = activePhase === "streaming";
98
+ const connecting = activePhase === "connecting" || activePhase === "reconnecting";
80
99
  const frameTitle = pageTitle ? `Live browser view — ${pageTitle}` : "Live browser view";
81
- const view = live ? /* @__PURE__ */ jsxs(Fragment, { children: [
82
- /* @__PURE__ */ jsx(StatusPill, {
83
- busy: true,
84
- size: "sm",
85
- color: "destructive",
86
- className: "browser-live-view__badge",
87
- children: "Live"
88
- }),
89
- /* @__PURE__ */ jsx("iframe", {
90
- className: "browser-live-view__frame",
91
- src: source.url,
92
- title: frameTitle,
93
- allow: "clipboard-read; clipboard-write",
94
- onLoad: () => setReportedFrameState({
95
- url: source.url,
96
- value: "ready"
97
- })
98
- }, source.url),
99
- frameState === "loading" ? /* @__PURE__ */ jsxs(TransitionSurface, {
100
- className: "browser-live-view__state",
101
- role: "status",
102
- children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), "Connecting live view…"]
103
- }) : null
104
- ] }) : fallback ?? /* @__PURE__ */ jsx(EndedState, {
105
- title: failed ? "Live view unavailable" : "Live view ended",
106
- detail: pageTitle
107
- });
100
+ const statusId = React.useId();
101
+ const renderView = (placement) => {
102
+ const placementStatusId = `${statusId}-${placement}`;
103
+ if (!live && !connecting) return fallback ?? /* @__PURE__ */ jsx(EndedState, {
104
+ title: statusLabel ?? PHASE_TEXT[activePhase],
105
+ detail: pageTitle
106
+ });
107
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
108
+ live && placement === "inline" ? /* @__PURE__ */ jsx(StatusPill, {
109
+ busy: true,
110
+ size: "sm",
111
+ color: "destructive",
112
+ className: "browser-live-view__badge",
113
+ children: "Live"
114
+ }) : null,
115
+ source ? placement === "dialog" ? /* @__PURE__ */ jsx("iframe", {
116
+ src: source.url,
117
+ title: frameTitle,
118
+ allow: "clipboard-read; clipboard-write"
119
+ }) : /* @__PURE__ */ jsx("iframe", {
120
+ className: "browser-live-view__frame",
121
+ src: source.url,
122
+ title: frameTitle,
123
+ allow: "clipboard-read; clipboard-write",
124
+ onLoad: () => setReportedFrameState({
125
+ url: source.url,
126
+ value: "ready"
127
+ })
128
+ }, source.url) : renderMedia?.(placement, placementStatusId),
129
+ connecting ? /* @__PURE__ */ jsxs(TransitionSurface, {
130
+ className: "browser-live-view__state",
131
+ id: placementStatusId,
132
+ role: "status",
133
+ children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), statusLabel ?? PHASE_TEXT[activePhase]]
134
+ }) : null,
135
+ live && statusLabel ? /* @__PURE__ */ jsx("p", {
136
+ className: "browser-live-view__notice",
137
+ id: placementStatusId,
138
+ role: "status",
139
+ children: statusLabel
140
+ }) : null
141
+ ] });
142
+ };
108
143
  return /* @__PURE__ */ jsxs("div", {
109
- ...props,
144
+ ...rest,
110
145
  className: cx("browser-live-view", className),
111
- "data-expired": expired || failed || void 0,
112
- "data-frame-state": frameState,
113
- children: [view, /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: /* @__PURE__ */ jsx(Button, {
146
+ "data-expired": activePhase === "idle" || activePhase === "failed" || void 0,
147
+ "data-fill": fill || void 0,
148
+ "data-frame-state": source ? frameState : void 0,
149
+ "data-phase": activePhase,
150
+ children: [renderView("inline"), expandable ? /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: /* @__PURE__ */ jsx(Button, {
114
151
  variant: "ghost",
115
152
  color: "neutral",
116
153
  size: "sm",
@@ -126,16 +163,9 @@ function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, .
126
163
  children: frameTitle
127
164
  }), /* @__PURE__ */ jsx("div", {
128
165
  className: "browser-live-view__dialog-body",
129
- children: live ? /* @__PURE__ */ jsx("iframe", {
130
- src: source.url,
131
- title: frameTitle,
132
- allow: "clipboard-read; clipboard-write"
133
- }) : fallback ?? /* @__PURE__ */ jsx(EndedState, {
134
- title: failed ? "Live view unavailable" : "Live view ended",
135
- detail: pageTitle
136
- })
166
+ children: renderView("dialog")
137
167
  })]
138
- }) })] })] })]
168
+ }) })] })] }) : null]
139
169
  });
140
170
  }
141
171
  //#endregion
@@ -2,8 +2,8 @@ import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { J as SpinnerIcon, rt as XIcon } from "../../icons-B4mGvCvc.js";
3
3
  import { Button } from "../foundations/Button.js";
4
4
  import { Tabs } from "../foundations/Tabs.js";
5
- import { WebPreview, WebPreviewNavigation, WebPreviewNavigationButton, WebPreviewUrl } from "../general-purpose/WebPreview.js";
6
5
  import { BrowserLiveView } from "./BrowserLiveView.js";
6
+ import { WebPreview, WebPreviewNavigation, WebPreviewNavigationButton, WebPreviewUrl } from "../general-purpose/WebPreview.js";
7
7
  import * as React from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/components/agents-sdk/BrowserRunPanel.tsx
@@ -7,8 +7,8 @@ import { Dialog } from "../foundations/Dialog.js";
7
7
  import { i as formatErrorMessage } from "../../format-DB2mX9DA.js";
8
8
  import { Separator } from "../foundations/Separator.js";
9
9
  import { AppIcon } from "../foundations/AppIcon.js";
10
- import { SearchField } from "../foundations/SearchField.js";
11
10
  import { n as getMcpServerProjection, t as McpServerIcon } from "../../mcp-server-SD_S-IpB.js";
11
+ import { SearchField } from "../foundations/SearchField.js";
12
12
  import * as React from "react";
13
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
14
  //#region src/components/agents-sdk/McpPluginCatalog.tsx
@@ -6,8 +6,8 @@ import { Dialog } from "../foundations/Dialog.js";
6
6
  import { o as titleCase } from "../../format-DB2mX9DA.js";
7
7
  import { Separator } from "../foundations/Separator.js";
8
8
  import { ScrollArea } from "../foundations/ScrollArea.js";
9
- import { t as ProviderLogo } from "../../provider-logos-zjZycgV6.js";
10
9
  import { EmptyState } from "../foundations/EmptyState.js";
10
+ import { t as ProviderLogo } from "../../provider-logos-zjZycgV6.js";
11
11
  import * as React from "react";
12
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
13
  import { createPortal } from "react-dom";
@@ -1,2 +1,2 @@
1
- import { a as thinkPendingExecutionApprovalsQueryOptions, i as ThinkChatRoot, n as ThinkChatMessages, o as useThinkChat, r as ThinkChatProvider, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-DkA4Wr71.js";
1
+ import { a as thinkPendingExecutionApprovalsQueryOptions, i as ThinkChatRoot, n as ThinkChatMessages, o as useThinkChat, r as ThinkChatProvider, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-BES_3Mb-.js";
2
2
  export { ThinkChat, ThinkChatMessages, ThinkChatProvider, ThinkChatRoot, thinkPendingExecutionApprovalsQueryOptions, useThinkChat, useThinkPendingExecutionApprovals };
@@ -2,9 +2,9 @@ import { useExpansionState } from "../ai-sdk/ExpansionState.js";
2
2
  import { Activity, ActivityContent, ActivityItem, ActivityItemGroup, ActivityText, ActivityTrigger } from "../ai-sdk/Activity.js";
3
3
  import { Button } from "../foundations/Button.js";
4
4
  import { MessageResponse } from "../ai-sdk/Message.js";
5
+ import { AgentActivityFavicon, AgentActivityIcon } from "./AgentActivity.js";
5
6
  import { useOptionalAgentToolRuns } from "./AgentToolRunsContext.js";
6
7
  import { SubagentRunList } from "./SubagentRunList.js";
7
- import { AgentActivityFavicon, AgentActivityIcon } from "./AgentActivity.js";
8
8
  import { useOptionalThinkChatLive } from "./ThinkChatContext.js";
9
9
  import { isBrowserToolPart, isExecuteToolPart, isFetchToolPart, isPartWorking, isSessionContextToolPart, isSkillToolPart, isThinkChatActivityPart, isWorkspaceToolPart } from "./ThinkChatToolParts.js";
10
10
  import { ThinkChatBrowserPanel, ThinkChatExecutePanel, ThinkChatFetchPanel, ThinkChatSessionContextPanel, ThinkChatSkillPanel, ThinkChatWorkspacePanel } from "./ThinkChatToolPanels.js";
@@ -6,10 +6,10 @@ import { Menu } from "../foundations/Menu.js";
6
6
  import { i as formatErrorMessage } from "../../format-DB2mX9DA.js";
7
7
  import { t as NavigationLink } from "../../navigation-link-kqMa81v5.js";
8
8
  import { EmptyState } from "../foundations/EmptyState.js";
9
- import { AppTopBar } from "../general-purpose/AppTopBar.js";
10
9
  import { getThinkExecutionRunAccessibleName, getThinkExecutionRunId, getThinkExecutionRunStatus, getThinkExecutionRunStatusTone, isSameThinkExecutionRun, isThinkSubmissionRun } from "./ThinkExecutionRun.js";
11
10
  import { ThinkExecutionRunSummary } from "./ThinkExecutionStatus.js";
12
11
  import { ThinkExecutionDetail } from "./ThinkExecutionDetail.js";
12
+ import { AppTopBar } from "../general-purpose/AppTopBar.js";
13
13
  import * as React from "react";
14
14
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
15
  import { queryOptions, useMutation, useSuspenseQuery } from "@tanstack/react-query";
@@ -3,12 +3,13 @@ import { $ as TerminalIcon, C as FileIcon, J as SpinnerIcon, c as BoxIcon, f as
3
3
  import { Button } from "../foundations/Button.js";
4
4
  import { n as mergeRefs } from "../../merge-refs-DF_7w2x_.js";
5
5
  import { ScrollArea } from "../foundations/ScrollArea.js";
6
- import { AppTopBar } from "../general-purpose/AppTopBar.js";
7
- import { ResizableSidePanel } from "../general-purpose/ResizableSidePanel.js";
8
- import { a as WorkspaceNavigationRestorationBoundary, i as WorkspaceNavigationFocusRestorer, n as WorkspaceNavigationProvider } from "../../WorkspaceLink-DtH66bAY.js";
9
- import { c as resolveThinkApprovalProps, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-DkA4Wr71.js";
6
+ import { EmptyState } from "../foundations/EmptyState.js";
10
7
  import { McpPluginCatalog } from "./McpPluginCatalog.js";
8
+ import { a as WorkspaceNavigationRestorationBoundary, i as WorkspaceNavigationFocusRestorer, n as WorkspaceNavigationProvider } from "../../WorkspaceLink-DtH66bAY.js";
9
+ import { c as resolveThinkApprovalProps, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-BES_3Mb-.js";
10
+ import { AppTopBar } from "../general-purpose/AppTopBar.js";
11
11
  import { ThinkExecutionWorkbench } from "./ThinkExecutionWorkbench.js";
12
+ import { ResizableSidePanel } from "../general-purpose/ResizableSidePanel.js";
12
13
  import { ThinkFullAppViewSwitch } from "./ThinkFullAppViewSwitch.js";
13
14
  import { ThinkThreadStatusIndicators } from "./ThinkThreadPicker.js";
14
15
  import { ThinkThreadShell } from "./ThinkThreadShell.js";
@@ -119,13 +120,13 @@ function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, co
119
120
  label: "Execution",
120
121
  icon: /* @__PURE__ */ jsx(TerminalIcon, {}),
121
122
  render: () => /* @__PURE__ */ jsx(React.Suspense, {
122
- fallback: /* @__PURE__ */ jsxs("div", {
123
- className: "think-full-app__workbench",
123
+ fallback: /* @__PURE__ */ jsx("div", {
124
+ className: "think-full-app__workbench think-full-app__workbench--loading",
124
125
  role: "status",
125
- children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), /* @__PURE__ */ jsx("span", {
126
- className: "sigvelo-visually-hidden",
127
- children: "Loading execution"
128
- })]
126
+ children: /* @__PURE__ */ jsx(EmptyState, {
127
+ icon: /* @__PURE__ */ jsx(SpinnerIcon, {}),
128
+ description: "Loading execution"
129
+ })
129
130
  }),
130
131
  children: /* @__PURE__ */ jsx(ThinkExecutionWorkbench, {
131
132
  source: agent.stub,
@@ -1,4 +1,4 @@
1
- import { r as ToggleGroupProps } from "../../ToggleGroup-_pQMyHGM.js";
1
+ import { r as ToggleGroupProps } from "../../ToggleGroup-BrQZOQn_.js";
2
2
  import * as React from "react";
3
3
 
4
4
  //#region src/components/agents-sdk/ThinkFullAppViewSwitch.d.ts
@@ -1,6 +1,6 @@
1
1
  import { n as mergeBaseClassName } from "../../class-names-BiMDVpUo.js";
2
- import { ToggleGroup } from "../foundations/ToggleGroup.js";
3
2
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
3
+ import { ToggleGroup } from "../foundations/ToggleGroup.js";
4
4
  import "react";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/components/agents-sdk/ThinkFullAppViewSwitch.tsx
@@ -1,7 +1,7 @@
1
1
  import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { Badge } from "../foundations/Badge.js";
3
- import { Switch } from "../foundations/Switch.js";
4
3
  import { getThinkRoutineNextRun } from "./ThinkRoutine.js";
4
+ import { Switch } from "../foundations/Switch.js";
5
5
  import { ThinkRoutineRuns } from "./ThinkRoutineRuns.js";
6
6
  import * as React from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -4,9 +4,9 @@ import { Button, buttonVariants } from "../foundations/Button.js";
4
4
  import { Menu } from "../foundations/Menu.js";
5
5
  import { i as formatErrorMessage } from "../../format-DB2mX9DA.js";
6
6
  import { n as isPlainPrimaryLinkActivation, t as NavigationLink } from "../../navigation-link-kqMa81v5.js";
7
- import { AlertDialog } from "../foundations/AlertDialog.js";
8
7
  import { EmptyState } from "../foundations/EmptyState.js";
9
8
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
9
+ import { AlertDialog } from "../foundations/AlertDialog.js";
10
10
  import { ResponsiveSidebarShell } from "../general-purpose/ResponsiveSidebarShell.js";
11
11
  import { ThinkRoutineBrowser } from "./ThinkRoutineBrowser.js";
12
12
  import { ThinkRoutineDetail } from "./ThinkRoutineDetail.js";
@@ -4,9 +4,9 @@ import { Button, buttonVariants } from "../foundations/Button.js";
4
4
  import { i as formatErrorMessage } from "../../format-DB2mX9DA.js";
5
5
  import { n as isPlainPrimaryLinkActivation, t as NavigationLink } from "../../navigation-link-kqMa81v5.js";
6
6
  import { ScrollArea } from "../foundations/ScrollArea.js";
7
- import { AlertDialog } from "../foundations/AlertDialog.js";
8
7
  import { EmptyState } from "../foundations/EmptyState.js";
9
8
  import { SearchField } from "../foundations/SearchField.js";
9
+ import { AlertDialog } from "../foundations/AlertDialog.js";
10
10
  import * as React from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
  //#region src/components/agents-sdk/ThinkThreadPicker.tsx
@@ -2,7 +2,7 @@ import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { n as mergeRefs } from "../../merge-refs-DF_7w2x_.js";
3
3
  import { a as WorkspaceNavigationRestorationBoundary, n as WorkspaceNavigationProvider, o as useRequiredWorkspaceNavigationRestoration, r as resolveWorkspaceLink } from "../../WorkspaceLink-DtH66bAY.js";
4
4
  import { WorkspaceBrowser } from "./WorkspaceBrowser.js";
5
- import { t as WorkspaceFileView } from "../../WorkspaceFileView-DeGzWwhK.js";
5
+ import { t as WorkspaceFileView } from "../../WorkspaceFileView-D0r7xnq5.js";
6
6
  import * as React from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  //#region src/components/agents-sdk/WorkspaceExplorer.tsx
@@ -1,2 +1,2 @@
1
- import { t as WorkspaceFileView } from "../../WorkspaceFileView-DeGzWwhK.js";
1
+ import { t as WorkspaceFileView } from "../../WorkspaceFileView-D0r7xnq5.js";
2
2
  export { WorkspaceFileView };
@@ -21,10 +21,20 @@ interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "ti
21
21
  * `children` land under the description, for the action that makes the region
22
22
  * non-empty.
23
23
  *
24
+ * A region waiting on data is empty too, and this is the shape for it:
25
+ * `icon={<SpinnerIcon />}` with a description of what is being waited on, in a
26
+ * `role="status"` container. The description is not optional there —
27
+ * `prefers-reduced-motion` stops the spinner outright, so an icon on its own
28
+ * leaves a still circle and no way to tell loading from broken.
29
+ *
24
30
  * @example
25
31
  * ```tsx
26
32
  * <EmptyState description="No runs yet." />
27
33
  *
34
+ * <div role="status">
35
+ * <EmptyState icon={<SpinnerIcon />} description="Loading conversation" />
36
+ * </div>
37
+ *
28
38
  * <EmptyState
29
39
  * icon={<MessageIcon />}
30
40
  * title="Start a conversation"
@@ -14,10 +14,20 @@ import { jsx, jsxs } from "react/jsx-runtime";
14
14
  * `children` land under the description, for the action that makes the region
15
15
  * non-empty.
16
16
  *
17
+ * A region waiting on data is empty too, and this is the shape for it:
18
+ * `icon={<SpinnerIcon />}` with a description of what is being waited on, in a
19
+ * `role="status"` container. The description is not optional there —
20
+ * `prefers-reduced-motion` stops the spinner outright, so an icon on its own
21
+ * leaves a still circle and no way to tell loading from broken.
22
+ *
17
23
  * @example
18
24
  * ```tsx
19
25
  * <EmptyState description="No runs yet." />
20
26
  *
27
+ * <div role="status">
28
+ * <EmptyState icon={<SpinnerIcon />} description="Loading conversation" />
29
+ * </div>
30
+ *
21
31
  * <EmptyState
22
32
  * icon={<MessageIcon />}
23
33
  * title="Start a conversation"
@@ -1,2 +1,2 @@
1
- import { n as ToggleGroupItemProps, r as ToggleGroupProps, t as ToggleGroup } from "../../ToggleGroup-_pQMyHGM.js";
1
+ import { n as ToggleGroupItemProps, r as ToggleGroupProps, t as ToggleGroup } from "../../ToggleGroup-BrQZOQn_.js";
2
2
  export { ToggleGroup, ToggleGroupItemProps, ToggleGroupProps };
@@ -3,8 +3,8 @@ import { n as mergeRefs } from "../../merge-refs-DF_7w2x_.js";
3
3
  import { toggleVariants } from "./Toggle.js";
4
4
  import * as React from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { Toggle } from "@base-ui/react/toggle";
7
6
  import { ToggleGroup as ToggleGroup$1 } from "@base-ui/react/toggle-group";
7
+ import { Toggle } from "@base-ui/react/toggle";
8
8
  //#region src/components/foundations/ToggleGroup.tsx
9
9
  /**
10
10
  * Tracks the pressed item's box so the segmented thumb can slide to it instead
@@ -1,7 +1,7 @@
1
1
  import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { Badge } from "../foundations/Badge.js";
3
- import { Switch } from "../foundations/Switch.js";
4
3
  import { ToggleGroup } from "../foundations/ToggleGroup.js";
4
+ import { Switch } from "../foundations/Switch.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/general-purpose/PricingBillingToggle.tsx
7
7
  /** Controlled billing-period selector composed from the shared Switch or ToggleGroup. */
@@ -1,8 +1,8 @@
1
1
  import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { Separator } from "../foundations/Separator.js";
3
3
  import { Card } from "../foundations/Card.js";
4
- import { Progress } from "../foundations/Progress.js";
5
4
  import { Slider } from "../foundations/Slider.js";
5
+ import { Progress } from "../foundations/Progress.js";
6
6
  import { formatPricingUsage, getUsagePrice } from "./Pricing.js";
7
7
  import * as React from "react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,11 +1,11 @@
1
1
  import { t as cx } from "../../class-names-BiMDVpUo.js";
2
2
  import { r as ArrowLeftIcon } from "../../icons-B4mGvCvc.js";
3
3
  import { TransitionSurface } from "../foundations/TransitionSurface.js";
4
+ import { SubagentRunActions, SubagentRunMilestone, SubagentRunMilestones, SubagentRunProgress } from "../agents-sdk/SubagentRunDetails.js";
5
+ import { SubagentRunIndicator, getSubagentRunName } from "../agents-sdk/SubagentRunIndicator.js";
6
+ import { t as ThinkChat } from "../../ThinkChat-BES_3Mb-.js";
4
7
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
5
8
  import { NaniteMark } from "./NaniteScene.js";
6
- import { SubagentRunIndicator, getSubagentRunName } from "../agents-sdk/SubagentRunIndicator.js";
7
- import { SubagentRunActions, SubagentRunMilestone, SubagentRunMilestones, SubagentRunProgress } from "../agents-sdk/SubagentRunDetails.js";
8
- import { t as ThinkChat } from "../../ThinkChat-DkA4Wr71.js";
9
9
  import * as React from "react";
10
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useAgentChat } from "@cloudflare/think/react";
@@ -59,14 +59,14 @@
59
59
 
60
60
  /* Takes the whole transcript region, the way the scroller it stands in for
61
61
  does, so nothing moves when the rows arrive. The composer floats over its
62
- lower edge, so the spinner sits slightly high rather than under it. */
62
+ lower edge, so the state sits slightly high rather than under it. The
63
+ .empty-state inside brings its own type and colour. */
63
64
  .agent-chat__transcript-loading {
64
65
  display: grid;
65
66
  block-size: 100%;
66
67
  min-block-size: 0;
67
68
  place-items: center;
68
69
  padding-block-end: var(--agent-chat-composer-size, 5rem);
69
- color: var(--sigvelo-color-text-muted);
70
70
  }
71
71
 
72
72
  .agent-chat[data-composer-hidden] .agent-chat__transcript-loading {
@@ -135,6 +135,10 @@ body {
135
135
  }
136
136
  }
137
137
 
138
+ /* A spinner that cannot spin is a circle. Plenty of people — most of them on
139
+ phones — browse with this on, so nothing may rely on the rotation to say
140
+ "still working": pair the icon with text that reads the same either way.
141
+ `.empty-state` is that pairing for a whole region. */
138
142
  @media (prefers-reduced-motion: reduce) {
139
143
  .sigvelo-icon--spinner {
140
144
  animation: none;
@@ -15,6 +15,18 @@
15
15
  overflow: hidden;
16
16
  }
17
17
 
18
+ /* `fill`: the view is the surface, not a card on it. Nothing sits beside it to
19
+ be separated from, so the aspect box, the hairline and the corners go and the
20
+ frame takes whatever its container gives it. The picture still letterboxes
21
+ inside — `object-fit: contain` further down is what keeps the remote page's
22
+ own proportions honest at any shape. */
23
+ .browser-live-view[data-fill] {
24
+ block-size: 100%;
25
+ aspect-ratio: auto;
26
+ border: 0;
27
+ border-radius: 0;
28
+ }
29
+
18
30
  .browser-live-view__frame {
19
31
  inline-size: 100%;
20
32
  block-size: 100%;
@@ -60,6 +72,20 @@
60
72
  max-inline-size: 80%;
61
73
  }
62
74
 
75
+ /* Host-drawn media. Styled by element rather than by class so a host that
76
+ renders its own picture into the frame inherits the shape without opting in:
77
+ `contain` keeps the remote viewport's proportions whatever the box is, and
78
+ the letterbox inherits the frame's fill, so a host that recolors the frame
79
+ recolors the bars with it. */
80
+ .browser-live-view video,
81
+ .browser-live-view canvas {
82
+ display: block;
83
+ inline-size: 100%;
84
+ block-size: 100%;
85
+ object-fit: contain;
86
+ background-color: inherit;
87
+ }
88
+
63
89
  /* An expired view showing a screenshot fallback keeps the image flush */
64
90
  .browser-live-view[data-expired] > img {
65
91
  inline-size: 100%;
@@ -83,6 +109,25 @@
83
109
  z-index: 1;
84
110
  }
85
111
 
112
+ /* A fault that leaves the picture running: a caption on the frame, opposite
113
+ the expand control, rather than an overlay that would hide what still
114
+ arrives. */
115
+ .browser-live-view__notice {
116
+ position: absolute;
117
+ inset-block-end: var(--sigvelo-spacing-2);
118
+ inset-inline-start: var(--sigvelo-spacing-2);
119
+ z-index: 1;
120
+ max-inline-size: calc(100% - var(--sigvelo-spacing-12));
121
+ margin: 0;
122
+ padding: var(--sigvelo-spacing-1) var(--sigvelo-spacing-2);
123
+ border-radius: var(--sigvelo-radius-md);
124
+ background-color: var(--sigvelo-color-surface-raised);
125
+ box-shadow: var(--sigvelo-elevation-raised);
126
+ color: var(--sigvelo-color-text-muted);
127
+ font-size: var(--sigvelo-text-xs);
128
+ pointer-events: none;
129
+ }
130
+
86
131
  /* Expand affordance, video-player style: quiet until the box is hovered or
87
132
  the button is focused */
88
133
  .browser-live-view__expand {
@@ -158,6 +158,12 @@ body.is-resizing-side-panel .think-full-app__view-scope {
158
158
  );
159
159
  }
160
160
 
161
+ /* The panel stands in for itself while its first read is in flight, so the
162
+ waiting state sits where the content will rather than in the top corner. */
163
+ .think-full-app__workbench--loading {
164
+ justify-content: center;
165
+ }
166
+
161
167
  .think-full-app__workbench.workspace-explorer {
162
168
  border: 0;
163
169
  border-radius: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/react-components",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "description": "MCP-B React components built on Base UI and shared design tokens, including Cloudflare Think chat primitives.",
5
5
  "homepage": "https://design-system.sigvelo.com",
6
6
  "bugs": {
@@ -53,7 +53,7 @@
53
53
  "streamdown": "^2.5.0",
54
54
  "unist-util-visit": "^5.1.0",
55
55
  "yet-another-react-lightbox": "^3.32.1",
56
- "@mcp-b/design-tokens": "0.38.0"
56
+ "@mcp-b/design-tokens": "0.39.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@ai-sdk/react": "^3.0.230",
@@ -1,6 +1,6 @@
1
1
  import { TransitionSurface } from "./components/foundations/TransitionSurface.js";
2
- import { AgentToolRunsProvider, useOptionalAgentToolRuns, useSourceScopedAgentToolEvents } from "./components/agents-sdk/AgentToolRunsContext.js";
3
2
  import { AgentChat, compactingNotice } from "./components/agents-sdk/AgentChat.js";
3
+ import { AgentToolRunsProvider, useOptionalAgentToolRuns, useSourceScopedAgentToolEvents } from "./components/agents-sdk/AgentToolRunsContext.js";
4
4
  import { SubagentRunList } from "./components/agents-sdk/SubagentRunList.js";
5
5
  import { ThinkChatContext, ThinkChatLiveContext, useOptionalThinkChatContext, useThinkChatContext } from "./components/agents-sdk/ThinkChatContext.js";
6
6
  import { ThinkChatActivity, createThinkChatActivityRenderer, renderThinkChatActivityPart } from "./components/agents-sdk/ThinkChatActivity.js";
@@ -1,10 +1,10 @@
1
1
  import { A as MaximizeIcon, d as CheckIcon, h as CodeIcon, r as ArrowLeftIcon, tt as WarningIcon, x as EyeIcon, y as DownloadIcon } from "./icons-B4mGvCvc.js";
2
2
  import { r as formatClock } from "./format-DB2mX9DA.js";
3
3
  import { a as CodeBlockCopyButton, i as CodeBlockContent, r as CodeBlockContainer, t as CodeBlock } from "./CodeBlock-DO4Hdu1R.js";
4
- import { AppTopBar } from "./components/general-purpose/AppTopBar.js";
5
4
  import { inferWorkspaceLanguage, inferWorkspaceMedia, isWorkspaceMarkdownPath, isWorkspaceSkillPath, parseWorkspaceSkill } from "./components/agents-sdk/WorkspaceFile.js";
6
5
  import { c as useWorkspaceNavigationContext, s as useWorkspaceNavigationRestoration } from "./WorkspaceLink-DtH66bAY.js";
7
6
  import { n as createWorkspaceRehypePlugins, t as WorkspaceMessageResponse } from "./WorkspaceMessageResponse-CJCmGvTx.js";
7
+ import { AppTopBar } from "./components/general-purpose/AppTopBar.js";
8
8
  import { WorkspaceHeader } from "./components/agents-sdk/WorkspaceHeader.js";
9
9
  import * as React from "react";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";