@workerdeck/ui 0.9.0 → 0.12.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 (65) hide show
  1. package/README.md +81 -3
  2. package/build/SessionPanel-Dy9lQrOV.d.mts +319 -0
  3. package/build/SessionPanel-NQ8ksCfj.mjs +8474 -0
  4. package/build/SessionPanel-NQ8ksCfj.mjs.map +1 -0
  5. package/build/format-DqR56Y8l.mjs +162 -0
  6. package/build/format-DqR56Y8l.mjs.map +1 -0
  7. package/build/format-ljc3lKpA.d.mts +59 -0
  8. package/build/format.d.mts +66 -0
  9. package/build/format.mjs +119 -0
  10. package/build/format.mjs.map +1 -0
  11. package/build/index.d.mts +671 -88
  12. package/build/index.mjs +387 -5160
  13. package/build/index.mjs.map +1 -1
  14. package/build/workspace.d.mts +226 -0
  15. package/build/workspace.mjs +861 -0
  16. package/build/workspace.mjs.map +1 -0
  17. package/package.json +22 -4
  18. package/src/components/agent/CodeEditor.tsx +300 -0
  19. package/src/components/agent/Composer.tsx +522 -87
  20. package/src/components/agent/ContextDialog.tsx +99 -0
  21. package/src/components/agent/Conversation.tsx +11 -3
  22. package/src/components/agent/EditorTabs.tsx +165 -0
  23. package/src/components/agent/FileCard.tsx +26 -0
  24. package/src/components/agent/FileTree.tsx +287 -0
  25. package/src/components/agent/FileViewer.tsx +148 -0
  26. package/src/components/agent/HostFilesDialog.tsx +218 -0
  27. package/src/components/agent/Loader.tsx +82 -14
  28. package/src/components/agent/McpDialog.tsx +363 -0
  29. package/src/components/agent/Message.tsx +51 -17
  30. package/src/components/agent/ModelSelect.tsx +34 -6
  31. package/src/components/agent/PermissionModeSelect.tsx +133 -22
  32. package/src/components/agent/PermissionPrompt.tsx +164 -6
  33. package/src/components/agent/PromptTokenText.tsx +39 -0
  34. package/src/components/agent/QuestionPrompt.tsx +122 -0
  35. package/src/components/agent/Reasoning.tsx +20 -5
  36. package/src/components/agent/Response.tsx +128 -0
  37. package/src/components/agent/SessionBrowser.tsx +428 -0
  38. package/src/components/agent/SessionEmptyState.tsx +65 -0
  39. package/src/components/agent/SessionInfoDialog.tsx +163 -0
  40. package/src/components/agent/SessionPanel.tsx +783 -91
  41. package/src/components/agent/SessionWorkspace.tsx +317 -0
  42. package/src/components/agent/SkillsDialog.tsx +195 -0
  43. package/src/components/agent/StatusBar.tsx +85 -18
  44. package/src/components/agent/ToolCallCard.tsx +252 -30
  45. package/src/components/agent/Transcript.tsx +513 -30
  46. package/src/components/agent/UsageDialog.tsx +168 -0
  47. package/src/components/agent/line-prompt.tsx +249 -0
  48. package/src/components/agent/pulse.tsx +60 -0
  49. package/src/components/agent/transcript-variant.tsx +123 -0
  50. package/src/components/prompt-area/prompt-area-engine.ts +53 -0
  51. package/src/components/prompt-area/types.ts +15 -0
  52. package/src/components/prompt-area/use-prompt-area.ts +20 -0
  53. package/src/components/ui/CodeBlock.tsx +40 -2
  54. package/src/components/ui/CopyButton.tsx +28 -3
  55. package/src/components/ui/Dialog.tsx +92 -0
  56. package/src/components/ui/Menu.tsx +55 -0
  57. package/src/components/ui/Splitter.tsx +133 -0
  58. package/src/components/ui/Tooltip.tsx +22 -5
  59. package/src/format.ts +11 -0
  60. package/src/index.ts +67 -2
  61. package/src/lib/clipboard.ts +56 -0
  62. package/src/lib/format.ts +114 -0
  63. package/src/lib/status.ts +124 -0
  64. package/src/lib/tool-icon.ts +96 -0
  65. package/src/workspace.ts +28 -0
package/build/index.d.mts CHANGED
@@ -1,22 +1,28 @@
1
+ import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-ljc3lKpA.mjs";
2
+ import { _ as permissionModeChoices, a as SessionVitals, c as TranscriptVariant, d as useTranscriptVariant, f as PERMISSION_MODES, g as PermissionModeSelectProps, h as PermissionModeSelect, i as SessionSurfacePanel, l as TranscriptVariantProvider, m as PermissionModeMeta, n as SessionPanel, o as TranscriptDensity, p as PermissionModeChoice, r as SessionPanelProps, s as TranscriptDensityProvider, t as SessionControls, u as useTranscriptDensity, v as permissionModeMeta } from "./SessionPanel-Dy9lQrOV.mjs";
1
3
  import * as _$react from "react";
2
- import { ButtonHTMLAttributes, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from "react";
4
+ import { ButtonHTMLAttributes, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactElement, ReactNode, Ref, RefObject, TextareaHTMLAttributes } from "react";
3
5
  import { VariantProps } from "class-variance-authority";
4
6
  import { ClassValue } from "clsx";
5
7
  import * as _$_base_ui_react_select0 from "@base-ui/react/select";
6
8
  import { Select as Select$1 } from "@base-ui/react/select";
9
+ import { LucideIcon } from "lucide-react";
7
10
  import * as _$_base_ui_react_alert_dialog0 from "@base-ui/react/alert-dialog";
8
11
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
12
+ import { Menu as Menu$1 } from "@base-ui/react/menu";
13
+ import * as _$_base_ui_react_dialog0 from "@base-ui/react/dialog";
14
+ import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
9
15
  import * as _$_base_ui_react_tooltip0 from "@base-ui/react/tooltip";
10
16
  import { Tooltip } from "@base-ui/react/tooltip";
11
17
  import { toast } from "sonner";
12
- import { ModelOption, PermissionMode, PermissionRequest, QuestionBehavior, SessionInfo, SessionStatus, SlashCommandInfo, UserQuestion } from "@workerdeck/protocol";
13
- import { TranscriptItem, TranscriptState } from "@workerdeck/react";
18
+ import { ContextUsage, ModelOption, PermissionRequest, ProfileEngine, QuestionBehavior, RateLimitInfo, SessionInfo, SessionRow, SessionStatus, SkillInfo, SlashCommandInfo, UserQuestion, ViewConfig, WorkspaceScope } from "@workerdeck/protocol";
19
+ import { ConnectionState, TranscriptItem, TranscriptState, UseAttachmentsResult } from "@workerdeck/react";
14
20
  import * as _$class_variance_authority_types0 from "class-variance-authority/types";
15
21
  import { WorkerDeckClient } from "@workerdeck/client";
16
22
 
17
23
  //#region src/components/ui/Button.d.ts
18
24
  declare const buttonVariants: (props?: ({
19
- variant?: "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | null | undefined;
25
+ variant?: "default" | "link" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
20
26
  size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-sm" | null | undefined;
21
27
  } & _$class_variance_authority_types0.ClassProp) | undefined) => string;
22
28
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}
@@ -80,16 +86,65 @@ declare const AlertDialogContent: FunctionComponent<AlertDialog$1.Popup.Props>;
80
86
  declare const AlertDialogTitle: FunctionComponent<AlertDialog$1.Title.Props>;
