@mcp-b/react-components 0.42.0 → 0.43.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 (50) hide show
  1. package/dist/{AgentChat-DVr2giwD.d.ts → AgentChat-Bibfj7u1.d.ts} +1 -1
  2. package/dist/{AgentChatStartScreen-CO49yepa.d.ts → AgentChatStartScreen-Bkv7Avni.d.ts} +6 -0
  3. package/dist/McpPluginCatalog-mbGw8FTu.d.ts +92 -0
  4. package/dist/ResponsiveSidebarShell-DOXd5T-d.d.ts +111 -0
  5. package/dist/SetupChecklist-H1JRCIIe.js +77 -0
  6. package/dist/{ThinkChatActivity-CsDql-ER.d.ts → ThinkChatActivity-CgvmTXXB.d.ts} +1 -1
  7. package/dist/Workspace-F3raHdYV.d.ts +140 -0
  8. package/dist/{WorkspaceFileView-DwdXiKku.js → WorkspaceFileView-DWMKxX_u.js} +0 -1
  9. package/dist/components/agents-sdk/AgentChat.d.ts +1 -1
  10. package/dist/components/agents-sdk/ManagerOffice.js +1 -1
  11. package/dist/components/agents-sdk/McpPluginCatalog.d.ts +1 -91
  12. package/dist/components/agents-sdk/McpPluginCatalog.js +1 -1
  13. package/dist/components/agents-sdk/SubagentRunSelector.js +1 -1
  14. package/dist/components/agents-sdk/ThinkChat.d.ts +2 -2
  15. package/dist/components/agents-sdk/ThinkChat.js +1 -1
  16. package/dist/components/agents-sdk/ThinkChatActivity.d.ts +1 -1
  17. package/dist/components/agents-sdk/ThinkChatActivity.js +1 -1
  18. package/dist/components/agents-sdk/ThinkExecutionDetail.js +1 -1
  19. package/dist/components/agents-sdk/ThinkFullApp.d.ts +20 -6
  20. package/dist/components/agents-sdk/ThinkFullApp.js +6 -5
  21. package/dist/components/agents-sdk/ThinkFullAppViewSwitch.js +1 -1
  22. package/dist/components/agents-sdk/ThinkRoutineDetail.js +1 -1
  23. package/dist/components/agents-sdk/ThinkRoutineLibrary.d.ts +4 -3
  24. package/dist/components/agents-sdk/ThinkRoutineLibrary.js +17 -31
  25. package/dist/components/agents-sdk/ThinkSidepanel.d.ts +173 -0
  26. package/dist/components/agents-sdk/ThinkSidepanel.js +656 -0
  27. package/dist/components/agents-sdk/ThinkThreadPicker.d.ts +4 -5
  28. package/dist/components/agents-sdk/ThinkThreadPicker.js +6 -6
  29. package/dist/components/agents-sdk/Workspace.d.ts +1 -139
  30. package/dist/components/agents-sdk/WorkspaceBrowser.d.ts +1 -1
  31. package/dist/components/agents-sdk/WorkspaceExplorer.d.ts +1 -1
  32. package/dist/components/agents-sdk/WorkspaceExplorer.js +3 -3
  33. package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
  34. package/dist/components/ai-sdk/AgentChatStartScreen.d.ts +1 -1
  35. package/dist/components/ai-sdk/AgentChatStartScreen.js +5 -2
  36. package/dist/components/foundations/ToggleGroup.d.ts +1 -1
  37. package/dist/components/foundations/ToggleGroup.js +1 -1
  38. package/dist/components/general-purpose/PricingBillingToggle.js +1 -1
  39. package/dist/components/general-purpose/PricingUsageCalculator.js +1 -1
  40. package/dist/components/general-purpose/ResponsiveSidebarShell.d.ts +1 -104
  41. package/dist/components/general-purpose/ResponsiveSidebarShell.js +2 -2
  42. package/dist/components/general-purpose/SetupChecklist.js +1 -76
  43. package/dist/components/general-purpose/ThemeModeControl.js +1 -1
  44. package/dist/components/nanites/AgentToolDetail.js +3 -3
  45. package/dist/styles/agent-chat.css +20 -15
  46. package/dist/styles/index.css +1 -0
  47. package/dist/styles/responsive-sidebar-shell.css +12 -9
  48. package/dist/styles/think-sidepanel.css +74 -0
  49. package/package.json +2 -2
  50. package/dist/{ThinkChat-DkA4Wr71.js → ThinkChat-BES_3Mb-.js} +1 -1
