@invergent/agent-chat-react 2.8.1 → 2.8.4

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.
package/dist/index.js CHANGED
@@ -364,20 +364,69 @@ function BrowserControlBar({
364
364
  )
365
365
  ] });
366
366
  }
367
+ function toWsUrl(src) {
368
+ const url = new URL(src, window.location.href);
369
+ if (url.protocol === "http:") {
370
+ url.protocol = "ws:";
371
+ } else if (url.protocol === "https:") {
372
+ url.protocol = "wss:";
373
+ }
374
+ return url.toString();
375
+ }
367
376
  function BrowserLiveView({
368
377
  src,
369
- testId = "browser-iframe"
378
+ testId = "browser-rfb",
379
+ onDisconnect
370
380
  }) {
371
- return /* @__PURE__ */ jsx(
372
- "iframe",
373
- {
374
- "data-testid": testId,
375
- title: "Browser live view",
376
- src,
377
- className: "h-full w-full border-0 bg-black",
378
- allow: "clipboard-read; clipboard-write"
379
- }
380
- );
381
+ const containerRef = useRef(null);
382
+ const onDisconnectRef = useRef(onDisconnect);
383
+ onDisconnectRef.current = onDisconnect;
384
+ const [state, setState] = useState("connecting");
385
+ useEffect(() => {
386
+ const container = containerRef.current;
387
+ if (!container) return;
388
+ setState("connecting");
389
+ let rfb;
390
+ let disposed = false;
391
+ const handleConnect = () => setState("connected");
392
+ const handleDisconnect = (event) => {
393
+ const detail = event.detail;
394
+ setState("disconnected");
395
+ onDisconnectRef.current?.(detail?.clean ?? false);
396
+ };
397
+ void import('@novnc/novnc').then((mod) => {
398
+ if (disposed || !containerRef.current) return;
399
+ const instance = new mod.default(containerRef.current, toWsUrl(src), {
400
+ wsProtocols: ["binary"]
401
+ });
402
+ instance.viewOnly = false;
403
+ instance.scaleViewport = true;
404
+ instance.addEventListener("connect", handleConnect);
405
+ instance.addEventListener("disconnect", handleDisconnect);
406
+ rfb = instance;
407
+ }).catch(() => {
408
+ if (!disposed) setState("disconnected");
409
+ });
410
+ return () => {
411
+ disposed = true;
412
+ if (rfb) {
413
+ rfb.removeEventListener("connect", handleConnect);
414
+ rfb.removeEventListener("disconnect", handleDisconnect);
415
+ rfb.disconnect();
416
+ }
417
+ };
418
+ }, [src]);
419
+ return /* @__PURE__ */ jsxs("div", { className: "relative h-full w-full bg-black", children: [
420
+ /* @__PURE__ */ jsx("div", { ref: containerRef, "data-testid": testId, className: "h-full w-full" }),
421
+ state !== "connected" && /* @__PURE__ */ jsx(
422
+ "div",
423
+ {
424
+ "data-testid": "browser-rfb-overlay",
425
+ className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/70 text-sm text-muted-foreground",
426
+ children: state === "connecting" ? "Connecting to browser\u2026" : "Live view disconnected \u2014 take control again to reconnect."
427
+ }
428
+ )
429
+ ] });
381
430
  }