81
87
  declare const AlertDialogDescription: FunctionComponent<AlertDialog$1.Description.Props>;
82
88
  //#endregion
89
+ //#region src/components/ui/Menu.d.ts
90
+ declare const Menu: <Payload>(props: Menu$1.Root.Props<Payload>) => _$react.JSX.Element;
91
+ declare const MenuTrigger: Menu$1.Trigger;
92
+ declare const MenuContent: FunctionComponent<Menu$1.Popup.Props & Pick<Menu$1.Positioner.Props, 'align' | 'side' | 'sideOffset'>>;
93
+ declare const MenuItem: FunctionComponent<Menu$1.Item.Props & {
94
+ destructive?: boolean;
95
+ }>;
96
+ declare const MenuSeparator: FunctionComponent<Menu$1.Separator.Props>;
97
+ //#endregion
98
+ //#region src/components/ui/Dialog.d.ts
99
+ declare const Dialog: typeof Dialog$1.Root;
100
+ declare const DialogTrigger: Dialog$1.Trigger;
101
+ declare const DialogClose: _$react.ForwardRefExoticComponent<Omit<_$_base_ui_react_dialog0.DialogCloseProps, "ref"> & _$react.RefAttributes<HTMLButtonElement>>;
102
+ /**
103
+ * A dismissible panel, sized for reading rather than confirming — the web
104
+ * counterpart of the iOS app's detail sheets (context, usage, session info, MCP).
105
+ *
106
+ * Taller than {@link AlertDialogContent} and scrollable inside, because these
107
+ * carry lists whose length is the engine's business, not the layout's.
108
+ */
109
+ declare const DialogContent: FunctionComponent<Dialog$1.Popup.Props & {
110
+ size?: 'sm' | 'md' | 'lg';
111
+ }>;
112
+ /** Title row with the close button, pinned above the scrolling body. */
113
+ declare const DialogHeader: FunctionComponent<{
114
+ title: string;
115
+ description?: string; /** Rendered between the title and the close button. */
116
+ actions?: React.ReactNode;
117
+ }>;
118
+ /** The scrolling region under the header. */
119
+ declare const DialogBody: FunctionComponent<React.HTMLAttributes<HTMLDivElement>>;
120
+ /** A label/value row — the shape every one of these panels is mostly made of. */
121
+ declare const DialogRow: FunctionComponent<{
122
+ label: string;
123
+ children: React.ReactNode;
124
+ mono?: boolean;
125
+ }>;
126
+ //#endregion
83
127
  //#region src/components/ui/Tooltip.d.ts
84
128
  declare const TooltipProvider: _$react.FC<_$_base_ui_react_tooltip0.TooltipProviderProps>;
85
129
  declare const TooltipContent: FunctionComponent<Tooltip.Popup.Props & Pick<Tooltip.Positioner.Props, 'side' | 'sideOffset'>>;
86
- /** Convenience wrapper: <Tip content="..."><Button/></Tip> */
130
+ /**
131
+ * Convenience wrapper: `<Tip content="..."><Button/></Tip>`.
132
+ *
133
+ * Pass `render` when the trigger must *be* an element you already have — a tab, a
134
+ * row — rather than something wrapped in a span. The default span is fine beside
135
+ * a button but would break any layout that styles its own children (a flex tab
136
+ * strip gets an extra box between the container and its items).
137
+ */
87
138
  declare function Tip({
88
139
  content,
140
+ render,
141
+ side,
89
142
  children
90
143
  }: {
91
144
  content: ReactNode;
92
- children: ReactNode;
145
+ render?: ReactElement;
146
+ side?: 'top' | 'right' | 'bottom' | 'left';
147
+ children?: ReactNode;
93
148
  }): _$react.JSX.Element;
94
149
  //#endregion
95
150
  //#region src/components/ui/Sonner.d.ts
@@ -99,9 +154,13 @@ declare function Toaster(): _$react.JSX.Element;
99
154
  //#region src/components/ui/CopyButton.d.ts
100
155
  interface CopyButtonProps extends Omit<ButtonProps, 'onClick' | 'children'> {
101
156
  value: string;
157
+ /** Draw the state as characters (`⧉` / `✓`) rather than line-art icons — for
158
+ * terminal-styled surfaces, where an SVG reads as another app's button. */
159
+ glyph?: boolean;
102
160
  }
