@workerdeck/ui 0.9.0 → 0.11.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.
- package/README.md +81 -3
- package/build/SessionPanel-CyhygZx_.d.mts +277 -0
- package/build/SessionPanel-_U8tjX29.mjs +8409 -0
- package/build/SessionPanel-_U8tjX29.mjs.map +1 -0
- package/build/format-DqR56Y8l.mjs +162 -0
- package/build/format-DqR56Y8l.mjs.map +1 -0
- package/build/format-ljc3lKpA.d.mts +59 -0
- package/build/format.d.mts +2 -0
- package/build/format.mjs +2 -0
- package/build/index.d.mts +610 -87
- package/build/index.mjs +6 -5104
- package/build/index.mjs.map +1 -1
- package/build/workspace.d.mts +199 -0
- package/build/workspace.mjs +849 -0
- package/build/workspace.mjs.map +1 -0
- package/package.json +22 -4
- package/src/components/agent/CodeEditor.tsx +300 -0
- package/src/components/agent/Composer.tsx +522 -87
- package/src/components/agent/ContextDialog.tsx +99 -0
- package/src/components/agent/Conversation.tsx +11 -3
- package/src/components/agent/EditorTabs.tsx +165 -0
- package/src/components/agent/FileCard.tsx +26 -0
- package/src/components/agent/FileTree.tsx +287 -0
- package/src/components/agent/FileViewer.tsx +148 -0
- package/src/components/agent/HostFilesDialog.tsx +218 -0
- package/src/components/agent/Loader.tsx +120 -14
- package/src/components/agent/McpDialog.tsx +363 -0
- package/src/components/agent/Message.tsx +51 -17
- package/src/components/agent/ModelSelect.tsx +34 -6
- package/src/components/agent/PermissionModeSelect.tsx +133 -22
- package/src/components/agent/PermissionPrompt.tsx +164 -6
- package/src/components/agent/PromptTokenText.tsx +39 -0
- package/src/components/agent/QuestionPrompt.tsx +122 -0
- package/src/components/agent/Reasoning.tsx +20 -5
- package/src/components/agent/Response.tsx +128 -0
- package/src/components/agent/SessionEmptyState.tsx +65 -0
- package/src/components/agent/SessionInfoDialog.tsx +163 -0
- package/src/components/agent/SessionPanel.tsx +756 -91
- package/src/components/agent/SessionWorkspace.tsx +282 -0
- package/src/components/agent/SkillsDialog.tsx +195 -0
- package/src/components/agent/StatusBar.tsx +85 -18
- package/src/components/agent/ToolCallCard.tsx +243 -30
- package/src/components/agent/Transcript.tsx +495 -30
- package/src/components/agent/UsageDialog.tsx +168 -0
- package/src/components/agent/line-prompt.tsx +249 -0
- package/src/components/agent/transcript-variant.tsx +61 -0
- package/src/components/prompt-area/prompt-area-engine.ts +53 -0
- package/src/components/prompt-area/types.ts +15 -0
- package/src/components/prompt-area/use-prompt-area.ts +20 -0
- package/src/components/ui/CodeBlock.tsx +40 -2
- package/src/components/ui/CopyButton.tsx +28 -3
- package/src/components/ui/Dialog.tsx +92 -0
- package/src/components/ui/Menu.tsx +55 -0
- package/src/components/ui/Splitter.tsx +133 -0
- package/src/components/ui/Tooltip.tsx +22 -5
- package/src/format.ts +10 -0
- package/src/index.ts +63 -2
- package/src/lib/clipboard.ts +56 -0
- package/src/lib/format.ts +114 -0
- package/src/lib/tool-icon.ts +96 -0
- 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
|
|
5
|
-
|
|
6
|
-
|
|
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,277 @@
|
|
|
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
|
+
//#endregion
|
|
107
|
+
//#region src/components/agent/SessionPanel.d.ts
|
|
108
|
+
interface SessionPanelProps {
|
|
109
|
+
client: WorkerDeckClient;
|
|
110
|
+
sessionId: string | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Optional slot rendered at the top, above the status bar.
|
|
113
|
+
*
|
|
114
|
+
* Pass a **function** to take the session-actions (`⋯`) menu into your own
|
|
115
|
+
* chrome: it is called with the menu element, and wherever you put it is
|
|
116
|
+
* where it lives — the status bar then renders without it, so it never
|
|
117
|
+
* appears twice. Pass a plain node (or nothing) and the menu stays in the
|
|
118
|
+
* status bar's trailing slot.
|
|
119
|
+
*
|
|
120
|
+
* The seam exists because the menu can only be *built* here — it needs the
|
|
121
|
+
* capability record, the host-file verdict and the panel's own dialog state —
|
|
122
|
+
* but an embedder with a real header usually wants it up there with the rest
|
|
123
|
+
* of the session's controls, not stranded on the status line.
|
|
124
|
+
*/
|
|
125
|
+
header?: ReactNode | ((slots: {
|
|
126
|
+
actions: ReactNode;
|
|
127
|
+
}) => ReactNode);
|
|
128
|
+
/**
|
|
129
|
+
* Where the info/context/usage/MCP/skills/files surfaces live. `'internal'`
|
|
130
|
+
* (default) renders them as dialogs inside the panel. `'external'` renders
|
|
131
|
+
* NO dialogs and no `⋯` menu: every affordance that would open one calls
|
|
132
|
+
* {@link onOpenPanel} instead, so an embedder can host those surfaces in its
|
|
133
|
+
* own chrome (a VS Code sidebar, a drawer) and keep the panel purely a
|
|
134
|
+
* conversation surface.
|
|
135
|
+
*/
|
|
136
|
+
panelSurface?: 'internal' | 'external';
|
|
137
|
+
/**
|
|
138
|
+
* Where the status bar lives. `'internal'` (default) draws it across the top
|
|
139
|
+
* of the panel. `'external'` draws none — the readings still leave through
|
|
140
|
+
* {@link onVitals}, so an embedder with a status line of its own (VS Code's
|
|
141
|
+
* window status bar) renders them there instead of stacking a second bar
|
|
142
|
+
* inside a panel that already sits in one.
|
|
143
|
+
*
|
|
144
|
+
* Deliberately independent of {@link panelSurface}: hosting the dialogs and
|
|
145
|
+
* hosting the bar are separate decisions. One coupling to know about — the
|
|
146
|
+
* `⋯` menu lives in the bar's trailing slot, so `statusSurface: 'external'`
|
|
147
|
+
* with `panelSurface: 'internal'` must pass a **function** {@link header} to
|
|
148
|
+
* take the menu, or it has nowhere left to go.
|
|
149
|
+
*/
|
|
150
|
+
statusSurface?: 'internal' | 'external';
|
|
151
|
+
/** Where `panelSurface: 'external'` routes opens. Absent = the affordances
|
|
152
|
+
* (status-bar clicks, `/mcp`) become inert rather than half-working. */
|
|
153
|
+
onOpenPanel?: (panel: SessionSurfacePanel) => void;
|
|
154
|
+
/** Live session vitals, fired whenever they change — for embedders mirroring
|
|
155
|
+
* status/context/usage into chrome outside the panel (identity-stable via an
|
|
156
|
+
* internal ref, so an inline closure is fine). */
|
|
157
|
+
onVitals?: (vitals: SessionVitals) => void;
|
|
158
|
+
/**
|
|
159
|
+
* How the transcript draws a turn — `'cards'` (default) or `'lines'`, the
|
|
160
|
+
* space-efficient terminal treatment: no boxes, no bubbles, one full-width
|
|
161
|
+
* hover-highlit row per event behind a gutter glyph. An embedder in a dock
|
|
162
|
+
* (the VS Code panel) wants `'lines'`; a full-width dashboard usually doesn't.
|
|
163
|
+
*/
|
|
164
|
+
transcriptVariant?: TranscriptVariant;
|
|
165
|
+
/**
|
|
166
|
+
* Where the session's own controls — model and permission mode — live.
|
|
167
|
+
* `'internal'` (default) draws them in the composer's toolbar row.
|
|
168
|
+
* `'external'` draws neither, and the composer collapses to a single line
|
|
169
|
+
* with its attach/send buttons beside the field: the embedder renders the
|
|
170
|
+
* pickers in its own chrome (VS Code's status bar, where a click opens a
|
|
171
|
+
* QuickPick) and drives them through {@link onControls}.
|
|
172
|
+
*
|
|
173
|
+
* The options themselves ride {@link SessionVitals} — an embedder must not
|
|
174
|
+
* attach a second time to learn what the models are.
|
|
175
|
+
*/
|
|
176
|
+
controlsSurface?: 'internal' | 'external';
|
|
177
|
+
/**
|
|
178
|
+
* Handed the session's setters once the panel is live, and `undefined` on
|
|
179
|
+
* unmount. The counterpart to `controlsSurface: 'external'`: vitals carry the
|
|
180
|
+
* readings out, this carries the commands back in. Stable identity — safe to
|
|
181
|
+
* stash in a ref.
|
|
182
|
+
*/
|
|
183
|
+
onControls?: (controls: SessionControls | undefined) => void;
|
|
184
|
+
/**
|
|
185
|
+
* Click anywhere the panel isn't already doing something and the caret lands
|
|
186
|
+
* in the composer — the terminal/chat convention, and what a docked panel
|
|
187
|
+
* wants: the field is why the panel is focussed at all.
|
|
188
|
+
*
|
|
189
|
+
* Only dead space. A click that hits a control (a tool row expanding, a link,
|
|
190
|
+
* a button) or that ends a text selection is that action, not a request for
|
|
191
|
+
* the input. Off by default: a full-page surface has plenty of dead space that
|
|
192
|
+
* means nothing in particular.
|
|
193
|
+
*/
|
|
194
|
+
focusComposerOnClick?: boolean;
|
|
195
|
+
/**
|
|
196
|
+
* What this session looked like when it was last looked at: how many
|
|
197
|
+
* transcript items had been seen, and when. Present and behind the current
|
|
198
|
+
* transcript → **catch-up**: a recap row at the boundary, everything above it
|
|
199
|
+
* dimmed, and a bar offering to jump there or to dismiss.
|
|
200
|
+
*
|
|
201
|
+
* The embedder owns the watermark because only it knows what "looked at"
|
|
202
|
+
* means in its own chrome — a hidden dock is not being read. The panel reports
|
|
203
|
+
* the number to remember through `SessionVitals.itemCount`.
|
|
204
|
+
*/
|
|
205
|
+
unseen?: {
|
|
206
|
+
itemCount: number;
|
|
207
|
+
since?: number;
|
|
208
|
+
};
|
|
209
|
+
className?: string;
|
|
210
|
+
}
|
|
211
|
+
/** What an embedder needs to *change* a session it doesn't own the attach for. */
|
|
212
|
+
type SessionControls = {
|
|
213
|
+
setModel: (model?: string) => void;
|
|
214
|
+
setPermissionMode: (mode: PermissionMode) => void;
|
|
215
|
+
interrupt: () => void;
|
|
216
|
+
};
|
|
217
|
+
/** The panels the session surface can raise. One at a time, by identity: a bag
|
|
218
|
+
* of booleans would let two open at once. */
|
|
219
|
+
type SessionSurfacePanel = 'info' | 'context' | 'usage' | 'mcp' | 'files' | 'skills';
|
|
220
|
+
/** What {@link SessionPanelProps.onVitals} reports: the live readings a host
|
|
221
|
+
* chrome outside the panel would otherwise have to attach a second time for —
|
|
222
|
+
* which the tool bridge forbids (it asks the first attached client). */
|
|
223
|
+
type SessionVitals = {
|
|
224
|
+
status: TranscriptState['status'];
|
|
225
|
+
/**
|
|
226
|
+
* How the client is reaching the gateway. Load-bearing for a host rendering
|
|
227
|
+
* these outside the panel: `status` is the last thing the session *said*, and
|
|
228
|
+
* over a dropped socket that is a stale reading. The panel's own bar gives
|
|
229
|
+
* the connection the status slot when it isn't `'live'` for exactly this
|
|
230
|
+
* reason — an embedder showing `status` alone would present stale as current.
|
|
231
|
+
*/
|
|
232
|
+
connection: ConnectionState;
|
|
233
|
+
engine: TranscriptState['engine'];
|
|
234
|
+
capabilities: TranscriptState['capabilities'];
|
|
235
|
+
model: string | undefined;
|
|
236
|
+
/** The models this session can switch to — the panel's own list, so an
|
|
237
|
+
* external picker offers exactly what the internal one would. */
|
|
238
|
+
models: ModelOption[];
|
|
239
|
+
permissionMode: TranscriptState['permissionMode'];
|
|
240
|
+
/** The modes it can switch into, already filtered by the capability record
|
|
241
|
+
* and the session's bypass grant (see `permissionModeChoices`). */
|
|
242
|
+
permissionModes: PermissionModeChoice[];
|
|
243
|
+
cwd: TranscriptState['cwd'];
|
|
244
|
+
contextUsage: TranscriptState['contextUsage'];
|
|
245
|
+
rateLimits: TranscriptState['rateLimits'];
|
|
246
|
+
/** How many transcript rows exist right now — the number an embedder stores
|
|
247
|
+
* as its "seen" watermark while the panel is actually on screen, and compares
|
|
248
|
+
* against later to know what is new. */
|
|
249
|
+
itemCount: number;
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* The all-in-one embeddable session surface: status bar, streaming transcript,
|
|
253
|
+
* permission prompts, composer. Attaches via useClaudeSession; remount (key) to switch
|
|
254
|
+
* sessions.
|
|
255
|
+
*
|
|
256
|
+
* Every affordance is gated on the session's **capability record** rather than on
|
|
257
|
+
* the engine name — an absent capability hides the control instead of offering
|
|
258
|
+
* one that can only fail.
|
|
259
|
+
*/
|
|
260
|
+
declare function SessionPanel({
|
|
261
|
+
client,
|
|
262
|
+
sessionId,
|
|
263
|
+
header,
|
|
264
|
+
panelSurface,
|
|
265
|
+
statusSurface,
|
|
266
|
+
onOpenPanel,
|
|
267
|
+
onVitals,
|
|
268
|
+
transcriptVariant,
|
|
269
|
+
controlsSurface,
|
|
270
|
+
onControls,
|
|
271
|
+
focusComposerOnClick,
|
|
272
|
+
unseen,
|
|
273
|
+
className
|
|
274
|
+
}: SessionPanelProps): _$react.JSX.Element;
|
|
275
|
+
//#endregion
|
|
276
|
+
export { SessionVitals as a, useTranscriptVariant as c, PermissionModeMeta as d, PermissionModeSelect as f, permissionModeMeta as h, SessionSurfacePanel as i, PERMISSION_MODES as l, permissionModeChoices as m, SessionPanel as n, TranscriptVariant as o, PermissionModeSelectProps as p, SessionPanelProps as r, TranscriptVariantProvider as s, SessionControls as t, PermissionModeChoice as u };
|
|
277
|
+
//# sourceMappingURL=SessionPanel-CyhygZx_.d.mts.map
|