@mcp-b/react-components 0.9.0 → 0.11.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.
@@ -0,0 +1,188 @@
1
+ import { t as cx } from "../class-names-9UtZwb0J.js";
2
+ import { F as WarningIcon, L as XIcon, M as SpinnerIcon, a as CheckIcon, k as RefreshIcon } from "../icons-D2Q5n5C1.js";
3
+ import { Button } from "./Button.js";
4
+ import { Badge } from "./Badge.js";
5
+ import * as React from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/McpServerConnections.tsx
8
+ /**
9
+ * Runtime MCP server list. Add servers with `McpServerPicker`; render connected
10
+ * state here from the upstream Agents SDK `MCPServersState`.
11
+ */
12
+ function McpServerConnections({ className, heading = "Connected MCP servers", mcp, onAuthorize, onDisconnect, onRefresh, onRemove, onRetry, ref, ...props }) {
13
+ const [pendingAction, setPendingAction] = React.useState(null);
14
+ const entries = Object.entries(mcp.servers);
15
+ async function runAction(action, serverId, server, handler) {
16
+ if (!handler) return;
17
+ setPendingAction(`${action}:${serverId}`);
18
+ try {
19
+ await handler(serverId, server);
20
+ } finally {
21
+ setPendingAction(null);
22
+ }
23
+ }
24
+ return /* @__PURE__ */ jsxs("section", {
25
+ ref,
26
+ className: cx("mcp-server-connections", className),
27
+ ...props,
28
+ children: [/* @__PURE__ */ jsxs("div", {
29
+ className: "mcp-server-connections__header",
30
+ children: [/* @__PURE__ */ jsx("h2", { children: heading }), /* @__PURE__ */ jsxs("span", {
31
+ className: "mcp-server-connections__summary",
32
+ children: [
33
+ entries.length,
34
+ " ",
35
+ entries.length === 1 ? "server" : "servers"
36
+ ]
37
+ })]
38
+ }), entries.length === 0 ? /* @__PURE__ */ jsx("p", {
39
+ className: "mcp-server-connections__empty",
40
+ children: "No MCP servers connected."
41
+ }) : /* @__PURE__ */ jsx("ul", {
42
+ className: "mcp-server-connections__list",
43
+ role: "list",
44
+ children: entries.map(([serverId, server]) => {
45
+ const counts = getServerCapabilityCounts(mcp, serverId);
46
+ const status = getServerStatus(server);
47
+ const state = server.state;
48
+ const pending = (action) => pendingAction === `${action}:${serverId}`;
49
+ return /* @__PURE__ */ jsxs("li", {
50
+ className: "mcp-server-connections__item",
51
+ children: [/* @__PURE__ */ jsxs("div", {
52
+ className: "mcp-server-connections__main",
53
+ children: [
54
+ /* @__PURE__ */ jsxs("div", {
55
+ className: "mcp-server-connections__title-row",
56
+ children: [/* @__PURE__ */ jsx("span", {
57
+ className: "mcp-server-connections__name",
58
+ children: server.name
59
+ }), /* @__PURE__ */ jsxs(Badge, {
60
+ color: status.color,
61
+ size: "sm",
62
+ className: "mcp-server-connections__status",
63
+ children: [status.icon, status.label]
64
+ })]
65
+ }),
66
+ /* @__PURE__ */ jsx("span", {
67
+ className: "mcp-server-connections__url",
68
+ children: server.server_url
69
+ }),
70
+ server.error ? /* @__PURE__ */ jsx("p", {
71
+ className: "mcp-server-connections__error",
72
+ children: server.error
73
+ }) : null,
74
+ server.instructions ? /* @__PURE__ */ jsx("p", {
75
+ className: "mcp-server-connections__instructions",
76
+ children: server.instructions
77
+ }) : null,
78
+ /* @__PURE__ */ jsxs("p", {
79
+ className: "mcp-server-connections__capabilities",
80
+ children: [
81
+ counts.tools,
82
+ " tools, ",
83
+ counts.prompts,
84
+ " prompts, ",
85
+ counts.resources,
86
+ " resources"
87
+ ]
88
+ })
89
+ ]
90
+ }), /* @__PURE__ */ jsxs("div", {
91
+ className: "mcp-server-connections__actions",
92
+ children: [
93
+ state === "authenticating" && onAuthorize ? /* @__PURE__ */ jsx(Button, {
94
+ type: "button",
95
+ size: "xs",
96
+ variant: "outline",
97
+ color: "primary",
98
+ disabled: pending("authorize"),
99
+ onClick: () => void runAction("authorize", serverId, server, onAuthorize),
100
+ children: pending("authorize") ? "Opening" : "Authorize"
101
+ }) : null,
102
+ state === "failed" && onRetry ? /* @__PURE__ */ jsxs(Button, {
103
+ type: "button",
104
+ size: "xs",
105
+ variant: "outline",
106
+ color: "neutral",
107
+ disabled: pending("retry"),
108
+ onClick: () => void runAction("retry", serverId, server, onRetry),
109
+ children: [/* @__PURE__ */ jsx(RefreshIcon, {}), pending("retry") ? "Retrying" : "Retry"]
110
+ }) : null,
111
+ (state === "ready" || state === "connected") && onRefresh ? /* @__PURE__ */ jsx(Button, {
112
+ type: "button",
113
+ size: "icon-xs",
114
+ variant: "ghost",
115
+ color: "neutral",
116
+ "aria-label": `Refresh ${server.name} capabilities`,
117
+ disabled: pending("refresh"),
118
+ onClick: () => void runAction("refresh", serverId, server, onRefresh),
119
+ children: /* @__PURE__ */ jsx(RefreshIcon, {})
120
+ }) : null,
121
+ state !== "failed" && onDisconnect ? /* @__PURE__ */ jsx(Button, {
122
+ type: "button",
123
+ size: "xs",
124
+ variant: "outline",
125
+ color: "neutral",
126
+ disabled: pending("disconnect"),
127
+ onClick: () => void runAction("disconnect", serverId, server, onDisconnect),
128
+ children: pending("disconnect") ? "Disconnecting" : "Disconnect"
129
+ }) : null,
130
+ onRemove ? /* @__PURE__ */ jsx(Button, {
131
+ type: "button",
132
+ size: "icon-xs",
133
+ variant: "ghost",
134
+ color: "destructive",
135
+ "aria-label": `Remove ${server.name}`,
136
+ disabled: pending("remove"),
137
+ onClick: () => void runAction("remove", serverId, server, onRemove),
138
+ children: /* @__PURE__ */ jsx(XIcon, {})
139
+ }) : null
140
+ ]
141
+ })]
142
+ }, serverId);
143
+ })
144
+ })]
145
+ });
146
+ }
147
+ function getServerCapabilityCounts(mcp, serverId) {
148
+ return {
149
+ tools: mcp.tools.filter((tool) => tool.serverId === serverId).length,
150
+ prompts: mcp.prompts.filter((prompt) => prompt.serverId === serverId).length,
151
+ resources: mcp.resources.filter((resource) => resource.serverId === serverId).length
152
+ };
153
+ }
154
+ function getServerStatus(server) {
155
+ const state = server.state;
156
+ if (state === "ready") return {
157
+ color: "success",
158
+ icon: /* @__PURE__ */ jsx(CheckIcon, {}),
159
+ label: "Ready"
160
+ };
161
+ if (state === "failed") return {
162
+ color: "destructive",
163
+ icon: /* @__PURE__ */ jsx(WarningIcon, {}),
164
+ label: "Failed"
165
+ };
166
+ if (state === "authenticating") return {
167
+ color: "warning",
168
+ icon: /* @__PURE__ */ jsx(WarningIcon, {}),
169
+ label: "Authorize"
170
+ };
171
+ if (state === "connecting") return {
172
+ color: "neutral",
173
+ icon: /* @__PURE__ */ jsx(SpinnerIcon, { className: "mcp-server-connections__spinner" }),
174
+ label: "Connecting"
175
+ };
176
+ if (state === "discovering") return {
177
+ color: "neutral",
178
+ icon: /* @__PURE__ */ jsx(SpinnerIcon, { className: "mcp-server-connections__spinner" }),
179
+ label: "Discovering"
180
+ };
181
+ return {
182
+ color: "neutral",
183
+ icon: /* @__PURE__ */ jsx(CheckIcon, {}),
184
+ label: "Connected"
185
+ };
186
+ }
187
+ //#endregion
188
+ export { McpServerConnections };
@@ -1,7 +1,41 @@
1
1
  import { r as ButtonProps } from "../Button-Ct5I6aTu.js";
