@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/README.md CHANGED
@@ -1,9 +1,17 @@
1
1
  # @workerdeck/ui
2
2
 
3
3
  Styled agent-control component library for WorkerDeck hosts: `SessionPanel` (status bar +
4
- streaming transcript + tool-call cards + permission prompts + composer), `SessionList`, and the
5
- underlying primitives (Button, Badge, Card, Select, AlertDialog, …). Built on **Tailwind v4 +
6
- Base UI + cva**, themed by CSS tokens with light/dark via `<html data-theme>`.
4
+ streaming transcript + tool-call cards + permission prompts + composer with attachments and
5
+ `@file` / `/command` completion, plus the panels behind it session info, context, plan usage,
6
+ MCP servers, project files), `SessionWorkspace` (a VS Code-shaped layout *around* that panel
7
+ file tree, editor tabs, Monaco — at `@workerdeck/ui/workspace`, so Monaco stays out of hosts that
8
+ don't want it), `SessionList`, and the underlying primitives (Button, Badge,
9
+ Card, Select, Dialog, AlertDialog, …). Built on **Tailwind v4 + Base UI + cva**, themed by CSS
10
+ tokens with light/dark via `<html data-theme>`.
11
+
12
+ Everything `SessionPanel` offers is gated on the session's **engine capability record**, so the
13
+ same component is correct for a Claude, Codex or provider session without the host branching:
14
+ a control the engine can't honor is absent rather than present-and-failing.
7
15
 
8
16
  The headless layer (`useClaudeSession`, transcript reducer) lives in `@workerdeck/react`;
9
17
  this package is the styling opinion on top.
@@ -57,6 +65,53 @@ const client = new WorkerDeckClient({ baseUrl: `${location.origin}/v1` })
57
65
  <SessionPanel key={sessionId} client={client} sessionId={sessionId} />
