@workerdeck/ui 0.9.0 → 0.10.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 (38) hide show
  1. package/README.md +44 -3
  2. package/build/index.d.mts +762 -21
  3. package/build/index.mjs +3245 -348
  4. package/build/index.mjs.map +1 -1
  5. package/package.json +5 -4
  6. package/src/components/agent/CodeEditor.tsx +300 -0
  7. package/src/components/agent/Composer.tsx +379 -56
  8. package/src/components/agent/ContextDialog.tsx +99 -0
  9. package/src/components/agent/EditorTabs.tsx +165 -0
  10. package/src/components/agent/FileTree.tsx +287 -0
  11. package/src/components/agent/FileViewer.tsx +148 -0
  12. package/src/components/agent/HostFilesDialog.tsx +218 -0
  13. package/src/components/agent/McpDialog.tsx +363 -0
  14. package/src/components/agent/ModelSelect.tsx +34 -6
  15. package/src/components/agent/PermissionModeSelect.tsx +99 -22
  16. package/src/components/agent/PermissionPrompt.tsx +72 -6
  17. package/src/components/agent/PromptTokenText.tsx +39 -0
  18. package/src/components/agent/SessionEmptyState.tsx +65 -0
  19. package/src/components/agent/SessionInfoDialog.tsx +163 -0
  20. package/src/components/agent/SessionPanel.tsx +379 -40
  21. package/src/components/agent/SessionWorkspace.tsx +282 -0
  22. package/src/components/agent/SkillsDialog.tsx +195 -0
  23. package/src/components/agent/StatusBar.tsx +85 -18
  24. package/src/components/agent/ToolCallCard.tsx +80 -4
  25. package/src/components/agent/Transcript.tsx +66 -17
  26. package/src/components/agent/UsageDialog.tsx +168 -0
  27. package/src/components/prompt-area/prompt-area-engine.ts +53 -0
  28. package/src/components/prompt-area/types.ts +15 -0
  29. package/src/components/prompt-area/use-prompt-area.ts +20 -0
  30. package/src/components/ui/CopyButton.tsx +8 -1
  31. package/src/components/ui/Dialog.tsx +92 -0
  32. package/src/components/ui/Menu.tsx +55 -0
  33. package/src/components/ui/Splitter.tsx +133 -0
  34. package/src/components/ui/Tooltip.tsx +22 -5
  35. package/src/index.ts +53 -1
  36. package/src/lib/clipboard.ts +56 -0
  37. package/src/lib/format.ts +48 -0
  38. package/src/lib/tool-icon.ts +74 -0
package/build/index.d.mts CHANGED
@@ -1,16 +1,20 @@
1
1
  import * as _$react from "react";