2
2
  import * as React from "react";
3
+ import Cloudflare from "cloudflare";
4
+ import { AiModelsSearchObject } from "@cloudflare/workers-types";
3
5
 
4
6
  //#region src/components/ModelSelector.d.ts
7
+ type CloudflareModelSelectorModels = readonly Cloudflare.AI.ModelListResponse[] | readonly AiModelsSearchObject[] | readonly string[];
8
+ interface CloudflareModelSelectorOption {
9
+ readonly id: string;
10
+ readonly provider: string;
11
+ readonly providerLabel: string;
12
+ readonly source: "ai-gateway" | "workers-ai";
13
+ readonly description: string | null;
14
+ }
15
+ interface CloudflareModelSelectorProps extends Omit<ModelSelectorProps, "children"> {
16
+ /** Raw `client.ai.models.list()` entries, `env.AI.models()` entries, or model ids. */
17
+ models: CloudflareModelSelectorModels;
18
+ /** Current runnable model id, such as `@cf/meta/llama...` or `openai/gpt-5.5`. */
19
+ selectedModelId?: string | null;
20
+ /** Called with a runnable Workers AI or AI Gateway model id. */
21
+ onSelectModel: (modelId: string) => void;
22
+ /** Disables the trigger while the caller is loading or saving. */
23
+ disabled?: boolean;
24
+ /** Search input placeholder. */
25
+ placeholder?: string;
26
+ /** Trigger fallback when no model is selected. */
27
+ triggerLabel?: React.ReactNode;
28
+ /** Empty state copy. */
29
+ emptyLabel?: React.ReactNode;
30
+ /** Whether a pasted `provider/model` id can be selected when absent from the catalog. */
31
+ allowTypedModel?: boolean;
32
+ }
33
+ declare function isCloudflareRunnableModelId(value: string): boolean;
34
+ declare function readCloudflareModelId(entry: unknown): string | null;
35
+ declare function getCloudflareModelProvider(modelId: string): string;
36
+ declare function formatCloudflareModelProvider(provider: string): string;
37
+ declare function normalizeCloudflareModelSelectorModels(models: CloudflareModelSelectorModels): CloudflareModelSelectorOption[];
38
+ declare function listCloudflareModelSelectorOptions(client: Cloudflare, params: Cloudflare.AI.ModelListParams): Promise<CloudflareModelSelectorOption[]>;
5
39
  interface ModelSelectorProps extends React.HTMLAttributes<HTMLDivElement> {
6
40
  /** Controlled dialog open state. */
7
41
  open?: boolean;
@@ -65,6 +99,18 @@ declare function ModelSelector({
65
99
  }: ModelSelectorProps & {
66
100
  ref?: React.Ref<HTMLDivElement>;
67
101
  }): React.JSX.Element;
102
+ declare function CloudflareModelSelector({
103
+ models,
104
+ selectedModelId,
105
+ onSelectModel,
106
+ disabled,
107
+ placeholder,
108
+ triggerLabel,
109
+ emptyLabel,
110
+ allowTypedModel,
111
+ onOpenChange,
112
+ ...props
113
+ }: CloudflareModelSelectorProps): React.JSX.Element;
68
114
  interface ModelSelectorTriggerProps extends Omit<ButtonProps, "variant" | "color" | "className"> {
69
115
  className?: string;
70
116
  }
@@ -195,4 +241,4 @@ declare function ModelSelectorShortcut({
195
241
  ref?: React.Ref<HTMLSpanElement>;
196
242
  }): React.JSX.Element;
197
243
  //#endregion
198
- export { ModelSelector, ModelSelectorContent, ModelSelectorContentProps, ModelSelectorDialog, ModelSelectorDialogProps, ModelSelectorEmpty, ModelSelectorEmptyProps, ModelSelectorGroup, ModelSelectorGroupProps, ModelSelectorInput, ModelSelectorInputProps, ModelSelectorItem, ModelSelectorItemProps, ModelSelectorList, ModelSelectorListProps, ModelSelectorLogo, ModelSelectorLogoGroup, ModelSelectorLogoGroupProps, ModelSelectorLogoProps, ModelSelectorName, ModelSelectorNameProps, ModelSelectorProps, ModelSelectorSeparator, ModelSelectorSeparatorProps, ModelSelectorShortcut, ModelSelectorShortcutProps, ModelSelectorTrigger, ModelSelectorTriggerProps };
244
+ export { CloudflareModelSelector, CloudflareModelSelectorModels, CloudflareModelSelectorOption, CloudflareModelSelectorProps, ModelSelector, ModelSelectorContent, ModelSelectorContentProps, ModelSelectorDialog, ModelSelectorDialogProps, ModelSelectorEmpty, ModelSelectorEmptyProps, ModelSelectorGroup, ModelSelectorGroupProps, ModelSelectorInput, ModelSelectorInputProps, ModelSelectorItem, ModelSelectorItemProps, ModelSelectorList, ModelSelectorListProps, ModelSelectorLogo, ModelSelectorLogoGroup, ModelSelectorLogoGroupProps, ModelSelectorLogoProps, ModelSelectorName, ModelSelectorNameProps, ModelSelectorProps, ModelSelectorSeparator, ModelSelectorSeparatorProps, ModelSelectorShortcut, ModelSelectorShortcutProps, ModelSelectorTrigger, ModelSelectorTriggerProps, formatCloudflareModelProvider, getCloudflareModelProvider, isCloudflareRunnableModelId, listCloudflareModelSelectorOptions, normalizeCloudflareModelSelectorModels, readCloudflareModelId };
@@ -1,2 +1,2 @@
1
- import { a as ModelSelectorGroup, c as ModelSelectorList, d as ModelSelectorName, f as ModelSelectorSeparator, i as ModelSelectorEmpty, l as ModelSelectorLogo, m as ModelSelectorTrigger, n as ModelSelectorContent, o as ModelSelectorInput, p as ModelSelectorShortcut, r as ModelSelectorDialog, s as ModelSelectorItem, t as ModelSelector, u as ModelSelectorLogoGroup } from "../ModelSelector-9G_-GooI.js";
2
- export { ModelSelector, ModelSelectorContent, ModelSelectorDialog, ModelSelectorEmpty, ModelSelectorGroup, ModelSelectorInput, ModelSelectorItem, ModelSelectorList, ModelSelectorLogo, ModelSelectorLogoGroup, ModelSelectorName, ModelSelectorSeparator, ModelSelectorShortcut, ModelSelectorTrigger };
1
+ import { _ as getCloudflareModelProvider, a as ModelSelectorEmpty, b as normalizeCloudflareModelSelectorModels, c as ModelSelectorItem, d as ModelSelectorLogoGroup, f as ModelSelectorName, g as formatCloudflareModelProvider, h as ModelSelectorTrigger, i as ModelSelectorDialog, l as ModelSelectorList, m as ModelSelectorShortcut, n as ModelSelector, o as ModelSelectorGroup, p as ModelSelectorSeparator, r as ModelSelectorContent, s as ModelSelectorInput, t as CloudflareModelSelector, u as ModelSelectorLogo, v as isCloudflareRunnableModelId, x as readCloudflareModelId, y as listCloudflareModelSelectorOptions } from "../ModelSelector-DXtpcRmT.js";
2
+ export { CloudflareModelSelector, ModelSelector, ModelSelectorContent, ModelSelectorDialog, ModelSelectorEmpty, ModelSelectorGroup, ModelSelectorInput, ModelSelectorItem, ModelSelectorList, ModelSelectorLogo, ModelSelectorLogoGroup, ModelSelectorName, ModelSelectorSeparator, ModelSelectorShortcut, ModelSelectorTrigger, formatCloudflareModelProvider, getCloudflareModelProvider, isCloudflareRunnableModelId, listCloudflareModelSelectorOptions, normalizeCloudflareModelSelectorModels, readCloudflareModelId };
@@ -141,180 +141,18 @@
141
141
  line-height: 1.5;
142
142
  }