382
431
  function BrowserStatusDot({
383
432
  status
@@ -572,7 +621,13 @@ function BrowserPane({
572
621
  /* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Full screen" })
573
622
  ] }) }) })
574
623
  ] }),
575
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsx(BrowserLiveView, { src: liveViewUrl }) : previewSnapshot ? /* @__PURE__ */ jsx(
624
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : canUseLiveView ? /* @__PURE__ */ jsx(
625
+ BrowserLiveView,
626
+ {
627
+ src: liveViewUrl,
628
+ onDisconnect: () => setLocalControlActive(false)
629
+ }
630
+ ) : previewSnapshot ? /* @__PURE__ */ jsx(
576
631
  BrowserPreviewImage,
577
632
  {
578
633
  src: previewSnapshot.src,
@@ -616,7 +671,8 @@ function BrowserPane({
616
671
  BrowserLiveView,
617
672
  {
618
673
  src: liveViewUrl,
619
- testId: "browser-fullscreen-iframe"
674
+ testId: "browser-fullscreen-rfb",
675
+ onDisconnect: () => setLocalControlActive(false)
620
676
  }
621
677
  ) : previewSnapshot ? /* @__PURE__ */ jsx(
622
678
  BrowserPreviewImage,
@@ -715,6 +771,36 @@ var ConversationScrollButton = ({
715
771
  }
716
772
  );
717
773
  };
774
+ var buttonGroupVariants = cva(
775
+ "group/button-group flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 *:data-[slot=input]:px-4 has-[>[data-variant=outline]]:*:data-[slot=input-group]:border-border has-[>[data-variant=outline]]:*:data-[slot=input-group]:px-2.5 has-[>[data-variant=outline]]:*:data-[slot=select-trigger]:border-border has-[>[data-variant=outline]]:*:[[role=combobox]]:px-2.5 has-[>[data-variant=outline]]:[&>[data-slot=input-group]:has(:focus-visible)]:border-ring has-[>[data-variant=outline]]:[&>[data-slot=select-trigger]:focus-visible]:border-ring has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-none [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[>[data-variant=outline]]:[&>input]:border-border has-[>[data-variant=outline]]:[&>input:focus-visible]:border-ring",
776
+ {
777
+ variants: {
778
+ orientation: {
779
+ horizontal: "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!",
780
+ vertical: "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-none!"
781
+ }
782
+ },
783
+ defaultVariants: {
784
+ orientation: "horizontal"
785
+ }
786
+ }
787
+ );
788
+ function ButtonGroup({
789
+ className,
790
+ orientation,
791
+ ...props
792
+ }) {
793
+ return /* @__PURE__ */ jsx(
794
+ "div",
795
+ {
796
+ role: "group",
797
+ "data-slot": "button-group",
798
+ "data-orientation": orientation,
799
+ className: cn(buttonGroupVariants({ orientation }), className),
800
+ ...props
801
+ }
802
+ );
803
+ }
718
804
 
719
805
  // src/lib/oauth-popup.ts
720
806
  function openOAuthPopup(url) {
@@ -777,8 +863,8 @@ var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
777
863
  "div",
778
864
  {
779
865
  className: cn(
780
- "group flex w-full flex-col gap-2",
781
- from === "user" ? "is-user max-w-[85%]" : "is-assistant max-w-full",
866
+ "group flex flex-col gap-2",
867
+ from === "user" ? "is-user ml-auto max-w-[85%]" : "is-assistant max-w-full",
782
868
  className
783
869
  ),
784
870
  ...props
@@ -4852,25 +4938,6 @@ function Command({
4852
4938
  }
4853
4939
  );
4854
4940
  }
4855
- function CommandInput({
4856
- className,
4857
- ...props
4858
- }) {
4859
- return /* @__PURE__ */ jsx("div", { "data-slot": "command-input-wrapper", className: "p-3", children: /* @__PURE__ */ jsxs(InputGroup, { className: "rounded-lg border-transparent bg-muted px-3", children: [
4860
- /* @__PURE__ */ jsx(
4861
- Command$1.Input,
4862
- {
4863
- "data-slot": "command-input",
4864
- className: cn(
4865
- "w-full px-2 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
4866
- className
4867
- ),
4868
- ...props
4869
- }
4870
- ),
4871
- /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, { className: "size-3.5 shrink-0 opacity-50" }) })
4872
- ] }) });
4873
- }
4874
4941
  function CommandList({
4875
4942
  className,
4876
4943
  ...props
@@ -5396,7 +5463,7 @@ var PromptInput = ({
5396
5463
  onSubmit: handleSubmit,
5397
5464
  ref: formRef,
5398
5465
  ...props,
5399
- children: /* @__PURE__ */ jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-3 py-1 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children })
5466
+ children: /* @__PURE__ */ jsx(InputGroup, { className: "overflow-hidden rounded-3xl border border-input bg-white px-4 py-2 shadow-sm dark:bg-card dark:shadow-none dark:ring-1 dark:ring-white/5 has-[textarea]:rounded-3xl has-[>[data-align=block-end]]:rounded-3xl has-[>[data-align=block-start]]:rounded-3xl", children })
5400
5467
  }
5401
5468
  )
5402
5469
  ] });
@@ -5531,7 +5598,7 @@ var PromptInputButton = ({
5531
5598
  InputGroupButton,
5532
5599
  {
5533
5600
  className: cn(
5534
- "rounded-sm border border-input/70 text-foreground hover:bg-accent",
5601
+ "rounded-sm border border-input/70 text-foreground bg-accent",
5535
5602
  newSize === "icon-sm" && "size-9",
5536
5603
  className
5537
5604
  ),
@@ -5589,7 +5656,7 @@ var PromptInputSubmit = ({
5589
5656
  InputGroupButton,
5590
5657
  {
5591
5658
  "aria-label": isGenerating ? "Stop" : "Submit",
5592
- className: cn("rounded-full", className),
5659
+ className: cn("rounded-full bg-amber-400 hover:bg-amber-500 text-black", className),
5593
5660
  onClick: handleClick,
5594
5661
  size,
5595
5662
  type: isGenerating && onStop ? "button" : "submit",
@@ -6072,6 +6139,168 @@ function Skeleton({ className, ...props }) {
6072
6139
  }
6073
6140
  );
6074
6141
  }
6142
+ var SEARCH_PLACEHOLDER = {
6143
+ commands: "Search commands\u2026",
6144
+ skills: "Search skills\u2026",
6145
+ scheduled: "Search scheduled tasks\u2026",
6146
+ all: "Type a command or search\u2026"
6147
+ };
6148
+ var NAV_HINT = "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc dismiss";
6149
+ var SEARCH_HINT = {
6150
+ commands: NAV_HINT,
6151
+ skills: "Esc dismiss",
6152
+ scheduled: NAV_HINT,
6153
+ all: NAV_HINT
6154
+ };
6155
+ var ROW_CLASS = "grid grid-cols-[120px_1fr] items-baseline gap-3 rounded-md px-3 py-[9px] data-[selected=true]:bg-foreground/[0.06] [&_svg]:hidden";
6156
+ function ComposerCommandMenu({
6157
+ menuMode,
6158
+ searchQuery,
6159
+ onSearchChange,
6160
+ skillsLoading,
6161
+ builtinCommands,
6162
+ adapterCommands,
6163
+ scheduledExamples,
6164
+ onCommandSelect,
6165
+ onEscapeDismiss
6166
+ }) {
6167
+ const controlledSearch = menuMode === "commands" || menuMode === "all";
6168
+ const showCommands = menuMode === "commands" || menuMode === "all";
6169
+ const showSkills = menuMode === "skills" || menuMode === "all";
6170
+ const skillsUnattached = menuMode === "skills" && !skillsLoading && adapterCommands.length === 0;
6171
+ return /* @__PURE__ */ jsx(
6172
+ PopoverContent,
6173
+ {
6174
+ side: "top",
6175
+ align: "start",
6176
+ className: "overflow-hidden rounded-xl p-0",
6177
+ style: { width: "var(--radix-popover-trigger-width)" },
6178
+ onCloseAutoFocus: (e) => e.preventDefault(),
6179
+ onEscapeKeyDown: () => {
6180
+ onEscapeDismiss();
6181
+ },
6182
+ children: /* @__PURE__ */ jsxs(Command, { children: [
6183
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 px-4 py-[13px]", children: [
6184
+ /* @__PURE__ */ jsx(SearchIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
6185
+ /* @__PURE__ */ jsx(
6186
+ Command$1.Input,
6187
+ {
6188
+ "data-slot": "command-input",
6189
+ placeholder: SEARCH_PLACEHOLDER[menuMode],
6190
+ className: "min-w-0 flex-1 bg-transparent text-[13.5px] text-foreground outline-hidden placeholder:text-muted-foreground",
6191
+ ...controlledSearch ? { value: searchQuery, onValueChange: onSearchChange } : {}
6192
+ }
6193
+ ),
6194
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 whitespace-nowrap text-[11px] text-muted-foreground", children: SEARCH_HINT[menuMode] })
6195
+ ] }),
6196
+ /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-foreground/[0.07]" }),
6197
+ skillsUnattached ? /* @__PURE__ */ jsx(SkillsEmptyState, {}) : /* @__PURE__ */ jsxs(CommandList, { className: "p-2", children: [
6198
+ !(skillsLoading && showSkills) && /* @__PURE__ */ jsx(CommandEmpty, { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: menuMode === "skills" ? "No skills match your search." : menuMode === "scheduled" ? "No scheduled tasks found." : "No commands found." }),
6199
+ showSkills && skillsLoading && adapterCommands.length === 0 && [0, 1, 2].map((i) => /* @__PURE__ */ jsxs(
6200
+ "div",
6201
+ {
6202
+ className: "grid grid-cols-[120px_1fr] items-baseline gap-3 px-3 py-[9px]",
6203
+ "aria-hidden": "true",
6204
+ children: [
6205
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
6206
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full max-w-[16rem]" })
6207
+ ]
6208
+ },
6209
+ `skill-skeleton-${i}`
6210
+ )),
6211
+ menuMode === "scheduled" && scheduledExamples.map((cmd) => /* @__PURE__ */ jsx(
6212
+ MenuRow,
6213
+ {
6214
+ cmd,
6215
+ onSelect: onCommandSelect
6216
+ },
6217
+ cmd.value
6218
+ )),
6219
+ showCommands && builtinCommands.map((cmd) => /* @__PURE__ */ jsx(
6220
+ MenuRow,
6221
+ {
6222
+ cmd,
6223
+ onSelect: onCommandSelect
6224
+ },
6225
+ cmd.value
6226
+ )),
6227
+ showSkills && adapterCommands.map((cmd) => /* @__PURE__ */ jsx(
6228
+ MenuRow,
6229
+ {
6230
+ cmd,
6231
+ keywords: cmd.isExpert ? [cmd.description, "expert"] : void 0,
6232
+ badge: cmd.isExpert ? "expert" : void 0,
6233
+ onSelect: onCommandSelect
6234
+ },
6235
+ cmd.value
6236
+ ))
6237
+ ] })
6238
+ ] })
6239
+ }
6240
+ );
6241
+ }
6242
+ function MenuRow({
6243
+ cmd,
6244
+ keywords,
6245
+ badge,
6246
+ onSelect
6247
+ }) {
6248
+ return /* @__PURE__ */ jsxs(
6249
+ CommandItem,
6250
+ {
6251
+ value: cmd.value,
6252
+ keywords: keywords ?? [cmd.description],
6253
+ onSelect: () => onSelect(cmd.value),
6254
+ className: ROW_CLASS,
6255
+ children: [
6256
+ /* @__PURE__ */ jsxs(
6257
+ "span",
6258
+ {
6259
+ className: "inline-flex min-w-0 max-w-full items-center gap-1.5",
6260
+ title: cmd.label,
6261
+ children: [
6262
+ /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[13px] font-medium text-amber-500", children: cmd.label }),
6263
+ badge && /* @__PURE__ */ jsx(
6264
+ "span",
6265
+ {
6266
+ className: "shrink-0 rounded-sm bg-amber-500/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-amber-500",
6267
+ "aria-label": "Expert specialist",
6268
+ children: badge
6269
+ }
6270
+ )
6271
+ ]
6272
+ }
6273
+ ),
6274
+ /* @__PURE__ */ jsx(
6275
+ "span",
6276
+ {
6277
+ className: "min-w-0 truncate text-[12.5px] text-muted-foreground",
6278
+ title: cmd.description,
6279
+ children: cmd.description
6280
+ }
6281
+ )
6282
+ ]
6283
+ }
6284
+ );
6285
+ }
6286
+ function SkillsEmptyState() {
6287
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2.5 px-6 py-[30px] text-center", children: [
6288
+ /* @__PURE__ */ jsx(
6289
+ "span",
6290
+ {
6291
+ className: "text-2xl leading-none text-muted-foreground/70",
6292
+ "aria-hidden": "true",
6293
+ children: "\u2726"
6294
+ }
6295
+ ),
6296
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "No skills attached" }),
6297
+ /* @__PURE__ */ jsxs("p", { className: "text-[12.5px] text-muted-foreground", children: [
6298
+ "Add them in",
6299
+ " ",
6300
+ /* @__PURE__ */ jsx("span", { className: "text-amber-500", children: "Configure \u2192 Skills & Tools" })
6301
+ ] })
6302
+ ] });
6303
+ }
6075
6304
  function ChatComposer(props) {
6076
6305
  return /* @__PURE__ */ jsx(PromptInputProvider, { children: /* @__PURE__ */ jsx(ChatComposerInner, { ...props }) });
6077
6306
  }