103
161
  declare function CopyButton({
104
162
  value,
163
+ glyph,
105
164
  className,
106
165
  variant,
107
166
  size,
@@ -121,6 +180,17 @@ interface CodeBlockProps {
121
180
  /** Header label, e.g. a language or "Parameters". */
122
181
  label?: ReactNode;
123
182
  copyable?: boolean;
183
+ /**
184
+ * `'panel'` (default) is the framed card: border, header strip, rounded.
185
+ * `'plain'` is the terminal treatment — the label is a dim line, the code a
186
+ * flat band, and copy is a character. For surfaces where a box around every
187
+ * payload is more chrome than content (the transcript's `lines` variant).
188
+ *
189
+ * A prop rather than a read of the transcript's variant context: this is a
190
+ * `ui/` primitive and has no business knowing what a transcript is. The agent
191
+ * component that renders it does.
192
+ */
193
+ variant?: 'panel' | 'plain';
124
194
  className?: string;
125
195
  }
126
196
  /** Plain (unhighlighted) code panel for structured data like tool inputs. Markdown code
@@ -129,9 +199,61 @@ declare function CodeBlock({
129
199
  code,
130
200
  label,
131
201
  copyable,
202
+ variant,
132
203
  className
133
204
  }: CodeBlockProps): _$react.JSX.Element;
134
205
  //#endregion
206
+ //#region src/components/ui/Splitter.d.ts
207
+ interface SplitterProps {
208
+ /**
209
+ * ARIA's sense of the word: a `vertical` splitter is a vertical bar between
210
+ * two side-by-side panes, and it resizes a **width**. A `horizontal` one sits
211
+ * between stacked panes and resizes a **height**.
212
+ */
213
+ orientation: 'vertical' | 'horizontal';
214
+ /** Current size of the pane this splitter controls, in pixels. */
215
+ value: number;
216
+ onValueChange: (value: number) => void;
217
+ min: number;
218
+ max: number;
219
+ /** Keyboard step. */
220
+ step?: number;
221
+ /** Set when dragging the splitter *away* from the origin should shrink the
222
+ * controlled pane — i.e. the pane is on the right or the bottom. */
223
+ inverted?: boolean;
224
+ /** Required: "Resize" alone does not say which of two splitters this is. */
225
+ 'aria-label': string;
226
+ className?: string;
227
+ }
228
+ /**
229
+ * A draggable pane divider.
230
+ *
231
+ * Hand-rolled rather than depended on: `@base-ui/react` ships no splitter, the
232
+ * behaviour is a hundred lines of pointer events, and this repo's instinct at
233
+ * this layer is to own it (the composer is vendored for the same reason).
234
+ *
235
+ * Pointer capture is what makes it survive a fast drag — without it the pointer
236
+ * leaves the 5px bar within a frame and the moves go to whatever is underneath,
237
+ * which for this layout is an iframe-free but still selection-happy code pane.
238
+ * The drag origin is captured on pointerdown and every move is measured against
239
+ * it, so the pane cannot drift relative to the cursor over a long drag the way
240
+ * per-move deltas do once clamping is involved.
241
+ *
242
+ * Keyboard-operable and announced as a separator, because a pane you can only
243
+ * size by dragging is a pane some people cannot size.
244
+ */
245
+ declare function Splitter({
246
+ orientation,
247
+ value,
248
+ onValueChange,
249
+ min,
250
+ max,
251
+ step,
252
+ inverted,
253
+ 'aria-label': label,
254
+ className
255
+ }: SplitterProps): _$react.JSX.Element;
256
+ //#endregion
135
257
  //#region src/components/ui/ProgressRing.d.ts
136
258
  interface ProgressRingProps {
137
259
  /** Filled share, 0–100 (clamped). */
@@ -235,6 +357,21 @@ type TriggerConfig = {
235
357
  * Return the display text for the chip, or void to use `suggestion.label`.
236
358
  */
237
359
  onSelect?: (suggestion: TriggerSuggestion) => string | void;
360
+ /**
361
+ * For 'dropdown' mode: opt a suggestion out of becoming a chip.
362
+ *
363
+ * Return a string and the trigger's range is replaced with that **plain,
364
+ * editable text** — the trigger character included — with the caret left at
365
+ * its end. Return undefined and the suggestion resolves to a chip as usual,
366
+ * so one dropdown can mix both kinds.
367
+ *
368
+ * For suggestions that are a typing aid rather than a token: something the
369
+ * user is meant to finish and edit, where a chip would falsely promise the
370
+ * host parses it back out. Takes precedence over `onSelect`, which is not
371
+ * called for a text-resolved suggestion (there is no chip to label), and
372
+ * `onChipAdd` does not fire either.
373
+ */
374
+ insertAsText?: (suggestion: TriggerSuggestion) => string | undefined;
238
375
  /**
239
376
  * For 'callback' and 'launch' modes: called when the trigger is activated.
240
377
  * Receives the full input text and cursor position. For 'launch' it fires on
@@ -577,26 +714,6 @@ declare function isSegmentsEmpty(segments: Segment[]): boolean;
577
714
  /** Extracts chips matching a specific trigger character. */
578
715
  declare function getChipsByTrigger(segments: Segment[], trigger: string): ChipSegment[];
579
716
  //#endregion
580
- //#region src/components/agent/SessionPanel.d.ts
581
- interface SessionPanelProps {
582
- client: WorkerDeckClient;
583
- sessionId: string | undefined;
584
- /** Optional slot rendered at the top, above the status bar. */
585
- header?: ReactNode;
586
- className?: string;
587
- }
588
- /**
589
- * The all-in-one embeddable session surface: status bar, streaming transcript,
590
- * permission prompts, composer. Attaches via useClaudeSession; remount (key) to switch
591
- * sessions.
592
- */
593
- declare function SessionPanel({
594
- client,
595
- sessionId,
596
- header,
597
- className
598
- }: SessionPanelProps): _$react.JSX.Element;
599
- //#endregion
600
717
  //#region src/components/agent/Transcript.d.ts
601
718
  interface TranscriptProps {
602
719
  state: TranscriptState;
@@ -607,24 +724,75 @@ interface TranscriptProps {
607
724
  * `(id) => client.attachmentUrl(sessionId, id)`. Same-origin and
608
725
  * cookie-authenticated, which is what lets an `<img src>` render one. */
609
726
  attachmentUrl?: (attachmentId: string) => string;
727
+ /** Whether this gateway serves `@file` search here — the empty state must not
728
+ * advertise an affordance the composer doesn't have. */
729
+ canBrowseFiles?: boolean;
730
+ /** Reads a host file as a data URL, for tool calls whose output is a picture
731
+ * on the host (codex's `image_gen`). Omit and those cards name the path. */
732
+ hostImage?: (path: string) => Promise<string | undefined>;
733
+ /**
734
+ * How a turn is drawn: `cards` (default, the chat convention) or `lines` —
735
+ * full-width transparent line items with a gutter glyph, for hosts where
736
+ * vertical space is scarce. See {@link TranscriptVariant}.
737
+ */
738
+ variant?: TranscriptVariant;
739
+ /**
740
+ * How much air each row gets: `comfortable` (default — a blank line between
741
+ * messages, as the Claude Code CLI does) or `compact`. Independent of
742
+ * {@link TranscriptVariant}. See {@link TranscriptDensity}.
743
+ */
744
+ density?: TranscriptDensity;
745
+ /**
746
+ * Catch-up: `from` is how many items had been seen last time, `since` when
747
+ * that was. A recap row is drawn at that boundary and everything above it is
748
+ * dimmed. Omit (or pass a boundary at/after the end) and the transcript
749
+ * renders exactly as before.
750
+ */
751
+ catchUp?: {
752
+ from: number;
753
+ since?: number;
754
+ };
755
+ /**
756
+ * Filled with a closure that scrolls the recap row into view — the seam the
757
+ * panel's catch-up strip presses. A ref rather than a DOM query because the
758
+ * rows are virtualized: when the recap row isn't mounted, only the
759
+ * virtualizer knows where it would be. Optional; embedders without a
760
+ * catch-up strip never touch it. `null` while no transcript is mounted.
761
+ */
762
+ jumpToRecapRef?: RefObject<(() => void) | null>;
610
763
  className?: string;
611
764
  }
612
765
  declare function Transcript({
613
766
  state,
614
767
  fileUrl,
615
768
  attachmentUrl,
769
+ canBrowseFiles,
770
+ hostImage,
771
+ variant,
772
+ density,
773
+ catchUp,
774
+ jumpToRecapRef,
616
775
  className
617
776
  }: TranscriptProps): _$react.JSX.Element;
618
777
  //#endregion
619
778
  //#region src/components/agent/Conversation.d.ts
620
779
  interface ConversationProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
621
780
  children: ReactNode;
781
+ /**
782
+ * How the view follows content that grows. `'smooth'` is right for a live
783
+ * turn — the text scrolls as it is written. `'instant'` is right while a
784
+ * transcript is *filling* (an attach replaying a whole session), where
785
+ * animating each arrival makes opening a session a several-second journey
786
+ * from its first row to its last.
787
+ */
788
+ resize?: 'smooth' | 'instant';
622
789
  }
623
790
  /** Scroll container that stays pinned to the bottom while streaming, unless the user
624
791
  * scrolls up — plus a floating scroll-to-bottom button. */
625
792
  declare function Conversation({
626
793
  className,
627
794
  children,
795
+ resize,
628
796
  ...props
629
797
  }: ConversationProps): _$react.JSX.Element;
630
798
  declare function ConversationContent({
@@ -644,11 +812,22 @@ declare function ConversationScrollButton({
644
812
  interface MessageProps extends HTMLAttributes<HTMLDivElement> {
645
813
  from: 'user' | 'assistant';
646
814
  }
647
- /** One chat turn row. User messages sit right in a bubble; assistant content is flat,
648
- * full-width (the AI-chat convention — assistant output is the page, user input is quoted). */
815
+ /**
816
+ * One chat turn row.
817
+ *
818
+ * `cards`: user messages sit right in a bubble; assistant content is flat,
819
+ * full-width (the AI-chat convention — assistant output is the page, user input
820
+ * is quoted).
821
+ *
822
+ * `lines`: both are left-aligned full-width line items behind a gutter glyph —
823
+ * `❯` for what was typed, `●` for what the model said. No bubble: a prompt is
824
+ * already distinguishable by its marker, and the bubble's padding is vertical
825
+ * space the terminal treatment refuses to spend.
826
+ */
649
827
  declare function Message({
650
828
  from,
651
829
  className,
830
+ children,
652
831
  ...props
653
832
  }: MessageProps): _$react.JSX.Element;
654
833
  declare function MessageContent({
@@ -689,14 +868,30 @@ declare function Reasoning({
689
868
  }: ReasoningProps): _$react.JSX.Element | null;
690
869
  //#endregion
691
870
  //#region src/components/agent/Loader.d.ts
692
- /** Three-dot pulse shown while the assistant hasn't produced output yet. */
871
+ interface LoaderProps {
872
+ /** Overrides the cycling verb — for a state that has one true name
873
+ * ("Starting session…"). */
874
+ label?: string;
875
+ /** When the current run began, for the elapsed clock. Absent = no clock. */
876
+ startedAt?: number;
877
+ /** Context tokens in play, shown beside the clock. */
878
+ tokens?: number;
879
+ className?: string;
880
+ }
881
+ /**
882
+ * "The agent is working and hasn't produced output yet."
883
+ *
884
+ * `lines`: a terminal working line — the mark's own pulse in the gutter (see
885
+ * `pulse.tsx`), a verb, and the readings that answer "should I still be
886
+ * waiting?" in one parenthesis. `cards`: the three-dot pulse, unchanged — the
887
+ * dashboard's loader is not a gutter glyph and has no column to pulse in.
888
+ */
693
889
  declare function Loader({
694
890
  label,
891
+ startedAt,
892
+ tokens,
695
893
  className
696
- }: {
697
- label?: string;
698
- className?: string;
699
- }): _$react.JSX.Element;
894
+ }: LoaderProps): _$react.JSX.Element;
700
895
  //#endregion
701
896
  //#region src/components/agent/ToolCallCard.d.ts
702
897
  type ToolCallItem = Extract<TranscriptItem, {
@@ -704,10 +899,19 @@ type ToolCallItem = Extract<TranscriptItem, {
704
899
  }>;
705
900
  interface ToolCallCardProps {
706
901
  item: ToolCallItem;
902
+ /**
903
+ * Reads a host file as a data URL, for tools whose output is a picture on the
904
+ * host. Resolves `undefined` when the gateway won't serve that path — a
905
+ * generated image saved outside the allowed roots (codex's default
906
+ * `$CODEX_HOME/generated_images/`) is one, and the card then names the path
907
+ * instead of showing it.
908
+ */
909
+ hostImage?: (path: string) => Promise<string | undefined>;
707
910
  className?: string;
708
911
  }
709
912
  declare function ToolCallCard({
710
913
  item,
914
+ hostImage,
711
915
  className
712
916
  }: ToolCallCardProps): _$react.JSX.Element;
713
917
  //#endregion
@@ -735,9 +939,23 @@ declare function FileCard({
735
939
  interface PermissionPromptProps {
736
940
  request: PermissionRequest;
737
941
  onApprove: (requestId: string) => void;
738
- onDeny: (requestId: string, message?: string) => void;
942
+ /** `message` is fed back to the agent, which can then try something else;
943
+ * `interrupt` also stops the turn. */
944
+ onDeny: (requestId: string, message?: string, interrupt?: boolean) => void;
739
945
  className?: string;
740
946
  }
947
+ /**
948
+ * Generic allow/deny prompt for a pending permission request.
949
+ *
950
+ * Three outcomes, not two: denying usually means "not that, try something else",
951
+ * so plain Deny lets the turn continue (with an optional reason the agent reads)
952
+ * while "Deny & stop" also interrupts.
953
+ *
954
+ * The heading is whatever the engine authored — `title`, else `displayName`.
955
+ * Composing "wants to use {tool}" instead would be wrong for codex, where an
956
+ * approval is usually an *escalation after a sandbox refusal* and the runner has
957
+ * already written the sentence that says so.
958
+ */
741
959
  declare function PermissionPrompt({
742
960
  request,
743
961
  onApprove,
@@ -776,8 +994,23 @@ declare function QuestionPrompt({
776
994
  }: QuestionPromptProps): _$react.JSX.Element;
777
995
  //#endregion
778
996
  //#region src/components/agent/Composer.d.ts
997
+ /** Files matching an `@` query, for the composer's file trigger. Structural so
998
+ * the ui package doesn't have to reach for the protocol's `HostFileMatch`. */
999
+ type ComposerFileMatch = {
1000
+ path: string;
1001
+ relative: string;
1002
+ };
1003
+ /** Imperative surface for panels that draft a message the user then finishes —
1004
+ * the skills dialog's "Use this skill". Nothing here sends. */
1005
+ type ComposerHandle = {
1006
+ /** Append plain text at the caret's end and focus, separating it from
1007
+ * whatever is already there. */
1008
+ insertText: (text: string) => void; /** Put the caret in the field, changing nothing. */
1009
+ focus: () => void;
1010
+ };
779
1011
  interface ComposerProps {
780
- onSend: (text: string) => void;
1012
+ /** `attachmentIds` are the staged uploads, in the order they were picked. */
1013
+ onSend: (text: string, attachmentIds: string[]) => void;
781
1014
  onInterrupt: () => void;
782
1015
  busy: boolean;
783
1016
  /** Disable input entirely (session failed/closed). */
@@ -785,14 +1018,70 @@ interface ComposerProps {
785
1018
  placeholder?: string;
786
1019
  /** Slash commands offered as autocomplete; picked ones render as chips. */
787
1020
  commands?: SlashCommandInfo[];
788
- /** Left side of the toolbar row (mode selects, attachments, …). */
1021
+ /**
1022
+ * Skills offered under a **`$`** popover of their own — codex's sigil, kept
1023
+ * separate from `/` because the two behave differently. A skill is a typing
1024
+ * aid, not a command: picking one inserts editable text (the skill's own
1025
+ * `defaultPrompt` where it has one, else `$name`) and nothing is sent. No
1026
+ * engine parses `$skillname` as syntax, which is exactly why these can never
1027
+ * resolve to a chip the way `commands` do.
1028
+ */
1029
+ skills?: SkillInfo[];
1030
+ /** Host-file search behind the `@` trigger. Omit to leave `@` inert — a
1031
+ * gateway without host files has nothing to complete. */
1032
+ onSearchFiles?: (query: string, options: {
1033
+ signal: AbortSignal;
1034
+ }) => Promise<ComposerFileMatch[]>;
1035
+ /** Attachment staging (see `useAttachments`). Omit for a text-only composer. */
1036
+ attachments?: UseAttachmentsResult;
1037
+ /** Left side of the toolbar row (mode selects, …). */
789
1038
  toolbar?: ReactNode;
1039
+ /**
1040
+ * `'stacked'` (default) gives the buttons a row of their own under the field —
1041
+ * right where a toolbar belongs. `'inline'` puts the field and the buttons on
1042
+ * ONE line, growing from a single row as the message does: for a host whose
1043
+ * session controls live in its own chrome (VS Code's status bar), where the
1044
+ * empty composer would otherwise spend two rows saying nothing.
1045
+ */
1046
+ layout?: 'stacked' | 'inline';
790
1047
  className?: string;
1048
+ ref?: Ref<ComposerHandle>;
791
1049
  }
792
- /** Framed prompt input built on prompt-area's contentEditable: typing "/" — at the
793
- * start or after whitespace — opens a suggestion dropdown fed by `commands`, and a
794
- * picked command becomes an inline chip. Submit button flips to stop while a turn
795
- * is running (messages still queue while busy). */
1050
+ /**
1051
+ * What a picked skill types into the composer.
1052
+ *
1053
+ * The engine's own `defaultPrompt` when it declared one — it knows what its
1054
+ * skill wants to be asked — and otherwise `$name`, which is codex's native way
1055
+ * of referring to a skill in prompt text: its `skill-creator` documents the form
1056
+ * (`Use $skill-x at /path/to/skill-x to solve problem y`) and its own bundled
1057
+ * prompts are written that way ("Use $pdf to …"). Spelling it the way the engine
1058
+ * spells it beats paraphrasing into "Use the X skill to".
1059
+ *
1060
+ * Either way it ends in a space so the caret lands ready for the rest of the
1061
+ * sentence, and either way it is ordinary text: nothing here is submitted, and
1062
+ * nothing is parsed back out.
1063
+ */
1064
+ declare function skillPrompt(skill: SkillInfo): string;
1065
+ /**
1066
+ * Framed prompt input built on prompt-area's contentEditable.
1067
+ *
1068
+ * Three completions ride the same field and behave nothing alike. `/` is the
1069
+ * CLI's command list and `$` is the engine's skill list — both local, so they
1070
+ * filter completely and instantly; `@` is a search against the host filesystem,
1071
+ * debounced and abortable so a fast typist makes one request rather than eight.
1072
+ *
1073
+ * `/` and `$` are separate keys rather than one merged menu, and that mirrors
1074
+ * the engines themselves: codex completes skills on `$` and reserves `/` for
1075
+ * commands. The behaviours differ too — a command resolves to a **chip**,
1076
+ * because the CLI really does parse `/name` out of the message, while a skill
1077
+ * resolves to plain editable **text**, because no engine parses `$name` as
1078
+ * syntax; it is prose the model reads. Rendering them alike would promise
1079
+ * something that does not happen.
1080
+ *
1081
+ * Files can arrive three ways — the paperclip, a drop, or a paste — because on a
1082
+ * desktop all three are things people already do, and the upload starts the
1083
+ * moment one lands rather than at send time.
1084
+ */
796
1085
  declare function Composer({
797
1086
  onSend,
798
1087
  onInterrupt,
@@ -800,8 +1089,13 @@ declare function Composer({
800
1089
  disabled,
801
1090
  placeholder,
802
1091
  commands,
1092
+ skills,
1093
+ onSearchFiles,
1094
+ attachments,
803
1095
  toolbar,
804
- className
1096
+ layout,
1097
+ className,
1098
+ ref
805
1099
  }: ComposerProps): _$react.JSX.Element;
806
1100
  //#endregion
807
1101
  //#region src/components/agent/ModelSelect.d.ts
@@ -831,51 +1125,208 @@ declare function ModelSelect({
831
1125
  className
832
1126
  }: ModelSelectProps): _$react.JSX.Element;
833
1127
  //#endregion
834
- //#region src/components/agent/PermissionModeSelect.d.ts
835
- type PermissionModeMeta = {
836
- value: PermissionMode;
837
- label: string;
838
- description: string;
839
- dangerous?: boolean;
840
- };
841
- /** The modes surfaced across UI surfaces (session creation, in-session switcher). */
842
- declare const PERMISSION_MODES: PermissionModeMeta[];
843
- interface PermissionModeSelectProps {
844
- /** The session's current mode (TranscriptState.permissionMode). */
845
- mode?: PermissionMode;
846
- onModeChange: (mode: PermissionMode) => void;
847
- /** Restrict what is offered — most of {@link PERMISSION_MODES} is Claude Code
848
- * vocabulary the provider engine has no meaning for. Defaults to all of them;
849
- * pass `PROVIDER_PERMISSION_MODES` for a provider session. */
850
- modes?: readonly PermissionMode[];
851
- /** 'toolbar' (default) is the composer's compact borderless trigger;
852
- * 'form' is a standard field-sized Select for create/settings forms. */
853
- variant?: 'toolbar' | 'form';
854
- disabled?: boolean;
855
- className?: string;
856
- }
857
- /** Permission-mode switcher: compact in the composer toolbar, field-sized in forms. */
858
- declare function PermissionModeSelect({
859
- mode,
860
- onModeChange,
861
- modes,
862
- variant,
863
- disabled,
864
- className
865
- }: PermissionModeSelectProps): _$react.JSX.Element;
866
- //#endregion
867
1128
  //#region src/components/agent/StatusBar.d.ts
868
1129
  interface StatusBarProps {
869
1130
  state: TranscriptState;
870
- connected: boolean;
1131
+ /** @deprecated Pass {@link StatusBarProps.connection}; kept so an embedder
1132
+ * still handing over a boolean keeps working. */
1133
+ connected?: boolean;
1134
+ /** How the client is doing at reaching the gateway. A dropped socket wins the
1135
+ * status slot: the session status held over a dead socket is a stale reading,
1136
+ * and presenting it as a live one is the thing worth avoiding. */
1137
+ connection?: ConnectionState;
1138
+ /**
1139
+ * Where the gauges lead. Each one opens the panel that answers *its* question
1140
+ * — the two meters measure different things, so sending both to one "details"
1141
+ * list would be a detour every time. Omit a handler and that gauge stays a
1142
+ * read-only tooltip.
1143
+ */
1144
+ onOpenStatus?: () => void;
1145
+ onOpenContext?: () => void;
1146
+ onOpenUsage?: () => void;
1147
+ /** Trailing slot — the session-actions menu, in the panel's top-right. */
1148
+ actions?: ReactNode;
871
1149
  className?: string;
872
1150
  }
873
1151
  declare function StatusBar({
874
1152
  state,
875
1153
  connected,
1154
+ connection,
1155
+ onOpenStatus,
1156
+ onOpenContext,
1157
+ onOpenUsage,
1158
+ actions,
876
1159
  className
877
1160
  }: StatusBarProps): _$react.JSX.Element;
878
1161
  //#endregion
1162
+ //#region src/components/agent/ContextDialog.d.ts
1163
+ interface ContextDialogProps {
1164
+ usage?: ContextUsage;
1165
+ open: boolean;
1166
+ onOpenChange: (open: boolean) => void;
1167
+ }
1168
+ /**
1169
+ * What is in the model's context window right now, category by category.
1170
+ *
1171
+ * One of the three panels the status bar opens. Context, usage and session info
1172
+ * are different questions asked at different moments, so they are different
1173
+ * screens rather than one "details" list you scroll past two answers to reach.
1174
+ */
1175
+ declare function ContextDialog({
1176
+ usage,
1177
+ open,
1178
+ onOpenChange
1179
+ }: ContextDialogProps): _$react.JSX.Element;
1180
+ //#endregion
1181
+ //#region src/components/agent/UsageDialog.d.ts
1182
+ interface UsageDialogProps {
1183
+ /** Windows in reading order — session, weekly, then per-model weeklies. */
1184
+ rateLimits: Array<{
1185
+ key: string;
1186
+ info: RateLimitInfo;
1187
+ }>;
1188
+ /** claude.ai plan behind the windows ('max', 'pro', …), when there is one. */
1189
+ subscriptionType?: string;
1190
+ engine: ProfileEngine;
1191
+ totalCostUsd: number;
1192
+ /** Local receipt time of the last window update. `rate_limit` events are one
1193
+ * per turn at best, so a stale reading is normal and worth saying out loud. */
1194
+ updatedAt?: number;
1195
+ open: boolean;
1196
+ onOpenChange: (open: boolean) => void;
1197
+ }
1198
+ /**
1199
+ * The plan's rate-limit windows, spelled out: how much of each is used, how that
1200
+ * compares to the pace that would spend the window exactly, and when it resets.
1201
+ *
1202
+ * The pace marker is the point. A bar alone says "17% used", which is only
1203
+ * alarming or reassuring once you know how far into the week you are — so every
1204
+ * window draws a tick at the elapsed share of its duration. Left of the tick is
1205
+ * under budget, right of it is ahead of it. The duration comes from the window
1206
+ * key (5h, 7d) because the CLI reports a reset time and a percentage and never a
1207
+ * duration; a window whose key doesn't say gets no marker rather than a guessed one.
1208
+ */
1209
+ declare function UsageDialog({
1210
+ rateLimits,
1211
+ subscriptionType,
1212
+ engine,
1213
+ totalCostUsd,
1214
+ updatedAt,
1215
+ open,
1216
+ onOpenChange
1217
+ }: UsageDialogProps): _$react.JSX.Element;
1218
+ //#endregion
1219
+ //#region src/components/agent/SessionInfoDialog.d.ts
1220
+ interface SessionInfoDialogProps {
1221
+ state: TranscriptState;
1222
+ client: WorkerDeckClient;
1223
+ sessionId: string | undefined;
1224
+ open: boolean;
1225
+ onOpenChange: (open: boolean) => void;
1226
+ }
1227
+ /**
1228
+ * What this session *is*: engine, profile, model, mode, where it runs, which
1229
+ * credentials it found, and the files it has handed over.
1230
+ *
1231
+ * The identity half of the session's facts. Context and usage have their own
1232
+ * panels — they change every turn and are consulted mid-run, while everything
1233
+ * here is fixed at creation and looked up once.
1234
+ */
1235
+ declare function SessionInfoDialog({
1236
+ state,
1237
+ client,
1238
+ sessionId,
1239
+ open,
1240
+ onOpenChange
1241
+ }: SessionInfoDialogProps): _$react.JSX.Element;
1242
+ //#endregion
1243
+ //#region src/components/agent/McpDialog.d.ts
1244
+ interface McpDialogProps {
1245
+ client: WorkerDeckClient;
1246
+ sessionId: string | undefined;
1247
+ open: boolean;
1248
+ onOpenChange: (open: boolean) => void;
1249
+ /**
1250
+ * Whether this engine can reconnect/enable/disable a server
1251
+ * (`EngineCapabilities.mcpServerActions`). False renders the panel read-only:
1252
+ * codex reports rich status but exposes no per-server action, and buttons
1253
+ * that 501 are worse than buttons that aren't there.
1254
+ */
1255
+ canManageServers?: boolean;
1256
+ }
1257
+ /**
1258
+ * The session's MCP servers, at the CLI's own `/mcp` depth: servers → one server
1259
+ * → its tools → one tool, with Reconnect / Enable / Disable where they apply.
1260
+ *
1261
+ * Two things vary by engine rather than being fixed here. **The actions** exist
1262
+ * only where the engine has them (`canManageServers`): codex reports rich status
1263
+ * but has no per-server reconnect or toggle, so its panel is read-only. And
1264
+ * **tool parameters** appear only where the engine reports a schema — codex
1265
+ * returns each tool's full JSON Schema, the Agent SDK returns none at all, so
1266
+ * the tool view either renders it or says why it can't, rather than leaving a
1267
+ * silent gap or claiming the absence is universal.
1268
+ */
1269
+ declare function McpDialog({
1270
+ client,
1271
+ sessionId,
1272
+ open,
1273
+ onOpenChange,
1274
+ canManageServers
1275
+ }: McpDialogProps): _$react.JSX.Element;
1276
+ //#endregion
1277
+ //#region src/components/agent/SkillsDialog.d.ts
1278
+ interface SkillsDialogProps {
1279
+ skills: SkillInfo[] | undefined;
1280
+ open: boolean;
1281
+ onOpenChange: (open: boolean) => void;
1282
+ /** Insert a skill's opening message into the composer, if the host offers
1283
+ * that. Omit and the dialog is read-only. */
1284
+ onUse?: (skill: SkillInfo) => void;
1285
+ }
1286
+ /**
1287
+ * What this session's engine can do beyond its own tools: the skills it found,
1288
+ * grouped by where they came from, with one drilled-down view each.
1289
+ *
1290
+ * The framing matters more here than in most panels. A skill is **not** a
1291
+ * command — the model decides to use one by reading its description, and there
1292
+ * is no wire syntax that invokes it. So this screen is a *discovery* surface,
1293
+ * and the one action it offers ("Use this skill") is honest about being a
1294
+ * drafting aid: it types a message for the operator to edit and send.
1295
+ *
1296
+ * Fed from the session's `skills` event rather than a REST route, because that
1297
+ * is the channel the engine refreshes on its own when a skill changes on disk.
1298
+ */
1299
+ declare function SkillsDialog({
1300
+ skills,
1301
+ open,
1302
+ onOpenChange,
1303
+ onUse
1304
+ }: SkillsDialogProps): _$react.JSX.Element;
1305
+ //#endregion
1306
+ //#region src/components/agent/HostFilesDialog.d.ts
1307
+ interface HostFilesDialogProps {
1308
+ client: WorkerDeckClient;
1309
+ /** The session's working directory — the browser is rooted here. */
1310
+ cwd: string | undefined;
1311
+ open: boolean;
1312
+ onOpenChange: (open: boolean) => void;
1313
+ }
1314
+ /**
1315
+ * Browse the project the session is working in.
1316
+ *
1317
+ * Deliberately rooted at the session's cwd rather than at the server's
1318
+ * `hostFiles.roots`: the roots are the *security* boundary (the server enforces
1319
+ * them on every request), but what someone wants while watching an agent is this
1320
+ * project's tree. Read-only — writing is a separate server opt-in and not
1321
+ * something a session viewer should be doing behind the agent's back.
1322
+ */
1323
+ declare function HostFilesDialog({
1324
+ client,
1325
+ cwd,
1326
+ open,
1327
+ onOpenChange
1328
+ }: HostFilesDialogProps): _$react.JSX.Element;
1329
+ //#endregion
879
1330
  //#region src/components/agent/SessionList.d.ts
880
1331
  interface SessionListItemProps {
881
1332
  session: SessionInfo;
@@ -906,6 +1357,111 @@ declare function SessionList({
906
1357
  className
907
1358
  }: SessionListProps): _$react.JSX.Element;
908
1359
  //#endregion
1360
+ //#region src/components/agent/SessionBrowser.d.ts
1361
+ /**
1362
+ * A sessions list with the affordances a list of thirty needs: search, facets,
1363
+ * grouping, sorting, unread counts, and one honest line about what is hidden.
1364
+ *
1365
+ * The *rules* are `@workerdeck/protocol`'s (`filterRows`/`groupRows`/
1366
+ * `subsetSummary`), not this component's — the VS Code sidebar renders the same
1367
+ * model with workbench chrome, its activity-bar badge counts the same rows this
1368
+ * would show, and iOS mirrors them in Swift. What lives here is the styled
1369
+ * rendering of that model, so a host that wants the dashboard's look gets it
1370
+ * without reimplementing the model behind it.
1371
+ *
1372
+ * `SessionList` remains beside this for the plain case (a fixed set of rows, no
1373
+ * controls); this is what you reach for when the list is the screen.
1374
+ */
1375
+ interface SessionBrowserProps {
1376
+ rows: SessionRow[];
1377
+ config: ViewConfig;
1378
+ onConfigChange: (config: ViewConfig) => void;
1379
+ /** The host's own folders, if it has such a notion. Absent — a dashboard, a
1380
+ * phone — makes the scope filter genuinely inert rather than empty. */
1381
+ scope?: WorkspaceScope;
1382
+ activeId?: string;
1383
+ onSelect?: (row: SessionRow) => void;
1384
+ onDelete?: (row: SessionRow) => void;
1385
+ /**
1386
+ * Rename, from the row's pencil. Empty string restores the derived title. A
1387
+ * gateway edit (`PATCH /sessions/:id`), never a local override — every client
1388
+ * should see the same name. Omit to make titles read-only.
1389
+ *
1390
+ * A hover affordance rather than the extension's double-click-the-title,
1391
+ * because here a single click on the row navigates: the *first* click of a
1392
+ * double-click would have already left the page.
1393
+ */
1394
+ onRename?: (row: SessionRow, title: string) => void;
1395
+ /** Rendered when nothing at all exists (as opposed to nothing matching). */
1396
+ emptyState?: React.ReactNode;
1397
+ className?: string;
1398
+ }
1399
+ declare function SessionBrowser({
1400
+ rows,
1401
+ config,
1402
+ onConfigChange,
1403
+ scope,
1404
+ activeId,
1405
+ onSelect,
1406
+ onDelete,
1407
+ onRename,
1408
+ emptyState,
1409
+ className
1410
+ }: SessionBrowserProps): _$react.JSX.Element;
1411
+ //#endregion
1412
+ //#region src/components/agent/SessionEmptyState.d.ts
1413
+ interface SessionEmptyStateProps {
1414
+ cwd?: string;
1415
+ /** Whether `/command` completion is live yet — the CLI reports its commands a
1416
+ * beat after the session starts, and promising a feature that isn't wired up
1417
+ * yet is worse than not mentioning it. */
1418
+ hasCommands?: boolean;
1419
+ /** Whether the engine has reported skills the `/` popover can offer. Its own
1420
+ * flag, not a variant of `hasCommands`: what `/` does differs — a command is
1421
+ * submitted, a skill is typed for you to edit — and an engine can have one
1422
+ * without the other. */
1423
+ hasSkills?: boolean;
1424
+ /** Whether this gateway serves `@file` search for the session's directory. */
1425
+ canBrowseFiles?: boolean;
1426
+ className?: string;
1427
+ }
1428
+ /**
1429
+ * What a session shows before it has said anything: where the agent is sitting,
1430
+ * and what the composer accepts beyond prose.
1431
+ *
1432
+ * Every hint is conditional on the affordance actually existing — an engine
1433
+ * without slash commands, or a gateway without host files, is not told about
1434
+ * them. Deliberately no project name (the header already carries it) and no
1435
+ * brand mark (its geometry is inlined in several places already and they are
1436
+ * meant to stay identical).
1437
+ */
1438
+ declare function SessionEmptyState({
1439
+ cwd,
1440
+ hasCommands,
1441
+ hasSkills,
1442
+ canBrowseFiles,
1443
+ className
1444
+ }: SessionEmptyStateProps): _$react.JSX.Element;
1445
+ //#endregion
1446
+ //#region src/components/agent/PromptTokenText.d.ts
1447
+ /**
1448
+ * A sent message, with its `@file` and `/command` tokens styled the way the CLI
1449
+ * writes them: monospace and tinted, no background — the bubble already has one,
1450
+ * and a second fill inside it reads as a button.
1451
+ *
1452
+ * Literal text, never markdown: what was typed is what was sent. The one pass
1453
+ * over it is this, so a message reads the same after sending as it did in the
1454
+ * composer. Two tokens, two meanings — a file is a reference, a command is an
1455
+ * action — so they are told apart by hue rather than by shape alone.
1456
+ */
1457
+ declare function PromptTokenText({
1458
+ text,
1459
+ className
1460
+ }: {
1461
+ text: string;
1462
+ className?: string;
1463
+ }): _$react.JSX.Element;
1464
+ //#endregion
909
1465
  //#region src/components/agent/status.d.ts
910
1466
  declare const STATUS_META: Record<SessionStatus, {
911
1467
  label: string;
@@ -916,17 +1472,44 @@ declare const STATUS_META: Record<SessionStatus, {
916
1472
  //#region src/lib/utils.d.ts
917
1473
  declare function cn(...inputs: ClassValue[]): string;
918
1474
  //#endregion
919
- //#region src/lib/format.d.ts
920
- declare function formatCost(usd: number | undefined): string;
921
- declare function formatDuration(ms: number): string;
922
- /** Compact token count, Claude Code-style: 850 → "850", 359_000 → "359.0k", 1_200_000 → "1.2M". */
923
- declare function formatTokens(tokens: number): string;
924
- declare function formatBytes(bytes: number): string;
925
- /** Countdown to an epoch-ms deadline: "2h 18m", "12m", "<1m"; "now" once passed. */
926
- declare function formatCountdown(untilEpochMs: number, now?: number): string;
927
- declare function formatRelativeTime(epochMs: number | undefined, now?: number): string;
928
- /** Compact one-line preview of a tool input for card headers. */
929
- declare function toolInputPreview(input: unknown, max?: number): string;
930
- //#endregion
931
- export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerProps, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyButton, type CopyButtonProps, FileCard, type FileCardProps, type FileDeliveredItem, Input, Loader, Message, MessageContent, type MessageProps, ModelSelect, type ModelSelectProps, PERMISSION_MODES, type PermissionModeMeta, PermissionModeSelect, type PermissionModeSelectProps, PermissionPrompt, type PermissionPromptProps, ProgressRing, type ProgressRingProps, PromptArea, type PromptAreaHandle, type PromptAreaProps, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, Spinner, StatusBar, type StatusBarProps, type TextSegment, Textarea, Tip, Toaster, ToolCallCard, type ToolCallCardProps, type ToolCallItem, TooltipContent, TooltipProvider, Transcript, type TranscriptProps, type TriggerConfig, type TriggerSuggestion, badgeVariants, buttonVariants, cn, commandTrigger, formatBytes, formatCost, formatCountdown, formatDuration, formatRelativeTime, formatTokens, getChipsByTrigger, hashtagTrigger, isSegmentsEmpty, mentionTrigger, parseUserQuestions, plainTextToSegments, segmentsToPlainText, toast, toolInputPreview, usePromptAreaState };
1475
+ //#region src/lib/clipboard.d.ts
1476
+ /**
1477
+ * Copy text to the clipboard, on origins where the modern API does not exist.
1478
+ *
1479
+ * `navigator.clipboard` is gated on a **secure context**: HTTPS, or localhost.
1480
+ * A WorkerDeck dashboard reached the way it is meant to be reached — plain HTTP
1481
+ * on a LAN address, from a laptop or a phone — is neither, so `navigator.clipboard`
1482
+ * is `undefined` there and touching `.writeText` throws outright. That is the
1483
+ * normal deployment, not an edge case, which is why this falls back rather than
1484
+ * feature-detecting into a disabled button.
1485
+ *
1486
+ * The fallback is `document.execCommand('copy')` over an off-screen textarea.
1487
+ * It is deprecated and it is also the only thing that works here; every browser
1488
+ * still implements it. Returns whether the text actually landed, so a caller can
1489
+ * avoid claiming success it did not have.
1490
+ */
1491
+ declare function copyText(value: string): Promise<boolean>;
1492
+ //#endregion
1493
+ //#region src/lib/tool-icon.d.ts
1494
+ /**
1495
+ * An icon per tool, so a transcript can be skimmed by shape rather than read.
1496
+ *
1497
+ * The same mapping the iOS app makes, in lucide's vocabulary rather than SF
1498
+ * Symbols — the two clients should be recognisably showing the same thing. An
1499
+ * unknown tool falls back to a wrench, and an MCP tool (`mcp__server__name`) to
1500
+ * the puzzle piece the MCP screens use, because "which server is this from" is
1501
+ * the useful thing to see at a glance.
1502
+ */
1503
+ declare function toolIcon(toolName: string): LucideIcon;
1504
+ /**
1505
+ * Does this tool *change* the workspace?
1506
+ *
1507
+ * Worth its own colour in a transcript: skimming a run, "what did it edit" is a
1508
+ * different question from "what did it look at", and a write is the one you
1509
+ * might need to undo. Names from both first-party engines; an MCP tool is
1510
+ * unknowable from its name, so it reads as neutral rather than guessed.
1511
+ */
1512
+ declare function isMutatingTool(toolName: string): boolean;
1513
+ //#endregion
1514
+ export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerFileMatch, type ComposerHandle, type ComposerProps, ContextDialog, type ContextDialogProps, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, FileCard, type FileCardProps, type FileDeliveredItem, HostFilesDialog, type HostFilesDialogProps, Input, Loader, McpDialog, type McpDialogProps, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, type MessageProps, ModelSelect, type ModelSelectProps, PERMISSION_MODES, type PermissionModeChoice, type PermissionModeMeta, PermissionModeSelect, type PermissionModeSelectProps, PermissionPrompt, type PermissionPromptProps, ProgressRing, type ProgressRingProps, PromptArea, type PromptAreaHandle, type PromptAreaProps, PromptTokenText, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, type SessionBrowserProps, type SessionControls, SessionEmptyState, type SessionEmptyStateProps, SessionInfoDialog, type SessionInfoDialogProps, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, type SessionSurfacePanel, type SessionVitals, SkillsDialog, type SkillsDialogProps, Spinner, Splitter, type SplitterProps, StatusBar, type StatusBarProps, type TextSegment, Textarea, Tip, Toaster, ToolCallCard, type ToolCallCardProps, type ToolCallItem, TooltipContent, TooltipProvider, Transcript, type TranscriptDensity, TranscriptDensityProvider, type TranscriptProps, type TranscriptVariant, TranscriptVariantProvider, type TriggerConfig, type TriggerSuggestion, UsageDialog, type UsageDialogProps, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptDensity, useTranscriptVariant };
932
1515
  //# sourceMappingURL=index.d.mts.map