@workerdeck/ui 0.23.0 → 1.1.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 (145) hide show
  1. package/build/{SessionPanel-DUt2VzXG.mjs → SessionPanel-I5QSLLb0.mjs} +2266 -3459
  2. package/build/SessionPanel-I5QSLLb0.mjs.map +1 -0
  3. package/build/SessionPanel-yNO60Tzw.d.mts +151 -0
  4. package/build/format-C_lpFq0l.d.mts +16 -0
  5. package/build/format.d.mts +8 -76
  6. package/build/format.mjs +2 -2
  7. package/build/index.d.mts +291 -1695
  8. package/build/index.mjs +6 -301
  9. package/build/index.mjs.map +1 -1
  10. package/build/scoped.css +32 -23
  11. package/build/{status-BE-zg88x.mjs → status-Dm9INVTt.mjs} +17 -88
  12. package/build/status-Dm9INVTt.mjs.map +1 -0
  13. package/build/workspace.d.mts +8 -187
  14. package/build/workspace.mjs +13 -144
  15. package/build/workspace.mjs.map +1 -1
  16. package/package.json +24 -24
  17. package/src/components/agent/CodeEditor.tsx +31 -103
  18. package/src/components/agent/Composer.tsx +114 -333
  19. package/src/components/agent/ContextDialog.tsx +20 -41
  20. package/src/components/agent/ContextRing.tsx +6 -28
  21. package/src/components/agent/Conversation.tsx +21 -33
  22. package/src/components/agent/EditorTabs.tsx +39 -67
  23. package/src/components/agent/EngineIcon.tsx +29 -72
  24. package/src/components/agent/EntryIcon.tsx +16 -0
  25. package/src/components/agent/FileCard.tsx +10 -16
  26. package/src/components/agent/FileTree.tsx +52 -125
  27. package/src/components/agent/FileViewer.tsx +30 -60
  28. package/src/components/agent/HostFilesDialog.tsx +40 -69
  29. package/src/components/agent/Loader.tsx +3 -24
  30. package/src/components/agent/McpDialog.tsx +64 -137
  31. package/src/components/agent/Message.tsx +2 -21
  32. package/src/components/agent/ModelSelect.tsx +33 -62
  33. package/src/components/agent/PermissionModeSelect.tsx +21 -79
  34. package/src/components/agent/PermissionPrompt.tsx +59 -63
  35. package/src/components/agent/ProjectIcon.tsx +228 -93
  36. package/src/components/agent/PromptTokenText.tsx +10 -16
  37. package/src/components/agent/QuestionPrompt.tsx +43 -64
  38. package/src/components/agent/Reasoning.tsx +13 -16
  39. package/src/components/agent/Response.tsx +3 -9
  40. package/src/components/agent/Scrubber.tsx +31 -80
  41. package/src/components/agent/SessionBrowser.tsx +64 -243
  42. package/src/components/agent/SessionEmptyState.tsx +10 -40
  43. package/src/components/agent/SessionInfoDialog.tsx +46 -78
  44. package/src/components/agent/SessionItem.tsx +53 -320
  45. package/src/components/agent/SessionList.tsx +23 -39
  46. package/src/components/agent/SessionPanel.tsx +315 -996
  47. package/src/components/agent/SessionStatusIcon.tsx +14 -28
  48. package/src/components/agent/SessionSteps.tsx +34 -187
  49. package/src/components/agent/SessionWorkspace.tsx +104 -219
  50. package/src/components/agent/SkillsDialog.tsx +35 -80
  51. package/src/components/agent/StatusBar.tsx +51 -136
  52. package/src/components/agent/SubagentStrip.tsx +12 -77
  53. package/src/components/agent/ToolCallCard.tsx +94 -135
  54. package/src/components/agent/Transcript.tsx +103 -1288
  55. package/src/components/agent/TranscriptItemView.tsx +155 -0
  56. package/src/components/agent/TranscriptRows.tsx +418 -0
  57. package/src/components/agent/UsageDialog.tsx +7 -29
  58. package/src/components/agent/UsageMeters.tsx +18 -73
  59. package/src/components/agent/pulse.tsx +9 -32
  60. package/src/components/agent/scrubber-marks.ts +33 -103
  61. package/src/components/agent/status.ts +1 -5
  62. package/src/components/agent/tool-result-fetch.tsx +3 -25
  63. package/src/components/agent/tool-result-image.tsx +32 -111
  64. package/src/components/agent/transcript-rows.ts +41 -118
  65. package/src/components/agent/transcript-variant.tsx +3 -80
  66. package/src/components/agent/use-height-epoch.ts +10 -24
  67. package/src/components/agent/use-path-links.ts +45 -63
  68. package/src/components/agent/use-subagent-frame.ts +106 -0
  69. package/src/components/agent/use-transcript-jumps.ts +49 -107
  70. package/src/components/prompt-area/animated-placeholder.tsx +6 -5
  71. package/src/components/prompt-area/clipboard-helpers.ts +26 -21
  72. package/src/components/prompt-area/cursor-helpers.ts +79 -37
  73. package/src/components/prompt-area/dom-helpers.ts +97 -69
  74. package/src/components/prompt-area/file-strip.tsx +90 -80
  75. package/src/components/prompt-area/html-to-markdown.ts +67 -46
  76. package/src/components/prompt-area/image-strip.tsx +8 -18
  77. package/src/components/prompt-area/index.ts +2 -15
  78. package/src/components/prompt-area/prompt-area-engine.ts +100 -115
  79. package/src/components/prompt-area/prompt-area-list-ops.ts +66 -59
  80. package/src/components/prompt-area/prompt-area.tsx +31 -38
  81. package/src/components/prompt-area/remove-button.tsx +3 -9
  82. package/src/components/prompt-area/segment-helpers.ts +4 -12
  83. package/src/components/prompt-area/trigger-popover.tsx +15 -27
  84. package/src/components/prompt-area/trigger-presets.ts +0 -10
  85. package/src/components/prompt-area/types.ts +3 -8
  86. package/src/components/prompt-area/use-chip-editing.ts +305 -0
  87. package/src/components/prompt-area/use-markdown-mode.ts +7 -17
  88. package/src/components/prompt-area/use-prompt-area-events.ts +80 -86
  89. package/src/components/prompt-area/use-prompt-area-keydown.ts +598 -0
  90. package/src/components/prompt-area/use-prompt-area-state.ts +5 -23
  91. package/src/components/prompt-area/use-prompt-area.ts +170 -896
  92. package/src/components/prompt-area/use-trigger-search.ts +21 -19
  93. package/src/components/terminal/PermissionPrompt.tsx +56 -59
  94. package/src/components/terminal/QuestionPrompt.tsx +28 -79
  95. package/src/components/terminal/StatusLine.tsx +13 -63
  96. package/src/components/terminal/TerminalTranscript.tsx +44 -160
  97. package/src/components/terminal/affordances.tsx +68 -98
  98. package/src/components/terminal/blocks.ts +20 -156
  99. package/src/components/terminal/diff.tsx +19 -67
  100. package/src/components/terminal/height.ts +163 -313
  101. package/src/components/terminal/image-box.ts +0 -44
  102. package/src/components/terminal/items.tsx +150 -305
  103. package/src/components/terminal/markdown.tsx +36 -95
  104. package/src/components/terminal/press.tsx +26 -53
  105. package/src/components/terminal/prompt.tsx +40 -170
  106. package/src/components/terminal/result-preview.ts +8 -56
  107. package/src/components/terminal/row.tsx +11 -98
  108. package/src/components/terminal/scrubber.tsx +108 -401
  109. package/src/components/terminal/surface.tsx +6 -54
  110. package/src/components/terminal/todos.ts +66 -0
  111. package/src/components/terminal/tool-run.ts +21 -192
  112. package/src/components/ui/AlertDialog.tsx +8 -23
  113. package/src/components/ui/Badge.tsx +18 -29
  114. package/src/components/ui/Button.tsx +7 -15
  115. package/src/components/ui/Card.tsx +2 -13
  116. package/src/components/ui/CodeBlock.tsx +10 -37
  117. package/src/components/ui/CopyButton.tsx +10 -23
  118. package/src/components/ui/Dialog.tsx +23 -36
  119. package/src/components/ui/Empty.tsx +6 -29
  120. package/src/components/ui/Input.tsx +14 -16
  121. package/src/components/ui/Menu.tsx +6 -18
  122. package/src/components/ui/PortalScope.tsx +1 -21
  123. package/src/components/ui/ProgressRing.tsx +8 -19
  124. package/src/components/ui/Select.tsx +18 -31
  125. package/src/components/ui/Sonner.tsx +1 -2
  126. package/src/components/ui/Spinner.tsx +1 -1
  127. package/src/components/ui/Splitter.tsx +30 -64
  128. package/src/components/ui/Textarea.tsx +2 -5
  129. package/src/components/ui/Tooltip.tsx +3 -13
  130. package/src/format.ts +0 -9
  131. package/src/index.ts +16 -113
  132. package/src/lib/clipboard.ts +8 -28
  133. package/src/lib/css.ts +8 -0
  134. package/src/lib/format.ts +101 -86
  135. package/src/lib/plan-request.ts +16 -0
  136. package/src/lib/status.ts +45 -95
  137. package/src/lib/tool-icon.ts +39 -47
  138. package/src/lib/utils.ts +1 -3
  139. package/src/styles/terminal.css +81 -49
  140. package/src/styles/theme.css +96 -32
  141. package/src/workspace.ts +1 -24
  142. package/build/SessionPanel-BobynUo4.d.mts +0 -669
  143. package/build/SessionPanel-DUt2VzXG.mjs.map +0 -1
  144. package/build/format-ljc3lKpA.d.mts +0 -59
  145. package/build/status-BE-zg88x.mjs.map +0 -1