@@ -0,0 +1,656 @@
1
+ import { t as cx } from "../../class-names-BiMDVpUo.js";
2
+ import { $ as WarningIcon, C as FolderIcon, G as SlackIcon, I as PaperclipIcon, K as SpinnerIcon, R as PencilIcon, S as FileIcon, T as InfoIcon, V as QueueIcon, Z as TerminalIcon, b as EyeIcon, c as BoxIcon, g as DiscordIcon, k as McpIcon, o as ArrowUpRightIcon, q as SquareIcon, r as ArrowLeftIcon, y as EllipsisIcon } from "../../icons-CVFSeTJn.js";
3
+ import { Button } from "../foundations/Button.js";
4
+ import { Tooltip } from "../foundations/Tooltip.js";
5
+ import { Menu } from "../foundations/Menu.js";
6
+ import { Dialog } from "../foundations/Dialog.js";
7
+ import { ChatGptSignInScreen } from "../extension/ChatGptSignInScreen.js";
8
+ import { Avatar } from "../foundations/Avatar.js";
9
+ import { EmptyState } from "../foundations/EmptyState.js";
10
+ import { AppIcon } from "../foundations/AppIcon.js";
11
+ import "../foundations/icons.js";
12
+ import { AppTopBar } from "../general-purpose/AppTopBar.js";
13
+ import { DescriptionList } from "../foundations/DescriptionList.js";
14
+ import { McpServerPickerAction, McpServerPickerItems } from "./McpServerPicker.js";
15
+ import { NaniteMark } from "../nanites/NaniteScene.js";
16
+ import { getThinkExecutionRunId } from "./ThinkExecutionRun.js";
17
+ import { ThinkThreadPicker, summarizeThinkThreads } from "./ThinkThreadPicker.js";
18
+ import { ThinkFullApp } from "./ThinkFullApp.js";
19
+ import { Switch } from "../foundations/Switch.js";
20
+ import { ThinkRoutineLibrary } from "./ThinkRoutineLibrary.js";
21
+ import { ActionGuide } from "../general-purpose/ActionGuide.js";
22
+ import { t as SetupChecklistAction } from "../../SetupChecklist-H1JRCIIe.js";
23
+ import { useTheme } from "../foundations/ThemeProvider.js";
24
+ import * as React from "react";
25
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
26
+ //#region src/components/agents-sdk/ThinkSidepanel.tsx
27
+ const EMPTY_THREADS = [];
28
+ function AppearanceMenu() {
29
+ const { preference, setPreference } = useTheme();
30
+ return /* @__PURE__ */ jsxs(Menu.RadioGroup, {
31
+ value: preference,
32
+ onValueChange: (value) => {
33
+ if (value === "light" || value === "dark" || value === "system") setPreference(value);
34
+ },
35
+ children: [
36
+ /* @__PURE__ */ jsxs(Menu.RadioItem, {
37
+ value: "light",
38
+ children: [/* @__PURE__ */ jsx(Menu.RadioItemIndicator, {}), "Light"]
39
+ }),
40
+ /* @__PURE__ */ jsxs(Menu.RadioItem, {
41
+ value: "dark",
42
+ children: [/* @__PURE__ */ jsx(Menu.RadioItemIndicator, {}), "Dark"]
43
+ }),
44
+ /* @__PURE__ */ jsxs(Menu.RadioItem, {
45
+ value: "system",
46
+ children: [/* @__PURE__ */ jsx(Menu.RadioItemIndicator, {}), "System"]
47
+ })
48
+ ]
49
+ });
50
+ }
51
+ function MenuGroupLabel({ hint, label }) {
52
+ return /* @__PURE__ */ jsxs(Menu.GroupLabel, {
53
+ className: "think-sidepanel__menu-group-label",
54
+ children: [label, /* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, {
55
+ render: /* @__PURE__ */ jsx("span", { className: "think-sidepanel__menu-hint" }),
56
+ children: /* @__PURE__ */ jsx(InfoIcon, {})
57
+ }), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, { children: /* @__PURE__ */ jsx(Tooltip.Popup, { children: hint }) }) })] })]
58
+ });
59
+ }
60
+ function OverflowMenu({ companion, follow, identityEmail, onIdentity, onModel, onSignOut, passkeyVault, renderLink }) {
61
+ return /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(AppTopBar.Button, {
62
+ label: "More actions",
63
+ tooltip: identityEmail ? `Signed in as ${identityEmail}` : void 0,
64
+ render: /* @__PURE__ */ jsx(Menu.Trigger, {}),
65
+ children: identityEmail ? /* @__PURE__ */ jsx(Avatar.Root, {
66
+ size: "sm",
67
+ children: /* @__PURE__ */ jsx(Avatar.Fallback, { children: identityEmail[0]?.toUpperCase() })
68
+ }) : /* @__PURE__ */ jsx(EllipsisIcon, {})
69
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
70
+ side: "bottom",
71
+ align: "end",
72
+ sideOffset: 4,
73
+ children: /* @__PURE__ */ jsxs(Menu.Popup, { children: [
74
+ /* @__PURE__ */ jsxs(Menu.Item, {
75
+ render: renderLink({
76
+ kind: "view",
77
+ view: "files"
78
+ }),
79
+ children: [/* @__PURE__ */ jsx(FileIcon, {}), "Files"]
80
+ }),
81
+ /* @__PURE__ */ jsxs(Menu.Item, {
82
+ render: renderLink({
83
+ kind: "view",
84
+ view: "plugins"
85
+ }),
86
+ children: [/* @__PURE__ */ jsx(BoxIcon, {}), "Plugins"]
87
+ }),
88
+ /* @__PURE__ */ jsxs(Menu.Item, {
89
+ render: renderLink({
90
+ kind: "view",
91
+ view: "schedules"
92
+ }),
93
+ children: [/* @__PURE__ */ jsx(QueueIcon, {}), "Routines"]
94
+ }),
95
+ follow ? /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
96
+ checked: follow.followed,
97
+ onCheckedChange: follow.onCheckedChange,
98
+ children: [/* @__PURE__ */ jsx(EyeIcon, {}), "Follow this conversation"]
99
+ }) : null,
100
+ onIdentity ? /* @__PURE__ */ jsxs(Menu.Item, {
101
+ onClick: onIdentity,
102
+ children: [/* @__PURE__ */ jsx(InfoIcon, {}), "Identity"]
103
+ }) : null,
104
+ onModel ? /* @__PURE__ */ jsxs(Menu.Item, {
105
+ onClick: onModel,
106
+ children: [/* @__PURE__ */ jsx(TerminalIcon, {}), "Model"]
107
+ }) : null,
108
+ companion ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu.Separator, {}), /* @__PURE__ */ jsxs(Menu.Group, { children: [
109
+ /* @__PURE__ */ jsx(MenuGroupLabel, {
110
+ label: "Companion app",
111
+ hint: "Connecting lets this employee chat with the browser and watch it work from anywhere."
112
+ }),
113
+ /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
114
+ className: "think-sidepanel__menu-switch-item",
115
+ checked: companion.enabled,
116
+ onCheckedChange: companion.setEnabled,
117
+ children: ["Connect this browser", /* @__PURE__ */ jsx(Switch.Root, {
118
+ "aria-hidden": true,
119
+ readOnly: true,
120
+ size: "sm",
121
+ checked: companion.enabled,
122
+ children: /* @__PURE__ */ jsx(Switch.Thumb, {})
123
+ })]
124
+ }),
125
+ /* @__PURE__ */ jsxs(Menu.Item, {
126
+ render: /* @__PURE__ */ jsx("a", {
127
+ href: companion.origin,
128
+ target: "_blank",
129
+ rel: "noreferrer",
130
+ "aria-label": companion.origin.replace(/^https?:\/\//, "")
131
+ }),
132
+ children: [/* @__PURE__ */ jsx(ArrowUpRightIcon, {}), companion.origin.replace(/^https?:\/\//, "")]
133
+ })
134
+ ] })] }) : null,
135
+ passkeyVault ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu.Separator, {}), /* @__PURE__ */ jsxs(Menu.Group, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, {
136
+ label: "Passkeys",
137
+ hint: "The employee saves and uses its own passkeys instead of the browser's."
138
+ }), /* @__PURE__ */ jsxs(Menu.CheckboxItem, {
139
+ className: "think-sidepanel__menu-switch-item",
140
+ checked: passkeyVault.enabled,
141
+ onCheckedChange: passkeyVault.setEnabled,
142
+ children: ["Use its own passkeys", /* @__PURE__ */ jsx(Switch.Root, {
143
+ "aria-hidden": true,
144
+ readOnly: true,
145
+ size: "sm",
146
+ checked: passkeyVault.enabled,
147
+ children: /* @__PURE__ */ jsx(Switch.Thumb, {})
148
+ })]
149
+ })] })] }) : null,
150
+ /* @__PURE__ */ jsx(Menu.Separator, {}),
151
+ /* @__PURE__ */ jsxs(Menu.Group, { children: [/* @__PURE__ */ jsx(Menu.GroupLabel, { children: "Appearance" }), /* @__PURE__ */ jsx(AppearanceMenu, {})] }),
152
+ onSignOut ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Menu.Separator, {}), /* @__PURE__ */ jsxs(Menu.Item, {
153
+ onClick: onSignOut,
154
+ children: [/* @__PURE__ */ jsx(ArrowUpRightIcon, {}), "Sign out"]
155
+ })] }) : null
156
+ ] })
157
+ }) })] });
158
+ }
159
+ function GateScreen({ brand, connectingLabel, identity, modelSetup, status }) {
160
+ if (status === "connecting") return /* @__PURE__ */ jsx("div", {
161
+ className: "think-sidepanel__gate",
162
+ role: "status",
163
+ children: /* @__PURE__ */ jsx(EmptyState, {
164
+ icon: /* @__PURE__ */ jsx(SpinnerIcon, {}),
165
+ description: connectingLabel ?? "Connecting…"
166
+ })
167
+ });
168
+ if (status === "offline") return /* @__PURE__ */ jsx("main", {
169
+ className: "think-sidepanel__gate",
170
+ role: "status",
171
+ children: /* @__PURE__ */ jsx(EmptyState, {
172
+ icon: /* @__PURE__ */ jsx(WarningIcon, {}),
173
+ title: `${brand.name} is offline`,
174
+ description: "Open the browser and turn the companion connection on. This screen reconnects on its own."
175
+ })
176
+ });
177
+ if (status === "identity-blocked" && identity) return /* @__PURE__ */ jsxs("div", {
178
+ className: "think-sidepanel__gate",
179
+ role: "alert",
180
+ children: [/* @__PURE__ */ jsx(EmptyState, {
181
+ icon: /* @__PURE__ */ jsx(WarningIcon, {}),
182
+ title: "Wrong browser profile",
183
+ description: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("p", { children: [
184
+ "This installation is assigned to ",
185
+ /* @__PURE__ */ jsx("strong", { children: identity.assignedAccount }),
186
+ ", but the live profile is ",
187
+ /* @__PURE__ */ jsx("strong", { children: identity.liveProfile }),
188
+ "."
189
+ ] }), /* @__PURE__ */ jsx("p", { children: identity.managed ? "Open the assigned profile. Organization policy controls this assignment." : "Open the assigned profile, or remove the binding." })] })
190
+ }), identity.managed || !identity.onUnbind ? null : /* @__PURE__ */ jsx(Button, {
191
+ type: "button",
192
+ variant: "ghost",
193
+ color: "destructive",
194
+ onClick: identity.onUnbind,
195
+ children: "Remove binding"
196
+ })]
197
+ });
198
+ if (status === "needs-model") return /* @__PURE__ */ jsx(ChatGptSignInScreen, {
199
+ busy: modelSetup?.busy,
200
+ error: modelSetup?.error,
201
+ label: modelSetup?.label,
202
+ title: `Meet ${brand.name}`,
203
+ brandName: "SigVelo",
204
+ brandLogo: brand.logo,
205
+ onSignIn: modelSetup?.onSignIn,
206
+ secondaryAction: modelSetup?.onCustomEndpoint ? {
207
+ label: "Set up a custom model endpoint",
208
+ onSelect: modelSetup.onCustomEndpoint
209
+ } : void 0
210
+ });
211
+ return null;
212
+ }
213
+ function IdentityDialog({ identity, onOpenChange, open }) {
214
+ return /* @__PURE__ */ jsx(Dialog.Root, {
215
+ open,
216
+ onOpenChange,
217
+ children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, {}), /* @__PURE__ */ jsx(Dialog.Viewport, { children: /* @__PURE__ */ jsxs(Dialog.Popup, { children: [
218
+ /* @__PURE__ */ jsxs(Dialog.Header, { children: [/* @__PURE__ */ jsx(Dialog.Title, { children: "Operating identity" }), /* @__PURE__ */ jsx(Dialog.Description, { children: "This employee operates the live browser profile as its own identity. Assigning the account keeps it from signing in with another profile." })] }),
219
+ /* @__PURE__ */ jsxs(DescriptionList.Root, {
220
+ variant: "divided",
221
+ children: [/* @__PURE__ */ jsxs(DescriptionList.Item, { children: [/* @__PURE__ */ jsx(DescriptionList.Term, { children: "Live profile" }), /* @__PURE__ */ jsx(DescriptionList.Details, { children: identity.liveProfile })] }), /* @__PURE__ */ jsxs(DescriptionList.Item, { children: [/* @__PURE__ */ jsx(DescriptionList.Term, { children: "Assigned account" }), /* @__PURE__ */ jsx(DescriptionList.Details, { children: identity.managed ? `${identity.assignedAccount} (managed by your organization)` : identity.assignedAccount })] })]
222
+ }),
223
+ /* @__PURE__ */ jsx(Dialog.Footer, { children: identity.managed ? /* @__PURE__ */ jsx("p", { children: "Organization policy controls this binding." }) : identity.onUnbind && identity.assignedAccount ? /* @__PURE__ */ jsx(Button, {
224
+ type: "button",
225
+ variant: "ghost",
226
+ color: "destructive",
227
+ onClick: () => {
228
+ Promise.resolve(identity.onUnbind?.()).then(() => onOpenChange(false));
229
+ },
230
+ children: "Remove binding"
231
+ }) : /* @__PURE__ */ jsx(Button, {
232
+ type: "button",
233
+ color: "primary",
234
+ disabled: !identity.canBind || !identity.onBind,
235
+ onClick: () => {
236
+ Promise.resolve(identity.onBind?.()).then(() => onOpenChange(false));
237
+ },
238
+ children: "Assign this profile"
239
+ }) })
240
+ ] }) })] })
241
+ });
242
+ }
243
+ function CapabilityGuide({ brandName, start }) {
244
+ const send = (text) => void start.onSubmit({
245
+ text,
246
+ files: []
247
+ });
248
+ return /* @__PURE__ */ jsx(ActionGuide, {
249
+ title: `${brandName} can work across your browser.`,
250
+ description: "They can act in signed-in tabs, keep workspace files, connect plugins, and run recurring work after this panel closes.",
251
+ sections: [
252
+ {
253
+ id: "quick-browser-job",
254
+ title: "Start with a quick browser job",
255
+ layout: "compact",
256
+ actions: [{
257
+ id: "organize-tabs",
258
+ icon: /* @__PURE__ */ jsx(BoxIcon, {}),
259
+ label: "Organize this window’s tabs by task"
260
+ }, {
261
+ id: "close-duplicate-tabs",
262
+ icon: /* @__PURE__ */ jsx(EyeIcon, {}),
263
+ label: "Close duplicate tabs in this window"
264
+ }]
265
+ },
266
+ {
267
+ id: "ongoing-work",
268
+ title: "Set up ongoing work",
269
+ layout: "cards",
270
+ actions: [
271
+ {
272
+ id: "create-routine",
273
+ icon: /* @__PURE__ */ jsx(QueueIcon, {}),
274
+ label: "Create a recurring task"
275
+ },
276
+ ...start.slack && !start.slack.configured ? [{
277
+ id: "connect-slack",
278
+ icon: /* @__PURE__ */ jsx(SlackIcon, {}),
279
+ label: "Connect Slack"
280
+ }] : [],
281
+ ...start.discord && !start.discord.configured ? [{
282
+ id: "connect-discord",
283
+ icon: /* @__PURE__ */ jsx(DiscordIcon, {}),
284
+ label: "Connect Discord"
285
+ }] : [],
286
+ ...start.onAttachFolder ? [{
287
+ id: "attach-local-folder",
288
+ icon: /* @__PURE__ */ jsx(FolderIcon, {}),
289
+ label: "Attach a local folder"
290
+ }] : [],
291
+ {
292
+ id: "connections",
293
+ icon: /* @__PURE__ */ jsx(McpIcon, {}),
294
+ label: start.hasConnectedApps ? "Use my connected apps" : "Connect another app"
295
+ }
296
+ ]
297
+ },
298
+ {
299
+ id: "larger-workflow",
300
+ title: "Build a larger workflow",
301
+ layout: "list",
302
+ actions: [
303
+ {
304
+ id: "automate-browser",
305
+ icon: /* @__PURE__ */ jsx(TerminalIcon, {}),
306
+ label: "Automate work across signed-in tabs",
307
+ variant: "ghost"
308
+ },
309
+ {
310
+ id: "move-workspace-files",
311
+ icon: /* @__PURE__ */ jsx(FolderIcon, {}),
312
+ label: "Move files between a website and the workspace",
313
+ variant: "ghost"
314
+ },
315
+ {
316
+ id: "record-browser-workflow",
317
+ icon: /* @__PURE__ */ jsx(EyeIcon, {}),
318
+ label: "Record a browser workflow as an MP4",
319
+ variant: "ghost"
320
+ }
321
+ ]
322
+ }
323
+ ],
324
+ onAction: (action) => {
325
+ switch (action.id) {
326
+ case "organize-tabs": return send("Organize this window’s tabs by task.");
327
+ case "close-duplicate-tabs": return send("Close duplicate tabs in this window.");
328
+ case "create-routine": return send("Help me create a recurring task that runs on a schedule.");
329
+ case "connect-slack": return start.slack?.onSelect();
330
+ case "connect-discord": return start.discord?.onSelect();
331
+ case "connections": return send(start.hasConnectedApps ? "Show me useful work I can do across my connected apps." : "Help me connect another app I use.");
332
+ case "automate-browser": return send("Automate a workflow across my signed-in browser tabs.");
333
+ case "move-workspace-files": return send("Move files between a signed-in website and the workspace.");
334
+ case "record-browser-workflow": return send("Record a browser workflow as an MP4.");
335
+ case "attach-local-folder": return start.onAttachFolder?.();
336
+ }
337
+ }
338
+ });
339
+ }
340
+ function StartComposerTray({ plugins, renderLink, start }) {
341
+ const hasPluginMenu = Boolean(plugins || start.slack || start.discord);
342
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
343
+ start.personalization ? /* @__PURE__ */ jsx(SetupChecklistAction, {
344
+ actionLabel: "Prompts",
345
+ label: "Prompts",
346
+ entries: start.personalization.entries,
347
+ onSelect: start.personalization.onSelect
348
+ }) : null,
349
+ start.onAttachFolder ? /* @__PURE__ */ jsxs(Button, {
350
+ type: "button",
351
+ variant: "ghost",
352
+ color: "neutral",
353
+ size: "md",
354
+ disabled: start.attachFolderBusy,
355
+ onClick: start.onAttachFolder,
356
+ "aria-label": "Connect a local folder",
357
+ children: [/* @__PURE__ */ jsx(PaperclipIcon, {}), /* @__PURE__ */ jsx("span", { children: "Connect a local folder" })]
358
+ }) : null,
359
+ hasPluginMenu ? /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsxs(Button, {
360
+ type: "button",
361
+ variant: "ghost",
362
+ color: "neutral",
363
+ size: "md",
364
+ render: /* @__PURE__ */ jsx(Menu.Trigger, { unstyled: true }),
365
+ "aria-label": "Connect plugins",
366
+ children: [/* @__PURE__ */ jsx("span", { children: "Connect plugins" }), /* @__PURE__ */ jsxs(AppIcon.Stack, {
367
+ "aria-hidden": "true",
368
+ children: [/* @__PURE__ */ jsx(AppIcon.Root, {
369
+ size: "sm",
370
+ variant: "surface",
371
+ children: /* @__PURE__ */ jsx(SlackIcon, {})
372
+ }), /* @__PURE__ */ jsx(AppIcon.Root, {
373
+ size: "sm",
374
+ variant: "surface",
375
+ children: /* @__PURE__ */ jsx(DiscordIcon, {})
376
+ })]
377
+ })]
378
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
379
+ side: "bottom",
380
+ align: "start",
381
+ sideOffset: 4,
382
+ children: /* @__PURE__ */ jsxs(Menu.Popup, {
383
+ "aria-label": "Plugins",
384
+ "data-recipe": "wide-scroll-picker",
385
+ children: [/* @__PURE__ */ jsx(McpServerPickerItems, {
386
+ actions: [...start.discord ? [{
387
+ id: "discord",
388
+ icon: /* @__PURE__ */ jsx(DiscordIcon, {}),
389
+ label: start.discord.configured ? "Discord" : "Connect Discord",
390
+ description: start.discord.description ?? (start.discord.configured ? "Connected" : "Talk to this employee from Discord"),
391
+ onSelect: start.discord.onSelect
392
+ }] : [], ...start.slack ? [{
393
+ id: "slack",
394
+ icon: /* @__PURE__ */ jsx(SlackIcon, {}),
395
+ label: start.slack.configured ? "Slack" : "Connect Slack",
396
+ description: start.slack.description ?? (start.slack.configured ? "Connected" : "Talk to this employee from Slack"),
397
+ onSelect: start.slack.onSelect
398
+ }] : []],
399
+ servers: plugins?.servers ?? [],
400
+ mcp: plugins?.mcp,
401
+ onConnect: plugins?.onConnect,
402
+ onDisconnect: plugins?.onDisconnect
403
+ }), /* @__PURE__ */ jsx(McpServerPickerAction, {
404
+ icon: /* @__PURE__ */ jsx(BoxIcon, {}),
405
+ label: "Browse plugins",
406
+ description: plugins?.onConnect ? "Find and connect supported tools" : "See what this browser is connected to",
407
+ render: renderLink({
408
+ kind: "view",
409
+ view: "plugins"
410
+ })
411
+ })]
412
+ })
413
+ }) })] }) : null
414
+ ] });
415
+ }
416
+ function startStarters(brandName, start, onShowGuide) {
417
+ return {
418
+ "aria-label": "Suggested prompts",
419
+ items: [
420
+ {
421
+ id: "capability-guide",
422
+ label: `See what ${brandName} can do`,
423
+ icon: /* @__PURE__ */ jsx(InfoIcon, {}),
424
+ muted: true
425
+ },
426
+ ...start.suggestionsError ? [{
427
+ id: "retry-suggestions",
428
+ label: "Try generating suggestions again",
429
+ icon: /* @__PURE__ */ jsx(InfoIcon, {}),
430
+ muted: true
431
+ }] : [],
432
+ ...start.suggestions?.map((suggestion, index) => ({
433
+ id: `suggestion:${index}:${suggestion.value}:${suggestion.label}`,
434
+ label: suggestion.label,
435
+ icon: suggestion.value.startsWith("/") ? /* @__PURE__ */ jsx(BoxIcon, {}) : suggestion.value.startsWith("@") ? /* @__PURE__ */ jsx(McpIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
436
+ })) ?? []
437
+ ],
438
+ onSelect: (item) => {
439
+ if (item.id === "capability-guide") {
440
+ onShowGuide();
441
+ return;
442
+ }
443
+ if (item.id === "retry-suggestions") {
444
+ start.onRetrySuggestions?.();
445
+ return;
446
+ }
447
+ const suggestion = start.suggestions?.find((candidate, index) => item.id === `suggestion:${index}:${candidate.value}:${candidate.label}`);
448
+ if (suggestion) start.onSubmit({
449
+ text: suggestion.value,
450
+ files: []
451
+ });
452
+ }
453
+ };
454
+ }
455
+ function BackToChat({ renderLink }) {
456
+ return /* @__PURE__ */ jsx(AppTopBar.Link, {
457
+ label: "Back to chat",
458
+ render: renderLink({
459
+ kind: "view",
460
+ view: "chat"
461
+ }),
462
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
463
+ });
464
+ }
465
+ function employeeMessages({ agentRun, brandName, guideOpen, hasConversation, hostMessages, onShowGuide, plugins, renderLink, start }) {
466
+ const onSubmit = hostMessages?.draft?.onSubmit ?? start?.onSubmit;
467
+ const draft = hasConversation ? hostMessages?.draft : onSubmit ? {
468
+ messages: hostMessages?.draft?.messages ?? [],
469
+ onSubmit,
470
+ status: hostMessages?.draft?.status
471
+ } : hostMessages?.draft;
472
+ return {
473
+ placeholder: "How can I help you today?",
474
+ approvalsEnabled: false,
475
+ ...hostMessages,
476
+ startScreen: start ? {
477
+ lead: guideOpen ? /* @__PURE__ */ jsx(CapabilityGuide, {
478
+ brandName,
479
+ start
480
+ }) : void 0,
481
+ composerTray: /* @__PURE__ */ jsx(StartComposerTray, {
482
+ plugins,
483
+ renderLink,
484
+ start
485
+ }),
486
+ starters: guideOpen ? void 0 : startStarters(brandName, start, onShowGuide)
487
+ } : hostMessages?.startScreen,
488
+ draft,
489
+ showComposer: agentRun ? false : hostMessages?.showComposer
490
+ };
491
+ }
492
+ /**
493
+ * The employee side panel: icon-and-tooltip chrome, start screen, schedules,
494
+ * conversation plus workbench. Hosts hydrate conversation, workspace,
495
+ * plugins, and callables. Storybook is the place to iterate the chrome.
496
+ */
497
+ function ThinkSidepanel({ agentRun, appBarLeading, brand, className, companion, connectingLabel, conversation, follow, identity, live, messages, modelSetup, onDeleteThread, onModel, onSignOut, passkeyVault, plugins, renderLink, schedules, sourceKey, start, status = "ready", thread, threads = EMPTY_THREADS, view, workspace, ...props }) {
498
+ const [identityOpen, setIdentityOpen] = React.useState(false);
499
+ const [guideOpen, setGuideOpen] = React.useState(false);
500
+ if (status !== "ready") return /* @__PURE__ */ jsx("div", {
501
+ className: cx("think-sidepanel", className),
502
+ "data-status": status,
503
+ ...props,
504
+ children: /* @__PURE__ */ jsx(GateScreen, {
505
+ brand,
506
+ connectingLabel,
507
+ identity,
508
+ modelSetup,
509
+ status
510
+ })
511
+ });
512
+ const overflow = /* @__PURE__ */ jsx(OverflowMenu, {
513
+ companion,
514
+ follow: thread && !agentRun ? follow : void 0,
515
+ identityEmail: identity?.email,
516
+ onIdentity: identity ? () => setIdentityOpen(true) : void 0,
517
+ onModel,
518
+ onSignOut,
519
+ passkeyVault,
520
+ renderLink
521
+ });
522
+ const identityDialog = identity ? /* @__PURE__ */ jsx(IdentityDialog, {
523
+ identity,
524
+ open: identityOpen,
525
+ onOpenChange: setIdentityOpen
526
+ }) : null;
527
+ const newThread = thread && !agentRun ? /* @__PURE__ */ jsx(AppTopBar.Link, {
528
+ label: "New thread",
529
+ render: renderLink({ kind: "new-thread" }),
530
+ children: /* @__PURE__ */ jsx(PencilIcon, {})
531
+ }) : void 0;
532
+ const chatLeading = newThread || view === "chat" && appBarLeading ? /* @__PURE__ */ jsxs(Fragment, { children: [newThread, view === "chat" ? appBarLeading : null] }) : void 0;
533
+ const chatMessages = employeeMessages({
534
+ agentRun,
535
+ brandName: brand.name,
536
+ guideOpen,
537
+ hasConversation: Boolean(conversation),
538
+ hostMessages: messages,
539
+ onShowGuide: () => setGuideOpen(true),
540
+ plugins,
541
+ renderLink,
542
+ start
543
+ });
544
+ if (view === "live") return /* @__PURE__ */ jsxs("div", {
545
+ className: cx("think-sidepanel", className),
546
+ "data-view": "live",
547
+ ...props,
548
+ children: [/* @__PURE__ */ jsxs("div", {
549
+ className: "think-sidepanel__live",
550
+ children: [/* @__PURE__ */ jsxs(AppTopBar.Root, {
551
+ "aria-label": "Live view controls",
552
+ children: [/* @__PURE__ */ jsx(AppTopBar.Leading, { children: /* @__PURE__ */ jsx(BackToChat, { renderLink }) }), /* @__PURE__ */ jsx(AppTopBar.Title, { children: "Live view" })]
553
+ }), live]
554
+ }), identityDialog]
555
+ });
556
+ if (view === "schedules") return /* @__PURE__ */ jsxs("div", {
557
+ className: cx("think-sidepanel", className),
558
+ "data-view": "schedules",
559
+ ...props,
560
+ children: [schedules?.editor ? /* @__PURE__ */ jsx("div", {
561
+ className: "think-sidepanel__editor",
562
+ children: schedules.editor
563
+ }) : schedules ? /* @__PURE__ */ jsx(ThinkRoutineLibrary, {
564
+ bar: {
565
+ leading: /* @__PURE__ */ jsx(BackToChat, { renderLink }),
566
+ primary: overflow
567
+ },
568
+ routines: schedules.routines,
569
+ showOwner: false,
570
+ selectedRoutineId: schedules.selectedRoutineId,
571
+ error: schedules.error,
572
+ renderRoutineLink: (routine) => renderLink({
573
+ kind: "routine",
574
+ routineId: routine.id
575
+ }),
576
+ createRoutineLink: renderLink({ kind: "create-routine" }),
577
+ renderEditRoutineLink: (routine) => renderLink({
578
+ kind: "edit-routine",
579
+ routineId: routine.id
580
+ }),
581
+ renderRunLink: (routine, run) => renderLink({
582
+ kind: "routine-run",
583
+ routineId: routine.id,
584
+ runId: getThinkExecutionRunId(run)
585
+ }),
586
+ onRunRoutine: schedules.onRunRoutine,
587
+ onRoutineEnabledChange: schedules.onRoutineEnabledChange,
588
+ onDeleteRoutine: schedules.onDeleteRoutine
589
+ }) : /* @__PURE__ */ jsx("div", {
590
+ className: "think-sidepanel__gate",
591
+ children: /* @__PURE__ */ jsx(EmptyState, {
592
+ title: "Schedules",
593
+ description: "No schedules to show."
594
+ })
595
+ }), identityDialog]
596
+ });
597
+ const workbenchView = view === "plugins" ? "plugins" : view === "files" ? "files" : "chat";
598
+ return /* @__PURE__ */ jsxs("div", {
599
+ className: cx("think-sidepanel", className),
600
+ "data-view": view,
601
+ ...props,
602
+ children: [/* @__PURE__ */ jsx(ThinkFullApp, {
603
+ conversation,
604
+ renderAgentToolRunLink: (run) => renderLink({
605
+ kind: "agent-run",
606
+ runId: run.runId
607
+ }),
608
+ bar: {
609
+ title: agentRun ? /* @__PURE__ */ jsxs("span", {
610
+ className: "think-sidepanel__run-title",
611
+ children: [/* @__PURE__ */ jsx(NaniteMark, {}), /* @__PURE__ */ jsx("span", {
612
+ className: "sigvelo-truncate",
613
+ children: agentRun.title
614
+ })]
615
+ }) : thread?.title ?? "New chat",
616
+ leading: agentRun ? /* @__PURE__ */ jsx(AppTopBar.Link, {
617
+ label: "Back to parent conversation",
618
+ render: thread ? renderLink({
619
+ kind: "thread",
620
+ threadId: thread.id
621
+ }) : renderLink({
622
+ kind: "view",
623
+ view: "chat"
624
+ }),
625
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, {})
626
+ }) : chatLeading,
627
+ compactLeading: !agentRun && (view === "files" || view === "plugins") ? /* @__PURE__ */ jsx(BackToChat, { renderLink }) : void 0,
628
+ actions: agentRun?.running && agentRun.onCancel ? /* @__PURE__ */ jsx(AppTopBar.Button, {
629
+ label: "Cancel run",
630
+ onClick: agentRun.onCancel,
631
+ children: /* @__PURE__ */ jsx(SquareIcon, {})
632
+ }) : void 0,
633
+ primary: overflow,
634
+ views: null
635
+ },
636
+ threadStatusSummary: agentRun ? void 0 : summarizeThinkThreads(threads),
637
+ sourceKey,
638
+ workspace: agentRun ? void 0 : workspace,
639
+ plugins: agentRun ? void 0 : plugins,
640
+ view: workbenchView,
641
+ threadSidebar: agentRun ? void 0 : ({ closeSidebarOnCompact }) => /* @__PURE__ */ jsx(ThinkThreadPicker, {
642
+ threads,
643
+ renderThreadLink: (item) => renderLink({
644
+ kind: "thread",
645
+ threadId: item.id
646
+ }),
647
+ createThreadLink: renderLink({ kind: "new-thread" }),
648
+ onSelect: closeSidebarOnCompact,
649
+ onDelete: onDeleteThread
650
+ }),
651
+ messages: chatMessages
652
+ }), identityDialog]
653
+ });
654
+ }
655
+ //#endregion
656
+ export { ThinkSidepanel };
@@ -42,11 +42,10 @@ interface ThinkThreadPickerProps extends Omit<React.HTMLAttributes<HTMLElement>,
42
42
  */
43
43
  renderThreadLink: (thread: ThinkThreadItem) => React.ReactElement;
44
44
  /**
45
- * Optional create action. An app whose threads are minted by their first
46
- * message should navigate to its new-thread screen here rather than create
47
- * one: a thread created on click is an empty thread until someone writes in it.
45
+ * App-authored TanStack Router Link to the new-thread screen. A thread
46
+ * created on click is an empty thread until someone writes in it.
48
47
  */
49
- onCreate?: () => void | Promise<void>;
48
+ createThreadLink?: React.ReactElement;
50
49
  /**
51
50
  * Notified on unmodified primary activation. The link still navigates — the
52
51
  * route is the selection — so this is for side effects such as closing a
@@ -77,7 +76,7 @@ declare function ThinkThreadStatusIndicators({
77
76
  declare function ThinkThreadPicker({
78
77
  threads,
79
78
  renderThreadLink,
80
- onCreate,
79
+ createThreadLink,
81
80
  onSelect,
82
81
  onDelete,
83
82
  className,