143
143
 
144
- .agent-connect__mcp {
145
- display: grid;
146
- gap: 0.5rem;
147
- min-inline-size: 0;
148
- }
149
-
150
- .agent-connect__mcp-heading {
151
- margin: 0;
152
- color: var(--sigvelo-color-text-muted);
153
- font-size: 0.74rem;
154
- font-weight: var(--sigvelo-font-weight-semibold);
155
- line-height: 1.25;
156
- }
157
-
158
- .agent-connect__mcp-list {
159
- display: grid;
160
- grid-template-columns: repeat(2, minmax(0, 1fr));
161
- gap: 0.35rem;
162
- max-block-size: 24rem;
163
- margin: 0;
164
- padding: 0;
165
- overflow-y: auto;
166
- overscroll-behavior: contain;
167
- list-style: none;
168
- }
169
-
170
- .agent-connect__mcp-item {
171
- display: grid;
172
- grid-template-columns: 1.625rem minmax(0, 1fr);
173
- gap: 0.5rem;
174
- align-items: start;
175
- min-inline-size: 0;
176
- padding: 0.5rem;
177
- border: var(--sigvelo-border-style) var(--sigvelo-border-width)
178
- var(--sigvelo-color-neutral-border-subtle);
179
- border-radius: var(--sigvelo-radius-md);
180
- background: var(--sigvelo-color-surface);
181
- }
182
-
183
- .agent-connect__mcp-icon {
184
- display: grid;
185
- place-items: center;
186
- inline-size: 1.625rem;
187
- block-size: 1.625rem;
188
- border-radius: var(--sigvelo-radius-sm);
189
- background: var(--sigvelo-color-neutral-bg-subtle);
190
- color: var(--sigvelo-color-text-muted);
191
- font-size: 0.72rem;
192
- font-weight: var(--sigvelo-font-weight-bold);
193
- line-height: 1;
194
- }
195
-
196
- .agent-connect__mcp-icon img {
197
- display: block;
198
- max-inline-size: 1rem;
199
- max-block-size: 1rem;
200
- }
201
-
202
- .agent-connect__mcp-copy {
203
- display: grid;
204
- gap: 0.08rem;
205
- min-inline-size: 0;
206
- }
207
-
208
- .agent-connect__mcp-name {
209
- color: var(--sigvelo-color-text);
210
- font-size: 0.78rem;
211
- font-weight: var(--sigvelo-font-weight-semibold);
212
- line-height: 1.2;
213
- overflow-wrap: anywhere;
214
- text-decoration: none;
215
- }
216
-
217
- .agent-connect__mcp-name:hover {
218
- color: var(--sigvelo-color-primary-text);
219
- text-decoration: underline;
220
- text-underline-offset: 0.16em;
221
- }
222
-
223
- .agent-connect__mcp-name:focus-visible {
224
- outline: 2px solid var(--sigvelo-color-focus);
225
- outline-offset: 2px;
226
- }
227
-
228
- .agent-connect__mcp-description {
229
- color: var(--sigvelo-color-text-muted);
230
- font-size: 0.7rem;
231
- line-height: 1.25;
232
- overflow-wrap: anywhere;
233
- }
234
-
235
- .agent-connect__mcp-setup {
236
- display: grid;
237
- gap: 0.3rem;
238
- margin-block-start: 0.2rem;
239
- min-inline-size: 0;
240
- }
241
-
242
- .agent-connect__mcp-setup p {
243
- margin: 0;
244
- color: var(--sigvelo-color-text-muted);
245
- font-size: 0.68rem;
246
- line-height: 1.3;
247
- overflow-wrap: anywhere;
248
- }
249
-
250
- .agent-connect__mcp-setup-auth {
251
- display: flex;
252
- flex-wrap: wrap;
253
- gap: 0.25rem;
254
- }
255
-
256
- .agent-connect__mcp-setup-auth span:first-child {
257
- color: var(--sigvelo-color-text);
258
- font-weight: var(--sigvelo-font-weight-semibold);
259
- }
260
-
261
- .agent-connect__mcp-setup-links {
262
- display: flex;
263
- flex-wrap: wrap;
264
- gap: 0.25rem;
265
- margin: 0;
266
- padding: 0;
267
- list-style: none;
268
- }
269
-
270
- .agent-connect__mcp-setup-links a {
271
- display: inline-flex;
272
- align-items: center;
273
- min-block-size: 1.35rem;
274
- padding: 0 0.35rem;
275
- border: var(--sigvelo-border-style) var(--sigvelo-border-width)
276
- var(--sigvelo-color-neutral-border-subtle);
277
- border-radius: var(--sigvelo-radius-sm);
278
- color: var(--sigvelo-color-text-muted);
279
- font-size: 0.65rem;
280
- font-weight: var(--sigvelo-font-weight-semibold);
281
- line-height: 1.1;
282
- text-decoration: none;
283
- }
284
-
285
- .agent-connect__mcp-setup-links a:hover {
286
- border-color: var(--sigvelo-color-primary-border-muted);
287
- color: var(--sigvelo-color-primary-text);
288
- }
289
-
290
- .agent-connect__mcp-setup-links a:focus-visible {
291
- outline: 2px solid var(--sigvelo-color-focus);
292
- outline-offset: 2px;
293
- }
294
-
295
144
  .agent-connect__mcp-form {
296
145
  display: grid;
297
146
  gap: 0.75rem;
298
147
  min-inline-size: 0;
299
148
  }