@@ -1,669 +0,0 @@
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 * as _$_workerdeck_react0 from "@workerdeck/react";
6
- import { ConnectionState, TranscriptState, UseToolCallHostOptions } from "@workerdeck/react";
7
- import { WorkerDeckClient } from "@workerdeck/client";
8
-
9
- //#region src/components/agent/PermissionModeSelect.d.ts
10
- type PermissionModeMeta = {
11
- value: PermissionMode; /** The name Claude Code itself uses. */
12
- label: string;
13
- /** The chip form, for bars where the label shares a line with three other
14
- * things and "Bypass permissions" would eat half of it. */
15
- shortLabel: string; /** What the mode actually does — the CLI's own one-liners. */
16
- description: string;
17
- icon: LucideIcon;
18
- dangerous?: boolean;
19
- };
20
- /**
21
- * The modes surfaced across UI surfaces (session creation, in-session switcher),
22
- * ordered by how much of the approval gate they give away.
23
- *
24
- * Notably `default` is **"Manual"**: the wire value is `default`, but calling it
25
- * that in the UI conflates a real mode (ask me every time) with "whatever the
26
- * server picked", which is the one confusion a mode chip exists to avoid. The
27
- * naming, the icons and the summaries are shared with the iOS app on purpose —
28
- * the two surfaces should read as the same list.
29
- */
30
- declare const PERMISSION_MODES: PermissionModeMeta[];
31
- declare const permissionModeMeta: (mode: PermissionMode) => PermissionModeMeta | undefined;
32
- /** One offered mode as plain data — no icon, no React. What a host chrome
33
- * outside the panel (a VS Code QuickPick) needs to draw the same list. */
34
- type PermissionModeChoice = {
35
- value: PermissionMode;
36
- label: string;
37
- description: string;
38
- dangerous?: boolean;
39
- /** Offered but unreachable: a session not started for bypass can never gain
40
- * it, and saying so beats omitting the row. */
41
- disabled?: boolean;
42
- };
43
- /**
44
- * The modes this session may actually be switched into, with the reasons baked
45
- * in — the same filtering {@link PermissionModeSelect} applies, so an embedder
46
- * rendering its own picker cannot drift from the panel's.
47
- */
48
- declare function permissionModeChoices(modes?: readonly PermissionMode[], canBypass?: boolean): PermissionModeChoice[];
49
- interface PermissionModeSelectProps {
50
- /** The session's current mode (TranscriptState.permissionMode). */
51
- mode?: PermissionMode;
52
- onModeChange: (mode: PermissionMode) => void;
53
- /** Restrict what is offered — most of {@link PERMISSION_MODES} is Claude Code
54
- * vocabulary the other engines have no meaning for. Defaults to all of them;
55
- * pass the session's `capabilities.permissionModes`. */
56
- modes?: readonly PermissionMode[];
57
- /**
58
- * Whether this session may be switched into `bypassPermissions` at all. The
59
- * CLI refuses unless the process was spawned for it, so a session that didn't
60
- * ask up front can never gain it. The row is shown disabled rather than hidden
61
- * — "you can't have this here" is a more useful answer than a row that
62
- * silently isn't there. `undefined` (an older server) offers it.
63
- */
64
- canBypass?: boolean;
65
- /** 'toolbar' (default) is the composer's compact borderless trigger;
66
- * 'form' is a standard field-sized Select for create/settings forms. */
67
- variant?: 'toolbar' | 'form';
68
- disabled?: boolean;
69
- className?: string;
70
- }
71
- /** Permission-mode switcher: compact in the composer toolbar, field-sized in forms. */
72
- declare function PermissionModeSelect({
73
- mode,
74
- onModeChange,
75
- modes,
76
- canBypass,
77
- variant,
78
- disabled,
79
- className
80
- }: PermissionModeSelectProps): _$react.JSX.Element;
81
- //#endregion
82
- //#region src/components/terminal/affordances.d.ts
83
- /**
84
- * The things a terminal cannot do, and this can.
85
- *
86
- * The theme's whole discipline is that it renders like a CLI — but it is not a
87
- * CLI, and refusing every affordance a pointer makes possible would be cosplay
88
- * rather than design. A terminal cannot highlight the row under your cursor and
89
- * cannot put a copy button on a block of output; a web view can do both for free
90
- * and they are genuinely useful.
91
- *
92
- * The rule that keeps this honest is that **each one costs no layout**. A hover
93
- * fill is a background. An action button is an overlay at the row's right edge,
94
- * one line tall, absolutely positioned so it displaces nothing. Turn them all
95
- * off and every glyph is on exactly the same cell it was on — which is what
96
- * makes `off` a real option rather than a degraded mode, and why it is the mode
97
- * a host projecting to a real terminal would choose.
98
- *
99
- * Off by nothing in particular: both default **on**, because the surface these
100
- * render on is a browser and pretending otherwise helps nobody. A host that
101
- * wants the pure article passes `affordances={false}`.
102
- */
103
- type TerminalAffordances = {
104
- /** Fill the row under the pointer, on anything pressable. */hover?: boolean; /** Reveal a row's actions (copy, and whatever a row adds) on hover or focus. */
105
- actions?: boolean;
106
- };
107
- declare function useAffordances(): Required<TerminalAffordances>;
108
- /**
109
- * A block that reveals its actions on hover.
110
- *
111
- * Wraps rather than decorates because the actions belong to the *block* — a
112
- * message is many rows and its copy button belongs at the top right of all of
113
- * them, not on whichever row the pointer happens to be over.
114
- */
115
- declare function WithActions({
116
- actions,
117
- children,
118
- className
119
- }: {
120
- actions: ReactNode;
121
- children: ReactNode;
122
- className?: string;
123
- }): _$react.JSX.Element;
124
- declare function CopyAction({
125
- text,
126
- label
127
- }: {
128
- text: string;
129
- label?: string;
130
- }): _$react.JSX.Element;
131
- //#endregion
132
- //#region src/components/agent/transcript-variant.d.ts
133
- /**
134
- * How the transcript draws a turn.
135
- *
136
- * - `cards` — the chat convention: bubbles, bordered tool cards, generous gaps.
137
- * Right for a wide dashboard where the transcript is the page.
138
- * - `terminal` — the CLI's own form: every row on a character cell, no boxes
139
- * anywhere, diffs as full-width bands. Right where the transcript sits beside
140
- * a terminal (a VS Code dock) and where vertical space is scarce.
141
- *
142
- * `terminal` is **not** a second set of branches in the components under
143
- * `components/agent/`: it is its own renderer (`components/terminal/`) that the
144
- * shell mounts *instead* of them. So a row component here never asks which
145
- * variant it is in — if it is drawing at all, it is drawing cards.
146
- *
147
- * A context rather than a prop chain because the pieces that DO need it sit
148
- * outside the transcript (the composer, the pending prompts) and because
149
- * `Message`/`ToolCallCard` are exported on their own, so an embedder composing
150
- * them by hand gets the right treatment for free.
151
- */
152
- type TranscriptVariant = 'cards' | 'terminal';
153
- declare function TranscriptVariantProvider({
154
- value,
155
- children
156
- }: {
157
- value: TranscriptVariant;
158
- children: ReactNode;
159
- }): _$react.JSX.Element;
160
- declare function useTranscriptVariant(): TranscriptVariant;
161
- /**
162
- * How much room the transcript gives each row.
163
- *
164
- * - `comfortable` — a blank line between messages, which is what the Claude Code
165
- * CLI does. The default: a transcript is prose before it is a table.
166
- * - `compact` — rows tight against each other, for a dock where every line of
167
- * vertical space is contested.
168
- *
169
- * Separate from the variant, and deliberately: they answer different questions.
170
- * The variant decides *how a row is drawn* and follows from the surface; density
171
- * decides *how much air is around it* and is a preference the reader holds.
172
- *
173
- * Reaches `cards` only. The terminal theme's spacing is a blank *line*, decided
174
- * per pair of blocks by `needsBlank` — a terminal has one line height, which is
175
- * the whole premise — so there is nothing there for this to turn.
176
- */
177
- type TranscriptDensity = 'comfortable' | 'compact';
178
- declare function TranscriptDensityProvider({
179
- value,
180
- children
181
- }: {
182
- value: TranscriptDensity;
183
- children: ReactNode;
184
- }): _$react.JSX.Element;
185
- declare function useTranscriptDensity(): TranscriptDensity;
186
- /**
187
- * The typeface the panel runs in.
188
- *
189
- * `sans` is the host's UI font; `mono` repoints the sans token at the mono stack
190
- * for the panel's subtree (see the `[data-agent-font='mono']` rule in
191
- * `theme.css`), so the transcript reads as part of a terminal rather than as a
192
- * web app beside one.
193
- *
194
- * No context and no hook, unlike variant and density: nothing branches on it in
195
- * JS. It is one attribute on the panel root and the cascade does the rest, which
196
- * is also what keeps it from leaking past the panel.
197
- */
198
- type TranscriptFont = 'sans' | 'mono';
199
- //#endregion
200
- //#region src/components/agent/SessionPanel.d.ts
201
- /**
202
- * The character cell the terminal theme draws on, in **whole pixels**.
203
- *
204
- * One object rather than two props because the panel mounts three separate
205
- * `TerminalSurface`s — the transcript, the pending prompts, the composer — and
206
- * they must agree: a prompt drawn at a different line height from the rows above
207
- * it is three surfaces on three grids, which is the failure this theme is built
208
- * to make impossible. Passing one value through one prop is what keeps them from
209
- * drifting.
210
- *
211
- * Absent means the CLI's own 13/18. A host that follows an editor font size
212
- * (VS Code) hands that down instead.
213
- */
214
- type TerminalMetrics = {
215
- fontSize?: number;
216
- lineHeight?: number;
217
- };
218
- interface SessionPanelProps {
219
- client: WorkerDeckClient;
220
- sessionId: string | undefined;
221
- /**
222
- * Optional slot rendered at the top, above the status bar.
223
- *
224
- * Pass a **function** to take the session-actions (`⋯`) menu into your own
225
- * chrome: it is called with the menu element, and wherever you put it is
226
- * where it lives — the status bar then renders without it, so it never
227
- * appears twice. Pass a plain node (or nothing) and the menu stays in the
228
- * status bar's trailing slot.
229
- *
230
- * The seam exists because the menu can only be *built* here — it needs the
231
- * capability record, the host-file verdict and the panel's own dialog state —
232
- * but an embedder with a real header usually wants it up there with the rest
233
- * of the session's controls, not stranded on the status line.
234
- */
235
- header?: ReactNode | ((slots: {
236
- actions: ReactNode;
237
- }) => ReactNode);
238
- /**
239
- * Where the info/context/usage/MCP/skills/files surfaces live. `'internal'`
240
- * (default) renders them as dialogs inside the panel. `'external'` renders
241
- * NO dialogs and no `⋯` menu: every affordance that would open one calls
242
- * {@link onOpenPanel} instead, so an embedder can host those surfaces in its
243
- * own chrome (a VS Code sidebar, a drawer) and keep the panel purely a
244
- * conversation surface.
245
- */
246
- panelSurface?: 'internal' | 'external';
247
- /**
248
- * Where the status bar lives. `'internal'` (default) draws it across the top
249
- * of the panel. `'external'` draws none — the readings still leave through
250
- * {@link onVitals}, so an embedder with a status line of its own (VS Code's
251
- * window status bar) renders them there instead of stacking a second bar
252
- * inside a panel that already sits in one.
253
- *
254
- * Deliberately independent of {@link panelSurface}: hosting the dialogs and
255
- * hosting the bar are separate decisions. One coupling to know about — the
256
- * `⋯` menu lives in the bar's trailing slot, so `statusSurface: 'external'`
257
- * with `panelSurface: 'internal'` must pass a **function** {@link header} to
258
- * take the menu, or it has nowhere left to go.
259
- */
260
- statusSurface?: 'internal' | 'external';
261
- /**
262
- * Which end of the panel the status bar sits at. Default `top`.
263
- *
264
- * `bottom` is the editor convention — VS Code's status bar runs along the
265
- * foot of the window — and suits a host where the panel *is* the editor area
266
- * and the chrome above it already belongs to the app. Placement only; the bar
267
- * is the same bar, with the same `⋯` menu in its trailing slot, so this
268
- * composes with {@link statusSurface} rather than competing with it (external
269
- * still means "there isn't one").
270
- */
271
- statusPlacement?: 'top' | 'bottom';
272
- /** Where `panelSurface: 'external'` routes opens. Absent = the affordances
273
- * (status-bar clicks, `/mcp`) become inert rather than half-working. */
274
- onOpenPanel?: (panel: SessionSurfacePanel) => void;
275
- /** Live session vitals, fired whenever they change — for embedders mirroring
276
- * status/context/usage into chrome outside the panel (identity-stable via an
277
- * internal ref, so an inline closure is fine). */
278
- onVitals?: (vitals: SessionVitals) => void;
279
- /**
280
- * How the transcript draws a turn — `'cards'` (default, the chat convention)
281
- * or `'terminal'`, the CLI's own form: every row on a character cell, no boxes
282
- * anywhere, diffs as full-width bands. An embedder in a dock (the VS Code
283
- * panel) wants `'terminal'`; a full-width dashboard may prefer cards.
284
- */
285
- transcriptVariant?: TranscriptVariant;
286
- /**
287
- * Terminal theme only: the pointer affordances a real terminal cannot offer —
288
- * the hover fill, the hover-revealed copy. `false` for none. None of them
289
- * costs layout, so turning them off changes no glyph's position. See
290
- * {@link TerminalAffordances}.
291
- */
292
- affordances?: TerminalAffordances | boolean;
293
- /**
294
- * Terminal theme only: the character cell, in whole pixels. See
295
- * {@link TerminalMetrics} — it reaches all three of the panel's terminal
296
- * surfaces, which is why it is one prop and not two per surface.
297
- */
298
- terminalMetrics?: TerminalMetrics;
299
- /**
300
- * Terminal theme only: replace the scrollbar with the **overview ruler** — a
301
- * `2ch` rail of coloured marks in three lanes (what you typed, the answer and
302
- * its turn end, errors and a waiting approval), which you can hover to peek,
303
- * click to jump, and drag to scrub.
304
- *
305
- * Its premise is the terminal theme's own: one line height and one cell make
306
- * every row's height derivable, so a mark's position is *computed* rather than
307
- * guessed from rows that have not mounted. That is why it is not offered under
308
- * `cards` — there the flag is inert.
309
- *
310
- * `false` keeps the native scrollbar. So does `affordances={false}`, which
311
- * leaves the marks painted but inert rather than removing a reader's only way
312
- * to scroll.
313
- */
314
- scrubber?: boolean;
315
- /**
316
- * Bookmarked **item indices**, painted full-width on the rail. Paint only —
317
- * the panel neither stores bookmarks nor offers a way to set one, because who
318
- * owns that store is the embedder's question (a private pin belongs with the
319
- * client's watermarks; a shared one is session metadata on the gateway).
320
- */
321
- scrubberMarks?: readonly number[];
322
- /**
323
- * Scroll a tool call into view; bump `nonce` to ask again for the same one.
324
- * See {@link TranscriptProps.reveal} — this is the panel's pass-through, and
325
- * exists so a surface *outside* the panel (a sessions list showing a session's
326
- * running sub-agents) can say "take me to that one" without opening a second
327
- * attach to find out where it is.
328
- */
329
- reveal?: {
330
- toolUseId: string;
331
- nonce: number;
332
- };
333
- /**
334
- * Open a **sub-agent takeover**: the panel body becomes that agent's own work,
335
- * with a way back. Bump `nonce` to ask again for the same one.
336
- *
337
- * A *request*, not a controlled value — the panel owns which agent is open,
338
- * exactly as it owns `panel`. Dismissal has to work with zero host wiring
339
- * (Back and Escape are the panel's own affordances), and the two hosts in
340
- * scope reach this across a postMessage bridge where a controlled prop would
341
- * need a live closure at the far end. Same shape and same reason as
342
- * {@link SessionPanelProps.reveal}.
343
- *
344
- * **Withdrawing the request closes the frame.** The prop going away without a
345
- * remount is itself a request — "the conversation, plainly" — and it leaves
346
- * through the same path Back takes, so the reader lands on the Task row they
347
- * came from. It has to mean that, because a host that keeps its request in
348
- * route state (the dashboard's `?subagent=`) has exactly one way to say it:
349
- * clear the search — which is what the sidebar's plain session click already
350
- * navigated with, and what the browser's Back button re-arrives on. Before
351
- * this, both were silently ignored and the frame outlived the address that
352
- * claimed it was gone. Still not a controlled value: the panel enters and
353
- * leaves frames on its own and *reports* through
354
- * {@link SessionPanelProps.onSubagentChange}; only a **change** of the prop
355
- * is a request.
356
- *
357
- * Hosts must still clear their request on a session switch: a stale one
358
- * replayed at remount would open a frame the new transcript cannot answer.
359
- *
360
- * Claude-only in practice, and gated by data rather than by a flag — codex and
361
- * provider sessions have no `parentToolUseId`, so they grow no task blocks and
362
- * no sub-agent rows, and nothing can raise this.
363
- */
364
- openSubagent?: {
365
- toolUseId: string;
366
- nonce: number;
367
- };
368
- /**
369
- * Which sub-agent the panel now has framed, or `undefined` for the session's
370
- * own conversation — the outward half of
371
- * {@link SessionPanelProps.openSubagent}, and a *statement* where that one is
372
- * a *request*. Deliberately not an echo: the panel enters frames the host
373
- * never asked for (a Task row pressed in the transcript) and leaves them on
374
- * its own (Back, Escape, a reveal), so a host that tracked only its own
375
- * requests would be wrong within one click. No nonce, for the same reason —
376
- * a state that arrives twice is the same state, where a request that arrives
377
- * twice is two requests.
378
- *
379
- * Never fired for a fresh mount's initial `undefined`, and never fired from
380
- * an unmount. The first would be a lie with consequences: the seeding effect
381
- * consumes `openSubagent` in the same commit, so for one commit the state is
382
- * `undefined` even though a frame is about to open, and a host folding
383
- * reports into route state would clear the very `?subagent=` request the
384
- * panel is in the middle of honouring. The second lets a panel keyed away on
385
- * a session switch stomp what the host already believes about the next one.
386
- * See the notify effect for the mechanics.
387
- *
388
- * What the sessions list's secondary selection feeds on: the row of the agent
389
- * on screen takes the blue and its session's card steps back to grey.
390
- */
391
- onSubagentChange?: (toolUseId: string | undefined) => void;
392
- /**
393
- * Hold the prompt of the turn you are reading at the top of the transcript.
394
- * Works in both variants: the terminal clips to one line (as the CLI does),
395
- * cards shows a frosted bar. The **real row** is pinned rather than a copy
396
- * drawn above it, so it lines up with the rows beneath by construction.
397
- */
398
- stickyPrompt?: boolean;
399
- /**
400
- * How much air the transcript gives each row — `'comfortable'` (default: a
401
- * blank line between messages, as the Claude Code CLI leaves) or `'compact'`
402
- * (rows tight against one another). Independent of `transcriptVariant`: the
403
- * variant follows from the surface, density is the reader's preference, and a
404
- * dock is allowed to be roomy.
405
- */
406
- transcriptDensity?: TranscriptDensity;
407
- /**
408
- * The panel's typeface — `'sans'` (default, the host's UI font) or `'mono'`,
409
- * which repoints the sans token at the mono stack **for this subtree only**.
410
- *
411
- * The third reader preference beside variant and density, and the same kind of
412
- * thing: how a transcript should read is a property of the person reading it.
413
- * Scoped to the panel because that is the whole claim — a monospace agent view
414
- * next to an ordinary app, not a monospace app.
415
- */
416
- transcriptFont?: TranscriptFont;
417
- /**
418
- * Where the session's own controls — model and permission mode — live.
419
- * `'internal'` (default) draws them in the composer's toolbar row.
420
- * `'status'` draws them in the panel's OWN status bar, beside the readings
421
- * they act on; the composer collapses to a single line either way. That is
422
- * VS Code's arrangement without VS Code — a host whose panel carries a status
423
- * bar of its own (`statusPlacement: 'bottom'`) gets the same streamlined
424
- * shape without having to host the pickers itself.
425
- * `'external'` draws neither: the embedder renders the pickers in its own
426
- * chrome (VS Code's window status bar, where a click opens a QuickPick) and
427
- * drives them through {@link onControls}.
428
- *
429
- * `'status'` needs a status bar to put them in — with
430
- * `statusSurface: 'external'` there is none, and the two together would hide
431
- * the controls entirely, so that combination falls back to the composer.
432
- *
433
- * The options themselves ride {@link SessionVitals} — an embedder must not
434
- * attach a second time to learn what the models are.
435
- */
436
- controlsSurface?: 'internal' | 'external' | 'status';
437
- /**
438
- * Handed the session's setters once the panel is live, and `undefined` on
439
- * unmount. The counterpart to `controlsSurface: 'external'`: vitals carry the
440
- * readings out, this carries the commands back in. Stable identity — safe to
441
- * stash in a ref.
442
- */
443
- onControls?: (controls: SessionControls | undefined) => void;
444
- /**
445
- * Click anywhere the panel isn't already doing something and the caret lands
446
- * in the composer — the terminal/chat convention, and what a docked panel
447
- * wants: the field is why the panel is focussed at all.
448
- *
449
- * Only dead space. A click that hits a control (a tool row expanding, a link,
450
- * a button) or that ends a text selection is that action, not a request for
451
- * the input. Off by default: a full-page surface has plenty of dead space that
452
- * means nothing in particular.
453
- */
454
- focusComposerOnClick?: boolean;
455
- /**
456
- * What this session looked like when it was last looked at: how many
457
- * transcript items had been seen, and when. Present and behind the current
458
- * transcript → **catch-up**: a recap row at the boundary, everything above it
459
- * dimmed, and a bar offering to jump there or to dismiss.
460
- *
461
- * The embedder owns the watermark because only it knows what "looked at"
462
- * means in its own chrome — a hidden dock is not being read. The panel reports
463
- * the number to remember through `SessionVitals.itemCount`.
464
- */
465
- unseen?: {
466
- itemCount: number;
467
- since?: number;
468
- };
469
- /**
470
- * A viewer, not a seat at the session: transcript, status bar and panels as
471
- * usual, but no composer and no approval prompts.
472
- *
473
- * For a surface that is *about* a run rather than in it — the dashboard's job
474
- * detail, where the session belongs to the queue and typing into it would be a
475
- * second operator arriving mid-run. Deliberately not "disabled controls": a
476
- * greyed-out composer says the session is busy, an absent one says this screen
477
- * does not drive it. The attach is still live and read paths are untouched,
478
- * so the transcript streams and the file tree browses.
479
- *
480
- * It does **not** claim to be an authorization boundary. Anything holding this
481
- * client can still send; what it removes is the affordance, and the honest
482
- * enforcement lives on the gateway.
483
- */
484
- readOnly?: boolean;
485
- /**
486
- * Options for the browser tool host this panel runs on its own attach — or
487
- * `false` to run none at all.
488
- *
489
- * The panel hosts server-bridged tool calls itself, because the bridge asks
490
- * the *first attached client* and the panel owns the session's one attach: an
491
- * embedder subscribing to the same handle separately would find this host
492
- * already answering, and refusing, anything outside its allow-list. So the
493
- * options come through here.
494
- *
495
- * Merged over the defaults, which host `eval_script` alone. Widening `tools`
496
- * is a real grant — this tab will execute what the gateway asks it to for
497
- * every name in the list — so it names them explicitly rather than accepting
498
- * a wildcard.
499
- */
500
- toolHost?: UseToolCallHostOptions | false;
501
- /**
502
- * Keep this session's transcript warm across remounts (default true), so
503
- * switching back to a recently viewed session paints instantly and replays
504
- * only what it missed — `UseClaudeSessionOptions.cacheTranscript`. Set
505
- * `false` for an embedder whose principal varies on one gateway URL by means
506
- * the client cannot see.
507
- */
508
- cacheTranscript?: boolean;
509
- /**
510
- * Replaces the default empty state when the transcript has no messages. Pass
511
- * your product's own onboarding content instead of WorkerDeck's generic
512
- * "`>_` Tell the agent what to do." placeholder.
513
- */
514
- emptyState?: ReactNode;
515
- /**
516
- * Called when a link in the transcript is clicked. The embedder decides what
517
- * happens: navigate in-app, open a browser tab, show a confirmation, or
518
- * suppress.
519
- *
520
- * Return `true` (or a truthy value) to indicate the click was handled — the
521
- * default action (`window.open(href, '_blank')`) is suppressed. Return
522
- * `false` / `undefined` / nothing to let the browser open the link normally.
523
- *
524
- * Absent means "browser default" — links open in a new tab as Streamdown's
525
- * `target="_blank"` intends. VS Code's webview overrides this through its own
526
- * native handler (the "allow once / add to allowlist" dialog) and does not
527
- * need this prop.
528
- *
529
- * **Typical embedder patterns:**
530
- * - Relative URLs → in-app navigation, no confirmation
531
- * - External URLs → confirmation dialog, or open unconditionally
532
- * - Suppress all links → `() => true`
533
- */
534
- onLinkClick?: (href: string) => boolean | void;
535
- /**
536
- * Client-side tool handlers. Each key is a tool name the model can call; the
537
- * handler receives the model's input and returns a result. The tool's
538
- * **schema** must be registered server-side (via `tools` on
539
- * `ProviderRunnerOptions`), but the handler runs here — right where the data
540
- * the tool needs lives.
541
- *
542
- * Shorthand for `toolHost.clientTools`; when both are set, this wins for
543
- * overlapping names.
544
- *
545
- * ```tsx
546
- * <SessionPanel
547
- * clientTools={{
548
- * app_navigate: async (input) => {
549
- * router.push((input as { path: string }).path)
550
- * return { value: 'navigated' }
551
- * },
552
- * }}
553
- * />
554
- * ```
555
- */
556
- clientTools?: Record<string, _$_workerdeck_react0.ClientToolHandler>;
557
- /**
558
- * Base font size in **whole pixels**. Drives the overall scale of everything
559
- * the panel draws — prompt, output, markdown, status bar — in both variants.
560
- *
561
- * Under the terminal theme it sets `--term-font-size` and derives
562
- * `--term-line` at the CLI's own 13 : 18 ratio (unless {@link terminalMetrics}
563
- * overrides those individually). Under cards it sets the panel root's
564
- * `font-size`, which scales every `rem`/`em`-based token the type scale uses.
565
- *
566
- * Absent means "platform default": 13 px for the terminal theme, the
567
- * inherited body size for cards. That is the right choice for a host that has
568
- * no preference — the panel reads at the size the rest of the app does.
569
- */
570
- fontSize?: number;
571
- className?: string;
572
- }
573
- /** What an embedder needs to *change* a session it doesn't own the attach for. */
574
- type SessionControls = {
575
- setModel: (model?: string) => void;
576
- setPermissionMode: (mode: PermissionMode) => void;
577
- interrupt: () => void;
578
- /**
579
- * Put the caret in the composer.
580
- *
581
- * For an embedder whose own chrome is how you arrive at a session — clicking a
582
- * row in VS Code's sidebar — where revealing the panel and being able to type
583
- * are the same intention. The panel cannot infer it: from in here, a session
584
- * appearing looks identical whether someone asked for it or it was restored.
585
- */
586
- focusComposer: () => void;
587
- };
588
- /** The panels the session surface can raise. One at a time, by identity: a bag
589
- * of booleans would let two open at once. */
590
- type SessionSurfacePanel = 'info' | 'context' | 'usage' | 'mcp' | 'files' | 'skills';
591
- /** What {@link SessionPanelProps.onVitals} reports: the live readings a host
592
- * chrome outside the panel would otherwise have to attach a second time for —
593
- * which the tool bridge forbids (it asks the first attached client). */
594
- type SessionVitals = {
595
- status: TranscriptState['status'];
596
- /**
597
- * How the client is reaching the gateway. Load-bearing for a host rendering
598
- * these outside the panel: `status` is the last thing the session *said*, and
599
- * over a dropped socket that is a stale reading. The panel's own bar gives
600
- * the connection the status slot when it isn't `'live'` for exactly this
601
- * reason — an embedder showing `status` alone would present stale as current.
602
- */
603
- connection: ConnectionState;
604
- engine: TranscriptState['engine'];
605
- capabilities: TranscriptState['capabilities'];
606
- model: string | undefined;
607
- /** The models this session can switch to — the panel's own list, so an
608
- * external picker offers exactly what the internal one would. */
609
- models: ModelOption[];
610
- permissionMode: TranscriptState['permissionMode'];
611
- /** The modes it can switch into, already filtered by the capability record
612
- * and the session's bypass grant (see `permissionModeChoices`). */
613
- permissionModes: PermissionModeChoice[];
614
- cwd: TranscriptState['cwd'];
615
- contextUsage: TranscriptState['contextUsage'];
616
- rateLimits: TranscriptState['rateLimits'];
617
- /** How many transcript rows exist right now — the number an embedder stores
618
- * as its "seen" watermark while the panel is actually on screen, and compares
619
- * against later to know what is new. */
620
- itemCount: number;
621
- /** Session-cumulative cost in USD. The internal status bar renders this via
622
- * `formatCost`; an external host needs it to reproduce that reading. */
623
- totalCostUsd: number;
624
- };
625
- /**
626
- * The all-in-one embeddable session surface: status bar, streaming transcript,
627
- * permission prompts, composer. Attaches via useClaudeSession; remount (key) to switch
628
- * sessions.
629
- *
630
- * Every affordance is gated on the session's **capability record** rather than on
631
- * the engine name — an absent capability hides the control instead of offering
632
- * one that can only fail.
633
- */
634
- declare function SessionPanel({
635
- client,
636
- sessionId,
637
- header,
638
- panelSurface,
639
- statusSurface,
640
- statusPlacement,
641
- onOpenPanel,
642
- onVitals,
643
- transcriptVariant,
644
- transcriptDensity,
645
- transcriptFont,
646
- affordances,
647
- terminalMetrics,
648
- scrubber,
649
- scrubberMarks,
650
- reveal,
651
- openSubagent,
652
- onSubagentChange,
653
- stickyPrompt,
654
- controlsSurface,
655
- onControls,
656
- focusComposerOnClick,
657
- unseen,
658
- readOnly,
659
- toolHost,
660
- clientTools,
661
- cacheTranscript,
662
- emptyState,
663
- onLinkClick,
664
- fontSize,
665
- className
666
- }: SessionPanelProps): _$react.JSX.Element;
667
- //#endregion
668
- export { permissionModeChoices as C, PermissionModeSelectProps as S, useAffordances as _, SessionVitals as a, PermissionModeMeta as b, TranscriptDensityProvider as c, TranscriptVariantProvider as d, useTranscriptDensity as f, WithActions as g, TerminalAffordances as h, SessionSurfacePanel as i, TranscriptFont as l, CopyAction as m, SessionPanel as n, TerminalMetrics as o, useTranscriptVariant as p, SessionPanelProps as r, TranscriptDensity as s, SessionControls as t, TranscriptVariant as u, PERMISSION_MODES as v, permissionModeMeta as w, PermissionModeSelect as x, PermissionModeChoice as y };
669
- //# sourceMappingURL=SessionPanel-BobynUo4.d.mts.map