@workerdeck/ui 0.11.0 → 0.13.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 (35) hide show
  1. package/build/{SessionPanel-_U8tjX29.mjs → SessionPanel-CKQa4i0Y.mjs} +337 -269
  2. package/build/SessionPanel-CKQa4i0Y.mjs.map +1 -0
  3. package/build/{SessionPanel-CyhygZx_.d.mts → SessionPanel-CZMA44NM.d.mts} +73 -2
  4. package/build/format.d.mts +65 -1
  5. package/build/format.mjs +118 -1
  6. package/build/format.mjs.map +1 -0
  7. package/build/index.d.mts +129 -10
  8. package/build/index.mjs +461 -5
  9. package/build/index.mjs.map +1 -1
  10. package/build/workspace.d.mts +36 -1
  11. package/build/workspace.mjs +16 -2
  12. package/build/workspace.mjs.map +1 -1
  13. package/package.json +4 -4
  14. package/src/components/agent/Composer.tsx +18 -10
  15. package/src/components/agent/EngineIcon.tsx +97 -0
  16. package/src/components/agent/Loader.tsx +11 -46
  17. package/src/components/agent/Message.tsx +10 -6
  18. package/src/components/agent/QuestionPrompt.tsx +1 -1
  19. package/src/components/agent/SessionBrowser.tsx +546 -0
  20. package/src/components/agent/SessionPanel.tsx +89 -14
  21. package/src/components/agent/SessionWorkspace.tsx +45 -0
  22. package/src/components/agent/StatusBar.tsx +9 -2
  23. package/src/components/agent/ToolCallCard.tsx +11 -2
  24. package/src/components/agent/Transcript.tsx +28 -11
  25. package/src/components/agent/line-prompt.tsx +2 -2
  26. package/src/components/agent/pulse.tsx +60 -0
  27. package/src/components/agent/transcript-variant.tsx +62 -0
  28. package/src/components/ui/Menu.tsx +1 -1
  29. package/src/components/ui/Select.tsx +1 -1
  30. package/src/components/ui/Tooltip.tsx +1 -1
  31. package/src/format.ts +1 -0
  32. package/src/index.ts +12 -0
  33. package/src/lib/status.ts +124 -0
  34. package/src/styles/theme.css +45 -15
  35. package/build/SessionPanel-_U8tjX29.mjs.map +0 -1
@@ -103,6 +103,30 @@ declare function TranscriptVariantProvider({
103
103
  children: ReactNode;
104
104
  }): _$react.JSX.Element;
105
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;
106
130
  //#endregion
107
131
  //#region src/components/agent/SessionPanel.d.ts