300
149
 
301
- .agent-connect__mcp-form--row {
302
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
303
- align-items: end;
304
- padding: 0.75rem;
305
- background: var(--sigvelo-color-surface);
306
- }
307
-
308
150
  .agent-connect__mcp-form-actions {
309
151
  display: flex;
310
152
  flex-wrap: wrap;
311
153
  gap: 0.5rem;
312
154
  }
313
155
 
314
- .agent-connect__mcp-form--row .agent-connect__mcp-form-actions {
315
- align-self: end;
316
- }
317
-
318
156
  .agent-connect__mcp-form-status {
319
157
  align-self: end;
320
158
  min-inline-size: 0;
@@ -340,10 +178,6 @@
340
178
  grid-template-columns: repeat(2, minmax(0, 1fr));
341
179
  }
342
180
 
343
- .agent-connect__mcp-list {
344
- grid-template-columns: 1fr;
345
- }
346
-
347
181
  .agent-connect-popover {
348
182
  inline-size: min(24rem, calc(100dvi - 1.5rem));
349
183
  }
@@ -0,0 +1,178 @@
1
+ .browser-run-panel {
2
+ min-inline-size: 0;
3
+ min-block-size: 0;
4
+ display: flex;
5
+ flex-direction: column;
6
+ background: var(--sigvelo-color-canvas);
7
+ color: var(--sigvelo-color-text);
8
+ font-family: var(--sigvelo-font-sans);
9
+ }
10
+
11
+ .browser-run-panel__header {
12
+ min-block-size: 3rem;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: space-between;
16
+ gap: 0.75rem;
17
+ padding: 0.5rem 0.625rem;
18
+ border-block-end: var(--sigvelo-border-style) var(--sigvelo-border-width)
19
+ color-mix(in srgb, var(--sigvelo-color-neutral-border-subtle) 62%, transparent);
20
+ background: var(--sigvelo-color-surface);
21
+ }
22
+
23
+ .browser-run-panel__identity {
24
+ min-inline-size: 0;
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 0.625rem;
28
+ }
29
+
30
+ .browser-run-panel__icon {
31
+ flex: none;
32
+ color: var(--sigvelo-color-text-muted);
33
+ }
34
+
35
+ .browser-run-panel__title-block {
36
+ min-inline-size: 0;
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: 0.125rem;
40
+ }
41
+
42
+ .browser-run-panel__title {
43
+ font-size: 0.8125rem;
44
+ font-weight: var(--sigvelo-font-weight-semibold);
45
+ line-height: 1.2;
46
+ }
47
+
48
+ .browser-run-panel__url,
49
+ .browser-run-panel__target-url {
50
+ min-inline-size: 0;
51
+ overflow: hidden;
52
+ color: var(--sigvelo-color-text-muted);
53
+ font-size: 0.75rem;
54
+ line-height: 1.2;
55
+ text-overflow: ellipsis;
56
+ white-space: nowrap;
57
+ }
58
+
59
+ .browser-run-panel__actions {
60
+ flex: none;
61
+ display: flex;
62
+ align-items: center;
63
+ gap: 0.25rem;
64
+ }
65
+
66
+ .browser-run-panel__actions svg {
67
+ width: 1rem;
68
+ height: 1rem;
69
+ }
70
+
71
+ .browser-run-panel__targets {
72
+ display: flex;
73
+ gap: 0.375rem;
74
+ padding: 0.5rem 0.625rem;
75
+ overflow-x: auto;
76
+ border-block-end: var(--sigvelo-border-style) var(--sigvelo-border-width)
77
+ color-mix(in srgb, var(--sigvelo-color-neutral-border-subtle) 50%, transparent);
78
+ background: color-mix(in oklab, var(--sigvelo-color-canvas), var(--sigvelo-color-surface) 58%);
79
+ }
80
+
81
+ .browser-run-panel__target {
82
+ min-inline-size: 8rem;
83
+ max-inline-size: 13rem;
84
+ display: flex;
85
+ flex: 0 0 auto;
86
+ flex-direction: column;
87
+ gap: 0.125rem;
88
+ padding: 0.375rem 0.5rem;
89
+ border: var(--sigvelo-border-style) var(--sigvelo-border-width)
90
+ color-mix(in srgb, var(--sigvelo-color-neutral-border-subtle) 68%, transparent);
91
+ border-radius: var(--sigvelo-radius-md);
92
+ background: var(--sigvelo-color-surface);
93
+ color: inherit;
94
+ font: inherit;
95
+ text-align: start;
96
+ cursor: pointer;
97
+ }
98
+
99
+ .browser-run-panel__target:hover {
100
+ border-color: var(--sigvelo-color-neutral-border);
101
+ }
102
+
103
+ .browser-run-panel__target:focus-visible {
104
+ outline: 2px solid var(--sigvelo-color-focus);
105
+ outline-offset: 2px;
106
+ }
107
+
108
+ .browser-run-panel__target[aria-pressed="true"] {
109
+ border-color: color-mix(in srgb, var(--sigvelo-color-primary-border) 82%, transparent);
110
+ background: var(--sigvelo-color-primary-bg-subtle);
111
+ }
112
+
113
+ .browser-run-panel__target-title {
114
+ overflow: hidden;
115
+ font-size: 0.75rem;
116
+ font-weight: var(--sigvelo-font-weight-semibold);
117
+ line-height: 1.2;
118
+ text-overflow: ellipsis;
119
+ white-space: nowrap;
120
+ }
121
+
122
+ .browser-run-panel__body {
123
+ min-block-size: 0;
124
+ display: flex;
125
+ flex: 1;
126
+ padding: 0.625rem;
127
+ }
128
+
129
+ .browser-run-panel__body > .browser-live-view {
130
+ flex: 1;
131
+ min-block-size: 16rem;
132
+ aspect-ratio: auto;
133
+ border-radius: var(--sigvelo-radius-md);
134
+ }
135
+
136
+ .browser-run-panel__state {
137
+ min-block-size: 14rem;
138
+ display: flex;
139
+ flex: 1;
140
+ flex-direction: column;
141
+ align-items: center;
142
+ justify-content: center;
143
+ gap: 0.5rem;
144
+ padding: 1rem;
145
+ border: var(--sigvelo-border-style) var(--sigvelo-border-width)
146
+ var(--sigvelo-color-neutral-border-subtle);
147
+ border-radius: var(--sigvelo-radius-md);
148
+ background: var(--sigvelo-color-neutral-bg-subtle);
149
+ color: var(--sigvelo-color-text-muted);
150
+ font-size: 0.8125rem;
151
+ text-align: center;
152
+ }
153
+
154
+ .browser-run-panel__state[data-tone="danger"] {
155
+ min-block-size: auto;
156
+ flex: none;
157
+ margin: 0.625rem 0.625rem 0;
158
+ border-color: var(--sigvelo-color-danger-border-subtle);
159
+ background: var(--sigvelo-color-danger-bg-subtle);
160
+ color: var(--sigvelo-color-danger-text);
161
+ }
162
+
163
+ .browser-run-panel__spinner {
164
+ animation: browser-run-panel-spin 900ms linear infinite;
165
+ }
166
+
167
+ @keyframes browser-run-panel-spin {
168
+ to {
169
+ transform: rotate(360deg);
170
+ }
171
+ }
172
+
173
+ @media (prefers-reduced-motion: reduce) {
174
+ .browser-run-panel__spinner,
175
+ .browser-run-panel__actions .button svg {
176
+ animation: none;
177
+ }
178
+ }
@@ -39,6 +39,7 @@
39
39
  @import "./nanite-scene.css" layer(components);
40
40
  @import "./number-field.css" layer(components);
41
41
  @import "./popover.css" layer(components);
42
+ @import "./mcp-server-connections.css" layer(components);
42
43
  @import "./mcp-server-picker.css" layer(components);
43
44
  @import "./preview-card.css" layer(components);
44
45
  @import "./progress.css" layer(components);
@@ -62,6 +63,7 @@
62
63
  @import "./streamdown.css" layer(components);
63
64
  @import "./artifact.css" layer(components);
64
65
  @import "./browser-live-view.css" layer(components);
66
+ @import "./browser-run-panel.css" layer(components);
65
67
  @import "./browser-replay.css" layer(components);
66
68
  @import "./chain-of-thought.css" layer(components);
67
69
  @import "./code-block.css" layer(components);