58
66
  ```
59
67
 
68
+ ### The workspace (optional)
69
+
70
+ `SessionWorkspace` wraps that same panel in a three-region layout — project tree on the left,
71
+ open files above, agent below — and is **strictly additive**: `SessionPanel` is untouched and
72
+ still complete on its own, so pick whichever fits. An app with its own file tree keeps the panel.
73
+
74
+ It lives at its **own entry point**, and Monaco is an **optional peer dependency** — install it
75
+ alongside `@workerdeck/ui` if you want the workspace, and skip both if you don't:
76
+
77
+ ```sh
78
+ npm install monaco-editor
79
+ ```
80
+
81
+ ```tsx
82
+ import { SessionWorkspace } from '@workerdeck/ui/workspace'
83
+
84
+ <SessionWorkspace key={sessionId} client={client} sessionId={sessionId} />
85
+ ```
86
+
87
+ It needs the gateway's host-filesystem routes (`hostFiles` in the server config); without them
88
+ the rail is simply absent and you get the panel. Editing additionally needs `hostFiles.write`,
89
+ which is a separate opt-in and defaults **off** — the editor reads `/fs/roots` and renders
90
+ read-only when it's not enabled. Saves are conditional on the hash the tab read, so a save that
91
+ collides with the agent's own edit is refused (409) and offered as a choice rather than silently
92
+ winning.
93
+
94
+ **If you bundle with Vite, you need one line** — the workspace uses Monaco, which reaches its
95
+ web workers with `new Worker(new URL(…, import.meta.url))`. Rollup resolves that at build time,
96
+ but Vite's dev dep-optimizer rewrites the package into `.vite/deps/` and breaks the relative URL;
97
+ Monaco then *silently* runs worker code on the main thread:
98
+
99
+ ```ts
100
+ // vite.config.ts
101
+ export default defineConfig({ optimizeDeps: { exclude: ['monaco-editor'] } })
102
+ ```
103
+
104
+ Monaco is loaded through a dynamic `import()`, so it costs nothing at runtime until a file is
105
+ opened. Our own dashboard additionally aliases away Monaco's four worker-backed language services
106
+ (TypeScript/JSON/CSS/HTML) — 8.8MB of build output for IntelliSense and schema validation, with
107
+ syntax highlighting unaffected — see `packages/web/vite.config.ts` if you want the same trade.
108
+
109
+ None of this reaches you through the root entry. That separation is why the workspace has its own
110
+ subpath rather than living in `@workerdeck/ui`: tree-shaking alone is not enough. Rollup does drop
111
+ `CodeEditor` from a `SessionPanel`-only bundle, but Vite resolves Monaco's worker URLs while
112
+ *transforming* the module — before tree-shaking runs — and emits ~9MB of worker assets that are
113
+ never retracted. Keeping Monaco unreachable from the root entry is what actually prevents that.
114
+
60
115
  Every component takes `className` and carries `data-slot` attributes for targeted overrides.
61
116
 
62
117
  `SessionPanel` is self-sufficient for errors: a `protocol_error` (the gateway or CLI refusing a
@@ -72,3 +127,26 @@ lose by forgetting a second mount isn't one.
72
127
  scoping — file an issue with your case.
73
128
  - Dark mode is driven **only** by `[data-theme='dark']` on the root element (the Tailwind
74
129
  `dark:` variant is remapped to it); `prefers-color-scheme` is not consulted at CSS level.
130
+ - The session surface centers its content at `--wd-content-max-w` (default `48rem`).
131
+ Embedders in narrow docks (a VS Code bottom panel, a drawer) set it to `100%` for
132
+ edge-to-edge content. Every component also carries `data-slot` attributes for targeted
133
+ overrides — e.g. `[data-slot='composer-hint']` is the "Enter to send" line, which a host
134
+ whose vertical space is precious can `display: none`.
135
+ - `SessionPanel` can hand its dialog surfaces to the embedder: `panelSurface: 'external'`
136
+ renders no dialogs and no `⋯` menu — every affordance that would open one calls
137
+ `onOpenPanel(panel)` instead, and `onVitals` streams the live readings (status, context,
138
+ rate limits, capabilities) those external surfaces need, so host chrome never has to
139
+ attach a second time (the tool bridge asks the first attached client). The VS Code
140
+ extension's sidebar sections are the reference consumer.
141
+ - `statusSurface: 'external'` is the separate opt-out for the **status bar itself**, for a host
142
+ whose chrome already has a status line (VS Code's window bar): the panel draws no bar and the
143
+ readings leave through `onVitals` as before. The two flags are independent, with one coupling
144
+ — the `⋯` menu lives in the bar's trailing slot, so `statusSurface: 'external'` alongside
145
+ `panelSurface: 'internal'` must pass a **function** `header` for the menu to land in.
146
+ Whatever draws the bar owes the panel's own rule: `SessionVitals.connection` wins the status
147
+ slot whenever it isn't `'live'`, because a session status held over a dropped socket is a
148
+ stale reading presented as a current one.
149
+ - `@workerdeck/ui/format` is a third entry point carrying the pure formatters (`45.2k`,
150
+ `2h 10m`) with no React in the graph — for a host that renders session readings outside
151
+ React, like an extension host drawing them into a window status bar, and wants them spelled
152
+ exactly as the panel spells them.
@@ -0,0 +1,319 @@
1
+ import * as _$react from "react";
2
+ import { ReactNode } from "react";
3
+ import { LucideIcon } from "lucide-react";
4
+ import { ModelOption, PermissionMode } from "@workerdeck/protocol";
5
+ import { ConnectionState, TranscriptState } from "@workerdeck/react";
6
+ import { WorkerDeckClient } from "@workerdeck/client";
7
+
8
+ //#region src/components/agent/PermissionModeSelect.d.ts
9
+ type PermissionModeMeta = {
10
+ value: PermissionMode; /** The name Claude Code itself uses. */
11
+ label: string;
12
+ /** The chip form, for bars where the label shares a line with three other
13
+ * things and "Bypass permissions" would eat half of it. */
14
+ shortLabel: string; /** What the mode actually does — the CLI's own one-liners. */
15
+ description: string;
16
+ icon: LucideIcon;
17
+ dangerous?: boolean;
18
+ };
19
+ /**
20
+ * The modes surfaced across UI surfaces (session creation, in-session switcher),
21
+ * ordered by how much of the approval gate they give away.
22
+ *
23
+ * Notably `default` is **"Manual"**: the wire value is `default`, but calling it
24
+ * that in the UI conflates a real mode (ask me every time) with "whatever the
25
+ * server picked", which is the one confusion a mode chip exists to avoid. The
26
+ * naming, the icons and the summaries are shared with the iOS app on purpose —
27
+ * the two surfaces should read as the same list.
28
+ */
29
+ declare const PERMISSION_MODES: PermissionModeMeta[];
30
+ declare const permissionModeMeta: (mode: PermissionMode) => PermissionModeMeta | undefined;
31
+ /** One offered mode as plain data — no icon, no React. What a host chrome
32
+ * outside the panel (a VS Code QuickPick) needs to draw the same list. */
33
+ type PermissionModeChoice = {
34
+ value: PermissionMode;
35
+ label: string;
36
+ description: string;
37
+ dangerous?: boolean;
38
+ /** Offered but unreachable: a session not started for bypass can never gain
39
+ * it, and saying so beats omitting the row. */
40
+ disabled?: boolean;
41
+ };
42
+ /**
43
+ * The modes this session may actually be switched into, with the reasons baked
44
+ * in — the same filtering {@link PermissionModeSelect} applies, so an embedder
45
+ * rendering its own picker cannot drift from the panel's.
46
+ */
47
+ declare function permissionModeChoices(modes?: readonly PermissionMode[], canBypass?: boolean): PermissionModeChoice[];
48
+ interface PermissionModeSelectProps {
49
+ /** The session's current mode (TranscriptState.permissionMode). */
50
+ mode?: PermissionMode;
51
+ onModeChange: (mode: PermissionMode) => void;
52
+ /** Restrict what is offered — most of {@link PERMISSION_MODES} is Claude Code
53
+ * vocabulary the other engines have no meaning for. Defaults to all of them;
54
+ * pass the session's `capabilities.permissionModes`. */
55
+ modes?: readonly PermissionMode[];
56
+ /**
57
+ * Whether this session may be switched into `bypassPermissions` at all. The
58
+ * CLI refuses unless the process was spawned for it, so a session that didn't
59
+ * ask up front can never gain it. The row is shown disabled rather than hidden
60
+ * — "you can't have this here" is a more useful answer than a row that
61
+ * silently isn't there. `undefined` (an older server) offers it.
62
+ */
63
+ canBypass?: boolean;
64
+ /** 'toolbar' (default) is the composer's compact borderless trigger;
65
+ * 'form' is a standard field-sized Select for create/settings forms. */
66
+ variant?: 'toolbar' | 'form';
67
+ disabled?: boolean;
68
+ className?: string;
69
+ }
70
+ /** Permission-mode switcher: compact in the composer toolbar, field-sized in forms. */
71
+ declare function PermissionModeSelect({
72
+ mode,
73
+ onModeChange,
74
+ modes,
75
+ canBypass,
76
+ variant,
77
+ disabled,
78
+ className
79
+ }: PermissionModeSelectProps): _$react.JSX.Element;
80
+ //#endregion
81
+ //#region src/components/agent/transcript-variant.d.ts
82
+ /**
83
+ * How the transcript draws a turn.
84
+ *
85
+ * - `cards` — the chat convention: bubbles, bordered tool cards, generous gaps.
86
+ * Right for a wide dashboard where the transcript is the page.
87
+ * - `lines` — one full-width line item per event, transparent, hover-highlit,
88
+ * with a glyph in a fixed left gutter. Right where vertical space is the
89
+ * scarce resource (a VS Code dock) and the terminal is the reference UX:
90
+ * nothing is boxed, the content and its marker carry the comprehension.
91
+ *
92
+ * A context rather than a prop chain because every row component needs it and
93
+ * only the transcript root knows it — and because `Message`/`ToolCallCard` are
94
+ * exported on their own, so an embedder composing them by hand gets the right
95
+ * treatment for free.
96
+ */
97
+ type TranscriptVariant = 'cards' | 'lines';
98
+ declare function TranscriptVariantProvider({
99
+ value,
100
+ children
101
+ }: {
102
+ value: TranscriptVariant;
103
+ children: ReactNode;
104
+ }): _$react.JSX.Element;
105
+ declare function useTranscriptVariant(): TranscriptVariant;
106
+ /**
107
+ * How much room the transcript gives each row.
108
+ *
109
+ * - `comfortable` — a blank line between messages, which is what the Claude Code
110
+ * CLI does and what the `lines` variant is trying to read like. The default:
111
+ * a transcript is prose before it is a table.
112
+ * - `compact` — rows tight against each other, for a dock where every line of
113
+ * vertical space is contested.
114
+ *
115
+ * Separate from the variant, and deliberately: they answer different questions.
116
+ * The variant decides *how a row is drawn* (boxed or not) and follows from the
117
+ * surface; density decides *how much air is around it* and is a preference the
118
+ * reader holds. Coupling them would mean a dock could not be roomy and a
119
+ * dashboard could not be dense.
120
+ */
121
+ type TranscriptDensity = 'comfortable' | 'compact';
122
+ declare function TranscriptDensityProvider({
123
+ value,
124
+ children
125
+ }: {
126
+ value: TranscriptDensity;
127
+ children: ReactNode;
128
+ }): _$react.JSX.Element;
129
+ declare function useTranscriptDensity(): TranscriptDensity;
130
+ //#endregion
131
+ //#region src/components/agent/SessionPanel.d.ts
132
+ interface SessionPanelProps {
133
+ client: WorkerDeckClient;
134
+ sessionId: string | undefined;
135
+ /**
136
+ * Optional slot rendered at the top, above the status bar.
137
+ *
138
+ * Pass a **function** to take the session-actions (`⋯`) menu into your own
139
+ * chrome: it is called with the menu element, and wherever you put it is
140
+ * where it lives — the status bar then renders without it, so it never
141
+ * appears twice. Pass a plain node (or nothing) and the menu stays in the
142
+ * status bar's trailing slot.
143
+ *
144
+ * The seam exists because the menu can only be *built* here — it needs the
145
+ * capability record, the host-file verdict and the panel's own dialog state —
146
+ * but an embedder with a real header usually wants it up there with the rest
147
+ * of the session's controls, not stranded on the status line.
148
+ */
149
+ header?: ReactNode | ((slots: {
150
+ actions: ReactNode;
151
+ }) => ReactNode);
152
+ /**
153
+ * Where the info/context/usage/MCP/skills/files surfaces live. `'internal'`
154
+ * (default) renders them as dialogs inside the panel. `'external'` renders
155
+ * NO dialogs and no `⋯` menu: every affordance that would open one calls
156
+ * {@link onOpenPanel} instead, so an embedder can host those surfaces in its
157
+ * own chrome (a VS Code sidebar, a drawer) and keep the panel purely a
158
+ * conversation surface.
159
+ */
160
+ panelSurface?: 'internal' | 'external';
161
+ /**
162
+ * Where the status bar lives. `'internal'` (default) draws it across the top
163
+ * of the panel. `'external'` draws none — the readings still leave through
164
+ * {@link onVitals}, so an embedder with a status line of its own (VS Code's
165
+ * window status bar) renders them there instead of stacking a second bar
166
+ * inside a panel that already sits in one.
167
+ *
168
+ * Deliberately independent of {@link panelSurface}: hosting the dialogs and
169
+ * hosting the bar are separate decisions. One coupling to know about — the
170
+ * `⋯` menu lives in the bar's trailing slot, so `statusSurface: 'external'`
171
+ * with `panelSurface: 'internal'` must pass a **function** {@link header} to
172
+ * take the menu, or it has nowhere left to go.
173
+ */
174
+ statusSurface?: 'internal' | 'external';
175
+ /** Where `panelSurface: 'external'` routes opens. Absent = the affordances
176
+ * (status-bar clicks, `/mcp`) become inert rather than half-working. */
177
+ onOpenPanel?: (panel: SessionSurfacePanel) => void;
178
+ /** Live session vitals, fired whenever they change — for embedders mirroring
179
+ * status/context/usage into chrome outside the panel (identity-stable via an
180
+ * internal ref, so an inline closure is fine). */
181
+ onVitals?: (vitals: SessionVitals) => void;
182
+ /**
183
+ * How the transcript draws a turn — `'cards'` (default) or `'lines'`, the
184
+ * space-efficient terminal treatment: no boxes, no bubbles, one full-width
185
+ * hover-highlit row per event behind a gutter glyph. An embedder in a dock
186
+ * (the VS Code panel) wants `'lines'`; a full-width dashboard usually doesn't.
187
+ */
188
+ transcriptVariant?: TranscriptVariant;
189
+ /**
190
+ * How much air the transcript gives each row — `'comfortable'` (default: a
191
+ * blank line between messages, as the Claude Code CLI leaves) or `'compact'`
192
+ * (rows tight against one another). Independent of `transcriptVariant`: the
193
+ * variant follows from the surface, density is the reader's preference, and a
194
+ * dock is allowed to be roomy.
195
+ */
196
+ transcriptDensity?: TranscriptDensity;
197
+ /**
198
+ * Where the session's own controls — model and permission mode — live.
199
+ * `'internal'` (default) draws them in the composer's toolbar row.
200
+ * `'external'` draws neither, and the composer collapses to a single line
201
+ * with its attach/send buttons beside the field: the embedder renders the
202
+ * pickers in its own chrome (VS Code's status bar, where a click opens a
203
+ * QuickPick) and drives them through {@link onControls}.
204
+ *
205
+ * The options themselves ride {@link SessionVitals} — an embedder must not
206
+ * attach a second time to learn what the models are.
207
+ */
208
+ controlsSurface?: 'internal' | 'external';
209
+ /**
210
+ * Handed the session's setters once the panel is live, and `undefined` on
211
+ * unmount. The counterpart to `controlsSurface: 'external'`: vitals carry the
212
+ * readings out, this carries the commands back in. Stable identity — safe to
213
+ * stash in a ref.
214
+ */
215
+ onControls?: (controls: SessionControls | undefined) => void;
216
+ /**
217
+ * Click anywhere the panel isn't already doing something and the caret lands
218
+ * in the composer — the terminal/chat convention, and what a docked panel
219
+ * wants: the field is why the panel is focussed at all.
220
+ *
221
+ * Only dead space. A click that hits a control (a tool row expanding, a link,
222
+ * a button) or that ends a text selection is that action, not a request for
223
+ * the input. Off by default: a full-page surface has plenty of dead space that
224
+ * means nothing in particular.
225
+ */
226
+ focusComposerOnClick?: boolean;
227
+ /**
228
+ * What this session looked like when it was last looked at: how many
229
+ * transcript items had been seen, and when. Present and behind the current
230
+ * transcript → **catch-up**: a recap row at the boundary, everything above it
231
+ * dimmed, and a bar offering to jump there or to dismiss.
232
+ *
233
+ * The embedder owns the watermark because only it knows what "looked at"
234
+ * means in its own chrome — a hidden dock is not being read. The panel reports
235
+ * the number to remember through `SessionVitals.itemCount`.
236
+ */
237
+ unseen?: {
238
+ itemCount: number;
239
+ since?: number;
240
+ };
241
+ className?: string;
242
+ }
243
+ /** What an embedder needs to *change* a session it doesn't own the attach for. */
244
+ type SessionControls = {
245
+ setModel: (model?: string) => void;
246
+ setPermissionMode: (mode: PermissionMode) => void;
247
+ interrupt: () => void;
248
+ /**
249
+ * Put the caret in the composer.
250
+ *
251
+ * For an embedder whose own chrome is how you arrive at a session — clicking a
252
+ * row in VS Code's sidebar — where revealing the panel and being able to type
253
+ * are the same intention. The panel cannot infer it: from in here, a session
254
+ * appearing looks identical whether someone asked for it or it was restored.
255
+ */
256
+ focusComposer: () => void;
257
+ };
258
+ /** The panels the session surface can raise. One at a time, by identity: a bag
259
+ * of booleans would let two open at once. */
260
+ type SessionSurfacePanel = 'info' | 'context' | 'usage' | 'mcp' | 'files' | 'skills';
261
+ /** What {@link SessionPanelProps.onVitals} reports: the live readings a host
262
+ * chrome outside the panel would otherwise have to attach a second time for —
263
+ * which the tool bridge forbids (it asks the first attached client). */
264
+ type SessionVitals = {
265
+ status: TranscriptState['status'];
266
+ /**
267
+ * How the client is reaching the gateway. Load-bearing for a host rendering
268
+ * these outside the panel: `status` is the last thing the session *said*, and
269
+ * over a dropped socket that is a stale reading. The panel's own bar gives
270
+ * the connection the status slot when it isn't `'live'` for exactly this
271
+ * reason — an embedder showing `status` alone would present stale as current.
272
+ */
273
+ connection: ConnectionState;
274
+ engine: TranscriptState['engine'];
275
+ capabilities: TranscriptState['capabilities'];
276
+ model: string | undefined;
277
+ /** The models this session can switch to — the panel's own list, so an
278
+ * external picker offers exactly what the internal one would. */
279
+ models: ModelOption[];
280
+ permissionMode: TranscriptState['permissionMode'];
281
+ /** The modes it can switch into, already filtered by the capability record
282
+ * and the session's bypass grant (see `permissionModeChoices`). */
283
+ permissionModes: PermissionModeChoice[];
284
+ cwd: TranscriptState['cwd'];
285
+ contextUsage: TranscriptState['contextUsage'];
286
+ rateLimits: TranscriptState['rateLimits'];
287
+ /** How many transcript rows exist right now — the number an embedder stores
288
+ * as its "seen" watermark while the panel is actually on screen, and compares
289
+ * against later to know what is new. */
290
+ itemCount: number;
291
+ };
292
+ /**
293
+ * The all-in-one embeddable session surface: status bar, streaming transcript,
294
+ * permission prompts, composer. Attaches via useClaudeSession; remount (key) to switch
295
+ * sessions.
296
+ *
297
+ * Every affordance is gated on the session's **capability record** rather than on
298
+ * the engine name — an absent capability hides the control instead of offering
299
+ * one that can only fail.
300
+ */
301
+ declare function SessionPanel({
302
+ client,
303
+ sessionId,
304
+ header,
305
+ panelSurface,
306
+ statusSurface,
307
+ onOpenPanel,
308
+ onVitals,
309
+ transcriptVariant,
310
+ transcriptDensity,
311
+ controlsSurface,
312
+ onControls,
313
+ focusComposerOnClick,
314
+ unseen,
315
+ className
316
+ }: SessionPanelProps): _$react.JSX.Element;
317
+ //#endregion
318
+ export { permissionModeChoices as _, SessionVitals as a, TranscriptVariant as c, useTranscriptVariant as d, PERMISSION_MODES as f, PermissionModeSelectProps as g, PermissionModeSelect as h, SessionSurfacePanel as i, TranscriptVariantProvider as l, PermissionModeMeta as m, SessionPanel as n, TranscriptDensity as o, PermissionModeChoice as p, SessionPanelProps as r, TranscriptDensityProvider as s, SessionControls as t, useTranscriptDensity as u, permissionModeMeta as v };
319
+ //# sourceMappingURL=SessionPanel-Dy9lQrOV.d.mts.map