@workerdeck/ui 0.23.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/{SessionPanel-DUt2VzXG.mjs → SessionPanel-I5QSLLb0.mjs} +2266 -3459
- package/build/SessionPanel-I5QSLLb0.mjs.map +1 -0
- package/build/SessionPanel-yNO60Tzw.d.mts +151 -0
- package/build/format-C_lpFq0l.d.mts +16 -0
- package/build/format.d.mts +8 -76
- package/build/format.mjs +2 -2
- package/build/index.d.mts +291 -1695
- package/build/index.mjs +6 -301
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +32 -23
- package/build/{status-BE-zg88x.mjs → status-Dm9INVTt.mjs} +17 -88
- package/build/status-Dm9INVTt.mjs.map +1 -0
- package/build/workspace.d.mts +8 -187
- package/build/workspace.mjs +13 -144
- package/build/workspace.mjs.map +1 -1
- package/package.json +24 -24
- package/src/components/agent/CodeEditor.tsx +31 -103
- package/src/components/agent/Composer.tsx +114 -333
- package/src/components/agent/ContextDialog.tsx +20 -41
- package/src/components/agent/ContextRing.tsx +6 -28
- package/src/components/agent/Conversation.tsx +21 -33
- package/src/components/agent/EditorTabs.tsx +39 -67
- package/src/components/agent/EngineIcon.tsx +29 -72
- package/src/components/agent/EntryIcon.tsx +16 -0
- package/src/components/agent/FileCard.tsx +10 -16
- package/src/components/agent/FileTree.tsx +52 -125
- package/src/components/agent/FileViewer.tsx +30 -60
- package/src/components/agent/HostFilesDialog.tsx +40 -69
- package/src/components/agent/Loader.tsx +3 -24
- package/src/components/agent/McpDialog.tsx +64 -137
- package/src/components/agent/Message.tsx +2 -21
- package/src/components/agent/ModelSelect.tsx +33 -62
- package/src/components/agent/PermissionModeSelect.tsx +21 -79
- package/src/components/agent/PermissionPrompt.tsx +59 -63
- package/src/components/agent/ProjectIcon.tsx +228 -93
- package/src/components/agent/PromptTokenText.tsx +10 -16
- package/src/components/agent/QuestionPrompt.tsx +43 -64
- package/src/components/agent/Reasoning.tsx +13 -16
- package/src/components/agent/Response.tsx +3 -9
- package/src/components/agent/Scrubber.tsx +31 -80
- package/src/components/agent/SessionBrowser.tsx +64 -243
- package/src/components/agent/SessionEmptyState.tsx +10 -40
- package/src/components/agent/SessionInfoDialog.tsx +46 -78
- package/src/components/agent/SessionItem.tsx +53 -320
- package/src/components/agent/SessionList.tsx +23 -39
- package/src/components/agent/SessionPanel.tsx +315 -996
- package/src/components/agent/SessionStatusIcon.tsx +14 -28
- package/src/components/agent/SessionSteps.tsx +34 -187
- package/src/components/agent/SessionWorkspace.tsx +104 -219
- package/src/components/agent/SkillsDialog.tsx +35 -80
- package/src/components/agent/StatusBar.tsx +51 -136
- package/src/components/agent/SubagentStrip.tsx +12 -77
- package/src/components/agent/ToolCallCard.tsx +94 -135
- package/src/components/agent/Transcript.tsx +103 -1288
- package/src/components/agent/TranscriptItemView.tsx +155 -0
- package/src/components/agent/TranscriptRows.tsx +418 -0
- package/src/components/agent/UsageDialog.tsx +7 -29
- package/src/components/agent/UsageMeters.tsx +18 -73
- package/src/components/agent/pulse.tsx +9 -32
- package/src/components/agent/scrubber-marks.ts +33 -103
- package/src/components/agent/status.ts +1 -5
- package/src/components/agent/tool-result-fetch.tsx +3 -25
- package/src/components/agent/tool-result-image.tsx +32 -111
- package/src/components/agent/transcript-rows.ts +41 -118
- package/src/components/agent/transcript-variant.tsx +3 -80
- package/src/components/agent/use-height-epoch.ts +10 -24
- package/src/components/agent/use-path-links.ts +45 -63
- package/src/components/agent/use-subagent-frame.ts +106 -0
- package/src/components/agent/use-transcript-jumps.ts +49 -107
- package/src/components/prompt-area/animated-placeholder.tsx +6 -5
- package/src/components/prompt-area/clipboard-helpers.ts +26 -21
- package/src/components/prompt-area/cursor-helpers.ts +79 -37
- package/src/components/prompt-area/dom-helpers.ts +97 -69
- package/src/components/prompt-area/file-strip.tsx +90 -80
- package/src/components/prompt-area/html-to-markdown.ts +67 -46
- package/src/components/prompt-area/image-strip.tsx +8 -18
- package/src/components/prompt-area/index.ts +2 -15
- package/src/components/prompt-area/prompt-area-engine.ts +100 -115
- package/src/components/prompt-area/prompt-area-list-ops.ts +66 -59
- package/src/components/prompt-area/prompt-area.tsx +31 -38
- package/src/components/prompt-area/remove-button.tsx +3 -9
- package/src/components/prompt-area/segment-helpers.ts +4 -12
- package/src/components/prompt-area/trigger-popover.tsx +15 -27
- package/src/components/prompt-area/trigger-presets.ts +0 -10
- package/src/components/prompt-area/types.ts +3 -8
- package/src/components/prompt-area/use-chip-editing.ts +305 -0
- package/src/components/prompt-area/use-markdown-mode.ts +7 -17
- package/src/components/prompt-area/use-prompt-area-events.ts +80 -86
- package/src/components/prompt-area/use-prompt-area-keydown.ts +598 -0
- package/src/components/prompt-area/use-prompt-area-state.ts +5 -23
- package/src/components/prompt-area/use-prompt-area.ts +170 -896
- package/src/components/prompt-area/use-trigger-search.ts +21 -19
- package/src/components/terminal/PermissionPrompt.tsx +56 -59
- package/src/components/terminal/QuestionPrompt.tsx +28 -79
- package/src/components/terminal/StatusLine.tsx +13 -63
- package/src/components/terminal/TerminalTranscript.tsx +44 -160
- package/src/components/terminal/affordances.tsx +68 -98
- package/src/components/terminal/blocks.ts +20 -156
- package/src/components/terminal/diff.tsx +19 -67
- package/src/components/terminal/height.ts +163 -313
- package/src/components/terminal/image-box.ts +0 -44
- package/src/components/terminal/items.tsx +150 -305
- package/src/components/terminal/markdown.tsx +36 -95
- package/src/components/terminal/press.tsx +26 -53
- package/src/components/terminal/prompt.tsx +40 -170
- package/src/components/terminal/result-preview.ts +8 -56
- package/src/components/terminal/row.tsx +11 -98
- package/src/components/terminal/scrubber.tsx +108 -401
- package/src/components/terminal/surface.tsx +6 -54
- package/src/components/terminal/todos.ts +66 -0
- package/src/components/terminal/tool-run.ts +21 -192
- package/src/components/ui/AlertDialog.tsx +8 -23
- package/src/components/ui/Badge.tsx +18 -29
- package/src/components/ui/Button.tsx +7 -15
- package/src/components/ui/Card.tsx +2 -13
- package/src/components/ui/CodeBlock.tsx +10 -37
- package/src/components/ui/CopyButton.tsx +10 -23
- package/src/components/ui/Dialog.tsx +23 -36
- package/src/components/ui/Empty.tsx +6 -29
- package/src/components/ui/Input.tsx +14 -16
- package/src/components/ui/Menu.tsx +6 -18
- package/src/components/ui/PortalScope.tsx +1 -21
- package/src/components/ui/ProgressRing.tsx +8 -19
- package/src/components/ui/Select.tsx +18 -31
- package/src/components/ui/Sonner.tsx +1 -2
- package/src/components/ui/Spinner.tsx +1 -1
- package/src/components/ui/Splitter.tsx +30 -64
- package/src/components/ui/Textarea.tsx +2 -5
- package/src/components/ui/Tooltip.tsx +3 -13
- package/src/format.ts +0 -9
- package/src/index.ts +16 -113
- package/src/lib/clipboard.ts +8 -28
- package/src/lib/css.ts +8 -0
- package/src/lib/format.ts +101 -86
- package/src/lib/plan-request.ts +16 -0
- package/src/lib/status.ts +45 -95
- package/src/lib/tool-icon.ts +39 -47
- package/src/lib/utils.ts +1 -3
- package/src/styles/terminal.css +81 -49
- package/src/styles/theme.css +96 -32
- package/src/workspace.ts +1 -24
- package/build/SessionPanel-BobynUo4.d.mts +0 -669
- package/build/SessionPanel-DUt2VzXG.mjs.map +0 -1
- package/build/format-ljc3lKpA.d.mts +0 -59
- package/build/status-BE-zg88x.mjs.map +0 -1
package/build/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
1
|
+
import { $ as isMutatingTool, A as PERMISSION_MODES, At as MenuItem, B as Composer, Bt as Input, C as TerminalPermissionPrompt, Ct as DialogClose, D as SubagentStrip, Dt as DialogTrigger, E as parseUserQuestions, Et as DialogRow, F as SkillsDialog, Ft as SelectItem, G as previewPatch, Gt as cn, H as TerminalSurface, Ht as badgeVariants, I as McpDialog, It as SelectItemText, J as Ink, K as Band, L as HostFilesDialog, Lt as SelectTrigger, M as permissionModeChoices, Mt as MenuTrigger, N as permissionModeMeta, Nt as Select, O as PermissionPrompt, Ot as Menu, P as ModelSelect, Pt as SelectContent, Q as useAffordances, Rt as SelectValue, S as TerminalQuestionPrompt, St as DialogBody, T as QuestionPrompt, Tt as DialogHeader, U as TerminalMarkdown, Ut as Button, V as skillPrompt, Vt as Badge, W as TerminalDiff, Wt as buttonVariants, X as CopyAction, Y as Row, Z as WithActions, _ as ConversationContent, _t as copyText, a as Transcript, at as commandTrigger, b as STATUS_META, bt as TooltipProvider, c as PromptTokenText, ct as usePromptAreaState, d as FileCard, dt as segmentsToPlainText, et as toolIcon, f as TerminalItemView, ft as ProgressRing, g as Conversation, gt as CopyButton, h as Loader, ht as Spinner, i as useMinuteClock, it as useTranscriptVariant, j as PermissionModeSelect, jt as MenuSeparator, k as Response, kt as MenuContent, l as Message, lt as PromptArea, m as SessionEmptyState, mt as CodeBlock, n as UsageDialog, nt as TranscriptVariantProvider, o as ToolCallCard, ot as hashtagTrigger, p as TerminalTranscript, pt as Splitter, q as Blank, r as UsageMeters, rt as useTranscriptDensity, s as Reasoning, st as mentionTrigger, t as SessionPanel, tt as TranscriptDensityProvider, u as MessageContent, ut as plainTextToSegments, v as ConversationScrollButton, vt as Tip, w as QUESTION_BEHAVIORS, wt as DialogContent, x as SessionInfoDialog, xt as Dialog, y as StatusBar, yt as TooltipContent, z as ContextDialog, zt as PortalScope } from "./SessionPanel-I5QSLLb0.mjs";
|
|
2
|
+
import { S as toolInputPreview, _ as formatRateLimitWindowLong, b as friendlyModel, c as tightestWindow, d as formatAgoPrecise, f as formatBytes, g as formatRateLimitWindow, h as formatDuration, i as meterSeverity, m as formatCountdown, o as modelLabel, p as formatCost, r as meterColorClass, s as statusPresentation, t as contextSeverity, u as windowLabel, v as formatRelativeTime, x as rateLimitWindowSeconds, y as formatTokens } from "./status-Dm9INVTt.mjs";
|
|
3
3
|
import { Fragment, forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { Anchor, ArrowRight, Atom, Beaker, BellRing, Bike, Binary, Blocks, Bot, Box, Brain, Briefcase, Brush, Bug, Building2, Cable, Camera, Car, Cat, Check, ChevronDown, ChevronRight, CircleAlert, CircleSlash, CircuitBoard, Cloud, Code, Coffee, Cog, Compass, Container, Cpu, CreditCard, Database, Diamond, Dog, Dot, Eraser, 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";
|
|
@@ -62,7 +62,6 @@ const AlertDialogDescription = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
|
62
62
|
});
|
|
63
63
|
//#endregion
|
|
64
64
|
//#region src/components/ui/Sonner.tsx
|
|
65
|
-
/** Token-themed toaster; relies on the [data-theme] swap, so no `theme` prop needed. */
|
|
66
65
|
function Toaster() {
|
|
67
66
|
return /* @__PURE__ */ jsx(Toaster$1, {
|
|
68
67
|
position: "bottom-right",
|
|
@@ -78,22 +77,6 @@ function Toaster() {
|
|
|
78
77
|
}
|
|
79
78
|
//#endregion
|
|
80
79
|
//#region src/components/ui/Empty.tsx
|
|
81
|
-
/**
|
|
82
|
-
* A view with nothing in it: icon, title, description, and at most one action.
|
|
83
|
-
*
|
|
84
|
-
* Centered and given room, because an empty view is the first thing a new
|
|
85
|
-
* install shows and a flush-left sentence in the top corner reads like a bug
|
|
86
|
-
* report. It lives here rather than in one client because every panel that can
|
|
87
|
-
* be empty should be empty the same way — the extension's views and the
|
|
88
|
-
* dashboard's four sidebars are the same shape of thing.
|
|
89
|
-
*
|
|
90
|
-
* **At most one action, and never one the view header already offers.** Creating
|
|
91
|
-
* a session and adding a gateway are the `+` in the native title bar, exclusively
|
|
92
|
-
* — so those empty states point at it in words rather than growing a second
|
|
93
|
-
* button that does the same thing two inches lower. A button here is for the way
|
|
94
|
-
* out of a state the header has no answer to: clearing a filter, widening a
|
|
95
|
-
* scope.
|
|
96
|
-
*/
|
|
97
80
|
function Empty({ icon, title, description, action, onAction }) {
|
|
98
81
|
return /* @__PURE__ */ jsxs("div", {
|
|
99
82
|
className: "flex flex-col items-center gap-2 px-5 py-8 text-center",
|
|
@@ -120,7 +103,6 @@ function Empty({ icon, title, description, action, onAction }) {
|
|
|
120
103
|
]
|
|
121
104
|
});
|
|
122
105
|
}
|
|
123
|
-
/** A key or icon named inline in an empty state's description — "use the + above". */
|
|
124
106
|
function EmptyKey({ children }) {
|
|
125
107
|
return /* @__PURE__ */ jsx("span", {
|
|
126
108
|
className: "rounded border border-border px-1 font-mono text-fg-3",
|
|
@@ -140,31 +122,11 @@ function getChipsByTrigger(segments, trigger) {
|
|
|
140
122
|
}
|
|
141
123
|
//#endregion
|
|
142
124
|
//#region src/components/terminal/StatusLine.tsx
|
|
143
|
-
/**
|
|
144
|
-
* The session's readings, as one line.
|
|
145
|
-
*
|
|
146
|
-
* The styled bar puts each of these in its own affordance — a progress ring, a
|
|
147
|
-
* badge, a tooltip — which is right for a dashboard and wrong here for the usual
|
|
148
|
-
* reason: a terminal has one line height, and five widgets of five different
|
|
149
|
-
* heights is five different rhythms in a row that is supposed to be quiet. So
|
|
150
|
-
* they are words, `·`-separated, exactly as the CLI's own status line writes
|
|
151
|
-
* them.
|
|
152
|
-
*
|
|
153
|
-
* The readings themselves come from the same helpers the styled bar uses
|
|
154
|
-
* (`lib/status.ts`), and that matters more than it looks: `statusPresentation`
|
|
155
|
-
* is where the rule lives that **a dropped socket outranks the session status**,
|
|
156
|
-
* because a status held over a dead socket is a stale reading being presented as
|
|
157
|
-
* a live one. Re-deriving that here would be a second answer to a question that
|
|
158
|
-
* already has one.
|
|
159
|
-
*/
|
|
160
|
-
/** Severity → tone. The 80/95 thresholds are `lib/status.ts`'s, not new ones. */
|
|
161
125
|
const SEVERITY_TONE = {
|
|
162
126
|
none: "dim",
|
|
163
127
|
warning: "yellow",
|
|
164
128
|
error: "red"
|
|
165
129
|
};
|
|
166
|
-
/** One reading. A button only when it leads somewhere — a segment that looks
|
|
167
|
-
* pressable and does nothing is worse than plain text. */
|
|
168
130
|
function Reading({ tone, onPress, label, children }) {
|
|
169
131
|
if (!onPress) return /* @__PURE__ */ jsx(Ink, {
|
|
170
132
|
tone,
|
|
@@ -312,50 +274,6 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
|
|
|
312
274
|
}
|
|
313
275
|
//#endregion
|
|
314
276
|
//#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
277
|
const GLYPHS = {
|
|
360
278
|
anchor: Anchor,
|
|
361
279
|
atom: Atom,
|
|
@@ -481,27 +399,11 @@ function ProjectIcon({ icon, src, name, className }) {
|
|
|
481
399
|
className: cn("inline-block size-3 shrink-0 object-contain", className)
|
|
482
400
|
});
|
|
483
401
|
}
|
|
484
|
-
|
|
402
|
+
const Glyph = GLYPHS[icon.name] ?? Folder;
|
|
403
|
+
return /* @__PURE__ */ jsx(Glyph, { className: cn("inline-block size-3 shrink-0", className) });
|
|
485
404
|
}
|
|
486
405
|
//#endregion
|
|
487
406
|
//#region src/components/agent/ContextRing.tsx
|
|
488
|
-
/**
|
|
489
|
-
* How full a session's context window is, sized for a **list row**.
|
|
490
|
-
*
|
|
491
|
-
* The reading the session screen has always drawn, moved somewhere it answers a
|
|
492
|
-
* question the session screen cannot: *which* of these thirty sessions is
|
|
493
|
-
* bloating. That is also why it is a ring and not a number — across a list, a
|
|
494
|
-
* ring is read at a glance and `71%` has to be read one row at a time.
|
|
495
|
-
*
|
|
496
|
-
* **Absent draws nothing, and absent is not zero.** A promptless session, a
|
|
497
|
-
* parked one from before the field existed, or an engine that reports no window
|
|
498
|
-
* has no reading; an empty ring would claim its context is empty rather than
|
|
499
|
-
* unknown. The title carries the exact numbers for anyone who wants them.
|
|
500
|
-
*
|
|
501
|
-
* Shared rather than spelled per client: the dashboard's row and the VS Code
|
|
502
|
-
* sidebar's card both draw it, and two copies would be two sets of thresholds
|
|
503
|
-
* the day one of them is nudged.
|
|
504
|
-
*/
|
|
505
407
|
function ContextRing({ usage, size = 11, className }) {
|
|
506
408
|
if (usage === void 0) return null;
|
|
507
409
|
return /* @__PURE__ */ jsx("span", {
|
|
@@ -516,23 +418,6 @@ function ContextRing({ usage, size = 11, className }) {
|
|
|
516
418
|
}
|
|
517
419
|
//#endregion
|
|
518
420
|
//#region src/components/agent/EngineIcon.tsx
|
|
519
|
-
/**
|
|
520
|
-
* The engine's own mark, monochrome.
|
|
521
|
-
*
|
|
522
|
-
* Inlined rather than depended on: the React package these come from
|
|
523
|
-
* (`@lobehub/icons`) pulls antd, `@lobehub/ui` and a second copy of
|
|
524
|
-
* lucide-react — an absurd amount of bundle for a few glyphs in a sidebar.
|
|
525
|
-
* These are paths from `@lobehub/icons-static-svg` (MIT, © LobeHub), already
|
|
526
|
-
* `fill="currentColor"` single-path marks, so they take the row's colour like
|
|
527
|
-
* any other glyph and need no light/dark variants.
|
|
528
|
-
*
|
|
529
|
-
* The marks are trademarks of their owners (Anthropic, OpenAI, Google,
|
|
530
|
-
* DeepSeek, Moonshot), used here only to identify which engine a session runs
|
|
531
|
-
* on.
|
|
532
|
-
*
|
|
533
|
-
* Codex is drawn as OpenAI: the session's engine *is* OpenAI's, and OpenAI's
|
|
534
|
-
* mark is the one a person recognises at 12px.
|
|
535
|
-
*/
|
|
536
421
|
const PATHS = {
|
|
537
422
|
claude: {
|
|
538
423
|
title: "Claude",
|
|
@@ -555,57 +440,25 @@ const PATHS = {
|
|
|
555
440
|
d: "M1.052 16.916l9.539 2.552a21.007 21.007 0 00.06 2.033l5.956 1.593a11.997 11.997 0 01-5.586.865l-.18-.016-.044-.004-.084-.009-.094-.01a11.605 11.605 0 01-.157-.02l-.107-.014-.11-.016a11.962 11.962 0 01-.32-.051l-.042-.008-.075-.013-.107-.02-.07-.015-.093-.019-.075-.016-.095-.02-.097-.023-.094-.022-.068-.017-.088-.022-.09-.024-.095-.025-.082-.023-.109-.03-.062-.02-.084-.025-.093-.028-.105-.034-.058-.019-.08-.026-.09-.031-.066-.024a6.293 6.293 0 01-.044-.015l-.068-.025-.101-.037-.057-.022-.08-.03-.087-.035-.088-.035-.079-.032-.095-.04-.063-.028-.063-.027a5.655 5.655 0 01-.041-.018l-.066-.03-.103-.047-.052-.024-.096-.046-.062-.03-.084-.04-.086-.044-.093-.047-.052-.027-.103-.055-.057-.03-.058-.032a6.49 6.49 0 01-.046-.026l-.094-.053-.06-.034-.051-.03-.072-.041-.082-.05-.093-.056-.052-.032-.084-.053-.061-.039-.079-.05-.07-.047-.053-.035a7.785 7.785 0 01-.054-.036l-.044-.03-.044-.03a6.066 6.066 0 01-.04-.028l-.057-.04-.076-.054-.069-.05-.074-.054-.056-.042-.076-.057-.076-.059-.086-.067-.045-.035-.064-.052-.074-.06-.089-.073-.046-.039-.046-.039a7.516 7.516 0 01-.043-.037l-.045-.04-.061-.053-.07-.062-.068-.06-.062-.058-.067-.062-.053-.05-.088-.084a13.28 13.28 0 01-.099-.097l-.029-.028-.041-.042-.069-.07-.05-.051-.05-.053a6.457 6.457 0 01-.168-.179l-.08-.088-.062-.07-.071-.08-.042-.049-.053-.062-.058-.068-.046-.056a7.175 7.175 0 01-.027-.033l-.045-.055-.066-.082-.041-.052-.05-.064-.02-.025a11.99 11.99 0 01-1.44-2.402zm-1.02-5.794l11.353 3.037a20.468 20.468 0 00-.469 2.011l10.817 2.894a12.076 12.076 0 01-1.845 2.005L.657 15.923l-.016-.046-.035-.104a11.965 11.965 0 01-.05-.153l-.007-.023a11.896 11.896 0 01-.207-.741l-.03-.126-.018-.08-.021-.097-.018-.081-.018-.09-.017-.084-.018-.094c-.026-.141-.05-.283-.071-.426l-.017-.118-.011-.083-.013-.102a12.01 12.01 0 01-.019-.161l-.005-.047a12.12 12.12 0 01-.034-2.145zm1.593-5.15l11.948 3.196c-.368.605-.705 1.231-1.01 1.875l11.295 3.022c-.142.82-.368 1.612-.668 2.365l-11.55-3.09L.124 10.26l.015-.1.008-.049.01-.067.015-.087.018-.098c.026-.148.056-.295.088-.442l.028-.124.02-.085.024-.097c.022-.09.045-.18.07-.268l.028-.102.023-.083.03-.1.025-.082.03-.096.026-.082.031-.095a11.896 11.896 0 011.01-2.232zm4.442-4.4L17.352 4.59a20.77 20.77 0 00-1.688 1.721l7.823 2.093c.267.852.442 1.744.513 2.665L2.106 5.213l.045-.065.027-.04.04-.055.046-.065.055-.076.054-.072.064-.086.05-.065.057-.073.055-.07.06-.074.055-.069.065-.077.054-.066.066-.077.053-.06.072-.082.053-.06.067-.074.054-.058.073-.078.058-.06.063-.067.168-.17.1-.098.059-.056.076-.071a12.084 12.084 0 012.272-1.677zM12.017 0h.097l.082.001.069.001.054.002.068.002.046.001.076.003.047.002.06.003.054.002.087.005.105.007.144.011.088.007.044.004.077.008.082.008.047.005.102.012.05.006.108.014.081.01.042.006.065.01.207.032.07.012.065.011.14.026.092.018.11.022.046.01.075.016.041.01L14.7.3l.042.01.065.015.049.012.071.017.096.024.112.03.113.03.113.032.05.015.07.02.078.024.073.023.05.016.05.016.076.025.099.033.102.036.048.017.064.023.093.034.11.041.116.045.1.04.047.02.06.024.041.018.063.026.04.018.057.025.11.048.1.046.074.035.075.036.06.028.092.046.091.045.102.052.053.028.049.026.046.024.06.033.041.022.052.029.088.05.106.06.087.051.057.034.053.032.096.059.088.055.098.062.036.024.064.041.084.056.04.027.062.042.062.043.023.017c.054.037.108.075.161.114l.083.06.065.048.056.043.086.065.082.064.04.03.05.041.086.069.079.065.085.071c.712.6 1.353 1.283 1.909 2.031L7.222.994l.062-.027.065-.028.081-.034.086-.035c.113-.045.227-.09.341-.131l.096-.035.093-.033.084-.03.096-.031c.087-.03.176-.058.264-.085l.091-.027.086-.025.102-.03.085-.023.1-.026L9.04.37l.09-.023.091-.022.095-.022.09-.02.098-.021.091-.02.095-.018.092-.018.1-.018.091-.016.098-.017.092-.014.097-.015.092-.013.102-.013.091-.012.105-.012.09-.01.105-.01c.093-.01.186-.018.28-.024l.106-.008.09-.005.11-.006.093-.004.1-.004.097-.002.099-.002.197-.002z"
|
|
556
441
|
}
|
|
557
442
|
};
|
|
558
|
-
/**
|
|
559
|
-
* Which mark a session wears.
|
|
560
|
-
*
|
|
561
|
-
* The two first-party engines are named directly. A `provider` session is
|
|
562
|
-
* whatever the host wired up, so its *model* is the only thing that says whose
|
|
563
|
-
* it is — sniffed loosely on purpose (`gemini-2.5-pro`, `deepseek-chat`,
|
|
564
|
-
* `kimi-k2`), and falling through to no mark rather than guessing wrong.
|
|
565
|
-
*/
|
|
566
443
|
function engineMark(engine, model) {
|
|
567
444
|
if (engine === "claude") return "claude";
|
|
568
445
|
if (engine === "codex") return "codex";
|
|
569
446
|
const id = model?.toLowerCase() ?? "";
|
|
570
|
-
if (!id) return
|
|
447
|
+
if (!id) return;
|
|
571
448
|
if (id.includes("gemini")) return "gemini";
|
|
572
449
|
if (id.includes("deepseek")) return "deepseek";
|
|
573
450
|
if (id.includes("moonshot") || id.includes("kimi")) return "moonshot";
|
|
574
451
|
if (id.includes("claude")) return "claude";
|
|
575
452
|
if (id.startsWith("gpt") || id.startsWith("o1") || id.startsWith("o3") || id.includes("openai")) return "codex";
|
|
576
453
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Which engines wear their vendor's colour, and **how far it reaches**.
|
|
579
|
-
*
|
|
580
|
-
* `MARK` is the glyph, `TEXT` is the model name beside it. They are the same for
|
|
581
|
-
* Anthropic and deliberately not for OpenAI, because the two brands differ in
|
|
582
|
-
* kind rather than in hue: coral is an accent, and OpenAI's guidelines forbid
|
|
583
|
-
* adding colour to the mark at all, so theirs is pure white/black. At full
|
|
584
|
-
* contrast that is right on a 12px glyph and wrong on an 11px label — a
|
|
585
|
-
* pure-white model name is *brighter than the session title above it*, which
|
|
586
|
-
* inverts the row's whole hierarchy to say something the mark has already said.
|
|
587
|
-
* So OpenAI's name keeps the muted line it always had, which is also the most
|
|
588
|
-
* literal reading of "don't add any colors".
|
|
589
|
-
*
|
|
590
|
-
* Anything absent falls through to muted on both counts.
|
|
591
|
-
*/
|
|
592
454
|
const VENDOR_MARK = {
|
|
593
455
|
claude: "text-vendor-claude",
|
|
594
456
|
codex: "text-vendor-openai"
|
|
595
457
|
};
|
|
596
458
|
const VENDOR_TEXT = { claude: "text-vendor-claude" };
|
|
597
|
-
/** The colour a session's engine mark wears. Pass it to `EngineIcon`'s
|
|
598
|
-
* `className` rather than to a parent: the svg carries its own `text-fg-3`,
|
|
599
|
-
* and only a class on the element itself is merged over it. */
|
|
600
459
|
function vendorMarkClass(engine, model) {
|
|
601
460
|
return VENDOR_MARK[engineMark(engine, model) ?? ""] ?? "text-fg-3";
|
|
602
461
|
}
|
|
603
|
-
/** The colour the model *name* wears beside that mark — muted unless the vendor
|
|
604
|
-
* is one whose accent survives at label size. See `VENDOR_TEXT`.
|
|
605
|
-
*
|
|
606
|
-
* The fallback is `text-fg-3` rather than the metadata line's own `text-fg-4`,
|
|
607
|
-
* so an unbranded model still sits one step above the project and gateway
|
|
608
|
-
* beside it — the order the spec lists them in, held without a colour. */
|
|
609
462
|
function vendorTextClass(engine, model) {
|
|
610
463
|
return VENDOR_TEXT[engineMark(engine, model) ?? ""] ?? "text-fg-3";
|
|
611
464
|
}
|
|
@@ -629,28 +482,6 @@ function EngineIcon({ engine, model, className }) {
|
|
|
629
482
|
}
|
|
630
483
|
//#endregion
|
|
631
484
|
//#region src/components/agent/SessionStatusIcon.tsx
|
|
632
|
-
/**
|
|
633
|
-
* State as one glyph — a ringing bell when it wants a human, a spinner while it
|
|
634
|
-
* works, a moon when it is only sleeping. Replaces the text badge: in a sidebar
|
|
635
|
-
* the word costs more room than it earns, and the states that matter are the two
|
|
636
|
-
* you can recognise without reading.
|
|
637
|
-
*
|
|
638
|
-
* **It reads `row.state`, not `info.status`, and that distinction is the whole
|
|
639
|
-
* point of the row model.** `sessionState` already folds in the arm this glyph
|
|
640
|
-
* cannot see for itself: a *background* sub-agent outlives its turn by design,
|
|
641
|
-
* so the turn ends, `status` comes to rest at `idle`, and the agent keeps
|
|
642
|
-
* working. Reading the raw status drew a **moon on a row filed under the
|
|
643
|
-
* "Working" header** — the list contradicting itself on one line, which is
|
|
644
|
-
* exactly what a derived view model exists to prevent. The value was in scope
|
|
645
|
-
* and unread.
|
|
646
|
-
*
|
|
647
|
-
* The terminal statuses still come off `info.status`, because `ended` collapses
|
|
648
|
-
* `failed` and `closed` into one bucket and those are worth telling apart here.
|
|
649
|
-
*
|
|
650
|
-
* It lives in its own file rather than inside the dashboard's browser because
|
|
651
|
-
* the extension's cards draw it too, and a second copy there is how the two
|
|
652
|
-
* lists last disagreed about what a parked session looks like.
|
|
653
|
-
*/
|
|
654
485
|
function SessionStatusIcon({ row, className }) {
|
|
655
486
|
const { info } = row;
|
|
656
487
|
const size = cn("size-4 shrink-0", className);
|
|
@@ -665,25 +496,6 @@ function SessionStatusIcon({ row, className }) {
|
|
|
665
496
|
}
|
|
666
497
|
//#endregion
|
|
667
498
|
//#region src/components/agent/SessionSteps.tsx
|
|
668
|
-
/**
|
|
669
|
-
* The steps under one session, **agents first**.
|
|
670
|
-
*
|
|
671
|
-
* The two kinds do different things when pressed and are worth different
|
|
672
|
-
* amounts of attention: an agent has work of its own to go and read, a task is a
|
|
673
|
-
* marker in a transcript. Interleaved in dispatch order they read as one
|
|
674
|
-
* undifferentiated list, and the rows you can actually open are scattered
|
|
675
|
-
* through it. Grouped, the openable ones are a block at the top and the markers
|
|
676
|
-
* are a tail you can skip.
|
|
677
|
-
*
|
|
678
|
-
* Stable **within** each group, deliberately: dispatch order is the only order
|
|
679
|
-
* these records have that means anything (it is the order the work was started
|
|
680
|
-
* in), so the sort partitions and never reorders inside a partition.
|
|
681
|
-
*
|
|
682
|
-
* `onSelect` is handed the **kind** as well as the id, because the two kinds go
|
|
683
|
-
* to different places — see `SessionItem`, which is what routes them. Passing
|
|
684
|
-
* only the id is what let a task be opened as if it were an agent, and a framed
|
|
685
|
-
* task id matches no items, so the panel drew an **empty agent view**.
|
|
686
|
-
*/
|
|
687
499
|
function sessionSteps(info, onSelect) {
|
|
688
500
|
const steps = (info.subagents ?? []).map((sub) => {
|
|
689
501
|
const kind = isAgentRecord(sub) ? "agent" : "task";
|
|
@@ -707,20 +519,9 @@ function stepState(status) {
|
|
|
707
519
|
default: return "done";
|
|
708
520
|
}
|
|
709
521
|
}
|
|
710
|
-
/** How many of these are still going — the live half of the disclosure's count. */
|
|
711
522
|
function runningSteps(steps) {
|
|
712
523
|
return steps.filter((s) => s.state === "running").length;
|
|
713
524
|
}
|
|
714
|
-
/**
|
|
715
|
-
* The disclosure, which is also the reading: `3 agents` — or `2 of 3 agents`
|
|
716
|
-
* while some have settled, because "how many are still going" is the live
|
|
717
|
-
* question and a bare total answers it wrong the moment one finishes.
|
|
718
|
-
*
|
|
719
|
-
* Sub-agents are an annotation on a working row rather than a state of their own
|
|
720
|
-
* (see `runningSubagents` in protocol's `session-list.ts`), so this never
|
|
721
|
-
* competes with the row's status glyph: that still says what the *session* is
|
|
722
|
-
* doing.
|
|
723
|
-
*/
|
|
724
525
|
function StepToggle({ expanded, running, total, noun, onToggle }) {
|
|
725
526
|
const label = running > 0 && running < total ? `${running}/${total}` : String(total);
|
|
726
527
|
const words = running > 0 && running < total ? `${running} of ${total} ${noun}s running` : `${total} ${noun}${total === 1 ? "" : "s"}`;
|
|
@@ -741,46 +542,6 @@ function StepToggle({ expanded, running, total, noun, onToggle }) {
|
|
|
741
542
|
})]
|
|
742
543
|
});
|
|
743
544
|
}
|
|
744
|
-
/**
|
|
745
|
-
* One step under its session — **pressable, all of them**, and what a press
|
|
746
|
-
* means is what tells the two kinds apart.
|
|
747
|
-
*
|
|
748
|
-
* Pressing an **agent** hands the panel over to that agent's own work
|
|
749
|
-
* (`SessionPanel.openSubagent`): it is not a session and never becomes one, but
|
|
750
|
-
* it has a surface, so it can be the selected thing. Pressing a **task** selects
|
|
751
|
-
* the *session* and travels to that task's marker inside it — a task is a
|
|
752
|
-
* reference to a place in a transcript, not a thing with a screen, so it can be
|
|
753
|
-
* followed but never held.
|
|
754
|
-
*
|
|
755
|
-
* That is a reversal, and a deliberate one. A task used to be inert markup on
|
|
756
|
-
* the argument that "a disabled-looking button still announces itself as one" —
|
|
757
|
-
* correct about the markup, wrong about the premise, because there *was* always
|
|
758
|
-
* somewhere to go and the row simply swallowed the click on its way there. A row
|
|
759
|
-
* that looks like a list item, sits in a list, and does nothing when pressed is
|
|
760
|
-
* the worse lie. So every step answers the pointer and every step answers a
|
|
761
|
-
* press; only what the press does differs.
|
|
762
|
-
*
|
|
763
|
-
* Divided from the card's header by **indentation and its own hit shape**, not
|
|
764
|
-
* by a rule. The rules came first, on the argument that at 11px an indent is not
|
|
765
|
-
* enough to say "list inside a row" — and they were right about the reading and
|
|
766
|
-
* wrong about the cost: a stack of hairlines across every open card turned the
|
|
767
|
-
* list into a ledger, and a rule cannot answer a pointer. A step that lights up
|
|
768
|
-
* under the cursor and fills when it is the one on screen says *list* far more
|
|
769
|
-
* plainly than a line between two of them, and it says it while doing the job
|
|
770
|
-
* the rule could not.
|
|
771
|
-
*
|
|
772
|
-
* **Only an agent can wear the selection**, and `active` is guarded on that here
|
|
773
|
-
* rather than trusted from the caller: a host that hands back a task's key is
|
|
774
|
-
* describing where it navigated, not what it selected, and the row must not
|
|
775
|
-
* paint itself blue for it.
|
|
776
|
-
*
|
|
777
|
-
* The hover is `--row-active` — **alpha, not a flat fill** — because this row
|
|
778
|
-
* has to answer the pointer on three different grounds: a transparent card, a
|
|
779
|
-
* blue one (its session is selected), and a grey one (a sibling agent is). A
|
|
780
|
-
* flat value tuned for any of those is wrong on the other two; a tint darkens or
|
|
781
|
-
* lifts whatever it lands on. It is the one place in the list where the alpha
|
|
782
|
-
* token earns its keep.
|
|
783
|
-
*/
|
|
784
545
|
function StepRow({ step, active = false, onSelect }) {
|
|
785
546
|
const agent = step.kind === "agent";
|
|
786
547
|
const selected = active && agent;
|
|
@@ -903,7 +664,7 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
903
664
|
children: sessionLabel(info)
|
|
904
665
|
}),
|
|
905
666
|
row.unseen > 0 ? /* @__PURE__ */ jsx("span", {
|
|
906
|
-
title: `${row.unseen} new`,
|
|
667
|
+
title: `${row.unseen} new message${row.unseen === 1 ? "" : "s"}`,
|
|
907
668
|
className: cn("flex h-4 min-w-6 shrink-0 items-center justify-center rounded-full px-2", "text-[0.75rem] leading-none tracking-[-0.005em] tabular-nums", row.state === "working" || row.state === "attention" ? "bg-accent text-accent-fg" : "bg-badge text-badge-fg"),
|
|
908
669
|
children: row.unseen
|
|
909
670
|
}) : null,
|
|
@@ -950,32 +711,12 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
|
|
|
950
711
|
}) : null]
|
|
951
712
|
});
|
|
952
713
|
}
|
|
953
|
-
/**
|
|
954
|
-
* The one 16px cell both lines hang their glyph in.
|
|
955
|
-
*
|
|
956
|
-
* A shared column rather than a leading character: the state and the engine mark
|
|
957
|
-
* are different widths and a bare glyph would let the two text columns start at
|
|
958
|
-
* different x. Centring inside a fixed cell is what makes them agree.
|
|
959
|
-
*/
|
|
960
714
|
function Gutter({ children }) {
|
|
961
715
|
return /* @__PURE__ */ jsx("span", {
|
|
962
716
|
className: "flex size-4 shrink-0 items-center justify-center",
|
|
963
717
|
children
|
|
964
718
|
});
|
|
965
719
|
}
|
|
966
|
-
/**
|
|
967
|
-
* Enter commits, Escape cancels, blur commits — the editor's inline-rename feel.
|
|
968
|
-
* An empty value is a deliberate "clear the name", which the gateway answers by
|
|
969
|
-
* handing back the derived title.
|
|
970
|
-
*
|
|
971
|
-
* The blur rule needs one guard. Selecting a session focuses a different surface
|
|
972
|
-
* — in the extension, a different VS Code view — so this document can lose focus
|
|
973
|
-
* a tick after a double-click opened the editor, and an unguarded blur reads
|
|
974
|
-
* that as "the user clicked away" and closes the editor in the frame it
|
|
975
|
-
* appeared. `document.hasFocus()` tells the two apart: focus moving WITHIN this
|
|
976
|
-
* document is the user leaving the field; the whole view losing focus is not.
|
|
977
|
-
* When the window comes back, so does the caret.
|
|
978
|
-
*/
|
|
979
720
|
function NameEditor({ initial, onCommit, onCancel }) {
|
|
980
721
|
const [value, setValue] = useState(initial);
|
|
981
722
|
const ref = useRef(null);
|
|
@@ -1013,22 +754,6 @@ function NameEditor({ initial, onCommit, onCancel }) {
|
|
|
1013
754
|
}
|
|
1014
755
|
//#endregion
|
|
1015
756
|
//#region src/components/agent/SessionBrowser.tsx
|
|
1016
|
-
/**
|
|
1017
|
-
* How a list row is drawn, in one place, so `SidebarRow` in `web` matches this
|
|
1018
|
-
* exactly rather than approximating it — the dashboard's other three sidebars
|
|
1019
|
-
* are that component, and a sessions list that hovered differently from the
|
|
1020
|
-
* gateways list beside it would read as a different product.
|
|
1021
|
-
*
|
|
1022
|
-
* Two rules are load-bearing:
|
|
1023
|
-
*
|
|
1024
|
-
* - **Fill means hover, and only hover.** It stays on the row whether or not
|
|
1025
|
-
* the row is selected, because a selected row still has to answer the
|
|
1026
|
-
* pointer. Selection gets the gutter instead.
|
|
1027
|
-
* - **`ml-0` on the selected row is not cosmetic.** It hands the accent border
|
|
1028
|
-
* the 4px the margin was holding, so the text does not shift sideways as a
|
|
1029
|
-
* row becomes the selected one. The squared left corners are what let the bar
|
|
1030
|
-
* sit flush against the sidebar edge.
|
|
1031
|
-
*/
|
|
1032
757
|
function rowShapeClass(active) {
|
|
1033
758
|
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");
|
|
1034
759
|
}
|
|
@@ -1248,9 +973,6 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
|
|
|
1248
973
|
]
|
|
1249
974
|
});
|
|
1250
975
|
}
|
|
1251
|
-
/** The bytes for a row's project icon, if it has an image one and the caller has
|
|
1252
|
-
* fetched it yet. Shared by the row and its group header so the two cannot draw
|
|
1253
|
-
* different pictures for one project. */
|
|
1254
976
|
function iconSrcOf(row, icons) {
|
|
1255
977
|
const icon = row?.info.project?.icon;
|
|
1256
978
|
return icon?.type === "image" ? icons?.[icon.hash] : void 0;
|
|
@@ -1292,16 +1014,6 @@ function SessionRowItem({ row, active, activeSubagentId, showGateway, showProjec
|
|
|
1292
1014
|
] })
|
|
1293
1015
|
});
|
|
1294
1016
|
}
|
|
1295
|
-
/**
|
|
1296
|
-
* One of the dashboard's hover actions.
|
|
1297
|
-
*
|
|
1298
|
-
* Hover-revealed rather than always on, which is the opposite of the
|
|
1299
|
-
* extension's single overflow glyph and the right call for each: there are
|
|
1300
|
-
* three of them here and a sidebar card has room for one, so the extension
|
|
1301
|
-
* spends that room on a menu and this spends the row's hover on the actions
|
|
1302
|
-
* themselves. Both stop the click — the whole card is pressable underneath, and
|
|
1303
|
-
* an action that also selected the session would do two things per press.
|
|
1304
|
-
*/
|
|
1305
1017
|
function RowAction({ label, title, onClick, children }) {
|
|
1306
1018
|
return /* @__PURE__ */ jsx(Button, {
|
|
1307
1019
|
variant: "ghost",
|
|
@@ -1316,13 +1028,6 @@ function RowAction({ label, title, onClick, children }) {
|
|
|
1316
1028
|
children
|
|
1317
1029
|
});
|
|
1318
1030
|
}
|
|
1319
|
-
/** A multi-select facet. Empty = no filter, which is why the trigger reads the
|
|
1320
|
-
* facet's name rather than "All": nothing is being excluded. */
|
|
1321
|
-
/**
|
|
1322
|
-
* One labelled control row. The label column is fixed so every control starts
|
|
1323
|
-
* on the same x — the thing that makes a stack of them read as a form rather
|
|
1324
|
-
* than as five unrelated widgets.
|
|
1325
|
-
*/
|
|
1326
1031
|
function FilterRow({ label, children }) {
|
|
1327
1032
|
return /* @__PURE__ */ jsxs("div", {
|
|
1328
1033
|
className: "flex items-center gap-2",
|