2
- import { ButtonHTMLAttributes, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from "react";
2
+ import { ButtonHTMLAttributes, CSSProperties, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactElement, ReactNode, Ref, TextareaHTMLAttributes } from "react";
3
3
  import { VariantProps } from "class-variance-authority";
4
4
  import { ClassValue } from "clsx";
5
5
  import * as _$_base_ui_react_select0 from "@base-ui/react/select";
6
6
  import { Select as Select$1 } from "@base-ui/react/select";
7
+ import { LucideIcon } from "lucide-react";
7
8
  import * as _$_base_ui_react_alert_dialog0 from "@base-ui/react/alert-dialog";
8
9
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
10
+ import { Menu as Menu$1 } from "@base-ui/react/menu";
11
+ import * as _$_base_ui_react_dialog0 from "@base-ui/react/dialog";
12
+ import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
9
13
  import * as _$_base_ui_react_tooltip0 from "@base-ui/react/tooltip";
10
14
  import { Tooltip } from "@base-ui/react/tooltip";
11
15
  import { toast } from "sonner";
12
- import { ModelOption, PermissionMode, PermissionRequest, QuestionBehavior, SessionInfo, SessionStatus, SlashCommandInfo, UserQuestion } from "@workerdeck/protocol";
13
- import { TranscriptItem, TranscriptState } from "@workerdeck/react";
16
+ import { ContextUsage, ModelOption, PermissionMode, PermissionRequest, ProfileEngine, QuestionBehavior, RateLimitInfo, SessionInfo, SessionStatus, SkillInfo, SlashCommandInfo, UserQuestion } from "@workerdeck/protocol";
17
+ import { ConnectionState, OpenFile, TranscriptItem, TranscriptState, UseAttachmentsResult, UseHostFileSearchResult, UseHostFileTreeResult } from "@workerdeck/react";
14
18
  import * as _$class_variance_authority_types0 from "class-variance-authority/types";
15
19
  import { WorkerDeckClient } from "@workerdeck/client";
16
20
 
@@ -80,16 +84,65 @@ declare const AlertDialogContent: FunctionComponent<AlertDialog$1.Popup.Props>;
80
84
  declare const AlertDialogTitle: FunctionComponent<AlertDialog$1.Title.Props>;
81
85
  declare const AlertDialogDescription: FunctionComponent<AlertDialog$1.Description.Props>;
82
86
  //#endregion
87
+ //#region src/components/ui/Menu.d.ts
88
+ declare const Menu: <Payload>(props: Menu$1.Root.Props<Payload>) => _$react.JSX.Element;
89
+ declare const MenuTrigger: Menu$1.Trigger;
90
+ declare const MenuContent: FunctionComponent<Menu$1.Popup.Props & Pick<Menu$1.Positioner.Props, 'align' | 'side' | 'sideOffset'>>;
91
+ declare const MenuItem: FunctionComponent<Menu$1.Item.Props & {
92
+ destructive?: boolean;
93
+ }>;
94
+ declare const MenuSeparator: FunctionComponent<Menu$1.Separator.Props>;
95
+ //#endregion
96
+ //#region src/components/ui/Dialog.d.ts
97
+ declare const Dialog: typeof Dialog$1.Root;
98
+ declare const DialogTrigger: Dialog$1.Trigger;
99
+ declare const DialogClose: _$react.ForwardRefExoticComponent<Omit<_$_base_ui_react_dialog0.DialogCloseProps, "ref"> & _$react.RefAttributes<HTMLButtonElement>>;
100
+ /**
101
+ * A dismissible panel, sized for reading rather than confirming — the web
102
+ * counterpart of the iOS app's detail sheets (context, usage, session info, MCP).
103
+ *
104
+ * Taller than {@link AlertDialogContent} and scrollable inside, because these
105
+ * carry lists whose length is the engine's business, not the layout's.
106
+ */
107
+ declare const DialogContent: FunctionComponent<Dialog$1.Popup.Props & {
108
+ size?: 'sm' | 'md' | 'lg';
109
+ }>;
110
+ /** Title row with the close button, pinned above the scrolling body. */
111
+ declare const DialogHeader: FunctionComponent<{
112
+ title: string;
113
+ description?: string; /** Rendered between the title and the close button. */
114
+ actions?: React.ReactNode;
115
+ }>;
116
+ /** The scrolling region under the header. */
117
+ declare const DialogBody: FunctionComponent<React.HTMLAttributes<HTMLDivElement>>;
118
+ /** A label/value row — the shape every one of these panels is mostly made of. */
119
+ declare const DialogRow: FunctionComponent<{
120
+ label: string;
121
+ children: React.ReactNode;
122
+ mono?: boolean;
123
+ }>;
124
+ //#endregion
83
125
  //#region src/components/ui/Tooltip.d.ts
84
126
  declare const TooltipProvider: _$react.FC<_$_base_ui_react_tooltip0.TooltipProviderProps>;
85
127
  declare const TooltipContent: FunctionComponent<Tooltip.Popup.Props & Pick<Tooltip.Positioner.Props, 'side' | 'sideOffset'>>;
86
- /** Convenience wrapper: <Tip content="..."><Button/></Tip> */
128
+ /**
129
+ * Convenience wrapper: `<Tip content="..."><Button/></Tip>`.
130
+ *
131
+ * Pass `render` when the trigger must *be* an element you already have — a tab, a
132
+ * row — rather than something wrapped in a span. The default span is fine beside
133
+ * a button but would break any layout that styles its own children (a flex tab
134
+ * strip gets an extra box between the container and its items).
135
+ */
87
136
  declare function Tip({
88
137
  content,
138
+ render,
139
+ side,
89
140
  children
90
141
  }: {
91
142
  content: ReactNode;
92
- children: ReactNode;
143
+ render?: ReactElement;
144
+ side?: 'top' | 'right' | 'bottom' | 'left';
145
+ children?: ReactNode;
93
146
  }): _$react.JSX.Element;
94
147
  //#endregion
95
148
  //#region src/components/ui/Sonner.d.ts
@@ -132,6 +185,57 @@ declare function CodeBlock({
132
185
  className
133
186
  }: CodeBlockProps): _$react.JSX.Element;
134
187
  //#endregion
188
+ //#region src/components/ui/Splitter.d.ts
189
+ interface SplitterProps {
190
+ /**
191
+ * ARIA's sense of the word: a `vertical` splitter is a vertical bar between
192
+ * two side-by-side panes, and it resizes a **width**. A `horizontal` one sits
193
+ * between stacked panes and resizes a **height**.
194
+ */
195
+ orientation: 'vertical' | 'horizontal';
196
+ /** Current size of the pane this splitter controls, in pixels. */
197
+ value: number;
198
+ onValueChange: (value: number) => void;
199
+ min: number;
200
+ max: number;
201
+ /** Keyboard step. */
202
+ step?: number;
203
+ /** Set when dragging the splitter *away* from the origin should shrink the
204
+ * controlled pane — i.e. the pane is on the right or the bottom. */
205
+ inverted?: boolean;
206
+ /** Required: "Resize" alone does not say which of two splitters this is. */
207
+ 'aria-label': string;
208
+ className?: string;
209
+ }
210
+ /**
211
+ * A draggable pane divider.
212
+ *
213
+ * Hand-rolled rather than depended on: `@base-ui/react` ships no splitter, the
214
+ * behaviour is a hundred lines of pointer events, and this repo's instinct at
215
+ * this layer is to own it (the composer is vendored for the same reason).
216
+ *
217
+ * Pointer capture is what makes it survive a fast drag — without it the pointer
218
+ * leaves the 5px bar within a frame and the moves go to whatever is underneath,
219
+ * which for this layout is an iframe-free but still selection-happy code pane.
220
+ * The drag origin is captured on pointerdown and every move is measured against
221
+ * it, so the pane cannot drift relative to the cursor over a long drag the way
222
+ * per-move deltas do once clamping is involved.
223
+ *
224
+ * Keyboard-operable and announced as a separator, because a pane you can only
225
+ * size by dragging is a pane some people cannot size.
226
+ */
227
+ declare function Splitter({
228
+ orientation,
229
+ value,
230
+ onValueChange,
231
+ min,
232
+ max,
233
+ step,
234
+ inverted,
235
+ 'aria-label': label,
236
+ className
237
+ }: SplitterProps): _$react.JSX.Element;
238
+ //#endregion
135
239
  //#region src/components/ui/ProgressRing.d.ts
136
240
  interface ProgressRingProps {
137
241
  /** Filled share, 0–100 (clamped). */
@@ -235,6 +339,21 @@ type TriggerConfig = {
235
339
  * Return the display text for the chip, or void to use `suggestion.label`.
236
340
  */
237
341
  onSelect?: (suggestion: TriggerSuggestion) => string | void;
342
+ /**
343
+ * For 'dropdown' mode: opt a suggestion out of becoming a chip.
344
+ *
345
+ * Return a string and the trigger's range is replaced with that **plain,
346
+ * editable text** — the trigger character included — with the caret left at
347
+ * its end. Return undefined and the suggestion resolves to a chip as usual,
348
+ * so one dropdown can mix both kinds.
349
+ *
350
+ * For suggestions that are a typing aid rather than a token: something the
351
+ * user is meant to finish and edit, where a chip would falsely promise the
352
+ * host parses it back out. Takes precedence over `onSelect`, which is not
353
+ * called for a text-resolved suggestion (there is no chip to label), and
354
+ * `onChipAdd` does not fire either.
355
+ */
356
+ insertAsText?: (suggestion: TriggerSuggestion) => string | undefined;
238
357
  /**
239
358
  * For 'callback' and 'launch' modes: called when the trigger is activated.
240
359
  * Receives the full input text and cursor position. For 'launch' it fires on
@@ -581,14 +700,33 @@ declare function getChipsByTrigger(segments: Segment[], trigger: string): ChipSe
581
700
  interface SessionPanelProps {
582
701
  client: WorkerDeckClient;
583
702
  sessionId: string | undefined;
584
- /** Optional slot rendered at the top, above the status bar. */
585
- header?: ReactNode;
703
+ /**
704
+ * Optional slot rendered at the top, above the status bar.
705
+ *
706
+ * Pass a **function** to take the session-actions (`⋯`) menu into your own
707
+ * chrome: it is called with the menu element, and wherever you put it is
708
+ * where it lives — the status bar then renders without it, so it never
709
+ * appears twice. Pass a plain node (or nothing) and the menu stays in the
710
+ * status bar's trailing slot.
711
+ *
712
+ * The seam exists because the menu can only be *built* here — it needs the
713
+ * capability record, the host-file verdict and the panel's own dialog state —
714
+ * but an embedder with a real header usually wants it up there with the rest
715
+ * of the session's controls, not stranded on the status line.
716
+ */
717
+ header?: ReactNode | ((slots: {
718
+ actions: ReactNode;
719
+ }) => ReactNode);
586
720
  className?: string;
587
721
  }
588
722
  /**
589
723
  * The all-in-one embeddable session surface: status bar, streaming transcript,
590
724
  * permission prompts, composer. Attaches via useClaudeSession; remount (key) to switch
591
725
  * sessions.
726
+ *
727
+ * Every affordance is gated on the session's **capability record** rather than on
728
+ * the engine name — an absent capability hides the control instead of offering
729
+ * one that can only fail.
592
730
  */
593
731
  declare function SessionPanel({
594
732
  client,
@@ -597,6 +735,197 @@ declare function SessionPanel({
597
735
  className
598
736
  }: SessionPanelProps): _$react.JSX.Element;
599
737
  //#endregion
738
+ //#region src/components/agent/SessionWorkspace.d.ts
739
+ interface SessionWorkspaceProps {
740
+ client: WorkerDeckClient;
741
+ sessionId: string | undefined;
742
+ /** Passed straight through to {@link SessionPanel} — including the render-prop
743
+ * form that claims the session-actions menu. */
744
+ header?: SessionPanelProps['header'];
745
+ /** Rail width in pixels on first render. */
746
+ defaultRailWidth?: number;
747
+ /** Start with the file rail collapsed even on a wide viewport. */
748
+ defaultRailCollapsed?: boolean;
749
+ className?: string;
750
+ }
751
+ /**
752
+ * A VS Code-shaped workspace around a live session: file tree on the left, open
753
+ * files above, the agent below.
754
+ *
755
+ * **Strictly additive.** {@link SessionPanel} is untouched and still the whole
756
+ * session surface on its own — an embedder picks one or the other, and one that
757
+ * has its own file tree keeps using the panel.
758
+ *
759
+ * Two things here are load-bearing and easy to break:
760
+ *
761
+ * 1. **The editor region is absent from the layout when nothing is open**, not
762
+ * collapsed to zero height. A zero-height pane leaves a draggable splitter and
763
+ * parks the composer at an odd offset; absence is what makes the agent's
764
+ * "claims the full column" state actually look like the panel alone.
765
+ * 2. **`SessionPanel` keeps its position in the tree across that transition.** It
766
+ * holds the WebSocket attach and the entire transcript, so moving it between
767
+ * parents — or wrapping it conditionally — would remount it and drop the
768
+ * session's rendered history on the floor the first time someone opens a file.
769
+ * The conditional children before it are `? :` expressions that leave a null in
770
+ * their slot, which is exactly what keeps its index stable.
771
+ */
772
+ declare function SessionWorkspace({
773
+ client,
774
+ sessionId,
775
+ header,
776
+ defaultRailWidth,
777
+ defaultRailCollapsed,
778
+ className
779
+ }: SessionWorkspaceProps): _$react.JSX.Element;
780
+ //#endregion
781
+ //#region src/components/agent/FileTree.d.ts
782
+ interface FileTreeProps {
783
+ /** Tree state from `useHostFileTree` — this component holds none of its own. */
784
+ tree: UseHostFileTreeResult;
785
+ /** Optional search from `useHostFileSearch`; omit and the box is not offered. */
786
+ search?: UseHostFileSearchResult;
787
+ /** Path of the focused file, highlighted in the tree. */
788
+ activePath?: string;
789
+ onOpenFile: (path: string) => void;
790
+ /** Offered as a button in the header when given. */
791
+ onCollapse?: () => void;
792
+ style?: CSSProperties;
793
+ className?: string;
794
+ }
795
+ /**
796
+ * The workspace's left rail: an expandable tree of the session's project,
797
+ * with a search box over the same fuzzy route `@file` completion uses.
798
+ *
799
+ * Presentational by construction — every piece of state it renders comes from
800
+ * the hooks in `@workerdeck/react`, and the only thing it owns is the search
801
+ * query, which is the text in its own input.
802
+ *
803
+ * Searching replaces the tree with matches rather than filtering it: the route
804
+ * answers with paths from all over the project, and threading those back into
805
+ * tree positions would mean expanding a dozen directories to show six results.
806
+ */
807
+ declare function FileTree({
808
+ tree,
809
+ search,
810
+ activePath,
811
+ onOpenFile,
812
+ onCollapse,
813
+ style,
814
+ className
815
+ }: FileTreeProps): _$react.JSX.Element;
816
+ //#endregion
817
+ //#region src/components/agent/EditorTabs.d.ts
818
+ interface EditorTabsProps {
819
+ files: OpenFile[];
820
+ activePath?: string;
821
+ onActivate: (path: string) => void;
822
+ onClose: (path: string) => void;
823
+ className?: string;
824
+ }
825
+ /**
826
+ * The open-file tab strip.
827
+ *
828
+ * Hand-rolled rather than built on `@base-ui/react`'s `Tabs`: a VS Code tab
829
+ * carries a close button, and a `<button>` inside a `<button>` is invalid HTML —
830
+ * getting the primitive to render something else costs more than the roving
831
+ * tabindex it would have provided. So that part is here, explicitly, along with
832
+ * the two affordances that actually make a tab strip feel right: middle-click to
833
+ * close, and the active tab scrolling itself into view.
834
+ *
835
+ * Deliberately state-free. Which files are open, which is focused and what
836
+ * closing does are all decided by `useOpenFiles`.
837
+ */
838
+ declare function EditorTabs({
839
+ files,
840
+ activePath,
841
+ onActivate,
842
+ onClose,
843
+ className
844
+ }: EditorTabsProps): _$react.JSX.Element;
845
+ //#endregion
846
+ //#region src/components/agent/FileViewer.d.ts
847
+ interface FileViewerProps {
848
+ file: OpenFile | undefined;
849
+ /** From `/fs/roots`. False renders the editor read-only rather than letting
850
+ * someone type into a file this gateway will refuse to write. */
851
+ canWrite?: boolean;
852
+ onChange?: (path: string, content: string) => void;
853
+ onSave?: (path: string) => void;
854
+ /** Discard this tab's edits — local only, no re-read. */
855
+ onRevert?: (path: string) => void;
856
+ /** Take the version on disk, discarding this tab's edits. */
857
+ onReload?: (path: string) => void;
858
+ /** Take this tab's version, over whatever is on disk now. */
859
+ onOverwrite?: (path: string) => void;
860
+ onDismissConflict?: (path: string) => void;
861
+ className?: string;
862
+ }
863
+ /**
864
+ * The focused file: Monaco, plus the states a file can be in that are not
865
+ * "here is some text".
866
+ *
867
+ * No path row — the tab's tooltip carries the path and the size, and a line of
868
+ * monospace above every file is chrome that never earns its height.
869
+ */
870
+ declare function FileViewer({
871
+ file,
872
+ canWrite,
873
+ onChange,
874
+ onSave,
875
+ onRevert,
876
+ onReload,
877
+ onOverwrite,
878
+ onDismissConflict,
879
+ className
880
+ }: FileViewerProps): _$react.JSX.Element | null;
881
+ //#endregion
882
+ //#region src/components/agent/CodeEditor.d.ts
883
+ interface CodeEditorProps {
884
+ /** Absolute path — decides the language and identifies the model. */
885
+ path: string;
886
+ /** Text to show. Applied to the model when it differs from what is on screen,
887
+ * so an external reload lands without fighting the user's cursor. */
888
+ value: string;
889
+ onChange?: (value: string) => void;
890
+ /** Ctrl/Cmd+S. Wired inside Monaco because the editor swallows keydown. */
891
+ onSave?: () => void;
892
+ readOnly?: boolean;
893
+ className?: string;
894
+ }
895
+ /**
896
+ * Monaco — VS Code's own editor — behind a small React surface.
897
+ *
898
+ * Two deliberate choices, both about `@workerdeck/ui` being a **published
899
+ * library** rather than an app:
900
+ *
901
+ * 1. **Loaded on demand.** The `import()` is inside an effect, so Monaco is a
902
+ * separate chunk that arrives when someone first opens a file. A dashboard
903
+ * that never opens one never pays for it, and Monaco's ~90 language grammars
904
+ * are themselves lazy (each `registerLanguage` carries an `import()` loader),
905
+ * so opening a `.ts` file fetches the TypeScript grammar and nothing else.
906
+ * 2. **No `MonacoEnvironment` is configured here, and none is needed.** Workers
907
+ * in a library become every embedder's bootstrapping problem, and
908
+ * `packages/web` ships prebuilt static files at a domain root, which is
909
+ * exactly where hardcoded worker URLs break. The editor is configured so it
910
+ * never asks for one: `wordBasedSuggestions` and `quickSuggestions` off,
911
+ * no diff editor. A host that wants the worker-backed language services
912
+ * (TypeScript IntelliSense, JSON schema validation) sets `MonacoEnvironment`
913
+ * itself before the first file is opened — Monaco is a singleton and nothing
914
+ * here fights that.
915
+ *
916
+ * One model per path, kept across tab switches, so undo history and view state
917
+ * survive clicking away and back — which is most of what makes tabs feel like
918
+ * tabs rather than like re-opening a file.
919
+ */
920
+ declare function CodeEditor({
921
+ path,
922
+ value,
923
+ onChange,
924
+ onSave,
925
+ readOnly,
926
+ className
927
+ }: CodeEditorProps): _$react.JSX.Element;
928
+ //#endregion
600
929
  //#region src/components/agent/Transcript.d.ts
601
930
  interface TranscriptProps {
602
931
  state: TranscriptState;
@@ -607,12 +936,20 @@ interface TranscriptProps {
607
936
  * `(id) => client.attachmentUrl(sessionId, id)`. Same-origin and
608
937
  * cookie-authenticated, which is what lets an `<img src>` render one. */
609
938
  attachmentUrl?: (attachmentId: string) => string;
939
+ /** Whether this gateway serves `@file` search here — the empty state must not
940
+ * advertise an affordance the composer doesn't have. */
941
+ canBrowseFiles?: boolean;
942
+ /** Reads a host file as a data URL, for tool calls whose output is a picture
943
+ * on the host (codex's `image_gen`). Omit and those cards name the path. */
944
+ hostImage?: (path: string) => Promise<string | undefined>;
610
945
  className?: string;
611
946
  }
612
947
  declare function Transcript({
613
948
  state,
614
949
  fileUrl,
615
950
  attachmentUrl,
951
+ canBrowseFiles,
952
+ hostImage,
616
953
  className
617
954
  }: TranscriptProps): _$react.JSX.Element;
618
955
  //#endregion
@@ -704,10 +1041,19 @@ type ToolCallItem = Extract<TranscriptItem, {
704
1041
  }>;
705
1042
  interface ToolCallCardProps {
706
1043
  item: ToolCallItem;
1044
+ /**
1045
+ * Reads a host file as a data URL, for tools whose output is a picture on the
1046
+ * host. Resolves `undefined` when the gateway won't serve that path — a
1047
+ * generated image saved outside the allowed roots (codex's default
1048
+ * `$CODEX_HOME/generated_images/`) is one, and the card then names the path
1049
+ * instead of showing it.
1050
+ */
1051
+ hostImage?: (path: string) => Promise<string | undefined>;
707
1052
  className?: string;
708
1053
  }
709
1054
  declare function ToolCallCard({
710
1055
  item,
1056
+ hostImage,
711
1057
  className
712
1058
  }: ToolCallCardProps): _$react.JSX.Element;
713
1059
  //#endregion
@@ -735,9 +1081,23 @@ declare function FileCard({
735
1081
  interface PermissionPromptProps {
736
1082
  request: PermissionRequest;
737
1083
  onApprove: (requestId: string) => void;
738
- onDeny: (requestId: string, message?: string) => void;
1084
+ /** `message` is fed back to the agent, which can then try something else;
1085
+ * `interrupt` also stops the turn. */
1086
+ onDeny: (requestId: string, message?: string, interrupt?: boolean) => void;
739
1087
  className?: string;
740
1088
  }
1089
+ /**
1090
+ * Generic allow/deny prompt for a pending permission request.
1091
+ *
1092
+ * Three outcomes, not two: denying usually means "not that, try something else",
1093
+ * so plain Deny lets the turn continue (with an optional reason the agent reads)
1094
+ * while "Deny & stop" also interrupts.
1095
+ *
1096
+ * The heading is whatever the engine authored — `title`, else `displayName`.
1097
+ * Composing "wants to use {tool}" instead would be wrong for codex, where an
1098
+ * approval is usually an *escalation after a sandbox refusal* and the runner has
1099
+ * already written the sentence that says so.
1100
+ */
741
1101
  declare function PermissionPrompt({
742
1102
  request,
743
1103
  onApprove,
@@ -776,8 +1136,22 @@ declare function QuestionPrompt({
776
1136
  }: QuestionPromptProps): _$react.JSX.Element;
777
1137
  //#endregion
778
1138
  //#region src/components/agent/Composer.d.ts
1139
+ /** Files matching an `@` query, for the composer's file trigger. Structural so
1140
+ * the ui package doesn't have to reach for the protocol's `HostFileMatch`. */
1141
+ type ComposerFileMatch = {
1142
+ path: string;
1143
+ relative: string;
1144
+ };
1145
+ /** Imperative surface for panels that draft a message the user then finishes —
1146
+ * the skills dialog's "Use this skill". Nothing here sends. */
1147
+ type ComposerHandle = {
1148
+ /** Append plain text at the caret's end and focus, separating it from
1149
+ * whatever is already there. */
1150
+ insertText: (text: string) => void;
1151
+ };
779
1152
  interface ComposerProps {
780
- onSend: (text: string) => void;
1153
+ /** `attachmentIds` are the staged uploads, in the order they were picked. */
1154
+ onSend: (text: string, attachmentIds: string[]) => void;
781
1155
  onInterrupt: () => void;
782
1156
  busy: boolean;
783
1157
  /** Disable input entirely (session failed/closed). */
@@ -785,14 +1159,62 @@ interface ComposerProps {
785
1159
  placeholder?: string;
786
1160
  /** Slash commands offered as autocomplete; picked ones render as chips. */
787
1161
  commands?: SlashCommandInfo[];
788
- /** Left side of the toolbar row (mode selects, attachments, …). */
1162
+ /**
1163
+ * Skills offered under a **`$`** popover of their own — codex's sigil, kept
1164
+ * separate from `/` because the two behave differently. A skill is a typing
1165
+ * aid, not a command: picking one inserts editable text (the skill's own
1166
+ * `defaultPrompt` where it has one, else `$name`) and nothing is sent. No
1167
+ * engine parses `$skillname` as syntax, which is exactly why these can never
1168
+ * resolve to a chip the way `commands` do.
1169
+ */
1170
+ skills?: SkillInfo[];
1171
+ /** Host-file search behind the `@` trigger. Omit to leave `@` inert — a
1172
+ * gateway without host files has nothing to complete. */
1173
+ onSearchFiles?: (query: string, options: {
1174
+ signal: AbortSignal;
1175
+ }) => Promise<ComposerFileMatch[]>;
1176
+ /** Attachment staging (see `useAttachments`). Omit for a text-only composer. */
1177
+ attachments?: UseAttachmentsResult;
1178
+ /** Left side of the toolbar row (mode selects, …). */
789
1179
  toolbar?: ReactNode;
790
1180
  className?: string;
1181
+ ref?: Ref<ComposerHandle>;
791
1182
  }
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). */
1183
+ /**
1184
+ * What a picked skill types into the composer.
1185
+ *
1186
+ * The engine's own `defaultPrompt` when it declared one — it knows what its
1187
+ * skill wants to be asked — and otherwise `$name`, which is codex's native way
1188
+ * of referring to a skill in prompt text: its `skill-creator` documents the form
1189
+ * (`Use $skill-x at /path/to/skill-x to solve problem y`) and its own bundled
1190
+ * prompts are written that way ("Use $pdf to …"). Spelling it the way the engine
1191
+ * spells it beats paraphrasing into "Use the X skill to".
1192
+ *
1193
+ * Either way it ends in a space so the caret lands ready for the rest of the
1194
+ * sentence, and either way it is ordinary text: nothing here is submitted, and
1195
+ * nothing is parsed back out.
1196
+ */
1197
+ declare function skillPrompt(skill: SkillInfo): string;
1198
+ /**
1199
+ * Framed prompt input built on prompt-area's contentEditable.
1200
+ *
1201
+ * Three completions ride the same field and behave nothing alike. `/` is the
1202
+ * CLI's command list and `$` is the engine's skill list — both local, so they
1203
+ * filter completely and instantly; `@` is a search against the host filesystem,
1204
+ * debounced and abortable so a fast typist makes one request rather than eight.
1205
+ *
1206
+ * `/` and `$` are separate keys rather than one merged menu, and that mirrors
1207
+ * the engines themselves: codex completes skills on `$` and reserves `/` for
1208
+ * commands. The behaviours differ too — a command resolves to a **chip**,
1209
+ * because the CLI really does parse `/name` out of the message, while a skill
1210
+ * resolves to plain editable **text**, because no engine parses `$name` as
1211
+ * syntax; it is prose the model reads. Rendering them alike would promise
1212
+ * something that does not happen.
1213
+ *
1214
+ * Files can arrive three ways — the paperclip, a drop, or a paste — because on a
1215
+ * desktop all three are things people already do, and the upload starts the
1216
+ * moment one lands rather than at send time.
1217
+ */
796
1218
  declare function Composer({
797
1219
  onSend,
798
1220
  onInterrupt,
@@ -800,8 +1222,12 @@ declare function Composer({
800
1222
  disabled,
801
1223
  placeholder,
802
1224
  commands,
1225
+ skills,
1226
+ onSearchFiles,
1227
+ attachments,
803
1228
  toolbar,
804
- className
1229
+ className,
1230
+ ref
805
1231
  }: ComposerProps): _$react.JSX.Element;
806
1232
  //#endregion
807
1233
  //#region src/components/agent/ModelSelect.d.ts
@@ -833,21 +1259,43 @@ declare function ModelSelect({
833
1259
  //#endregion
834
1260
  //#region src/components/agent/PermissionModeSelect.d.ts
835
1261
  type PermissionModeMeta = {
836
- value: PermissionMode;
1262
+ value: PermissionMode; /** The name Claude Code itself uses. */
837
1263
  label: string;
1264
+ /** The chip form, for bars where the label shares a line with three other
1265
+ * things and "Bypass permissions" would eat half of it. */
1266
+ shortLabel: string; /** What the mode actually does — the CLI's own one-liners. */
838
1267
  description: string;
1268
+ icon: LucideIcon;
839
1269
  dangerous?: boolean;
840
1270
  };
841
- /** The modes surfaced across UI surfaces (session creation, in-session switcher). */
1271
+ /**
1272
+ * The modes surfaced across UI surfaces (session creation, in-session switcher),
1273
+ * ordered by how much of the approval gate they give away.
1274
+ *
1275
+ * Notably `default` is **"Manual"**: the wire value is `default`, but calling it
1276
+ * that in the UI conflates a real mode (ask me every time) with "whatever the
1277
+ * server picked", which is the one confusion a mode chip exists to avoid. The
1278
+ * naming, the icons and the summaries are shared with the iOS app on purpose —
1279
+ * the two surfaces should read as the same list.
1280
+ */
842
1281
  declare const PERMISSION_MODES: PermissionModeMeta[];
1282
+ declare const permissionModeMeta: (mode: PermissionMode) => PermissionModeMeta | undefined;
843
1283
  interface PermissionModeSelectProps {
844
1284
  /** The session's current mode (TranscriptState.permissionMode). */
845
1285
  mode?: PermissionMode;
846
1286
  onModeChange: (mode: PermissionMode) => void;
847
1287
  /** 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. */
1288
+ * vocabulary the other engines have no meaning for. Defaults to all of them;
1289
+ * pass the session's `capabilities.permissionModes`. */
850
1290
  modes?: readonly PermissionMode[];
1291
+ /**
1292
+ * Whether this session may be switched into `bypassPermissions` at all. The
1293
+ * CLI refuses unless the process was spawned for it, so a session that didn't
1294
+ * ask up front can never gain it. The row is shown disabled rather than hidden
1295
+ * — "you can't have this here" is a more useful answer than a row that
1296
+ * silently isn't there. `undefined` (an older server) offers it.
1297
+ */
1298
+ canBypass?: boolean;
851
1299
  /** 'toolbar' (default) is the composer's compact borderless trigger;
852
1300
  * 'form' is a standard field-sized Select for create/settings forms. */
853
1301
  variant?: 'toolbar' | 'form';
@@ -859,6 +1307,7 @@ declare function PermissionModeSelect({
859
1307
  mode,
860
1308
  onModeChange,
861
1309
  modes,
1310
+ canBypass,
862
1311
  variant,
863
1312
  disabled,
864
1313
  className
@@ -867,15 +1316,205 @@ declare function PermissionModeSelect({
867
1316
  //#region src/components/agent/StatusBar.d.ts
868
1317
  interface StatusBarProps {
869
1318
  state: TranscriptState;
870
- connected: boolean;
1319
+ /** @deprecated Pass {@link StatusBarProps.connection}; kept so an embedder
1320
+ * still handing over a boolean keeps working. */
1321
+ connected?: boolean;
1322
+ /** How the client is doing at reaching the gateway. A dropped socket wins the
1323
+ * status slot: the session status held over a dead socket is a stale reading,
1324
+ * and presenting it as a live one is the thing worth avoiding. */
1325
+ connection?: ConnectionState;
1326
+ /**
1327
+ * Where the gauges lead. Each one opens the panel that answers *its* question
1328
+ * — the two meters measure different things, so sending both to one "details"
1329
+ * list would be a detour every time. Omit a handler and that gauge stays a
1330
+ * read-only tooltip.
1331
+ */
1332
+ onOpenStatus?: () => void;
1333
+ onOpenContext?: () => void;
1334
+ onOpenUsage?: () => void;
1335
+ /** Trailing slot — the session-actions menu, in the panel's top-right. */
1336
+ actions?: ReactNode;
871
1337
  className?: string;
872
1338
  }
873
1339
  declare function StatusBar({
874
1340
  state,
875
1341
  connected,
1342
+ connection,
1343
+ onOpenStatus,
1344
+ onOpenContext,
1345
+ onOpenUsage,
1346
+ actions,
876
1347
  className
877
1348
  }: StatusBarProps): _$react.JSX.Element;
878
1349
  //#endregion
1350
+ //#region src/components/agent/ContextDialog.d.ts
1351
+ interface ContextDialogProps {
1352
+ usage?: ContextUsage;
1353
+ open: boolean;
1354
+ onOpenChange: (open: boolean) => void;
1355
+ }
1356
+ /**
1357
+ * What is in the model's context window right now, category by category.
1358
+ *
1359
+ * One of the three panels the status bar opens. Context, usage and session info
1360
+ * are different questions asked at different moments, so they are different
1361
+ * screens rather than one "details" list you scroll past two answers to reach.
1362
+ */
1363
+ declare function ContextDialog({
1364
+ usage,
1365
+ open,
1366
+ onOpenChange
1367
+ }: ContextDialogProps): _$react.JSX.Element;
1368
+ //#endregion
1369
+ //#region src/components/agent/UsageDialog.d.ts
1370
+ interface UsageDialogProps {
1371
+ /** Windows in reading order — session, weekly, then per-model weeklies. */
1372
+ rateLimits: Array<{
1373
+ key: string;
1374
+ info: RateLimitInfo;
1375
+ }>;
1376
+ /** claude.ai plan behind the windows ('max', 'pro', …), when there is one. */
1377
+ subscriptionType?: string;
1378
+ engine: ProfileEngine;
1379
+ totalCostUsd: number;
1380
+ /** Local receipt time of the last window update. `rate_limit` events are one
1381
+ * per turn at best, so a stale reading is normal and worth saying out loud. */
1382
+ updatedAt?: number;
1383
+ open: boolean;
1384
+ onOpenChange: (open: boolean) => void;
1385
+ }
1386
+ /**
1387
+ * The plan's rate-limit windows, spelled out: how much of each is used, how that
1388
+ * compares to the pace that would spend the window exactly, and when it resets.
1389
+ *
1390
+ * The pace marker is the point. A bar alone says "17% used", which is only
1391
+ * alarming or reassuring once you know how far into the week you are — so every
1392
+ * window draws a tick at the elapsed share of its duration. Left of the tick is
1393
+ * under budget, right of it is ahead of it. The duration comes from the window
1394
+ * key (5h, 7d) because the CLI reports a reset time and a percentage and never a
1395
+ * duration; a window whose key doesn't say gets no marker rather than a guessed one.
1396
+ */
1397
+ declare function UsageDialog({
1398
+ rateLimits,
1399
+ subscriptionType,
1400
+ engine,
1401
+ totalCostUsd,
1402
+ updatedAt,
1403
+ open,
1404
+ onOpenChange
1405
+ }: UsageDialogProps): _$react.JSX.Element;
1406
+ //#endregion
1407
+ //#region src/components/agent/SessionInfoDialog.d.ts
1408
+ interface SessionInfoDialogProps {
1409
+ state: TranscriptState;
1410
+ client: WorkerDeckClient;
1411
+ sessionId: string | undefined;
1412
+ open: boolean;
1413
+ onOpenChange: (open: boolean) => void;
1414
+ }
1415
+ /**
1416
+ * What this session *is*: engine, profile, model, mode, where it runs, which
1417
+ * credentials it found, and the files it has handed over.
1418
+ *
1419
+ * The identity half of the session's facts. Context and usage have their own
1420
+ * panels — they change every turn and are consulted mid-run, while everything
1421
+ * here is fixed at creation and looked up once.
1422
+ */
1423
+ declare function SessionInfoDialog({
1424
+ state,
1425
+ client,
1426
+ sessionId,
1427
+ open,
1428
+ onOpenChange
1429
+ }: SessionInfoDialogProps): _$react.JSX.Element;
1430
+ //#endregion
1431
+ //#region src/components/agent/McpDialog.d.ts
1432
+ interface McpDialogProps {
1433
+ client: WorkerDeckClient;
1434
+ sessionId: string | undefined;
1435
+ open: boolean;
1436
+ onOpenChange: (open: boolean) => void;
1437
+ /**
1438
+ * Whether this engine can reconnect/enable/disable a server
1439
+ * (`EngineCapabilities.mcpServerActions`). False renders the panel read-only:
1440
+ * codex reports rich status but exposes no per-server action, and buttons
1441
+ * that 501 are worse than buttons that aren't there.
1442
+ */
1443
+ canManageServers?: boolean;
1444
+ }
1445
+ /**
1446
+ * The session's MCP servers, at the CLI's own `/mcp` depth: servers → one server
1447
+ * → its tools → one tool, with Reconnect / Enable / Disable where they apply.
1448
+ *
1449
+ * Two things vary by engine rather than being fixed here. **The actions** exist
1450
+ * only where the engine has them (`canManageServers`): codex reports rich status
1451
+ * but has no per-server reconnect or toggle, so its panel is read-only. And
1452
+ * **tool parameters** appear only where the engine reports a schema — codex
1453
+ * returns each tool's full JSON Schema, the Agent SDK returns none at all, so
1454
+ * the tool view either renders it or says why it can't, rather than leaving a
1455
+ * silent gap or claiming the absence is universal.
1456
+ */
1457
+ declare function McpDialog({
1458
+ client,
1459
+ sessionId,
1460
+ open,
1461
+ onOpenChange,
1462
+ canManageServers
1463
+ }: McpDialogProps): _$react.JSX.Element;
1464
+ //#endregion
1465
+ //#region src/components/agent/SkillsDialog.d.ts
1466
+ interface SkillsDialogProps {
1467
+ skills: SkillInfo[] | undefined;
1468
+ open: boolean;
1469
+ onOpenChange: (open: boolean) => void;
1470
+ /** Insert a skill's opening message into the composer, if the host offers
1471
+ * that. Omit and the dialog is read-only. */
1472
+ onUse?: (skill: SkillInfo) => void;
1473
+ }
1474
+ /**
1475
+ * What this session's engine can do beyond its own tools: the skills it found,
1476
+ * grouped by where they came from, with one drilled-down view each.
1477
+ *
1478
+ * The framing matters more here than in most panels. A skill is **not** a
1479
+ * command — the model decides to use one by reading its description, and there
1480
+ * is no wire syntax that invokes it. So this screen is a *discovery* surface,
1481
+ * and the one action it offers ("Use this skill") is honest about being a
1482
+ * drafting aid: it types a message for the operator to edit and send.
1483
+ *
1484
+ * Fed from the session's `skills` event rather than a REST route, because that
1485
+ * is the channel the engine refreshes on its own when a skill changes on disk.
1486
+ */
1487
+ declare function SkillsDialog({
1488
+ skills,
1489
+ open,
1490
+ onOpenChange,
1491
+ onUse
1492
+ }: SkillsDialogProps): _$react.JSX.Element;
1493
+ //#endregion
1494
+ //#region src/components/agent/HostFilesDialog.d.ts
1495
+ interface HostFilesDialogProps {
1496
+ client: WorkerDeckClient;
1497
+ /** The session's working directory — the browser is rooted here. */
1498
+ cwd: string | undefined;
1499
+ open: boolean;
1500
+ onOpenChange: (open: boolean) => void;
1501
+ }
1502
+ /**
1503
+ * Browse the project the session is working in.
1504
+ *
1505
+ * Deliberately rooted at the session's cwd rather than at the server's
1506
+ * `hostFiles.roots`: the roots are the *security* boundary (the server enforces
1507
+ * them on every request), but what someone wants while watching an agent is this
1508
+ * project's tree. Read-only — writing is a separate server opt-in and not
1509
+ * something a session viewer should be doing behind the agent's back.
1510
+ */
1511
+ declare function HostFilesDialog({
1512
+ client,
1513
+ cwd,
1514
+ open,
1515
+ onOpenChange
1516
+ }: HostFilesDialogProps): _$react.JSX.Element;
1517
+ //#endregion
879
1518
  //#region src/components/agent/SessionList.d.ts
880
1519
  interface SessionListItemProps {
881
1520
  session: SessionInfo;
@@ -906,6 +1545,59 @@ declare function SessionList({
906
1545
  className
907
1546
  }: SessionListProps): _$react.JSX.Element;
908
1547
  //#endregion
1548
+ //#region src/components/agent/SessionEmptyState.d.ts
1549
+ interface SessionEmptyStateProps {
1550
+ cwd?: string;
1551
+ /** Whether `/command` completion is live yet — the CLI reports its commands a
1552
+ * beat after the session starts, and promising a feature that isn't wired up
1553
+ * yet is worse than not mentioning it. */
1554
+ hasCommands?: boolean;
1555
+ /** Whether the engine has reported skills the `/` popover can offer. Its own
1556
+ * flag, not a variant of `hasCommands`: what `/` does differs — a command is
1557
+ * submitted, a skill is typed for you to edit — and an engine can have one
1558
+ * without the other. */
1559
+ hasSkills?: boolean;
1560
+ /** Whether this gateway serves `@file` search for the session's directory. */
1561
+ canBrowseFiles?: boolean;
1562
+ className?: string;
1563
+ }
1564
+ /**
1565
+ * What a session shows before it has said anything: where the agent is sitting,
1566
+ * and what the composer accepts beyond prose.
1567
+ *
1568
+ * Every hint is conditional on the affordance actually existing — an engine
1569
+ * without slash commands, or a gateway without host files, is not told about
1570
+ * them. Deliberately no project name (the header already carries it) and no
1571
+ * brand mark (its geometry is inlined in several places already and they are
1572
+ * meant to stay identical).
1573
+ */
1574
+ declare function SessionEmptyState({
1575
+ cwd,
1576
+ hasCommands,
1577
+ hasSkills,
1578
+ canBrowseFiles,
1579
+ className
1580
+ }: SessionEmptyStateProps): _$react.JSX.Element;
1581
+ //#endregion
1582
+ //#region src/components/agent/PromptTokenText.d.ts
1583
+ /**
1584
+ * A sent message, with its `@file` and `/command` tokens styled the way the CLI
1585
+ * writes them: monospace and tinted, no background — the bubble already has one,
1586
+ * and a second fill inside it reads as a button.
1587
+ *
1588
+ * Literal text, never markdown: what was typed is what was sent. The one pass
1589
+ * over it is this, so a message reads the same after sending as it did in the
1590
+ * composer. Two tokens, two meanings — a file is a reference, a command is an
1591
+ * action — so they are told apart by hue rather than by shape alone.
1592
+ */
1593
+ declare function PromptTokenText({
1594
+ text,
1595
+ className
1596
+ }: {
1597
+ text: string;
1598
+ className?: string;
1599
+ }): _$react.JSX.Element;
1600
+ //#endregion
909
1601
  //#region src/components/agent/status.d.ts
910
1602
  declare const STATUS_META: Record<SessionStatus, {
911
1603
  label: string;
@@ -916,6 +1608,36 @@ declare const STATUS_META: Record<SessionStatus, {
916
1608
  //#region src/lib/utils.d.ts
917
1609
  declare function cn(...inputs: ClassValue[]): string;
918
1610
  //#endregion
1611
+ //#region src/lib/clipboard.d.ts
1612
+ /**
1613
+ * Copy text to the clipboard, on origins where the modern API does not exist.
1614
+ *
1615
+ * `navigator.clipboard` is gated on a **secure context**: HTTPS, or localhost.
1616
+ * A WorkerDeck dashboard reached the way it is meant to be reached — plain HTTP
1617
+ * on a LAN address, from a laptop or a phone — is neither, so `navigator.clipboard`
1618
+ * is `undefined` there and touching `.writeText` throws outright. That is the
1619
+ * normal deployment, not an edge case, which is why this falls back rather than
1620
+ * feature-detecting into a disabled button.
1621
+ *
1622
+ * The fallback is `document.execCommand('copy')` over an off-screen textarea.
1623
+ * It is deprecated and it is also the only thing that works here; every browser
1624
+ * still implements it. Returns whether the text actually landed, so a caller can
1625
+ * avoid claiming success it did not have.
1626
+ */
1627
+ declare function copyText(value: string): Promise<boolean>;
1628
+ //#endregion
1629
+ //#region src/lib/tool-icon.d.ts
1630
+ /**
1631
+ * An icon per tool, so a transcript can be skimmed by shape rather than read.
1632
+ *
1633
+ * The same mapping the iOS app makes, in lucide's vocabulary rather than SF
1634
+ * Symbols — the two clients should be recognisably showing the same thing. An
1635
+ * unknown tool falls back to a wrench, and an MCP tool (`mcp__server__name`) to
1636
+ * the puzzle piece the MCP screens use, because "which server is this from" is
1637
+ * the useful thing to see at a glance.
1638
+ */
1639
+ declare function toolIcon(toolName: string): LucideIcon;
1640
+ //#endregion
919
1641
  //#region src/lib/format.d.ts
920
1642
  declare function formatCost(usd: number | undefined): string;
921
1643
  declare function formatDuration(ms: number): string;
@@ -925,8 +1647,27 @@ declare function formatBytes(bytes: number): string;
925
1647
  /** Countdown to an epoch-ms deadline: "2h 18m", "12m", "<1m"; "now" once passed. */
926
1648
  declare function formatCountdown(untilEpochMs: number, now?: number): string;
927
1649
  declare function formatRelativeTime(epochMs: number | undefined, now?: number): string;
1650
+ /**
1651
+ * Human label for a rate-limit window key, compact: 'five_hour' → "5h",
1652
+ * 'seven_day_opus' → "7d opus". The per-model suffix is an open set — the CLI
1653
+ * adds buckets as plans gain them — so it is rewritten rather than enumerated.
1654
+ */
1655
+ declare function formatRateLimitWindow(key: string): string;
1656
+ /** The same key spelled out, where there is room: 'five_hour' → "5-hour
1657
+ * session", 'seven_day_fable' → "Weekly · Fable". */
1658
+ declare function formatRateLimitWindowLong(key: string): string;
1659
+ /**
1660
+ * How long a rate-limit window is, in seconds — the denominator behind the pace
1661
+ * marker. Derived from the key rather than reported: the CLI sends a reset time
1662
+ * and a percentage, never a duration. `undefined` for a window whose key doesn't
1663
+ * say, and the marker is then simply not drawn rather than guessed.
1664
+ */
1665
+ declare function rateLimitWindowSeconds(key: string): number | undefined;
1666
+ /** "8 secs ago" / "3 mins ago" — a freshness line finer-grained than
1667
+ * {@link formatRelativeTime}, because a poll that just landed should say so. */
1668
+ declare function formatAgoPrecise(epochMs: number, now?: number): string;
928
1669
  /** Compact one-line preview of a tool input for card headers. */
929
1670
  declare function toolInputPreview(input: unknown, max?: number): string;
930
1671
  //#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 };
1672
+ export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, CodeEditor, type CodeEditorProps, 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, EditorTabs, type EditorTabsProps, FileCard, type FileCardProps, type FileDeliveredItem, FileTree, type FileTreeProps, FileViewer, type FileViewerProps, HostFilesDialog, type HostFilesDialogProps, Input, Loader, McpDialog, type McpDialogProps, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, 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, PromptTokenText, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionEmptyState, type SessionEmptyStateProps, SessionInfoDialog, type SessionInfoDialogProps, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, SessionWorkspace, type SessionWorkspaceProps, SkillsDialog, type SkillsDialogProps, Spinner, Splitter, type SplitterProps, StatusBar, type StatusBarProps, type TextSegment, Textarea, Tip, Toaster, ToolCallCard, type ToolCallCardProps, type ToolCallItem, TooltipContent, TooltipProvider, Transcript, type TranscriptProps, type TriggerConfig, type TriggerSuggestion, UsageDialog, type UsageDialogProps, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, getChipsByTrigger, hashtagTrigger, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState };
932
1673
  //# sourceMappingURL=index.d.mts.map