108
132
  interface SessionPanelProps {
@@ -148,6 +172,17 @@ interface SessionPanelProps {
148
172
  * take the menu, or it has nowhere left to go.
149
173
  */
150
174
  statusSurface?: 'internal' | 'external';
175
+ /**
176
+ * Which end of the panel the status bar sits at. Default `top`.
177
+ *
178
+ * `bottom` is the editor convention — VS Code's status bar runs along the
179
+ * foot of the window — and suits a host where the panel *is* the editor area
180
+ * and the chrome above it already belongs to the app. Placement only; the bar
181
+ * is the same bar, with the same `⋯` menu in its trailing slot, so this
182
+ * composes with {@link statusSurface} rather than competing with it (external
183
+ * still means "there isn't one").
184
+ */
185
+ statusPlacement?: 'top' | 'bottom';
151
186
  /** Where `panelSurface: 'external'` routes opens. Absent = the affordances
152
187
  * (status-bar clicks, `/mcp`) become inert rather than half-working. */
153
188
  onOpenPanel?: (panel: SessionSurfacePanel) => void;
@@ -162,6 +197,14 @@ interface SessionPanelProps {
162
197
  * (the VS Code panel) wants `'lines'`; a full-width dashboard usually doesn't.
163
198
  */
164
199
  transcriptVariant?: TranscriptVariant;
200
+ /**
201
+ * How much air the transcript gives each row — `'comfortable'` (default: a
202
+ * blank line between messages, as the Claude Code CLI leaves) or `'compact'`
203
+ * (rows tight against one another). Independent of `transcriptVariant`: the
204
+ * variant follows from the surface, density is the reader's preference, and a
205
+ * dock is allowed to be roomy.
206
+ */
207
+ transcriptDensity?: TranscriptDensity;
165
208
  /**
166
209
  * Where the session's own controls — model and permission mode — live.
167
210
  * `'internal'` (default) draws them in the composer's toolbar row.
@@ -206,6 +249,22 @@ interface SessionPanelProps {
206
249
  itemCount: number;
207
250
  since?: number;
208
251
  };
252
+ /**
253
+ * A viewer, not a seat at the session: transcript, status bar and panels as
254
+ * usual, but no composer and no approval prompts.
255
+ *
256
+ * For a surface that is *about* a run rather than in it — the dashboard's job
257
+ * detail, where the session belongs to the queue and typing into it would be a
258
+ * second operator arriving mid-run. Deliberately not "disabled controls": a
259
+ * greyed-out composer says the session is busy, an absent one says this screen
260
+ * does not drive it. The attach is still live and read paths are untouched,
261
+ * so the transcript streams and the file tree browses.
262
+ *
263
+ * It does **not** claim to be an authorization boundary. Anything holding this
264
+ * client can still send; what it removes is the affordance, and the honest
265
+ * enforcement lives on the gateway.
266
+ */
267
+ readOnly?: boolean;
209
268
  className?: string;
210
269
  }
211
270
  /** What an embedder needs to *change* a session it doesn't own the attach for. */
@@ -213,6 +272,15 @@ type SessionControls = {
213
272
  setModel: (model?: string) => void;
214
273
  setPermissionMode: (mode: PermissionMode) => void;
215
274
  interrupt: () => void;
275
+ /**
276
+ * Put the caret in the composer.
277
+ *
278
+ * For an embedder whose own chrome is how you arrive at a session — clicking a
279
+ * row in VS Code's sidebar — where revealing the panel and being able to type
280
+ * are the same intention. The panel cannot infer it: from in here, a session
281
+ * appearing looks identical whether someone asked for it or it was restored.
282
+ */
283
+ focusComposer: () => void;
216
284
  };
217
285
  /** The panels the session surface can raise. One at a time, by identity: a bag
218
286
  * of booleans would let two open at once. */
@@ -263,15 +331,18 @@ declare function SessionPanel({
263
331
  header,
264
332
  panelSurface,
265
333
  statusSurface,
334
+ statusPlacement,
266
335
  onOpenPanel,
267
336
  onVitals,
268
337
  transcriptVariant,
338
+ transcriptDensity,
269
339
  controlsSurface,
270
340
  onControls,
271
341
  focusComposerOnClick,
272
342
  unseen,
343
+ readOnly,
273
344
  className
274
345
  }: SessionPanelProps): _$react.JSX.Element;
275
346
  //#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
347
+ 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 };
348
+ //# sourceMappingURL=SessionPanel-CZMA44NM.d.mts.map
@@ -1,2 +1,66 @@
1
1
  import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-ljc3lKpA.mjs";
2
- export { formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, rateLimitWindowSeconds, toolInputPreview };
2
+ import { ContextUsage, ModelOption, RateLimitInfo, SessionStatus } from "@workerdeck/protocol";
3
+
4
+ //#region src/lib/status.d.ts
5
+ /**
6
+ * How a session's live readings become a status line — the pure half, so every
7
+ * host spells "Needs approval", "80% is a warning" and "which window is the
8
+ * binding one" the same way.
9
+ *
10
+ * Structurally typed against `SessionVitals` rather than importing it: this file
11
+ * ships from the React-free `@workerdeck/ui/format` entry, and a host drawing
12
+ * the readings outside React (the VS Code extension host in the window status
13
+ * bar) must not pull a component graph in to do it. A real `SessionVitals`
14
+ * satisfies every shape here.
15
+ */
16
+ type StatusSeverity = 'none' | 'warning' | 'error';
17
+ /** What a status slot shows, before any host's icon vocabulary gets involved.
18
+ * `icon` is a VS Code codicon name — the one host-shaped thing left, because the
19
+ * alternative is a second mapping table in the only consumer. */
20
+ type StatusPresentation = {
21
+ icon: string;
22
+ label: string;
23
+ severity: StatusSeverity;
24
+ };
25
+ type StatusReadings = {
26
+ status: SessionStatus;
27
+ /** `@workerdeck/react`'s `ConnectionState`, structurally — the link state wins
28
+ * the slot, so it has to be part of the reading. */
29
+ connection?: 'live' | 'reconnecting' | 'offline';
30
+ };
31
+ /**
32
+ * The status slot, connection first. A session status held over a dead socket is
33
+ * the last thing we heard, not the current state — so a lost link takes the slot
34
+ * rather than letting "Running" imply a turn is still streaming.
35
+ */
36
+ declare function statusPresentation(vitals: StatusReadings | undefined): StatusPresentation;
37
+ /** 0–100 → the colour a meter wears. One pair of thresholds for every surface. */
38
+ declare function meterSeverity(pct: number | undefined): StatusSeverity;
39
+ /** The rate-limit window that gets the one visible slot: whichever is fullest,
40
+ * since the binding constraint is the one worth glancing at. */
41
+ declare function tightestWindow(rateLimits: Record<string, RateLimitInfo> | undefined): {
42
+ key: string;
43
+ info: RateLimitInfo;
44
+ } | undefined;
45
+ /** A rate-limit window's key, named for a human. */
46
+ declare function windowLabel(key: string): string;
47
+ type ModelReadings = {
48
+ model?: string;
49
+ models: readonly ModelOption[];
50
+ };
51
+ /**
52
+ * The catalog row a session is actually running, or `undefined` for a model the
53
+ * list doesn't name. Matched leniently: a session reports the *resolved* id
54
+ * (`claude-sonnet-5`) where the row may be keyed on the alias (`sonnet`), and
55
+ * either can carry a `[1m]` context-window suffix.
56
+ */
57
+ declare function currentModel(vitals: ModelReadings | undefined): ModelOption | undefined;
58
+ /** A session's model, named the way the picker names it. Falls back to the raw
59
+ * id, and to "Default" while the session is on the CLI's own pick. */
60
+ declare function modelLabel(vitals: ModelReadings | undefined): string;
61
+ /** Context percentage as its meter severity — the reading and the colour come
62
+ * from one place so a panel and a status bar never disagree. */
63
+ declare function contextSeverity(usage: ContextUsage | undefined): StatusSeverity;
64
+ //#endregion
65
+ export { ModelReadings, StatusPresentation, StatusReadings, StatusSeverity, contextSeverity, currentModel, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, meterSeverity, modelLabel, rateLimitWindowSeconds, statusPresentation, tightestWindow, toolInputPreview, windowLabel };
66
+ //# sourceMappingURL=format.d.mts.map
package/build/format.mjs CHANGED
@@ -1,2 +1,119 @@
1
1
  import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-DqR56Y8l.mjs";
2
- export { formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, rateLimitWindowSeconds, toolInputPreview };
2
+ //#region src/lib/status.ts
3
+ const STATUS_META = {
4
+ starting: {
5
+ icon: "loading~spin",
6
+ label: "Starting",
7
+ severity: "none"
8
+ },
9
+ running: {
10
+ icon: "loading~spin",
11
+ label: "Running",
12
+ severity: "none"
13
+ },
14
+ awaiting_approval: {
15
+ icon: "warning",
16
+ label: "Needs approval",
17
+ severity: "warning"
18
+ },
19
+ idle: {
20
+ icon: "check",
21
+ label: "Idle",
22
+ severity: "none"
23
+ },
24
+ parked: {
25
+ icon: "debug-pause",
26
+ label: "Parked",
27
+ severity: "none"
28
+ },
29
+ failed: {
30
+ icon: "error",
31
+ label: "Failed",
32
+ severity: "error"
33
+ },
34
+ closed: {
35
+ icon: "circle-slash",
36
+ label: "Closed",
37
+ severity: "none"
38
+ }
39
+ };
40
+ /**
41
+ * The status slot, connection first. A session status held over a dead socket is
42
+ * the last thing we heard, not the current state — so a lost link takes the slot
43
+ * rather than letting "Running" imply a turn is still streaming.
44
+ */
45
+ function statusPresentation(vitals) {
46
+ if (!vitals) return {
47
+ icon: "hubot",
48
+ label: "Connecting…",
49
+ severity: "none"
50
+ };
51
+ if (vitals.connection === "offline") return {
52
+ icon: "debug-disconnect",
53
+ label: "Offline",
54
+ severity: "error"
55
+ };
56
+ if (vitals.connection === "reconnecting") return {
57
+ icon: "sync~spin",
58
+ label: "Reconnecting…",
59
+ severity: "warning"
60
+ };
61
+ return STATUS_META[vitals.status] ?? {
62
+ icon: "hubot",
63
+ label: vitals.status,
64
+ severity: "none"
65
+ };
66
+ }
67
+ /** 0–100 → the colour a meter wears. One pair of thresholds for every surface. */
68
+ function meterSeverity(pct) {
69
+ if (pct === void 0) return "none";
70
+ if (pct >= 95) return "error";
71
+ if (pct >= 80) return "warning";
72
+ return "none";
73
+ }
74
+ /** The rate-limit window that gets the one visible slot: whichever is fullest,
75
+ * since the binding constraint is the one worth glancing at. */
76
+ function tightestWindow(rateLimits) {
77
+ const entries = Object.entries(rateLimits ?? {});
78
+ if (entries.length === 0) return void 0;
79
+ let best;
80
+ for (const [key, info] of entries) if ((info.status === "rejected" ? Number.POSITIVE_INFINITY : info.utilization ?? -1) > (best === void 0 ? Number.NEGATIVE_INFINITY : best.info.status === "rejected" ? Number.POSITIVE_INFINITY : best.info.utilization ?? -1)) best = {
81
+ key,
82
+ info
83
+ };
84
+ return best;
85
+ }
86
+ /** A rate-limit window's key, named for a human. */
87
+ function windowLabel(key) {
88
+ if (key === "five_hour") return "Session";
89
+ if (key === "seven_day") return "Weekly";
90
+ return key.replaceAll("_", " ");
91
+ }
92
+ /**
93
+ * The catalog row a session is actually running, or `undefined` for a model the
94
+ * list doesn't name. Matched leniently: a session reports the *resolved* id
95
+ * (`claude-sonnet-5`) where the row may be keyed on the alias (`sonnet`), and
96
+ * either can carry a `[1m]` context-window suffix.
97
+ */
98
+ function currentModel(vitals) {
99
+ const id = vitals?.model;
100
+ if (!id) return void 0;
101
+ const bare = (value) => value.replace(/\[.*\]$/, "");
102
+ const wanted = bare(id);
103
+ return vitals.models.find((m) => bare(m.value) === wanted || m.resolvedModel && bare(m.resolvedModel) === wanted);
104
+ }
105
+ /** A session's model, named the way the picker names it. Falls back to the raw
106
+ * id, and to "Default" while the session is on the CLI's own pick. */
107
+ function modelLabel(vitals) {
108
+ if (!vitals?.model) return "Default";
109
+ return currentModel(vitals)?.displayName ?? vitals.model;
110
+ }
111
+ /** Context percentage as its meter severity — the reading and the colour come
112
+ * from one place so a panel and a status bar never disagree. */
113
+ function contextSeverity(usage) {
114
+ return meterSeverity(usage?.percentage);
115
+ }
116
+ //#endregion
117
+ export { contextSeverity, currentModel, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, meterSeverity, modelLabel, rateLimitWindowSeconds, statusPresentation, tightestWindow, toolInputPreview, windowLabel };
118
+
119
+ //# sourceMappingURL=format.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.mjs","names":[],"sources":["../src/lib/status.ts"],"sourcesContent":["import type { ContextUsage, ModelOption, RateLimitInfo, SessionStatus } from '@workerdeck/protocol'\n\n/**\n * How a session's live readings become a status line — the pure half, so every\n * host spells \"Needs approval\", \"80% is a warning\" and \"which window is the\n * binding one\" the same way.\n *\n * Structurally typed against `SessionVitals` rather than importing it: this file\n * ships from the React-free `@workerdeck/ui/format` entry, and a host drawing\n * the readings outside React (the VS Code extension host in the window status\n * bar) must not pull a component graph in to do it. A real `SessionVitals`\n * satisfies every shape here.\n */\nexport type StatusSeverity = 'none' | 'warning' | 'error'\n\n/** What a status slot shows, before any host's icon vocabulary gets involved.\n * `icon` is a VS Code codicon name — the one host-shaped thing left, because the\n * alternative is a second mapping table in the only consumer. */\nexport type StatusPresentation = {\n icon: string\n label: string\n severity: StatusSeverity\n}\n\nexport type StatusReadings = {\n status: SessionStatus\n /** `@workerdeck/react`'s `ConnectionState`, structurally — the link state wins\n * the slot, so it has to be part of the reading. */\n connection?: 'live' | 'reconnecting' | 'offline'\n}\n\nconst STATUS_META: Record<SessionStatus, StatusPresentation> = {\n starting: { icon: 'loading~spin', label: 'Starting', severity: 'none' },\n running: { icon: 'loading~spin', label: 'Running', severity: 'none' },\n awaiting_approval: { icon: 'warning', label: 'Needs approval', severity: 'warning' },\n idle: { icon: 'check', label: 'Idle', severity: 'none' },\n parked: { icon: 'debug-pause', label: 'Parked', severity: 'none' },\n failed: { icon: 'error', label: 'Failed', severity: 'error' },\n closed: { icon: 'circle-slash', label: 'Closed', severity: 'none' },\n}\n\n/**\n * The status slot, connection first. A session status held over a dead socket is\n * the last thing we heard, not the current state — so a lost link takes the slot\n * rather than letting \"Running\" imply a turn is still streaming.\n */\nexport function statusPresentation(vitals: StatusReadings | undefined): StatusPresentation {\n if (!vitals) return { icon: 'hubot', label: 'Connecting…', severity: 'none' }\n if (vitals.connection === 'offline') {\n return { icon: 'debug-disconnect', label: 'Offline', severity: 'error' }\n }\n if (vitals.connection === 'reconnecting') {\n return { icon: 'sync~spin', label: 'Reconnecting…', severity: 'warning' }\n }\n return STATUS_META[vitals.status] ?? { icon: 'hubot', label: vitals.status, severity: 'none' }\n}\n\n/** 0–100 → the colour a meter wears. One pair of thresholds for every surface. */\nexport function meterSeverity(pct: number | undefined): StatusSeverity {\n if (pct === undefined) return 'none'\n if (pct >= 95) return 'error'\n if (pct >= 80) return 'warning'\n return 'none'\n}\n\n/** The rate-limit window that gets the one visible slot: whichever is fullest,\n * since the binding constraint is the one worth glancing at. */\nexport function tightestWindow(\n rateLimits: Record<string, RateLimitInfo> | undefined,\n): { key: string; info: RateLimitInfo } | undefined {\n const entries = Object.entries(rateLimits ?? {})\n if (entries.length === 0) return undefined\n let best: { key: string; info: RateLimitInfo } | undefined\n for (const [key, info] of entries) {\n // A rejected window outranks any utilization: it is the one actually blocking.\n const rank = info.status === 'rejected' ? Number.POSITIVE_INFINITY : (info.utilization ?? -1)\n const bestRank =\n best === undefined\n ? Number.NEGATIVE_INFINITY\n : best.info.status === 'rejected'\n ? Number.POSITIVE_INFINITY\n : (best.info.utilization ?? -1)\n if (rank > bestRank) best = { key, info }\n }\n return best\n}\n\n/** A rate-limit window's key, named for a human. */\nexport function windowLabel(key: string): string {\n if (key === 'five_hour') return 'Session'\n if (key === 'seven_day') return 'Weekly'\n return key.replaceAll('_', ' ')\n}\n\nexport type ModelReadings = { model?: string; models: readonly ModelOption[] }\n\n/**\n * The catalog row a session is actually running, or `undefined` for a model the\n * list doesn't name. Matched leniently: a session reports the *resolved* id\n * (`claude-sonnet-5`) where the row may be keyed on the alias (`sonnet`), and\n * either can carry a `[1m]` context-window suffix.\n */\nexport function currentModel(vitals: ModelReadings | undefined): ModelOption | undefined {\n const id = vitals?.model\n if (!id) return undefined\n const bare = (value: string) => value.replace(/\\[.*\\]$/, '')\n const wanted = bare(id)\n return vitals.models.find(\n (m) => bare(m.value) === wanted || (m.resolvedModel && bare(m.resolvedModel) === wanted),\n )\n}\n\n/** A session's model, named the way the picker names it. Falls back to the raw\n * id, and to \"Default\" while the session is on the CLI's own pick. */\nexport function modelLabel(vitals: ModelReadings | undefined): string {\n if (!vitals?.model) return 'Default'\n return currentModel(vitals)?.displayName ?? vitals.model\n}\n\n/** Context percentage as its meter severity — the reading and the colour come\n * from one place so a panel and a status bar never disagree. */\nexport function contextSeverity(usage: ContextUsage | undefined): StatusSeverity {\n return meterSeverity(usage?.percentage)\n}\n"],"mappings":";;AA+BA,MAAM,cAAyD;CAC7D,UAAU;EAAE,MAAM;EAAgB,OAAO;EAAY,UAAU;EAAQ;CACvE,SAAS;EAAE,MAAM;EAAgB,OAAO;EAAW,UAAU;EAAQ;CACrE,mBAAmB;EAAE,MAAM;EAAW,OAAO;EAAkB,UAAU;EAAW;CACpF,MAAM;EAAE,MAAM;EAAS,OAAO;EAAQ,UAAU;EAAQ;CACxD,QAAQ;EAAE,MAAM;EAAe,OAAO;EAAU,UAAU;EAAQ;CAClE,QAAQ;EAAE,MAAM;EAAS,OAAO;EAAU,UAAU;EAAS;CAC7D,QAAQ;EAAE,MAAM;EAAgB,OAAO;EAAU,UAAU;EAAQ;CACpE;;;;;;AAOD,SAAgB,mBAAmB,QAAwD;AACzF,KAAI,CAAC,OAAQ,QAAO;EAAE,MAAM;EAAS,OAAO;EAAe,UAAU;EAAQ;AAC7E,KAAI,OAAO,eAAe,UACxB,QAAO;EAAE,MAAM;EAAoB,OAAO;EAAW,UAAU;EAAS;AAE1E,KAAI,OAAO,eAAe,eACxB,QAAO;EAAE,MAAM;EAAa,OAAO;EAAiB,UAAU;EAAW;AAE3E,QAAO,YAAY,OAAO,WAAW;EAAE,MAAM;EAAS,OAAO,OAAO;EAAQ,UAAU;EAAQ;;;AAIhG,SAAgB,cAAc,KAAyC;AACrE,KAAI,QAAQ,KAAA,EAAW,QAAO;AAC9B,KAAI,OAAO,GAAI,QAAO;AACtB,KAAI,OAAO,GAAI,QAAO;AACtB,QAAO;;;;AAKT,SAAgB,eACd,YACkD;CAClD,MAAM,UAAU,OAAO,QAAQ,cAAc,EAAE,CAAC;AAChD,KAAI,QAAQ,WAAW,EAAG,QAAO,KAAA;CACjC,IAAI;AACJ,MAAK,MAAM,CAAC,KAAK,SAAS,QASxB,MAPa,KAAK,WAAW,aAAa,OAAO,oBAAqB,KAAK,eAAe,OAExF,SAAS,KAAA,IACL,OAAO,oBACP,KAAK,KAAK,WAAW,aACnB,OAAO,oBACN,KAAK,KAAK,eAAe,IACb,QAAO;EAAE;EAAK;EAAM;AAE3C,QAAO;;;AAIT,SAAgB,YAAY,KAAqB;AAC/C,KAAI,QAAQ,YAAa,QAAO;AAChC,KAAI,QAAQ,YAAa,QAAO;AAChC,QAAO,IAAI,WAAW,KAAK,IAAI;;;;;;;;AAWjC,SAAgB,aAAa,QAA4D;CACvF,MAAM,KAAK,QAAQ;AACnB,KAAI,CAAC,GAAI,QAAO,KAAA;CAChB,MAAM,QAAQ,UAAkB,MAAM,QAAQ,WAAW,GAAG;CAC5D,MAAM,SAAS,KAAK,GAAG;AACvB,QAAO,OAAO,OAAO,MAClB,MAAM,KAAK,EAAE,MAAM,KAAK,UAAW,EAAE,iBAAiB,KAAK,EAAE,cAAc,KAAK,OAClF;;;;AAKH,SAAgB,WAAW,QAA2C;AACpE,KAAI,CAAC,QAAQ,MAAO,QAAO;AAC3B,QAAO,aAAa,OAAO,EAAE,eAAe,OAAO;;;;AAKrD,SAAgB,gBAAgB,OAAiD;AAC/E,QAAO,cAAc,OAAO,WAAW"}
package/build/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-ljc3lKpA.mjs";
2
- import { a as SessionVitals, c as useTranscriptVariant, d as PermissionModeMeta, f as PermissionModeSelect, h as permissionModeMeta, i as SessionSurfacePanel, l as PERMISSION_MODES, m as permissionModeChoices, n as SessionPanel, o as TranscriptVariant, p as PermissionModeSelectProps, r as SessionPanelProps, s as TranscriptVariantProvider, t as SessionControls, u as PermissionModeChoice } from "./SessionPanel-CyhygZx_.mjs";
2
+ import { _ as permissionModeChoices, a as SessionVitals, c as TranscriptVariant, d as useTranscriptVariant, f as PERMISSION_MODES, g as PermissionModeSelectProps, h as PermissionModeSelect, i as SessionSurfacePanel, l as TranscriptVariantProvider, m as PermissionModeMeta, n as SessionPanel, o as TranscriptDensity, p as PermissionModeChoice, r as SessionPanelProps, s as TranscriptDensityProvider, t as SessionControls, u as useTranscriptDensity, v as permissionModeMeta } from "./SessionPanel-CZMA44NM.mjs";
3
3
  import * as _$react from "react";
4
4
  import { ButtonHTMLAttributes, FunctionComponent, HTMLAttributes, InputHTMLAttributes, ReactElement, ReactNode, Ref, RefObject, TextareaHTMLAttributes } from "react";
5
5
  import { VariantProps } from "class-variance-authority";
@@ -15,7 +15,7 @@ import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
15
15
  import * as _$_base_ui_react_tooltip0 from "@base-ui/react/tooltip";
16
16
  import { Tooltip } from "@base-ui/react/tooltip";
17
17
  import { toast } from "sonner";
18
- import { ContextUsage, ModelOption, PermissionRequest, ProfileEngine, QuestionBehavior, RateLimitInfo, SessionInfo, SessionStatus, SkillInfo, SlashCommandInfo, UserQuestion } from "@workerdeck/protocol";
18
+ import { ContextUsage, ModelOption, PermissionRequest, ProfileEngine, QuestionBehavior, RateLimitInfo, SessionInfo, SessionRow, SessionStatus, SkillInfo, SlashCommandInfo, UserQuestion, ViewConfig, WorkspaceScope } from "@workerdeck/protocol";
19
19
  import { ConnectionState, TranscriptItem, TranscriptState, UseAttachmentsResult } from "@workerdeck/react";
20
20
  import * as _$class_variance_authority_types0 from "class-variance-authority/types";
21
21
  import { WorkerDeckClient } from "@workerdeck/client";
@@ -736,6 +736,12 @@ interface TranscriptProps {
736
736
  * vertical space is scarce. See {@link TranscriptVariant}.
737
737
  */
738
738
  variant?: TranscriptVariant;
739
+ /**
740
+ * How much air each row gets: `comfortable` (default — a blank line between
741
+ * messages, as the Claude Code CLI does) or `compact`. Independent of
742
+ * {@link TranscriptVariant}. See {@link TranscriptDensity}.
743
+ */
744
+ density?: TranscriptDensity;
739
745
  /**
740
746
  * Catch-up: `from` is how many items had been seen last time, `since` when
741
747
  * that was. A recap row is drawn at that boundary and everything above it is
@@ -763,6 +769,7 @@ declare function Transcript({
763
769
  canBrowseFiles,
764
770
  hostImage,
765
771
  variant,
772
+ density,
766
773
  catchUp,
767
774
  jumpToRecapRef,
768
775
  className
@@ -808,9 +815,12 @@ interface MessageProps extends HTMLAttributes<HTMLDivElement> {
808
815
  /**
809
816
  * One chat turn row.
810
817
  *
811
- * `cards`: user messages sit right in a bubble; assistant content is flat,
812
- * full-width (the AI-chat convention assistant output is the page, user input
813
- * is quoted).
818
+ * `cards`: user messages sit in a bubble, assistant content is flat and
819
+ * full-width. Both are **left-aligned**: the transcript is a log read top to
820
+ * bottom, and an editor-shaped host (a full-width session view beside a sessions
821
+ * rail) has no right edge to anchor to — a bubble drifting right in a 1600px
822
+ * column separates a prompt from the reply it produced. The bubble alone is
823
+ * enough to say who spoke.
814
824
  *
815
825
  * `lines`: both are left-aligned full-width line items behind a gutter glyph —
816
826
  * `❯` for what was typed, `●` for what the model said. No bubble: a prompt is
@@ -874,9 +884,10 @@ interface LoaderProps {
874
884
  /**
875
885
  * "The agent is working and hasn't produced output yet."
876
886
  *
877
- * `lines`: a terminal working line — animated glyph in the gutter, a verb, and
878
- * the readings that answer "should I still be waiting?" in one parenthesis.
879
- * `cards`: the three-dot pulse, unchanged.
887
+ * `lines`: a terminal working line — the mark's own pulse in the gutter (see
888
+ * `pulse.tsx`), a verb, and the readings that answer "should I still be
889
+ * waiting?" in one parenthesis. `cards`: the three-dot pulse, unchanged — the
890
+ * dashboard's loader is not a gutter glyph and has no column to pulse in.
880
891
  */
881
892
  declare function Loader({
882
893
  label,
@@ -1136,8 +1147,11 @@ interface StatusBarProps {
1136
1147
  onOpenStatus?: () => void;
1137
1148
  onOpenContext?: () => void;
1138
1149
  onOpenUsage?: () => void;
1139
- /** Trailing slot — the session-actions menu, in the panel's top-right. */
1150
+ /** Trailing slot — the session-actions menu, at the bar's trailing edge. */
1140
1151
  actions?: ReactNode;
1152
+ /** Which edge the bar sits on, so its separating rule goes on the other side.
1153
+ * Placement is the panel's decision; this only styles it. */
1154
+ placement?: 'top' | 'bottom';
1141
1155
  className?: string;
1142
1156
  }
1143
1157
  declare function StatusBar({
@@ -1148,6 +1162,7 @@ declare function StatusBar({
1148
1162
  onOpenContext,
1149
1163
  onOpenUsage,
1150
1164
  actions,
1165
+ placement,
1151
1166
  className
1152
1167
  }: StatusBarProps): _$react.JSX.Element;
1153
1168
  //#endregion
@@ -1349,6 +1364,110 @@ declare function SessionList({
1349
1364
  className
1350
1365
  }: SessionListProps): _$react.JSX.Element;
1351
1366
  //#endregion
1367
+ //#region src/components/agent/SessionBrowser.d.ts
1368
+ /**
1369
+ * A sessions list with the affordances a list of thirty needs: search, facets,
1370
+ * grouping, sorting, unread counts, and one honest line about what is hidden.
1371
+ *
1372
+ * The *rules* are `@workerdeck/protocol`'s (`filterRows`/`groupRows`/
1373
+ * `subsetSummary`), not this component's — the VS Code sidebar renders the same
1374
+ * model with workbench chrome, its activity-bar badge counts the same rows this
1375
+ * would show, and iOS mirrors them in Swift. What lives here is the styled
1376
+ * rendering of that model, so a host that wants the dashboard's look gets it
1377
+ * without reimplementing the model behind it.
1378
+ *
1379
+ * `SessionList` remains beside this for the plain case (a fixed set of rows, no
1380
+ * controls); this is what you reach for when the list is the screen.
1381
+ */
1382
+ interface SessionBrowserProps {
1383
+ rows: SessionRow[];
1384
+ config: ViewConfig;
1385
+ onConfigChange: (config: ViewConfig) => void;
1386
+ /** The host's own folders, if it has such a notion. Absent — a dashboard, a
1387
+ * phone — makes the scope filter genuinely inert rather than empty. */
1388
+ scope?: WorkspaceScope;
1389
+ activeId?: string;
1390
+ onSelect?: (row: SessionRow) => void;
1391
+ onDelete?: (row: SessionRow) => void;
1392
+ /**
1393
+ * Rename, from the row's pencil. Empty string restores the derived title. A
1394
+ * gateway edit (`PATCH /sessions/:id`), never a local override — every client
1395
+ * should see the same name. Omit to make titles read-only.
1396
+ *
1397
+ * A hover affordance rather than the extension's double-click-the-title,
1398
+ * because here a single click on the row navigates: the *first* click of a
1399
+ * double-click would have already left the page.
1400
+ */
1401
+ onRename?: (row: SessionRow, title: string) => void;
1402
+ /** Rendered when nothing at all exists (as opposed to nothing matching). */
1403
+ emptyState?: React.ReactNode;
1404
+ /**
1405
+ * Whether the search + facet bar is shown. Defaults to `true` — a list that
1406
+ * *is* the screen shows its controls.
1407
+ *
1408
+ * A host with somewhere better to put the toggle (a view title bar) passes
1409
+ * `false` and owns the boolean itself, the way the VS Code extension does: the
1410
+ * key lives where the commands do. Two rules come with it, and they are why
1411
+ * this hides only the bar and nothing else — **closing the bar never clears
1412
+ * the filters**, and the subset line below it renders either way, so a list
1413
+ * filtered by a control you can't currently see still says so.
1414
+ */
1415
+ showControls?: boolean;
1416
+ className?: string;
1417
+ }
1418
+ /**
1419
+ * How a list row is drawn, in one place, so `SidebarRow` in `web` matches this
1420
+ * exactly rather than approximating it — the dashboard's other three sidebars
1421
+ * are that component, and a sessions list that hovered differently from the
1422
+ * gateways list beside it would read as a different product.
1423
+ *
1424
+ * Two rules are load-bearing:
1425
+ *
1426
+ * - **Fill means hover, and only hover.** It stays on the row whether or not
1427
+ * the row is selected, because a selected row still has to answer the
1428
+ * pointer. Selection gets the gutter instead.
1429
+ * - **`ml-0` on the selected row is not cosmetic.** It hands the accent border
1430
+ * the 4px the margin was holding, so the text does not shift sideways as a
1431
+ * row becomes the selected one. The squared left corners are what let the bar
1432
+ * sit flush against the sidebar edge.
1433
+ */
1434
+ declare function rowShapeClass(active: boolean): string;
1435
+ declare function SessionBrowser({
1436
+ rows,
1437
+ config,
1438
+ onConfigChange,
1439
+ scope,
1440
+ activeId,
1441
+ onSelect,
1442
+ onDelete,
1443
+ onRename,
1444
+ emptyState,
1445
+ showControls,
1446
+ className
1447
+ }: SessionBrowserProps): _$react.JSX.Element;
1448
+ /**
1449
+ * State as one glyph on the right edge — a ringing bell when it wants a human, a
1450
+ * spinner while it works, a moon when it is only sleeping. Replaces the text
1451
+ * badge: in a sidebar the word costs more room than it earns, and the states
1452
+ * that matter are the two you can recognise without reading.
1453
+ */
1454
+ declare function SessionStatusIcon({
1455
+ row
1456
+ }: {
1457
+ row: SessionRow;
1458
+ }): _$react.JSX.Element;
1459
+ //#endregion
1460
+ //#region src/components/agent/EngineIcon.d.ts
1461
+ declare function EngineIcon({
1462
+ engine,
1463
+ model,
1464
+ className
1465
+ }: {
1466
+ engine: string;
1467
+ model?: string;
1468
+ className?: string;
1469
+ }): _$react.JSX.Element;
1470
+ //#endregion
1352
1471
  //#region src/components/agent/SessionEmptyState.d.ts
1353
1472
  interface SessionEmptyStateProps {
1354
1473
  cwd?: string;
@@ -1451,5 +1570,5 @@ declare function toolIcon(toolName: string): LucideIcon;
1451
1570
  */
1452
1571
  declare function isMutatingTool(toolName: string): boolean;
1453
1572
  //#endregion
1454
- export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerFileMatch, type ComposerHandle, type ComposerProps, ContextDialog, type ContextDialogProps, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, FileCard, type FileCardProps, type FileDeliveredItem, HostFilesDialog, type HostFilesDialogProps, Input, Loader, McpDialog, type McpDialogProps, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, type MessageProps, ModelSelect, type ModelSelectProps, PERMISSION_MODES, type PermissionModeChoice, type PermissionModeMeta, PermissionModeSelect, type PermissionModeSelectProps, PermissionPrompt, type PermissionPromptProps, ProgressRing, type ProgressRingProps, PromptArea, type PromptAreaHandle, type PromptAreaProps, PromptTokenText, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, type SessionControls, SessionEmptyState, type SessionEmptyStateProps, SessionInfoDialog, type SessionInfoDialogProps, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, type SessionSurfacePanel, type SessionVitals, SkillsDialog, type SkillsDialogProps, Spinner, Splitter, type SplitterProps, StatusBar, type StatusBarProps, type TextSegment, Textarea, Tip, Toaster, ToolCallCard, type ToolCallCardProps, type ToolCallItem, TooltipContent, TooltipProvider, Transcript, type TranscriptProps, type TranscriptVariant, TranscriptVariantProvider, type TriggerConfig, type TriggerSuggestion, UsageDialog, type UsageDialogProps, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptVariant };
1573
+ export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardHeader, CardTitle, type ChipSegment, CodeBlock, type CodeBlockProps, Composer, type ComposerFileMatch, type ComposerHandle, type ComposerProps, ContextDialog, type ContextDialogProps, Conversation, ConversationContent, type ConversationProps, ConversationScrollButton, CopyButton, type CopyButtonProps, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, EngineIcon, FileCard, type FileCardProps, type FileDeliveredItem, HostFilesDialog, type HostFilesDialogProps, Input, Loader, McpDialog, type McpDialogProps, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, type MessageProps, ModelSelect, type ModelSelectProps, PERMISSION_MODES, type PermissionModeChoice, type PermissionModeMeta, PermissionModeSelect, type PermissionModeSelectProps, PermissionPrompt, type PermissionPromptProps, ProgressRing, type ProgressRingProps, PromptArea, type PromptAreaHandle, type PromptAreaProps, PromptTokenText, QUESTION_BEHAVIORS, type QuestionBehaviorMeta, QuestionPrompt, type QuestionPromptProps, Reasoning, type ReasoningProps, Response, type ResponseProps, STATUS_META, type Segment, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, type SessionBrowserProps, type SessionControls, SessionEmptyState, type SessionEmptyStateProps, SessionInfoDialog, type SessionInfoDialogProps, SessionList, SessionListItem, type SessionListItemProps, type SessionListProps, SessionPanel, type SessionPanelProps, SessionStatusIcon, type SessionSurfacePanel, type SessionVitals, SkillsDialog, type SkillsDialogProps, Spinner, Splitter, type SplitterProps, StatusBar, type StatusBarProps, type TextSegment, Textarea, Tip, Toaster, ToolCallCard, type ToolCallCardProps, type ToolCallItem, TooltipContent, TooltipProvider, Transcript, type TranscriptDensity, TranscriptDensityProvider, type TranscriptProps, type TranscriptVariant, TranscriptVariantProvider, type TriggerConfig, type TriggerSuggestion, UsageDialog, type UsageDialogProps, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, rowShapeClass, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptDensity, useTranscriptVariant };
1455
1574
  //# sourceMappingURL=index.d.mts.map