@workerdeck/ui 0.15.0 → 0.17.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 +60 -0
- package/build/{SessionPanel-J2U8v88q.d.mts → SessionPanel-CnNYEX80.d.mts} +170 -21
- package/build/{SessionPanel-DI1NO4l8.mjs → SessionPanel-DMPhsNlW.mjs} +4759 -1483
- package/build/SessionPanel-DMPhsNlW.mjs.map +1 -0
- package/build/{format-ljc3lKpA.d.mts → format-DfI_je9S.d.mts} +1 -1
- package/build/format.d.mts +39 -4
- package/build/format.mjs +2 -118
- package/build/index.d.mts +493 -45
- package/build/index.mjs +343 -17
- package/build/index.mjs.map +1 -1
- package/build/status-Ydzi7n6j.mjs +143 -0
- package/build/status-Ydzi7n6j.mjs.map +1 -0
- package/build/workspace.d.mts +9 -1
- package/build/workspace.mjs +108 -5
- package/build/workspace.mjs.map +1 -1
- package/package.json +16 -7
- package/src/components/agent/Composer.tsx +189 -89
- package/src/components/agent/Conversation.tsx +12 -12
- package/src/components/agent/FileCard.tsx +0 -26
- package/src/components/agent/FileTree.tsx +9 -8
- package/src/components/agent/Loader.tsx +22 -72
- package/src/components/agent/Message.tsx +11 -46
- package/src/components/agent/PermissionPrompt.tsx +0 -92
- package/src/components/agent/ProjectIcon.tsx +119 -0
- package/src/components/agent/QuestionPrompt.tsx +0 -122
- package/src/components/agent/Reasoning.tsx +5 -19
- package/src/components/agent/Response.tsx +1 -132
- package/src/components/agent/SessionBrowser.tsx +84 -3
- package/src/components/agent/SessionPanel.tsx +249 -28
- package/src/components/agent/SessionWorkspace.tsx +29 -0
- package/src/components/agent/StatusBar.tsx +20 -4
- package/src/components/agent/ToolCallCard.tsx +85 -112
- package/src/components/agent/Transcript.tsx +780 -203
- package/src/components/agent/UsageDialog.tsx +20 -106
- package/src/components/agent/UsageMeters.tsx +133 -0
- package/src/components/agent/pulse.tsx +3 -2
- package/src/components/agent/tool-result-fetch.tsx +36 -0
- package/src/components/agent/tool-result-image.tsx +209 -0
- package/src/components/agent/transcript-rows.ts +173 -0
- package/src/components/agent/transcript-variant.tsx +29 -51
- package/src/components/agent/use-height-epoch.ts +60 -0
- package/src/components/agent/use-path-links.ts +147 -0
- package/src/components/agent/use-transcript-jumps.ts +190 -0
- package/src/components/prompt-area/cursor-helpers.ts +65 -0
- package/src/components/prompt-area/use-prompt-area.ts +16 -10
- package/src/components/terminal/PermissionPrompt.tsx +119 -0
- package/src/components/terminal/QuestionPrompt.tsx +322 -0
- package/src/components/terminal/StatusLine.tsx +159 -0
- package/src/components/terminal/TerminalTranscript.tsx +225 -0
- package/src/components/terminal/affordances.tsx +118 -0
- package/src/components/terminal/blocks.ts +232 -0
- package/src/components/terminal/diff.tsx +130 -0
- package/src/components/terminal/height.ts +770 -0
- package/src/components/terminal/image-box.ts +53 -0
- package/src/components/terminal/items.tsx +486 -0
- package/src/components/terminal/markdown.tsx +191 -0
- package/src/components/terminal/press.tsx +120 -0
- package/src/components/terminal/prompt.tsx +343 -0
- package/src/components/terminal/result-preview.ts +86 -0
- package/src/components/terminal/row.tsx +132 -0
- package/src/components/terminal/scrubber.tsx +784 -0
- package/src/components/terminal/surface.tsx +80 -0
- package/src/components/terminal/tool-run.ts +224 -0
- package/src/index.ts +36 -1
- package/src/lib/status.ts +59 -3
- package/src/lib/tool-icon.ts +14 -0
- package/src/styles/terminal.css +1081 -0
- package/src/styles/theme.css +41 -0
- package/build/SessionPanel-DI1NO4l8.mjs.map +0 -1
- package/build/format.mjs.map +0 -1
- package/src/components/agent/line-prompt.tsx +0 -249
package/build/index.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as TranscriptDensityProvider, A as PermissionModeSelect, At as MenuTrigger, B as TerminalSurface, Bt as Button, C as TerminalQuestionPrompt, Ct as DialogHeader, D as parseUserQuestions, Dt as MenuContent, E as QuestionPrompt, Et as Menu, F as McpDialog, Ft as SelectTrigger, G as Blank, H as TerminalDiff, Ht as cn, I as HostFilesDialog, It as SelectValue, J as CopyAction, K as Ink, L as ContextDialog, Lt as Input, M as permissionModeMeta, Mt as SelectContent, N as ModelSelect, Nt as SelectItem, O as PermissionPrompt, Ot as MenuItem, P as SkillsDialog, Pt as SelectItemText, Q as toolIcon, R as Composer, Rt as Badge, S as SessionInfoDialog, St as DialogContent, T as QUESTION_BEHAVIORS, Tt as DialogTrigger, U as previewPatch, V as TerminalMarkdown, Vt as buttonVariants, W as Band, X as useAffordances, Y as WithActions, Z as isMutatingTool, _ as Conversation, _t as TooltipContent, a as Transcript, at as mentionTrigger, b as StatusBar, bt as DialogBody, c as ToolCallCard, ct as plainTextToSegments, d as Response, dt as Splitter, et as TranscriptVariantProvider, f as PromptTokenText, ft as CodeBlock, g as FileCard, gt as Tip, h as Loader, ht as copyText, i as useMinuteClock, it as hashtagTrigger, j as permissionModeChoices, jt as Select, k as PERMISSION_MODES, kt as MenuSeparator, l as SessionEmptyState, lt as segmentsToPlainText, m as MessageContent, mt as CopyButton, n as UsageDialog, nt as useTranscriptVariant, o as TerminalItemView, ot as usePromptAreaState, p as Message, pt as Spinner, q as Row, r as UsageMeters, rt as commandTrigger, s as TerminalTranscript, st as PromptArea, t as SessionPanel, tt as useTranscriptDensity, u as Reasoning, ut as ProgressRing, v as ConversationContent, vt as TooltipProvider, w as TerminalPermissionPrompt, wt as DialogRow, x as STATUS_META, xt as DialogClose, y as ConversationScrollButton, yt as Dialog, z as skillPrompt, zt as badgeVariants } from "./SessionPanel-DMPhsNlW.mjs";
|
|
2
2
|
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";
|
|
3
|
+
import { a as statusPresentation, c as windowLabel, i as modelLabel, o as tightestWindow, r as meterSeverity, t as contextSeverity } from "./status-Ydzi7n6j.mjs";
|
|
3
4
|
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import { BellRing, CircleAlert, CircleSlash, Layers, Moon, PauseCircle, Pencil, Search, SearchX, Trash2, X } from "lucide-react";
|
|
5
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Anchor, Atom, Beaker, BellRing, Bike, Binary, Blocks, Bot, Box, Brain, Briefcase, Brush, Bug, Building2, Cable, Camera, Car, Cat, CircleAlert, CircleSlash, CircuitBoard, Cloud, Code, Coffee, Cog, Compass, Container, Cpu, CreditCard, Database, Diamond, Dog, Feather, Film, Flame, FlaskConical, Folder, Gamepad2, Gauge, Gem, Ghost, Gift, GitBranch, Globe, GraduationCap, Hammer, Hexagon, House, Image, Key, Landmark, Laptop, Layers, Leaf, Library, Lightbulb, Lock, Mail, Map as Map$1, MessageCircle, Mic, Monitor, Moon, Mountain, Music, Network, Newspaper, Notebook, Orbit, Package, Palette, PauseCircle, PenTool, Pencil, Phone, PiggyBank, Plane, Plug, Puzzle, Radar, Radio, Receipt, Rocket, Ruler, Satellite, Scale, Scissors, Search, SearchX, Server, Shield, Ship, ShoppingCart, Signal, Smartphone, Sparkles, Sprout, Square, Star, Sun, Table, Tag, Target, Telescope, Terminal, TestTube, Trash2, TreePine, Trophy, Truck, Umbrella, Users, Wallet, Wand, Waves, Webhook, Wifi, Wrench, X, Zap } from "lucide-react";
|
|
6
7
|
import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
|
|
7
8
|
import { Toaster as Toaster$1, toast } from "sonner";
|
|
8
|
-
import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, filterRows, groupRows, hasFacetFilter, sessionLabel, subsetSummary } from "@workerdeck/protocol";
|
|
9
|
+
import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, filterRows, groupRows, hasFacetFilter, projectLabel, projectsOf, sessionLabel, subsetSummary } from "@workerdeck/protocol";
|
|
9
10
|
//#region src/components/ui/Card.tsx
|
|
10
11
|
function Card({ className, ...props }) {
|
|
11
12
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -139,6 +140,108 @@ function getChipsByTrigger(segments, trigger) {
|
|
|
139
140
|
return segments.filter((seg) => seg.type === "chip" && seg.trigger === trigger);
|
|
140
141
|
}
|
|
141
142
|
//#endregion
|
|
143
|
+
//#region src/components/terminal/StatusLine.tsx
|
|
144
|
+
/**
|
|
145
|
+
* The session's readings, as one line.
|
|
146
|
+
*
|
|
147
|
+
* The styled bar puts each of these in its own affordance — a progress ring, a
|
|
148
|
+
* badge, a tooltip — which is right for a dashboard and wrong here for the usual
|
|
149
|
+
* reason: a terminal has one line height, and five widgets of five different
|
|
150
|
+
* heights is five different rhythms in a row that is supposed to be quiet. So
|
|
151
|
+
* they are words, `·`-separated, exactly as the CLI's own status line writes
|
|
152
|
+
* them.
|
|
153
|
+
*
|
|
154
|
+
* The readings themselves come from the same helpers the styled bar uses
|
|
155
|
+
* (`lib/status.ts`), and that matters more than it looks: `statusPresentation`
|
|
156
|
+
* is where the rule lives that **a dropped socket outranks the session status**,
|
|
157
|
+
* because a status held over a dead socket is a stale reading being presented as
|
|
158
|
+
* a live one. Re-deriving that here would be a second answer to a question that
|
|
159
|
+
* already has one.
|
|
160
|
+
*/
|
|
161
|
+
/** Severity → tone. The 80/95 thresholds are `lib/status.ts`'s, not new ones. */
|
|
162
|
+
const SEVERITY_TONE = {
|
|
163
|
+
none: "dim",
|
|
164
|
+
warning: "yellow",
|
|
165
|
+
error: "red"
|
|
166
|
+
};
|
|
167
|
+
/** One reading. A button only when it leads somewhere — a segment that looks
|
|
168
|
+
* pressable and does nothing is worse than plain text. */
|
|
169
|
+
function Reading({ tone, onPress, label, children }) {
|
|
170
|
+
if (!onPress) return /* @__PURE__ */ jsx(Ink, {
|
|
171
|
+
tone,
|
|
172
|
+
children
|
|
173
|
+
});
|
|
174
|
+
return /* @__PURE__ */ jsx("button", {
|
|
175
|
+
type: "button",
|
|
176
|
+
className: "term-reading",
|
|
177
|
+
onClick: onPress,
|
|
178
|
+
title: label,
|
|
179
|
+
children: /* @__PURE__ */ jsx(Ink, {
|
|
180
|
+
tone,
|
|
181
|
+
children
|
|
182
|
+
})
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function TerminalStatusLine({ state, rateLimits, connection, onOpenStatus, onOpenContext, onOpenUsage }) {
|
|
186
|
+
const presentation = statusPresentation({
|
|
187
|
+
status: state.status,
|
|
188
|
+
connection
|
|
189
|
+
});
|
|
190
|
+
const usage = state.contextUsage;
|
|
191
|
+
const window = tightestWindow(rateLimits ?? state.rateLimits);
|
|
192
|
+
const model = modelLabel({
|
|
193
|
+
model: state.model,
|
|
194
|
+
models: state.models ?? []
|
|
195
|
+
});
|
|
196
|
+
const parts = [/* @__PURE__ */ jsx(Reading, {
|
|
197
|
+
tone: SEVERITY_TONE[presentation.severity],
|
|
198
|
+
onPress: onOpenStatus,
|
|
199
|
+
label: "Session status",
|
|
200
|
+
children: presentation.label
|
|
201
|
+
}, "status")];
|
|
202
|
+
if (usage) parts.push(/* @__PURE__ */ jsxs(Reading, {
|
|
203
|
+
tone: SEVERITY_TONE[contextSeverity(usage)],
|
|
204
|
+
onPress: onOpenContext,
|
|
205
|
+
label: "Context window",
|
|
206
|
+
children: [
|
|
207
|
+
Math.round(usage.percentage),
|
|
208
|
+
"% ctx (",
|
|
209
|
+
formatTokens(usage.totalTokens),
|
|
210
|
+
")"
|
|
211
|
+
]
|
|
212
|
+
}, "context"));
|
|
213
|
+
if (window) parts.push(/* @__PURE__ */ jsxs(Reading, {
|
|
214
|
+
tone: SEVERITY_TONE[meterSeverity(window.info.utilization)],
|
|
215
|
+
onPress: onOpenUsage,
|
|
216
|
+
label: "Plan usage",
|
|
217
|
+
children: [
|
|
218
|
+
Math.round(window.info.utilization ?? 0),
|
|
219
|
+
"% ",
|
|
220
|
+
windowLabel(window.key)
|
|
221
|
+
]
|
|
222
|
+
}, "usage"));
|
|
223
|
+
if (state.totalCostUsd > 0) parts.push(/* @__PURE__ */ jsx(Ink, {
|
|
224
|
+
tone: "faint",
|
|
225
|
+
children: formatCost(state.totalCostUsd)
|
|
226
|
+
}, "cost"));
|
|
227
|
+
if (model) parts.push(/* @__PURE__ */ jsx(Ink, {
|
|
228
|
+
tone: "faint",
|
|
229
|
+
children: model
|
|
230
|
+
}, "model"));
|
|
231
|
+
if (state.permissionMode && state.permissionMode !== "default") parts.push(/* @__PURE__ */ jsx(Ink, {
|
|
232
|
+
tone: "yellow",
|
|
233
|
+
children: state.permissionMode
|
|
234
|
+
}, "mode"));
|
|
235
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
236
|
+
"data-slot": "status-line",
|
|
237
|
+
tone: "dim",
|
|
238
|
+
children: parts.map((part, index) => /* @__PURE__ */ jsxs("span", { children: [index > 0 ? /* @__PURE__ */ jsx(Ink, {
|
|
239
|
+
tone: "faint",
|
|
240
|
+
children: " · "
|
|
241
|
+
}) : null, part] }, index))
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
//#endregion
|
|
142
245
|
//#region src/components/agent/SessionList.tsx
|
|
143
246
|
function SessionListItem({ session, active, onSelect, onDelete }) {
|
|
144
247
|
const meta = STATUS_META[session.status];
|
|
@@ -208,6 +311,179 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
|
|
|
208
311
|
});
|
|
209
312
|
}
|
|
210
313
|
//#endregion
|
|
314
|
+
//#region src/components/agent/ProjectIcon.tsx
|
|
315
|
+
/**
|
|
316
|
+
* A project's icon — the render side of protocol's `ProjectIcon`, for a list
|
|
317
|
+
* row or a group header.
|
|
318
|
+
*
|
|
319
|
+
* **The glyph arm is a curated set, and that is the design rather than a
|
|
320
|
+
* shortcut.** The gateway validates a glyph name by *shape* only (lucide's
|
|
321
|
+
* lowercase-kebab convention) and explicitly declines to grow an icon catalog,
|
|
322
|
+
* so the contract already says a client must fall back on a name it does not
|
|
323
|
+
* know.
|
|
324
|
+
*
|
|
325
|
+
* The alternative was measured rather than argued, against the VS Code
|
|
326
|
+
* sidebar's own bundle: `sidebar.js` is **31 KB** with one glyph, **77 KB**
|
|
327
|
+
* with the 110 below (~418 bytes each), and **927 KB** with a
|
|
328
|
+
* `import * as` over lucide's ~1,600 — which is what it costs, because a
|
|
329
|
+
* namespace import defeats tree-shaking by construction. (`DynamicIcon` is the
|
|
330
|
+
* third option and worse in a different currency: ~1,600 chunk files shipped
|
|
331
|
+
* inside the `.vsix`.) Twelve times the bundle to render a name nobody has
|
|
332
|
+
* declared yet is not a trade worth making; 46 KB to cover the names people
|
|
333
|
+
* actually use is.
|
|
334
|
+
*
|
|
335
|
+
* The set is chosen to cover what people call a project; an unlisted-but-valid
|
|
336
|
+
* name draws {@link Folder}, which is what the row drew before this feature
|
|
337
|
+
* existed. **Grow it freely** — each addition is ~400 bytes and the fallback
|
|
338
|
+
* means a missing one is a shrug, not a hole.
|
|
339
|
+
*
|
|
340
|
+
* **The image arm draws nothing until its bytes arrive**, and takes them as a
|
|
341
|
+
* resolved `src` rather than fetching: the wire carries only an address
|
|
342
|
+
* (media type, size, content hash), and *who* fetches it differs per client —
|
|
343
|
+
* a VS Code webview cannot reach a gateway at all and must be handed a data
|
|
344
|
+
* URL by its extension host, while a browser can fetch and `createObjectURL`.
|
|
345
|
+
* A component that fetched would be wrong on one of them. Absent `src` renders
|
|
346
|
+
* nothing rather than a placeholder box: an icon is decoration beside a name
|
|
347
|
+
* that is already there, and a box that becomes a picture a beat later is more
|
|
348
|
+
* movement than the picture is worth.
|
|
349
|
+
*
|
|
350
|
+
* One thing an image icon cannot do, and a glyph can: **take the row's
|
|
351
|
+
* colour.** An `<img>`-embedded SVG is its own document, so `currentColor` does
|
|
352
|
+
* not reach it and its own `prefers-color-scheme` resolves against the *OS*
|
|
353
|
+
* rather than the host's theme (measured: it does resolve, which is the
|
|
354
|
+
* surprise — so a monochrome mark tuned for both schemes is right on a dark OS
|
|
355
|
+
* in a dark editor and wrong on a light OS in a dark one). A repo that wants a
|
|
356
|
+
* mark that always matches its row should declare a glyph; one that wants its
|
|
357
|
+
* brand should declare the image and accept that it is a picture.
|
|
358
|
+
*/
|
|
359
|
+
const GLYPHS = {
|
|
360
|
+
anchor: Anchor,
|
|
361
|
+
atom: Atom,
|
|
362
|
+
beaker: Beaker,
|
|
363
|
+
bike: Bike,
|
|
364
|
+
binary: Binary,
|
|
365
|
+
blocks: Blocks,
|
|
366
|
+
bot: Bot,
|
|
367
|
+
box: Box,
|
|
368
|
+
brain: Brain,
|
|
369
|
+
briefcase: Briefcase,
|
|
370
|
+
brush: Brush,
|
|
371
|
+
bug: Bug,
|
|
372
|
+
"building-2": Building2,
|
|
373
|
+
cable: Cable,
|
|
374
|
+
camera: Camera,
|
|
375
|
+
car: Car,
|
|
376
|
+
cat: Cat,
|
|
377
|
+
"circuit-board": CircuitBoard,
|
|
378
|
+
cloud: Cloud,
|
|
379
|
+
code: Code,
|
|
380
|
+
coffee: Coffee,
|
|
381
|
+
cog: Cog,
|
|
382
|
+
compass: Compass,
|
|
383
|
+
container: Container,
|
|
384
|
+
cpu: Cpu,
|
|
385
|
+
"credit-card": CreditCard,
|
|
386
|
+
database: Database,
|
|
387
|
+
diamond: Diamond,
|
|
388
|
+
dog: Dog,
|
|
389
|
+
feather: Feather,
|
|
390
|
+
film: Film,
|
|
391
|
+
flame: Flame,
|
|
392
|
+
"flask-conical": FlaskConical,
|
|
393
|
+
folder: Folder,
|
|
394
|
+
"gamepad-2": Gamepad2,
|
|
395
|
+
gauge: Gauge,
|
|
396
|
+
gem: Gem,
|
|
397
|
+
ghost: Ghost,
|
|
398
|
+
gift: Gift,
|
|
399
|
+
"git-branch": GitBranch,
|
|
400
|
+
globe: Globe,
|
|
401
|
+
"graduation-cap": GraduationCap,
|
|
402
|
+
hammer: Hammer,
|
|
403
|
+
hexagon: Hexagon,
|
|
404
|
+
house: House,
|
|
405
|
+
image: Image,
|
|
406
|
+
key: Key,
|
|
407
|
+
landmark: Landmark,
|
|
408
|
+
laptop: Laptop,
|
|
409
|
+
layers: Layers,
|
|
410
|
+
leaf: Leaf,
|
|
411
|
+
library: Library,
|
|
412
|
+
lightbulb: Lightbulb,
|
|
413
|
+
lock: Lock,
|
|
414
|
+
mail: Mail,
|
|
415
|
+
map: Map$1,
|
|
416
|
+
"message-circle": MessageCircle,
|
|
417
|
+
mic: Mic,
|
|
418
|
+
monitor: Monitor,
|
|
419
|
+
moon: Moon,
|
|
420
|
+
mountain: Mountain,
|
|
421
|
+
music: Music,
|
|
422
|
+
network: Network,
|
|
423
|
+
newspaper: Newspaper,
|
|
424
|
+
notebook: Notebook,
|
|
425
|
+
orbit: Orbit,
|
|
426
|
+
package: Package,
|
|
427
|
+
palette: Palette,
|
|
428
|
+
"pen-tool": PenTool,
|
|
429
|
+
phone: Phone,
|
|
430
|
+
"piggy-bank": PiggyBank,
|
|
431
|
+
plane: Plane,
|
|
432
|
+
plug: Plug,
|
|
433
|
+
puzzle: Puzzle,
|
|
434
|
+
radar: Radar,
|
|
435
|
+
radio: Radio,
|
|
436
|
+
receipt: Receipt,
|
|
437
|
+
rocket: Rocket,
|
|
438
|
+
ruler: Ruler,
|
|
439
|
+
satellite: Satellite,
|
|
440
|
+
scale: Scale,
|
|
441
|
+
scissors: Scissors,
|
|
442
|
+
server: Server,
|
|
443
|
+
shield: Shield,
|
|
444
|
+
ship: Ship,
|
|
445
|
+
"shopping-cart": ShoppingCart,
|
|
446
|
+
signal: Signal,
|
|
447
|
+
smartphone: Smartphone,
|
|
448
|
+
sparkles: Sparkles,
|
|
449
|
+
sprout: Sprout,
|
|
450
|
+
square: Square,
|
|
451
|
+
star: Star,
|
|
452
|
+
sun: Sun,
|
|
453
|
+
table: Table,
|
|
454
|
+
tag: Tag,
|
|
455
|
+
target: Target,
|
|
456
|
+
telescope: Telescope,
|
|
457
|
+
terminal: Terminal,
|
|
458
|
+
"test-tube": TestTube,
|
|
459
|
+
"tree-pine": TreePine,
|
|
460
|
+
trophy: Trophy,
|
|
461
|
+
truck: Truck,
|
|
462
|
+
umbrella: Umbrella,
|
|
463
|
+
users: Users,
|
|
464
|
+
wallet: Wallet,
|
|
465
|
+
wand: Wand,
|
|
466
|
+
waves: Waves,
|
|
467
|
+
webhook: Webhook,
|
|
468
|
+
wifi: Wifi,
|
|
469
|
+
wrench: Wrench,
|
|
470
|
+
zap: Zap
|
|
471
|
+
};
|
|
472
|
+
function ProjectIcon({ icon, src, name, className }) {
|
|
473
|
+
if (!icon) return null;
|
|
474
|
+
if (icon.type === "image") {
|
|
475
|
+
if (!src) return null;
|
|
476
|
+
return /* @__PURE__ */ jsx("img", {
|
|
477
|
+
src,
|
|
478
|
+
alt: "",
|
|
479
|
+
"aria-hidden": true,
|
|
480
|
+
title: name,
|
|
481
|
+
className: cn("inline-block size-3 shrink-0 object-contain", className)
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
return /* @__PURE__ */ jsx(GLYPHS[icon.name] ?? Folder, { className: cn("inline-block size-3 shrink-0", className) });
|
|
485
|
+
}
|
|
486
|
+
//#endregion
|
|
211
487
|
//#region src/components/agent/SessionBrowser.tsx
|
|
212
488
|
/**
|
|
213
489
|
* How a list row is drawn, in one place, so `SidebarRow` in `web` matches this
|
|
@@ -228,7 +504,7 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
|
|
|
228
504
|
function rowShapeClass(active) {
|
|
229
505
|
return cn("px-2 py-1.5 hover:bg-row-hover", active ? "mr-1 ml-0 rounded-r-md border-l-4 border-l-accent" : "mx-1 rounded-md");
|
|
230
506
|
}
|
|
231
|
-
function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, showControls = true, className }) {
|
|
507
|
+
function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, showControls = true, projectIcons, className }) {
|
|
232
508
|
const visible = useMemo(() => filterRows(rows, config, scope), [
|
|
233
509
|
rows,
|
|
234
510
|
config,
|
|
@@ -237,6 +513,7 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
237
513
|
const groups = useMemo(() => groupRows(visible, config), [visible, config]);
|
|
238
514
|
const subset = subsetSummary(config, scope, visible.length, rows.length);
|
|
239
515
|
const adapters = useMemo(() => adaptersOf(rows), [rows]);
|
|
516
|
+
const projects = useMemo(() => projectsOf(rows), [rows]);
|
|
240
517
|
const gateways = useMemo(() => {
|
|
241
518
|
const seen = /* @__PURE__ */ new Map();
|
|
242
519
|
for (const row of rows) seen.set(row.hostId, row.hostName);
|
|
@@ -302,6 +579,18 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
302
579
|
onChange: (gateways) => set({ gateways })
|
|
303
580
|
})
|
|
304
581
|
}) : null,
|
|
582
|
+
projects.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
|
|
583
|
+
label: "Project",
|
|
584
|
+
children: /* @__PURE__ */ jsx(FacetSelect, {
|
|
585
|
+
label: "Project",
|
|
586
|
+
value: config.projects ?? [],
|
|
587
|
+
options: projects.map((p) => ({
|
|
588
|
+
value: p.key,
|
|
589
|
+
label: p.label
|
|
590
|
+
})),
|
|
591
|
+
onChange: (next) => set({ projects: next })
|
|
592
|
+
})
|
|
593
|
+
}) : null,
|
|
305
594
|
/* @__PURE__ */ jsx(FilterRow, {
|
|
306
595
|
label: "Group",
|
|
307
596
|
children: /* @__PURE__ */ jsx(OneOfSelect, {
|
|
@@ -320,6 +609,10 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
320
609
|
value: "adapter",
|
|
321
610
|
label: "By engine"
|
|
322
611
|
},
|
|
612
|
+
...projects.length > 1 ? [{
|
|
613
|
+
value: "project",
|
|
614
|
+
label: "By project"
|
|
615
|
+
}] : [],
|
|
323
616
|
...gateways.length > 1 ? [{
|
|
324
617
|
value: "gateway",
|
|
325
618
|
label: "By gateway"
|
|
@@ -346,6 +639,10 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
346
639
|
value: "state",
|
|
347
640
|
label: "State"
|
|
348
641
|
},
|
|
642
|
+
...projects.length > 1 ? [{
|
|
643
|
+
value: "project",
|
|
644
|
+
label: "Project"
|
|
645
|
+
}] : [],
|
|
349
646
|
...gateways.length > 1 ? [{
|
|
350
647
|
value: "gateway",
|
|
351
648
|
label: "Gateway"
|
|
@@ -388,18 +685,28 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
388
685
|
children: groups.map((group) => /* @__PURE__ */ jsxs("div", {
|
|
389
686
|
className: "flex flex-col gap-1",
|
|
390
687
|
children: [config.groupBy !== "none" && group.label ? /* @__PURE__ */ jsxs("div", {
|
|
391
|
-
className: "flex items-
|
|
392
|
-
children: [
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
688
|
+
className: "flex items-center gap-2 px-3 text-label font-medium text-fg-4",
|
|
689
|
+
children: [
|
|
690
|
+
config.groupBy === "project" ? /* @__PURE__ */ jsx(ProjectIcon, {
|
|
691
|
+
icon: group.rows[0]?.info.project?.icon,
|
|
692
|
+
src: iconSrcOf(group.rows[0], projectIcons),
|
|
693
|
+
name: group.label
|
|
694
|
+
}) : null,
|
|
695
|
+
/* @__PURE__ */ jsx("span", {
|
|
696
|
+
className: "uppercase tracking-wide",
|
|
697
|
+
children: group.label
|
|
698
|
+
}),
|
|
699
|
+
/* @__PURE__ */ jsx("span", {
|
|
700
|
+
className: "text-fg-4/70",
|
|
701
|
+
children: group.rows.length
|
|
702
|
+
})
|
|
703
|
+
]
|
|
399
704
|
}) : null, group.rows.map((row) => /* @__PURE__ */ jsx(SessionRowItem, {
|
|
400
705
|
row,
|
|
401
706
|
active: row.info.id === activeId,
|
|
402
707
|
showGateway: gateways.length > 1,
|
|
708
|
+
showProject: config.groupBy !== "project",
|
|
709
|
+
projectIcons,
|
|
403
710
|
onSelect,
|
|
404
711
|
onDelete,
|
|
405
712
|
onRename
|
|
@@ -409,17 +716,27 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
|
|
|
409
716
|
]
|
|
410
717
|
});
|
|
411
718
|
}
|
|
412
|
-
|
|
719
|
+
/** The bytes for a row's project icon, if it has an image one and the caller has
|
|
720
|
+
* fetched it yet. Shared by the row and its group header so the two cannot draw
|
|
721
|
+
* different pictures for one project. */
|
|
722
|
+
function iconSrcOf(row, icons) {
|
|
723
|
+
const icon = row?.info.project?.icon;
|
|
724
|
+
return icon?.type === "image" ? icons?.[icon.hash] : void 0;
|
|
725
|
+
}
|
|
726
|
+
function SessionRowItem({ row, active, showGateway, showProject = true, projectIcons, onSelect, onDelete, onRename }) {
|
|
413
727
|
const { info } = row;
|
|
414
728
|
const [editing, setEditing] = useState(false);
|
|
415
729
|
const folder = info.cwd.split("/").filter(Boolean).pop() ?? info.cwd;
|
|
730
|
+
const project = showProject ? projectLabel(row) : folder;
|
|
731
|
+
const projectIcon = showProject ? info.project?.icon : void 0;
|
|
416
732
|
const details = [
|
|
417
733
|
showGateway ? row.hostName : void 0,
|
|
418
734
|
friendlyModel(info.model),
|
|
419
|
-
|
|
735
|
+
project,
|
|
420
736
|
info.profile ? `@${info.profile}` : void 0,
|
|
421
737
|
formatCost(info.totalCostUsd)
|
|
422
738
|
].filter(Boolean);
|
|
739
|
+
const cut = details.indexOf(project);
|
|
423
740
|
return /* @__PURE__ */ jsxs("div", {
|
|
424
741
|
"data-slot": "session-row",
|
|
425
742
|
"data-active": active || void 0,
|
|
@@ -458,7 +775,16 @@ function SessionRowItem({ row, active, showGateway, onSelect, onDelete, onRename
|
|
|
458
775
|
type: "button",
|
|
459
776
|
tabIndex: -1,
|
|
460
777
|
className: "min-w-0 flex-1 truncate text-left font-mono outline-none",
|
|
461
|
-
children: details.join(" · ")
|
|
778
|
+
children: cut < 0 ? details.join(" · ") : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
779
|
+
details.slice(0, cut).map((part) => `${part} · `),
|
|
780
|
+
/* @__PURE__ */ jsx(ProjectIcon, {
|
|
781
|
+
icon: projectIcon,
|
|
782
|
+
src: iconSrcOf(row, projectIcons),
|
|
783
|
+
name: project,
|
|
784
|
+
className: "mr-1 align-[-0.2em]"
|
|
785
|
+
}),
|
|
786
|
+
details.slice(cut).join(" · ")
|
|
787
|
+
] })
|
|
462
788
|
}),
|
|
463
789
|
onRename && !editing ? /* @__PURE__ */ jsx(Button, {
|
|
464
790
|
variant: "ghost",
|
|
@@ -667,6 +993,6 @@ function EngineIcon({ engine, model, className }) {
|
|
|
667
993
|
});
|
|
668
994
|
}
|
|
669
995
|
//#endregion
|
|
670
|
-
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, Conversation, ConversationContent, ConversationScrollButton, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, HostFilesDialog, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, STATUS_META, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionList, SessionListItem, SessionPanel, SessionStatusIcon, SkillsDialog, Spinner, Splitter, StatusBar, Textarea, Tip, Toaster, ToolCallCard, TooltipContent, TooltipProvider, Transcript, TranscriptDensityProvider, TranscriptVariantProvider, UsageDialog, 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 };
|
|
996
|
+
export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Band, Blank, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, Conversation, ConversationContent, ConversationScrollButton, CopyAction, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, HostFilesDialog, Ink, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, ProjectIcon, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, Row, STATUS_META, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionList, SessionListItem, SessionPanel, SessionStatusIcon, SkillsDialog, Spinner, Splitter, StatusBar, TerminalDiff, TerminalItemView, TerminalMarkdown, TerminalPermissionPrompt, TerminalQuestionPrompt, TerminalStatusLine, TerminalSurface, TerminalTranscript, Textarea, Tip, Toaster, ToolCallCard, TooltipContent, TooltipProvider, Transcript, TranscriptDensityProvider, TranscriptVariantProvider, UsageDialog, UsageMeters, WithActions, badgeVariants, buttonVariants, cn, commandTrigger, copyText, engineMark, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, previewPatch, rateLimitWindowSeconds, rowShapeClass, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useMinuteClock, usePromptAreaState, useTranscriptDensity, useTranscriptVariant };
|
|
671
997
|
|
|
672
998
|
//# sourceMappingURL=index.mjs.map
|