@@ -6102,6 +6331,26 @@ function formatBytes2(n) {
6102
6331
  }
6103
6332
  return `${n} B`;
6104
6333
  }
6334
+ function ComposerMenuButton({
6335
+ icon: Icon,
6336
+ label,
6337
+ onClick
6338
+ }) {
6339
+ return /* @__PURE__ */ jsxs(
6340
+ Button,
6341
+ {
6342
+ type: "button",
6343
+ variant: "secondary",
6344
+ size: "sm",
6345
+ className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6346
+ onClick,
6347
+ children: [
6348
+ /* @__PURE__ */ jsx(Icon, {}),
6349
+ label
6350
+ ]
6351
+ }
6352
+ );
6353
+ }
6105
6354
  function AttachmentPreviewStrip() {
6106
6355
  const attachments = useProviderAttachments();
6107
6356
  if (attachments.files.length === 0) return null;
@@ -6306,6 +6555,11 @@ function ChatComposerInner({
6306
6555
  textarea.setSelectionRange(end, end);
6307
6556
  });
6308
6557
  }, []);
6558
+ const openMenu = useCallback((mode) => {
6559
+ setMenuMode(mode);
6560
+ setMenuDismissed(false);
6561
+ setButtonMenuOpen(true);
6562
+ }, []);
6309
6563
  const handleCommandSelect = useCallback(
6310
6564
  (commandValue) => {
6311
6565
  textInput.setInput(`${commandValue} `);
@@ -6397,58 +6651,28 @@ function ChatComposerInner({
6397
6651
  children: [
6398
6652
  /* @__PURE__ */ jsx(AttachmentPreviewStrip, {}),
6399
6653
  viewMode === "expert" && !disabled && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 px-1 pb-2", children: [
6400
- /* @__PURE__ */ jsxs(
6401
- Button,
6654
+ /* @__PURE__ */ jsx(
6655
+ ComposerMenuButton,
6402
6656
  {
6403
- type: "button",
6404
- variant: "secondary",
6405
- size: "sm",
6406
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6407
- onClick: () => {
6408
- setMenuMode("commands");
6409
- setMenuDismissed(false);
6410
- setButtonMenuOpen(true);
6411
- },
6412
- children: [
6413
- /* @__PURE__ */ jsx(TerminalIcon, {}),
6414
- "Commands"
6415
- ]
6657
+ icon: TerminalIcon,
6658
+ label: "Commands",
6659
+ onClick: () => openMenu("commands")
6416
6660
  }
6417
6661
  ),
6418
- /* @__PURE__ */ jsxs(
6419
- Button,
6662
+ /* @__PURE__ */ jsx(
6663
+ ComposerMenuButton,
6420
6664
  {
6421
- type: "button",
6422
- variant: "secondary",
6423
- size: "sm",
6424
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6425
- onClick: () => {
6426
- setMenuMode("skills");
6427
- setMenuDismissed(false);
6428
- setButtonMenuOpen(true);
6429
- },
6430
- children: [
6431
- /* @__PURE__ */ jsx(SparklesIcon, {}),
6432
- "Skills"
6433
- ]
6665
+ icon: SparklesIcon,
6666
+ label: "Skills",
6667
+ onClick: () => openMenu("skills")
6434
6668
  }
6435
6669
  ),
6436
- loopsEnabled && /* @__PURE__ */ jsxs(
6437
- Button,
6670
+ loopsEnabled && /* @__PURE__ */ jsx(
6671
+ ComposerMenuButton,
6438
6672
  {
6439
- type: "button",
6440
- variant: "secondary",
6441
- size: "sm",
6442
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6443
- onClick: () => {
6444
- setMenuMode("scheduled");
6445
- setMenuDismissed(false);
6446
- setButtonMenuOpen(true);
6447
- },
6448
- children: [
6449
- /* @__PURE__ */ jsx(ClockIcon, {}),
6450
- "Scheduled Tasks"
6451
- ]
6673
+ icon: ClockIcon,
6674
+ label: "Scheduled Tasks",
6675
+ onClick: () => openMenu("scheduled")
6452
6676
  }
6453
6677
  )
6454
6678
  ] }),
@@ -6602,29 +6826,32 @@ function ChatComposerInner({
6602
6826
  ] }),
6603
6827
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6604
6828
  onViewModeChange && /* @__PURE__ */ jsxs(
6605
- "div",
6829
+ ButtonGroup,
6606
6830
  {
6607
- role: "group",
6608
6831
  "aria-label": "Chat view mode",
6609
- className: "inline-flex overflow-hidden rounded-md border border-border",
6832
+ className: "overflow-hidden rounded-md border border-border",
6610
6833
  children: [
6611
6834
  /* @__PURE__ */ jsx(
6612
- "button",
6835
+ Button,
6613
6836
  {
6614
6837
  type: "button",
6838
+ size: "xs",
6839
+ className: "capitalize font-normal",
6840
+ variant: viewMode === "simple" ? "secondary" : "ghost",
6615
6841
  "aria-pressed": viewMode === "simple",
6616
6842
  onClick: () => onViewModeChange("simple"),
6617
- className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6618
6843
  children: "Simple"
6619
6844
  }
6620
6845
  ),
6621
6846
  /* @__PURE__ */ jsx(
6622
- "button",
6847
+ Button,
6623
6848
  {
6624
6849
  type: "button",
6850
+ size: "xs",
6851
+ className: "capitalize font-normal",
6852
+ variant: viewMode === "expert" ? "secondary" : "ghost",
6625
6853
  "aria-pressed": viewMode === "expert",
6626
6854
  onClick: () => onViewModeChange("expert"),
6627
- className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6628
6855
  children: "Advanced"
6629
6856
  }
6630
6857
  )
@@ -6636,7 +6863,7 @@ function ChatComposerInner({
6636
6863
  {
6637
6864
  status,
6638
6865
  onStop,
6639
- className: "md:size-8"
6866
+ className: "size-10"
6640
6867
  }
6641
6868
  )
6642
6869
  ] })
@@ -6645,135 +6872,17 @@ function ChatComposerInner({
6645
6872
  }
6646
6873
  ) }),
6647
6874
  /* @__PURE__ */ jsx(
6648
- PopoverContent,
6875
+ ComposerCommandMenu,
6649
6876
  {
6650
- side: "top",
6651
- align: "start",
6652
- className: "overflow-hidden rounded-xl p-0",
6653
- style: { width: "var(--radix-popover-trigger-width)" },
6654
- onCloseAutoFocus: (e) => e.preventDefault(),
6655
- onEscapeKeyDown: () => {
6656
- focusTextareaAtEnd();
6657
- },
6658
- children: /* @__PURE__ */ jsxs(Command, { children: [
6659
- menuMode === "skills" ? /* @__PURE__ */ jsx(CommandInput, { placeholder: "Search skills..." }) : menuMode === "scheduled" ? /* @__PURE__ */ jsx(CommandInput, { placeholder: "Search scheduled tasks..." }) : /* @__PURE__ */ jsx(
6660
- CommandInput,
6661
- {
6662
- placeholder: "Type a command or search...",
6663
- value: searchQuery,
6664
- onValueChange: handleSearchChange
6665
- }
6666
- ),
6667
- /* @__PURE__ */ jsxs(CommandList, { children: [
6668
- !(skillsLoading && (menuMode === "skills" || menuMode === "all")) && /* @__PURE__ */ jsx(CommandEmpty, { children: menuMode === "skills" ? "No skills found." : menuMode === "scheduled" ? "No scheduled tasks found." : "No commands found." }),
6669
- (menuMode === "skills" || menuMode === "all") && skillsLoading && adapterCommands.length === 0 && [0, 1, 2].map((i) => /* @__PURE__ */ jsxs(
6670
- "div",
6671
- {
6672
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 px-2 py-2",
6673
- "aria-hidden": "true",
6674
- children: [
6675
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-28" }),
6676
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full max-w-[16rem]" })
6677
- ]
6678
- },
6679
- `skill-skeleton-${i}`
6680
- )),
6681
- menuMode === "scheduled" && scheduledExamples.map((cmd) => /* @__PURE__ */ jsxs(
6682
- CommandItem,
6683
- {
6684
- value: cmd.value,
6685
- keywords: [cmd.description],
6686
- onSelect: () => handleCommandSelect(cmd.value),
6687
- className: "grid grid-cols-[14rem_1fr] items-baseline gap-3 [&_svg]:hidden",
6688
- children: [
6689
- /* @__PURE__ */ jsx(
6690
- "span",
6691
- {
6692
- className: "font-mono font-semibold text-foreground truncate",
6693
- title: cmd.label,
6694
- children: cmd.label
6695
- }
6696
- ),
6697
- /* @__PURE__ */ jsx(
6698
- "span",
6699
- {
6700
- className: "min-w-0 truncate text-sm text-muted-foreground",
6701
- title: cmd.description,
6702
- children: cmd.description
6703
- }
6704
- )
6705
- ]
6706
- },
6707
- cmd.value
6708
- )),
6709
- (menuMode === "commands" || menuMode === "all") && builtinCommands.map((cmd) => /* @__PURE__ */ jsxs(
6710
- CommandItem,
6711
- {
6712
- value: cmd.value,
6713
- keywords: [cmd.description],
6714
- onSelect: () => handleCommandSelect(cmd.value),
6715
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
6716
- children: [
6717
- /* @__PURE__ */ jsx(
6718
- "span",
6719
- {
6720
- className: "font-mono font-semibold text-foreground truncate",
6721
- title: cmd.label,
6722
- children: cmd.label
6723
- }
6724
- ),
6725
- /* @__PURE__ */ jsx(
6726
- "span",
6727
- {
6728
- className: "min-w-0 truncate text-sm text-muted-foreground",
6729
- title: cmd.description,
6730
- children: cmd.description
6731
- }
6732
- )
6733
- ]
6734
- },
6735
- cmd.value
6736
- )),
6737
- (menuMode === "skills" || menuMode === "all") && adapterCommands.map((cmd) => /* @__PURE__ */ jsxs(
6738
- CommandItem,
6739
- {
6740
- value: cmd.value,
6741
- keywords: cmd.isExpert ? [cmd.description, "expert"] : [cmd.description],
6742
- onSelect: () => handleCommandSelect(cmd.value),
6743
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
6744
- children: [
6745
- /* @__PURE__ */ jsxs(
6746
- "span",
6747
- {
6748
- className: "inline-flex items-center gap-1.5 min-w-0 max-w-full",
6749
- title: cmd.label,
6750
- children: [
6751
- /* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-foreground truncate", children: cmd.label }),
6752
- cmd.isExpert && /* @__PURE__ */ jsx(
6753
- "span",
6754
- {
6755
- className: "shrink-0 rounded-sm bg-primary/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-primary",
6756
- "aria-label": "Expert specialist",
6757
- children: "expert"
6758
- }
6759
- )
6760
- ]
6761
- }
6762
- ),
6763
- /* @__PURE__ */ jsx(
6764
- "span",
6765
- {
6766
- className: "min-w-0 truncate text-sm text-muted-foreground",
6767
- title: cmd.description,
6768
- children: cmd.description
6769
- }
6770
- )
6771
- ]
6772
- },
6773
- cmd.value
6774
- ))
6775
- ] })
6776
- ] })
6877
+ menuMode,
6878
+ searchQuery,
6879
+ onSearchChange: handleSearchChange,
6880
+ skillsLoading,
6881
+ builtinCommands,
6882
+ adapterCommands,
6883
+ scheduledExamples,
6884
+ onCommandSelect: handleCommandSelect,
6885
+ onEscapeDismiss: focusTextareaAtEnd
6777
6886
  }
6778
6887
  )
6779
6888
  ]