@workerdeck/ui 0.21.0 → 0.23.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 +3 -2
- package/build/{SessionPanel-BjNAnWMF.d.mts → SessionPanel-BobynUo4.d.mts} +75 -5
- package/build/{SessionPanel-DNuPKg5c.mjs → SessionPanel-DUt2VzXG.mjs} +672 -231
- package/build/SessionPanel-DUt2VzXG.mjs.map +1 -0
- package/build/index.d.mts +54 -21
- package/build/index.mjs +7 -6
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +3611 -0
- package/build/workspace.d.mts +7 -1
- package/build/workspace.mjs +4 -2
- package/build/workspace.mjs.map +1 -1
- package/package.json +10 -6
- package/src/components/agent/Composer.tsx +10 -10
- package/src/components/agent/ContextDialog.tsx +3 -2
- package/src/components/agent/Conversation.tsx +1 -1
- package/src/components/agent/McpDialog.tsx +3 -1
- package/src/components/agent/Response.tsx +4 -0
- package/src/components/agent/Scrubber.tsx +248 -0
- package/src/components/agent/SessionList.tsx +3 -1
- package/src/components/agent/SessionPanel.tsx +132 -16
- package/src/components/agent/SessionSteps.tsx +10 -4
- package/src/components/agent/SessionWorkspace.tsx +8 -0
- package/src/components/agent/SkillsDialog.tsx +3 -2
- package/src/components/agent/StatusBar.tsx +3 -3
- package/src/components/agent/Transcript.tsx +147 -73
- package/src/components/agent/UsageDialog.tsx +3 -1
- package/src/components/agent/scrubber-marks.ts +277 -0
- package/src/components/terminal/PermissionPrompt.tsx +3 -0
- package/src/components/terminal/QuestionPrompt.tsx +3 -0
- package/src/components/terminal/StatusLine.tsx +3 -1
- package/src/components/ui/AlertDialog.tsx +23 -20
- package/src/components/ui/Dialog.tsx +26 -23
- package/src/components/ui/Menu.tsx +20 -17
- package/src/components/ui/PortalScope.tsx +27 -0
- package/src/components/ui/Select.tsx +19 -16
- package/src/components/ui/Tooltip.tsx +13 -10
- package/src/styles/scoped.entry.css +16 -0
- package/src/styles/terminal.css +1 -1
- package/src/styles/theme.css +213 -0
- package/build/SessionPanel-DNuPKg5c.mjs.map +0 -1
|
@@ -117,6 +117,33 @@ const Input = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("
|
|
|
117
117
|
}));
|
|
118
118
|
Input.displayName = "Input";
|
|
119
119
|
//#endregion
|
|
120
|
+
//#region src/components/ui/PortalScope.tsx
|
|
121
|
+
/**
|
|
122
|
+
* Re-establishes the `.wd-root` styling scope inside a portal.
|
|
123
|
+
*
|
|
124
|
+
* The scoped stylesheet (`@workerdeck/ui/scoped.css`) rewrites every rule to
|
|
125
|
+
* live under `.wd-root`, so an embedder's page keeps its own design system and
|
|
126
|
+
* the panel keeps this one. Base UI popups (Menu, Dialog, AlertDialog, Select,
|
|
127
|
+
* Tooltip) portal to `document.body` — OUTSIDE the embedder's wrapper — so
|
|
128
|
+
* without this they would render unstyled, or worse, styled by the host.
|
|
129
|
+
*
|
|
130
|
+
* `display: contents` (inline, so no stylesheet needs to load for it) makes the
|
|
131
|
+
* element generate no box: positioning, hit-testing and the popup's own layout
|
|
132
|
+
* are untouched. It still carries the class, which is all the scope needs —
|
|
133
|
+
* design tokens declared on `.wd-root` inherit through it, and every
|
|
134
|
+
* `.wd-root <x>` rule matches below it. Theme keeps working because the dark
|
|
135
|
+
* token block matches `[data-theme='dark']` on ANY ancestor, and `document.body`
|
|
136
|
+
* sits under the host's themed `<html>` just like the panel does.
|
|
137
|
+
*
|
|
138
|
+
* Under the classic `theme.css` integration the class matches no rule and the
|
|
139
|
+
* element is inert, so the wrapper is unconditional.
|
|
140
|
+
*/
|
|
141
|
+
const PortalScope = ({ children }) => /* @__PURE__ */ jsx("div", {
|
|
142
|
+
className: "wd-root",
|
|
143
|
+
style: { display: "contents" },
|
|
144
|
+
children
|
|
145
|
+
});
|
|
146
|
+
//#endregion
|
|
120
147
|
//#region src/components/ui/Select.tsx
|
|
121
148
|
const Select$1 = Select.Root;
|
|
122
149
|
const SelectValue = Select.Value;
|
|
@@ -130,7 +157,7 @@ const SelectTrigger = ({ className, children, ...props }) => /* @__PURE__ */ jsx
|
|
|
130
157
|
children: /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5" })
|
|
131
158
|
})]
|
|
132
159
|
});
|
|
133
|
-
const SelectContent = ({ className, align = "start", alignItemWithTrigger = false, side = "bottom", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
|
|
160
|
+
const SelectContent = ({ className, align = "start", alignItemWithTrigger = false, side = "bottom", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(PortalScope, { children: /* @__PURE__ */ jsx(Select.Positioner, {
|
|
134
161
|
align,
|
|
135
162
|
alignItemWithTrigger,
|
|
136
163
|
side,
|
|
@@ -141,7 +168,7 @@ const SelectContent = ({ className, align = "start", alignItemWithTrigger = fals
|
|
|
141
168
|
className: cn("max-h-[min(24rem,var(--available-height))] min-w-[var(--anchor-width)] overflow-y-auto", "rounded-md border border-border bg-surface p-1 text-fg-1 shadow-(--shadow-lg) outline-none", className),
|
|
142
169
|
...props
|
|
143
170
|
})
|
|
144
|
-
}) });
|
|
171
|
+
}) }) });
|
|
145
172
|
const SelectItem = ({ className, children, ...props }) => /* @__PURE__ */ jsxs(Select.Item, {
|
|
146
173
|
"data-slot": "select-item",
|
|
147
174
|
className: cn("flex cursor-pointer items-start gap-2 rounded-sm px-2 py-1.5 text-body-sm text-text outline-none select-none", "data-highlighted:bg-surface-hover", className),
|
|
@@ -158,7 +185,7 @@ const SelectItem = ({ className, children, ...props }) => /* @__PURE__ */ jsxs(S
|
|
|
158
185
|
//#region src/components/ui/Menu.tsx
|
|
159
186
|
const Menu$1 = Menu.Root;
|
|
160
187
|
const MenuTrigger = Menu.Trigger;
|
|
161
|
-
const MenuContent = ({ className, align = "end", side = "bottom", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
|
|
188
|
+
const MenuContent = ({ className, align = "end", side = "bottom", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(PortalScope, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
|
|
162
189
|
align,
|
|
163
190
|
side,
|
|
164
191
|
sideOffset,
|
|
@@ -168,7 +195,7 @@ const MenuContent = ({ className, align = "end", side = "bottom", sideOffset = 6
|
|
|
168
195
|
className: cn("min-w-48 rounded-md border border-border bg-surface p-1 text-fg-1 shadow-(--shadow-lg) outline-none", "transition-[opacity,transform] duration-(--motion-base)", "data-starting-style:scale-95 data-starting-style:opacity-0", "data-ending-style:scale-95 data-ending-style:opacity-0", className),
|
|
169
196
|
...props
|
|
170
197
|
})
|
|
171
|
-
}) });
|
|
198
|
+
}) }) });
|
|
172
199
|
const MenuItem = ({ className, destructive, ...props }) => /* @__PURE__ */ jsx(Menu.Item, {
|
|
173
200
|
"data-slot": "menu-item",
|
|
174
201
|
className: cn("flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-body-sm outline-none select-none", "data-highlighted:bg-surface-hover", destructive ? "text-danger" : "text-text", className),
|
|
@@ -190,12 +217,12 @@ const DialogClose = Dialog.Close;
|
|
|
190
217
|
* Taller than {@link AlertDialogContent} and scrollable inside, because these
|
|
191
218
|
* carry lists whose length is the engine's business, not the layout's.
|
|
192
219
|
*/
|
|
193
|
-
const DialogContent = ({ className, children, size = "md", ...props }) => /* @__PURE__ */
|
|
220
|
+
const DialogContent = ({ className, children, size = "md", ...props }) => /* @__PURE__ */ jsx(Dialog.Portal, { children: /* @__PURE__ */ jsxs(PortalScope, { children: [/* @__PURE__ */ jsx(Dialog.Backdrop, { className: cn("fixed inset-0 z-70 bg-black/40 backdrop-blur-[1px]", "transition-opacity duration-(--motion-base)", "data-starting-style:opacity-0 data-ending-style:opacity-0") }), /* @__PURE__ */ jsx(Dialog.Popup, {
|
|
194
221
|
"data-slot": "dialog-content",
|
|
195
222
|
className: cn("fixed top-1/2 left-1/2 z-70 flex max-h-[min(42rem,calc(100dvh-3rem))] -translate-x-1/2 -translate-y-1/2 flex-col", size === "sm" && "w-[min(24rem,calc(100vw-2rem))]", size === "md" && "w-[min(32rem,calc(100vw-2rem))]", size === "lg" && "w-[min(46rem,calc(100vw-2rem))]", "rounded-lg border border-border bg-surface shadow-(--shadow-lg) outline-none", "transition-[opacity,transform] duration-(--motion-base)", "data-starting-style:scale-95 data-starting-style:opacity-0", "data-ending-style:scale-95 data-ending-style:opacity-0", className),
|
|
196
223
|
...props,
|
|
197
224
|
children
|
|
198
|
-
})] });
|
|
225
|
+
})] }) });
|
|
199
226
|
/** Title row with the close button, pinned above the scrolling body. */
|
|
200
227
|
const DialogHeader = ({ title, description, actions }) => /* @__PURE__ */ jsxs("div", {
|
|
201
228
|
className: "flex items-start gap-2 border-b border-border px-4 py-3",
|
|
@@ -237,7 +264,7 @@ const DialogRow = ({ label, children, mono }) => /* @__PURE__ */ jsxs("div", {
|
|
|
237
264
|
//#endregion
|
|
238
265
|
//#region src/components/ui/Tooltip.tsx
|
|
239
266
|
const TooltipProvider = Tooltip.Provider;
|
|
240
|
-
const TooltipContent = ({ className, side = "top", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
|
|
267
|
+
const TooltipContent = ({ className, side = "top", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(PortalScope, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
|
|
241
268
|
side,
|
|
242
269
|
sideOffset,
|
|
243
270
|
className: "isolate z-90",
|
|
@@ -246,7 +273,7 @@ const TooltipContent = ({ className, side = "top", sideOffset = 6, ...props }) =
|
|
|
246
273
|
className: cn("rounded-md border border-border bg-surface px-2 py-1 text-label text-fg-2 shadow-(--shadow-md) outline-none", className),
|
|
247
274
|
...props
|
|
248
275
|
})
|
|
249
|
-
}) });
|
|
276
|
+
}) }) });
|
|
250
277
|
/**
|
|
251
278
|
* Convenience wrapper: `<Tip content="..."><Button/></Tip>`.
|
|
252
279
|
*
|
|
@@ -6281,7 +6308,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
6281
6308
|
}
|
|
6282
6309
|
};
|
|
6283
6310
|
const errorRow = attachments?.error ? /* @__PURE__ */ jsxs("div", {
|
|
6284
|
-
className: cn("mx-auto mt-1 flex w-full max-w-[var(--wd-
|
|
6311
|
+
className: cn("mx-auto mt-1 flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-danger"),
|
|
6285
6312
|
children: [
|
|
6286
6313
|
/* @__PURE__ */ jsx(TriangleAlert, { className: "size-3 shrink-0" }),
|
|
6287
6314
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -6354,10 +6381,10 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
6354
6381
|
}
|
|
6355
6382
|
return /* @__PURE__ */ jsxs("div", {
|
|
6356
6383
|
"data-slot": "composer",
|
|
6357
|
-
className: cn("px-
|
|
6384
|
+
className: cn("px-[var(--wd-composer-padding)] pb-[var(--wd-composer-padding)]", className),
|
|
6358
6385
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
6359
6386
|
...dropHandlers,
|
|
6360
|
-
className: cn("mx-auto w-full max-w-[var(--wd-
|
|
6387
|
+
className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)] overflow-hidden border border-border bg-bg", "transition-colors rounded-lg shadow-(--shadow-xs)", "focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/30", dragging && "border-ring ring-2 ring-ring/30", disabled && "opacity-60"),
|
|
6361
6388
|
children: [staged.length > 0 && attachments ? /* @__PURE__ */ jsx(AttachmentStrip, { attachments }) : null, inline ? /* @__PURE__ */ jsxs("div", {
|
|
6362
6389
|
className: "flex items-end gap-1 p-1",
|
|
6363
6390
|
children: [
|
|
@@ -6372,7 +6399,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
6372
6399
|
minHeight: 20,
|
|
6373
6400
|
maxHeight: 192,
|
|
6374
6401
|
"aria-label": "Message the agent",
|
|
6375
|
-
className: "min-w-0 flex-1 py-
|
|
6402
|
+
className: "min-w-0 flex-1 py-1 text-body-sm text-text",
|
|
6376
6403
|
onImagePaste: (file) => attachments?.add([file])
|
|
6377
6404
|
}),
|
|
6378
6405
|
submitButton
|
|
@@ -6387,7 +6414,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
6387
6414
|
minHeight: 28,
|
|
6388
6415
|
maxHeight: 192,
|
|
6389
6416
|
"aria-label": "Message the agent",
|
|
6390
|
-
className: "px-3 pt-2.5 pb-
|
|
6417
|
+
className: "px-3 pt-2.5 pb-0 text-body-sm text-text",
|
|
6391
6418
|
onImagePaste: (file) => attachments?.add([file])
|
|
6392
6419
|
}), /* @__PURE__ */ jsxs("div", {
|
|
6393
6420
|
className: "flex items-center justify-between gap-2 px-2 pb-2",
|
|
@@ -6494,81 +6521,84 @@ const usageTint$1 = (pct) => pct >= 90 ? "bg-danger" : pct >= 70 ? "bg-warning"
|
|
|
6494
6521
|
* are different questions asked at different moments, so they are different
|
|
6495
6522
|
* screens rather than one "details" list you scroll past two answers to reach.
|
|
6496
6523
|
*/
|
|
6497
|
-
function ContextDialog({ usage, open, onOpenChange }) {
|
|
6524
|
+
function ContextDialog({ usage, open, onOpenChange, className }) {
|
|
6498
6525
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
6499
6526
|
open,
|
|
6500
6527
|
onOpenChange,
|
|
6501
|
-
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
className: "
|
|
6512
|
-
children: "
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
className:
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
className: "
|
|
6537
|
-
children: "
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
children: [/* @__PURE__ */ jsxs("
|
|
6546
|
-
className: "flex
|
|
6547
|
-
children: [/* @__PURE__ */
|
|
6548
|
-
className: "
|
|
6549
|
-
|
|
6528
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
6529
|
+
className,
|
|
6530
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
6531
|
+
title: "Context",
|
|
6532
|
+
description: usage?.model
|
|
6533
|
+
}), /* @__PURE__ */ jsx(DialogBody, { children: !usage ? /* @__PURE__ */ jsx("p", {
|
|
6534
|
+
className: "py-6 text-center text-body-sm text-fg-4",
|
|
6535
|
+
children: "No reading yet — the context window is measured after a turn completes."
|
|
6536
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6537
|
+
/* @__PURE__ */ jsxs("div", {
|
|
6538
|
+
className: "flex items-baseline justify-between gap-4",
|
|
6539
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
6540
|
+
className: "text-label text-fg-3",
|
|
6541
|
+
children: "Used"
|
|
6542
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
6543
|
+
className: "font-mono text-body-sm text-fg-1",
|
|
6544
|
+
children: [
|
|
6545
|
+
formatTokens(usage.totalTokens),
|
|
6546
|
+
" / ",
|
|
6547
|
+
formatTokens(usage.maxTokens),
|
|
6548
|
+
" ·",
|
|
6549
|
+
" ",
|
|
6550
|
+
usage.percentage.toFixed(0),
|
|
6551
|
+
"%"
|
|
6552
|
+
]
|
|
6553
|
+
})]
|
|
6554
|
+
}),
|
|
6555
|
+
/* @__PURE__ */ jsx("div", {
|
|
6556
|
+
className: "mt-2 h-2 overflow-hidden rounded-full bg-border",
|
|
6557
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
6558
|
+
className: cn("h-full rounded-full", usageTint$1(usage.percentage)),
|
|
6559
|
+
style: { width: `${Math.min(100, Math.max(2, usage.percentage))}%` }
|
|
6560
|
+
})
|
|
6561
|
+
}),
|
|
6562
|
+
usage.categories.length > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
6563
|
+
className: "mt-5",
|
|
6564
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
6565
|
+
className: "text-label font-medium text-fg-3",
|
|
6566
|
+
children: "Breakdown"
|
|
6567
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
6568
|
+
className: "mt-2 flex flex-col gap-3",
|
|
6569
|
+
children: usage.categories.map((category) => {
|
|
6570
|
+
const share = category.tokens / Math.max(usage.maxTokens, 1) * 100;
|
|
6571
|
+
const color = cssColor$1(category.color);
|
|
6572
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
6573
|
+
className: "flex items-baseline justify-between gap-3",
|
|
6574
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
6575
|
+
className: "flex min-w-0 items-center gap-2",
|
|
6576
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
6577
|
+
className: "size-2 shrink-0 rounded-full bg-fg-4",
|
|
6578
|
+
style: color ? { backgroundColor: color } : void 0
|
|
6579
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
6580
|
+
className: "truncate text-body-sm text-fg-1",
|
|
6581
|
+
children: category.name
|
|
6582
|
+
})]
|
|
6550
6583
|
}), /* @__PURE__ */ jsx("span", {
|
|
6551
|
-
className: "
|
|
6552
|
-
children: category.
|
|
6584
|
+
className: "shrink-0 font-mono text-label text-fg-3",
|
|
6585
|
+
children: formatTokens(category.tokens)
|
|
6553
6586
|
})]
|
|
6554
|
-
}), /* @__PURE__ */ jsx("
|
|
6555
|
-
className: "
|
|
6556
|
-
children:
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
})]
|
|
6570
|
-
}) : null
|
|
6571
|
-
] }) })] })
|
|
6587
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
6588
|
+
className: "mt-1 h-1 overflow-hidden rounded-full bg-border",
|
|
6589
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
6590
|
+
className: "h-full rounded-full bg-fg-4",
|
|
6591
|
+
style: {
|
|
6592
|
+
width: `${Math.min(100, share)}%`,
|
|
6593
|
+
backgroundColor: color
|
|
6594
|
+
}
|
|
6595
|
+
})
|
|
6596
|
+
})] }, category.name);
|
|
6597
|
+
})
|
|
6598
|
+
})]
|
|
6599
|
+
}) : null
|
|
6600
|
+
] }) })]
|
|
6601
|
+
})
|
|
6572
6602
|
});
|
|
6573
6603
|
}
|
|
6574
6604
|
//#endregion
|
|
@@ -6765,7 +6795,7 @@ const STATUS_VARIANT = {
|
|
|
6765
6795
|
* the tool view either renders it or says why it can't, rather than leaving a
|
|
6766
6796
|
* silent gap or claiming the absence is universal.
|
|
6767
6797
|
*/
|
|
6768
|
-
function McpDialog({ client, sessionId, open, onOpenChange, canManageServers = true }) {
|
|
6798
|
+
function McpDialog({ client, sessionId, open, onOpenChange, canManageServers = true, className }) {
|
|
6769
6799
|
const [servers, setServers] = useState();
|
|
6770
6800
|
const [error, setError] = useState();
|
|
6771
6801
|
const [loading, setLoading] = useState(false);
|
|
@@ -6807,35 +6837,38 @@ function McpDialog({ client, sessionId, open, onOpenChange, canManageServers = t
|
|
|
6807
6837
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
6808
6838
|
open,
|
|
6809
6839
|
onOpenChange,
|
|
6810
|
-
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
children: error
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6840
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
6841
|
+
className,
|
|
6842
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
6843
|
+
title: tool?.name ?? server?.name ?? "MCP servers",
|
|
6844
|
+
description: tool ? `${server?.name} tool` : server ? server.serverInfo?.name : void 0,
|
|
6845
|
+
actions: selectedServer ? /* @__PURE__ */ jsxs(Button, {
|
|
6846
|
+
variant: "ghost",
|
|
6847
|
+
size: "xs",
|
|
6848
|
+
onClick: () => selectedTool ? setSelectedTool(void 0) : setSelectedServer(void 0),
|
|
6849
|
+
children: [/* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" }), "Back"]
|
|
6850
|
+
}) : /* @__PURE__ */ jsxs(Button, {
|
|
6851
|
+
variant: "ghost",
|
|
6852
|
+
size: "xs",
|
|
6853
|
+
onClick: () => void load(),
|
|
6854
|
+
disabled: loading,
|
|
6855
|
+
children: [loading ? /* @__PURE__ */ jsx(Spinner, { className: "size-3 text-current" }) : /* @__PURE__ */ jsx(RotateCw, { className: "size-3" }), "Refresh"]
|
|
6856
|
+
})
|
|
6857
|
+
}), /* @__PURE__ */ jsxs(DialogBody, { children: [error ? /* @__PURE__ */ jsx("div", {
|
|
6858
|
+
className: "mb-3 rounded-md bg-danger-bg px-3 py-2 text-body-sm text-danger",
|
|
6859
|
+
children: error
|
|
6860
|
+
}) : null, tool ? /* @__PURE__ */ jsx(ToolView, { tool }) : server ? /* @__PURE__ */ jsx(ServerView, {
|
|
6861
|
+
server,
|
|
6862
|
+
busy: busyServer === server.name,
|
|
6863
|
+
canManage: canManageServers,
|
|
6864
|
+
onAct: (action) => void act(server.name, action),
|
|
6865
|
+
onSelectTool: setSelectedTool
|
|
6866
|
+
}) : error && !servers ? null : /* @__PURE__ */ jsx(ServerList, {
|
|
6867
|
+
servers,
|
|
6868
|
+
loading,
|
|
6869
|
+
onSelect: setSelectedServer
|
|
6870
|
+
})] })]
|
|
6871
|
+
})
|
|
6839
6872
|
});
|
|
6840
6873
|
}
|
|
6841
6874
|
function ServerList({ servers, loading, onSelect }) {
|
|
@@ -7035,7 +7068,7 @@ const SCOPE_LABEL = {
|
|
|
7035
7068
|
* Fed from the session's `skills` event rather than a REST route, because that
|
|
7036
7069
|
* is the channel the engine refreshes on its own when a skill changes on disk.
|
|
7037
7070
|
*/
|
|
7038
|
-
function SkillsDialog({ skills, open, onOpenChange, onUse }) {
|
|
7071
|
+
function SkillsDialog({ skills, open, onOpenChange, onUse, className }) {
|
|
7039
7072
|
const [selected, setSelected] = useState();
|
|
7040
7073
|
const skill = skills?.find((s) => s.name === selected);
|
|
7041
7074
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
@@ -7044,23 +7077,26 @@ function SkillsDialog({ skills, open, onOpenChange, onUse }) {
|
|
|
7044
7077
|
if (!next) setSelected(void 0);
|
|
7045
7078
|
onOpenChange(next);
|
|
7046
7079
|
},
|
|
7047
|
-
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7080
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
7081
|
+
className,
|
|
7082
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
7083
|
+
title: skill ? skill.displayName ?? skill.name : "Skills",
|
|
7084
|
+
description: skill ? skill.name !== (skill.displayName ?? skill.name) ? skill.name : void 0 : "Capabilities the agent can choose to use. Not commands — the model picks them from their descriptions.",
|
|
7085
|
+
actions: skill ? /* @__PURE__ */ jsxs(Button, {
|
|
7086
|
+
variant: "ghost",
|
|
7087
|
+
size: "xs",
|
|
7088
|
+
onClick: () => setSelected(void 0),
|
|
7089
|
+
children: [/* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" }), "Back"]
|
|
7090
|
+
}) : void 0
|
|
7091
|
+
}), /* @__PURE__ */ jsx(DialogBody, { children: skill ? /* @__PURE__ */ jsx(SkillView, {
|
|
7092
|
+
skill,
|
|
7093
|
+
onUse,
|
|
7094
|
+
onUsed: () => onOpenChange(false)
|
|
7095
|
+
}) : /* @__PURE__ */ jsx(SkillList, {
|
|
7096
|
+
skills,
|
|
7097
|
+
onSelect: setSelected
|
|
7098
|
+
}) })]
|
|
7099
|
+
})
|
|
7064
7100
|
});
|
|
7065
7101
|
}
|
|
7066
7102
|
function SkillList({ skills, onSelect }) {
|
|
@@ -7940,7 +7976,7 @@ function TabStrip({ tabs, active, onSelect }) {
|
|
|
7940
7976
|
}
|
|
7941
7977
|
//#endregion
|
|
7942
7978
|
//#region src/components/terminal/PermissionPrompt.tsx
|
|
7943
|
-
function TerminalPermissionPrompt({ request, onApprove, onDeny }) {
|
|
7979
|
+
function TerminalPermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
7944
7980
|
const [focused, setFocused] = useState(0);
|
|
7945
7981
|
const [denying, setDenying] = useState(false);
|
|
7946
7982
|
const [reason, setReason] = useState("");
|
|
@@ -7978,6 +8014,7 @@ function TerminalPermissionPrompt({ request, onApprove, onDeny }) {
|
|
|
7978
8014
|
];
|
|
7979
8015
|
return /* @__PURE__ */ jsxs("div", {
|
|
7980
8016
|
"data-slot": "permission-prompt",
|
|
8017
|
+
className,
|
|
7981
8018
|
onKeyDown: (event) => {
|
|
7982
8019
|
if (event.key === "Escape") {
|
|
7983
8020
|
event.preventDefault();
|
|
@@ -8035,7 +8072,7 @@ function answerFor(selection) {
|
|
|
8035
8072
|
if (selection.otherActive && selection.other.trim()) parts.push(selection.other.trim());
|
|
8036
8073
|
return parts.join(", ");
|
|
8037
8074
|
}
|
|
8038
|
-
function TerminalQuestionPrompt({ request, onAnswer, onDismiss }) {
|
|
8075
|
+
function TerminalQuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
8039
8076
|
const questions = parseUserQuestions(request.input);
|
|
8040
8077
|
const [selections, setSelections] = useState(() => questions.map(() => EMPTY));
|
|
8041
8078
|
const [cursors, setCursors] = useState(() => questions.map(() => 0));
|
|
@@ -8077,6 +8114,7 @@ function TerminalQuestionPrompt({ request, onAnswer, onDismiss }) {
|
|
|
8077
8114
|
const move = (delta) => setTab((current) => Math.min(questions.length, Math.max(0, current + delta)));
|
|
8078
8115
|
return /* @__PURE__ */ jsxs("div", {
|
|
8079
8116
|
"data-slot": "question-prompt",
|
|
8117
|
+
className,
|
|
8080
8118
|
onKeyDown: (event) => {
|
|
8081
8119
|
if (event.key === "Escape") {
|
|
8082
8120
|
event.preventDefault();
|
|
@@ -8576,7 +8614,7 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
|
|
|
8576
8614
|
const terminal = useTranscriptVariant() === "terminal";
|
|
8577
8615
|
return /* @__PURE__ */ jsxs("div", {
|
|
8578
8616
|
"data-slot": "status-bar",
|
|
8579
|
-
className: cn("flex h-[
|
|
8617
|
+
className: cn("flex h-[var(--wd-status-bar-height)] items-baseline gap-2 border-border bg-surface p-1.5", placement === "bottom" ? terminal ? void 0 : "border-t" : "border-b", className),
|
|
8580
8618
|
children: [
|
|
8581
8619
|
/* @__PURE__ */ jsx(Slot, {
|
|
8582
8620
|
onClick: onOpenStatus,
|
|
@@ -8614,13 +8652,19 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
|
|
|
8614
8652
|
}) : null]
|
|
8615
8653
|
})
|
|
8616
8654
|
}) : null,
|
|
8617
|
-
controls,
|
|
8655
|
+
controls ? /* @__PURE__ */ jsx("span", {
|
|
8656
|
+
className: "self-center",
|
|
8657
|
+
children: controls
|
|
8658
|
+
}) : null,
|
|
8618
8659
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
8619
8660
|
/* @__PURE__ */ jsx("span", {
|
|
8620
8661
|
className: "font-mono text-label text-fg-3",
|
|
8621
8662
|
children: formatCost(state.totalCostUsd)
|
|
8622
8663
|
}),
|
|
8623
|
-
actions
|
|
8664
|
+
actions ? /* @__PURE__ */ jsx("span", {
|
|
8665
|
+
className: "self-center",
|
|
8666
|
+
children: actions
|
|
8667
|
+
}) : null
|
|
8624
8668
|
]
|
|
8625
8669
|
});
|
|
8626
8670
|
}
|
|
@@ -8650,7 +8694,7 @@ function Conversation({ className, children, ...props }) {
|
|
|
8650
8694
|
function ConversationContent({ className, children, ...props }) {
|
|
8651
8695
|
return /* @__PURE__ */ jsx(StickToBottom.Content, {
|
|
8652
8696
|
"data-slot": "conversation-content",
|
|
8653
|
-
className: cn("mx-auto flex w-full max-w-[var(--wd-
|
|
8697
|
+
className: cn("mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] flex-col gap-4 px-4 py-4", className),
|
|
8654
8698
|
...props,
|
|
8655
8699
|
children
|
|
8656
8700
|
});
|
|
@@ -8801,6 +8845,7 @@ const Response = memo(function Response({ children, streaming, className }) {
|
|
|
8801
8845
|
mode: streaming ? "streaming" : "static",
|
|
8802
8846
|
parseIncompleteMarkdown: streaming,
|
|
8803
8847
|
shikiTheme: ["github-light", "github-dark"],
|
|
8848
|
+
linkSafety: { enabled: false },
|
|
8804
8849
|
className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
|
|
8805
8850
|
children
|
|
8806
8851
|
});
|
|
@@ -9845,7 +9890,7 @@ function blockHeight(block, m) {
|
|
|
9845
9890
|
//#region src/components/terminal/scrubber.tsx
|
|
9846
9891
|
/** The member closest to a rail-space y — what a press or peek on a merged
|
|
9847
9892
|
* cluster resolves to. */
|
|
9848
|
-
function nearestMember(cluster, y) {
|
|
9893
|
+
function nearestMember$1(cluster, y) {
|
|
9849
9894
|
let best;
|
|
9850
9895
|
for (const member of cluster.marks) if (!best || Math.abs(member.y - y) < Math.abs(best.y - y)) best = member;
|
|
9851
9896
|
return best?.mark;
|
|
@@ -9865,7 +9910,7 @@ function nearestMember(cluster, y) {
|
|
|
9865
9910
|
* It also buys the marks their width back: three lanes in a 16px rail is 5px a
|
|
9866
9911
|
* lane, which is a hard target to hit and a hard colour to see.
|
|
9867
9912
|
*/
|
|
9868
|
-
const LANE = {
|
|
9913
|
+
const LANE$1 = {
|
|
9869
9914
|
user: "l",
|
|
9870
9915
|
subagent: "l",
|
|
9871
9916
|
turn: "r",
|
|
@@ -9877,7 +9922,7 @@ const LANE = {
|
|
|
9877
9922
|
bookmark: "f"
|
|
9878
9923
|
};
|
|
9879
9924
|
/** Who wins the colour when marks merge. */
|
|
9880
|
-
const LOUDNESS = {
|
|
9925
|
+
const LOUDNESS$1 = {
|
|
9881
9926
|
approval: 7,
|
|
9882
9927
|
error: 6,
|
|
9883
9928
|
turnFailed: 5,
|
|
@@ -9888,7 +9933,7 @@ const LOUDNESS = {
|
|
|
9888
9933
|
subagent: 1,
|
|
9889
9934
|
recap: 0
|
|
9890
9935
|
};
|
|
9891
|
-
const KIND_NAME = {
|
|
9936
|
+
const KIND_NAME$1 = {
|
|
9892
9937
|
user: "you",
|
|
9893
9938
|
subagent: "sub-agent",
|
|
9894
9939
|
turn: "response · turn end",
|
|
@@ -9899,7 +9944,7 @@ const KIND_NAME = {
|
|
|
9899
9944
|
recap: "catch-up boundary",
|
|
9900
9945
|
bookmark: "bookmark"
|
|
9901
9946
|
};
|
|
9902
|
-
const MIN_MARK = 2;
|
|
9947
|
+
const MIN_MARK$1 = 2;
|
|
9903
9948
|
/**
|
|
9904
9949
|
* Rail pixels per content pixel — the one scale both the marks and the viewport
|
|
9905
9950
|
* band are drawn at, so they cannot disagree about where a row sits.
|
|
@@ -9923,15 +9968,15 @@ const MIN_MARK = 2;
|
|
|
9923
9968
|
function railScale(railH, totalSize, viewportH) {
|
|
9924
9969
|
return totalSize > 0 ? railH / Math.max(totalSize, viewportH) : 0;
|
|
9925
9970
|
}
|
|
9926
|
-
const doneLine = (turn) => `${turn.isError ? turn.subtype : "done"} · ${formatDuration(turn.durationMs)} · ${formatCost(turn.totalCostUsd)}`;
|
|
9927
|
-
function excerpt(item) {
|
|
9971
|
+
const doneLine$1 = (turn) => `${turn.isError ? turn.subtype : "done"} · ${formatDuration(turn.durationMs)} · ${formatCost(turn.totalCostUsd)}`;
|
|
9972
|
+
function excerpt$1(item) {
|
|
9928
9973
|
switch (item.kind) {
|
|
9929
9974
|
case "user":
|
|
9930
9975
|
case "assistant_text":
|
|
9931
9976
|
case "thinking":
|
|
9932
9977
|
case "notice": return item.text;
|
|
9933
9978
|
case "tool_call": return `${item.name}(${toolInputPreview(item.input)})`;
|
|
9934
|
-
case "turn_result": return doneLine(item);
|
|
9979
|
+
case "turn_result": return doneLine$1(item);
|
|
9935
9980
|
case "file_delivered": return item.path;
|
|
9936
9981
|
default: return "";
|
|
9937
9982
|
}
|
|
@@ -10023,9 +10068,9 @@ function buildClusters(props, railH) {
|
|
|
10023
10068
|
for (const mark of marks) {
|
|
10024
10069
|
const within = mark.itemIndex >= 0 ? positionInRow?.(mark.itemIndex) : void 0;
|
|
10025
10070
|
const rowH = sizeOfRow(mark.rowIndex);
|
|
10026
|
-
const h = within ? MIN_MARK : Math.max(MIN_MARK, Math.round(rowH * scale));
|
|
10071
|
+
const h = within ? MIN_MARK$1 : Math.max(MIN_MARK$1, Math.round(rowH * scale));
|
|
10027
10072
|
const y = Math.min(Math.max(0, railH - h), Math.round((offsetOfRow(mark.rowIndex) + (within ? within.ordinal / within.count * rowH : 0)) * scale));
|
|
10028
|
-
const lane = LANE[mark.kind];
|
|
10073
|
+
const lane = LANE$1[mark.kind];
|
|
10029
10074
|
const list = lanes.get(lane) ?? [];
|
|
10030
10075
|
list.push({
|
|
10031
10076
|
mark,
|
|
@@ -10040,7 +10085,7 @@ function buildClusters(props, railH) {
|
|
|
10040
10085
|
let current = null;
|
|
10041
10086
|
for (const { mark, y, h } of list) if (current && y <= current.y + current.h + 1) {
|
|
10042
10087
|
current.h = Math.max(current.h, y + h - current.y);
|
|
10043
|
-
if (LOUDNESS[mark.kind] > LOUDNESS[current.kind]) current.kind = mark.kind;
|
|
10088
|
+
if (LOUDNESS$1[mark.kind] > LOUDNESS$1[current.kind]) current.kind = mark.kind;
|
|
10044
10089
|
current.marks.push({
|
|
10045
10090
|
mark,
|
|
10046
10091
|
y
|
|
@@ -10060,15 +10105,15 @@ function buildClusters(props, railH) {
|
|
|
10060
10105
|
}
|
|
10061
10106
|
}
|
|
10062
10107
|
if (pendingApprovals.length > 0) clusters.push({
|
|
10063
|
-
lane: LANE.approval,
|
|
10108
|
+
lane: LANE$1.approval,
|
|
10064
10109
|
kind: "approval",
|
|
10065
|
-
y: Math.max(0, railH - MIN_MARK),
|
|
10066
|
-
h: MIN_MARK,
|
|
10110
|
+
y: Math.max(0, railH - MIN_MARK$1),
|
|
10111
|
+
h: MIN_MARK$1,
|
|
10067
10112
|
marks: []
|
|
10068
10113
|
});
|
|
10069
10114
|
return clusters;
|
|
10070
10115
|
}
|
|
10071
|
-
function peekContent(cluster, first, { items, pendingApprovals, recapRow }) {
|
|
10116
|
+
function peekContent$1(cluster, first, { items, pendingApprovals, recapRow }) {
|
|
10072
10117
|
const more = cluster.marks.length > 1 ? ` · ${cluster.marks.length} marks` : "";
|
|
10073
10118
|
let body = null;
|
|
10074
10119
|
if (cluster.kind === "approval") {
|
|
@@ -10102,7 +10147,7 @@ function peekContent(cluster, first, { items, pendingApprovals, recapRow }) {
|
|
|
10102
10147
|
}), item.text]
|
|
10103
10148
|
}) : null, turn?.kind === "turn_result" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
10104
10149
|
"data-tone": turn.isError ? "red" : "faint",
|
|
10105
|
-
children: doneLine(turn)
|
|
10150
|
+
children: doneLine$1(turn)
|
|
10106
10151
|
}), turn.errors?.map((message, index) => /* @__PURE__ */ jsx("div", {
|
|
10107
10152
|
"data-tone": "red",
|
|
10108
10153
|
children: message
|
|
@@ -10115,7 +10160,7 @@ function peekContent(cluster, first, { items, pendingApprovals, recapRow }) {
|
|
|
10115
10160
|
children: [first.kind === "user" ? /* @__PURE__ */ jsx("span", {
|
|
10116
10161
|
"data-tone": "dim",
|
|
10117
10162
|
children: "❯ "
|
|
10118
|
-
}) : null, excerpt(item)]
|
|
10163
|
+
}) : null, excerpt$1(item)]
|
|
10119
10164
|
}), failure ? /* @__PURE__ */ jsx("div", {
|
|
10120
10165
|
className: "term-scrub-ex",
|
|
10121
10166
|
"data-tone": "red",
|
|
@@ -10125,7 +10170,7 @@ function peekContent(cluster, first, { items, pendingApprovals, recapRow }) {
|
|
|
10125
10170
|
}
|
|
10126
10171
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
10127
10172
|
"data-tone": "faint",
|
|
10128
|
-
children: [KIND_NAME[first?.kind ?? cluster.kind], more]
|
|
10173
|
+
children: [KIND_NAME$1[first?.kind ?? cluster.kind], more]
|
|
10129
10174
|
}), body] });
|
|
10130
10175
|
}
|
|
10131
10176
|
function TerminalScrubber(props) {
|
|
@@ -10202,12 +10247,12 @@ function TerminalScrubber(props) {
|
|
|
10202
10247
|
stick.scrollToBottom();
|
|
10203
10248
|
return;
|
|
10204
10249
|
}
|
|
10205
|
-
const mark = nearestMember(cluster, railY(clientY));
|
|
10250
|
+
const mark = nearestMember$1(cluster, railY(clientY));
|
|
10206
10251
|
if (mark) onJumpToRow(mark.rowIndex);
|
|
10207
10252
|
};
|
|
10208
10253
|
const showPeek = (cluster, clientY) => {
|
|
10209
10254
|
const y = railY(clientY);
|
|
10210
|
-
const mark = nearestMember(cluster, y);
|
|
10255
|
+
const mark = nearestMember$1(cluster, y);
|
|
10211
10256
|
setPeek((previous) => previous && previous.cluster === cluster && previous.mark === mark ? previous : {
|
|
10212
10257
|
cluster,
|
|
10213
10258
|
mark,
|
|
@@ -10288,13 +10333,328 @@ function TerminalScrubber(props) {
|
|
|
10288
10333
|
ref: peekRef,
|
|
10289
10334
|
className: "term-scrub-peek",
|
|
10290
10335
|
style: { top: peek.y },
|
|
10291
|
-
children: peekContent(peek.cluster, peek.mark, props)
|
|
10336
|
+
children: peekContent$1(peek.cluster, peek.mark, props)
|
|
10292
10337
|
}) : null
|
|
10293
10338
|
]
|
|
10294
10339
|
})
|
|
10295
10340
|
});
|
|
10296
10341
|
}
|
|
10297
10342
|
//#endregion
|
|
10343
|
+
//#region src/components/agent/scrubber-marks.ts
|
|
10344
|
+
/** The member closest to a rail-space y — what a press or peek on a merged
|
|
10345
|
+
* cluster resolves to. */
|
|
10346
|
+
function nearestMember(cluster, y) {
|
|
10347
|
+
let best;
|
|
10348
|
+
for (const member of cluster.marks) if (!best || Math.abs(member.y - y) < Math.abs(best.y - y)) best = member;
|
|
10349
|
+
return best?.mark;
|
|
10350
|
+
}
|
|
10351
|
+
/** The two lanes are channels, not classes: left is what went *in* (your
|
|
10352
|
+
* prompts, the sub-agents you dispatched), right is what came *out* (each
|
|
10353
|
+
* turn's answer, and everything that went wrong producing one). Full width is
|
|
10354
|
+
* for what is not a channel at all: the waiting approval, a bookmark, the
|
|
10355
|
+
* catch-up seam. See the terminal scrubber for the full argument. */
|
|
10356
|
+
const LANE = {
|
|
10357
|
+
user: "l",
|
|
10358
|
+
subagent: "l",
|
|
10359
|
+
turn: "r",
|
|
10360
|
+
turnFailed: "r",
|
|
10361
|
+
toolFailed: "r",
|
|
10362
|
+
error: "r",
|
|
10363
|
+
approval: "f",
|
|
10364
|
+
recap: "f",
|
|
10365
|
+
bookmark: "f"
|
|
10366
|
+
};
|
|
10367
|
+
/** Who wins the colour when marks merge. */
|
|
10368
|
+
const LOUDNESS = {
|
|
10369
|
+
approval: 7,
|
|
10370
|
+
error: 6,
|
|
10371
|
+
turnFailed: 5,
|
|
10372
|
+
toolFailed: 4,
|
|
10373
|
+
user: 3,
|
|
10374
|
+
turn: 2,
|
|
10375
|
+
bookmark: 1,
|
|
10376
|
+
subagent: 1,
|
|
10377
|
+
recap: 0
|
|
10378
|
+
};
|
|
10379
|
+
const KIND_NAME = {
|
|
10380
|
+
user: "you",
|
|
10381
|
+
subagent: "sub-agent",
|
|
10382
|
+
turn: "response · turn end",
|
|
10383
|
+
turnFailed: "turn failed",
|
|
10384
|
+
toolFailed: "tool failed",
|
|
10385
|
+
error: "error",
|
|
10386
|
+
approval: "pending approval",
|
|
10387
|
+
recap: "catch-up boundary",
|
|
10388
|
+
bookmark: "bookmark"
|
|
10389
|
+
};
|
|
10390
|
+
const doneLine = (turn) => `${turn.isError ? turn.subtype : "done"} · ${formatDuration(turn.durationMs)} · ${formatCost(turn.totalCostUsd)}`;
|
|
10391
|
+
function excerpt(item) {
|
|
10392
|
+
switch (item.kind) {
|
|
10393
|
+
case "user":
|
|
10394
|
+
case "assistant_text":
|
|
10395
|
+
case "thinking":
|
|
10396
|
+
case "notice": return item.text;
|
|
10397
|
+
case "tool_call": return `${item.name}(${toolInputPreview(item.input)})`;
|
|
10398
|
+
case "turn_result": return doneLine(item);
|
|
10399
|
+
case "file_delivered": return item.path;
|
|
10400
|
+
default: return "";
|
|
10401
|
+
}
|
|
10402
|
+
}
|
|
10403
|
+
function buildMarks(items, { frameParentId, bookmarks = [], recapItemIndex } = {}) {
|
|
10404
|
+
const marks = [];
|
|
10405
|
+
const subagentParents = /* @__PURE__ */ new Set();
|
|
10406
|
+
for (const item of items) {
|
|
10407
|
+
const parent = parentOf(item);
|
|
10408
|
+
if (parent !== void 0) subagentParents.add(parent);
|
|
10409
|
+
}
|
|
10410
|
+
let segment = {};
|
|
10411
|
+
const closeSegment = () => {
|
|
10412
|
+
const anchor = segment.response ?? segment.turn;
|
|
10413
|
+
if (anchor !== void 0) marks.push({
|
|
10414
|
+
kind: segment.failed ? "turnFailed" : "turn",
|
|
10415
|
+
itemIndex: anchor,
|
|
10416
|
+
turnIndex: segment.turn
|
|
10417
|
+
});
|
|
10418
|
+
segment = {};
|
|
10419
|
+
};
|
|
10420
|
+
items.forEach((item, index) => {
|
|
10421
|
+
if (item.kind === "tool_call" && subagentParents.has(item.id)) marks.push({
|
|
10422
|
+
kind: "subagent",
|
|
10423
|
+
itemIndex: index
|
|
10424
|
+
});
|
|
10425
|
+
if (item.kind === "user" && parentOf(item) === frameParentId) {
|
|
10426
|
+
closeSegment();
|
|
10427
|
+
marks.push({
|
|
10428
|
+
kind: "user",
|
|
10429
|
+
itemIndex: index
|
|
10430
|
+
});
|
|
10431
|
+
} else if (item.kind === "turn_result") {
|
|
10432
|
+
segment.turn = index;
|
|
10433
|
+
segment.failed = item.isError;
|
|
10434
|
+
closeSegment();
|
|
10435
|
+
} else if (item.kind === "notice" && item.level === "error") marks.push({
|
|
10436
|
+
kind: "error",
|
|
10437
|
+
itemIndex: index
|
|
10438
|
+
});
|
|
10439
|
+
else if (item.kind === "tool_call" && parentOf(item) === frameParentId && (item.status === "failed" || item.result?.isError === true)) marks.push({
|
|
10440
|
+
kind: "toolFailed",
|
|
10441
|
+
itemIndex: index
|
|
10442
|
+
});
|
|
10443
|
+
else if (item.kind === "assistant_text" && parentOf(item) === frameParentId) {
|
|
10444
|
+
if (frameParentId !== void 0) {
|
|
10445
|
+
marks.push({
|
|
10446
|
+
kind: "turn",
|
|
10447
|
+
itemIndex: index
|
|
10448
|
+
});
|
|
10449
|
+
return;
|
|
10450
|
+
}
|
|
10451
|
+
segment.response = index;
|
|
10452
|
+
}
|
|
10453
|
+
});
|
|
10454
|
+
closeSegment();
|
|
10455
|
+
for (const index of bookmarks) if (index >= 0 && index < items.length) marks.push({
|
|
10456
|
+
kind: "bookmark",
|
|
10457
|
+
itemIndex: index
|
|
10458
|
+
});
|
|
10459
|
+
if (recapItemIndex !== void 0) marks.push({
|
|
10460
|
+
kind: "recap",
|
|
10461
|
+
itemIndex: recapItemIndex
|
|
10462
|
+
});
|
|
10463
|
+
return marks;
|
|
10464
|
+
}
|
|
10465
|
+
/**
|
|
10466
|
+
* Place marks proportionally — y = `itemIndex / itemCount` of the rail, every
|
|
10467
|
+
* mark one item's share tall (floored at {@link MIN_MARK}) — then merge
|
|
10468
|
+
* adjacent ones per lane, the loudest colour winning. The same merge rule as
|
|
10469
|
+
* the terminal rail; only the position source differs.
|
|
10470
|
+
*/
|
|
10471
|
+
function clusterMarks(marks, railH, itemCount) {
|
|
10472
|
+
const count = Math.max(1, itemCount);
|
|
10473
|
+
const h = Math.max(2, Math.round(railH / count));
|
|
10474
|
+
const lanes = /* @__PURE__ */ new Map();
|
|
10475
|
+
for (const mark of marks) {
|
|
10476
|
+
const y = Math.min(Math.max(0, railH - h), Math.round(mark.itemIndex / count * railH));
|
|
10477
|
+
const lane = LANE[mark.kind];
|
|
10478
|
+
const list = lanes.get(lane) ?? [];
|
|
10479
|
+
list.push({
|
|
10480
|
+
mark,
|
|
10481
|
+
y
|
|
10482
|
+
});
|
|
10483
|
+
lanes.set(lane, list);
|
|
10484
|
+
}
|
|
10485
|
+
const clusters = [];
|
|
10486
|
+
for (const [lane, list] of lanes) {
|
|
10487
|
+
list.sort((a, b) => a.y - b.y);
|
|
10488
|
+
let current = null;
|
|
10489
|
+
for (const { mark, y } of list) if (current && y <= current.y + current.h + 1) {
|
|
10490
|
+
current.h = Math.max(current.h, y + h - current.y);
|
|
10491
|
+
if (LOUDNESS[mark.kind] > LOUDNESS[current.kind]) current.kind = mark.kind;
|
|
10492
|
+
current.marks.push({
|
|
10493
|
+
mark,
|
|
10494
|
+
y
|
|
10495
|
+
});
|
|
10496
|
+
} else {
|
|
10497
|
+
current = {
|
|
10498
|
+
lane,
|
|
10499
|
+
kind: mark.kind,
|
|
10500
|
+
y,
|
|
10501
|
+
h,
|
|
10502
|
+
marks: [{
|
|
10503
|
+
mark,
|
|
10504
|
+
y
|
|
10505
|
+
}]
|
|
10506
|
+
};
|
|
10507
|
+
clusters.push(current);
|
|
10508
|
+
}
|
|
10509
|
+
}
|
|
10510
|
+
return clusters;
|
|
10511
|
+
}
|
|
10512
|
+
/** The approval is not an item — the prompt renders below the transcript — so
|
|
10513
|
+
* its mark pins at the rail's foot, where the prompt is. Built by hand (no
|
|
10514
|
+
* item to derive a position from), hence `marks: []`. */
|
|
10515
|
+
function approvalCluster(railH) {
|
|
10516
|
+
return {
|
|
10517
|
+
lane: LANE.approval,
|
|
10518
|
+
kind: "approval",
|
|
10519
|
+
y: Math.max(0, railH - 2),
|
|
10520
|
+
h: 2,
|
|
10521
|
+
marks: []
|
|
10522
|
+
};
|
|
10523
|
+
}
|
|
10524
|
+
//#endregion
|
|
10525
|
+
//#region src/components/agent/Scrubber.tsx
|
|
10526
|
+
function peekContent(cluster, first, items, pendingApprovals) {
|
|
10527
|
+
const more = cluster.marks.length > 1 ? ` · ${cluster.marks.length} marks` : "";
|
|
10528
|
+
let body = null;
|
|
10529
|
+
if (cluster.kind === "approval") {
|
|
10530
|
+
const request = pendingApprovals[0];
|
|
10531
|
+
body = request ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", { children: request.title ?? "Permission required" }), /* @__PURE__ */ jsx("div", {
|
|
10532
|
+
className: "wd-scrub-ex",
|
|
10533
|
+
"data-tone": "muted",
|
|
10534
|
+
children: `${request.displayName ?? request.toolName}(${toolInputPreview(request.input)})`
|
|
10535
|
+
})] }) : null;
|
|
10536
|
+
} else if (first && first.kind !== "recap") {
|
|
10537
|
+
const item = items[first.itemIndex];
|
|
10538
|
+
if (first.kind === "turn" || first.kind === "turnFailed") {
|
|
10539
|
+
const turn = first.turnIndex === void 0 ? void 0 : items[first.turnIndex];
|
|
10540
|
+
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [item?.kind === "assistant_text" ? /* @__PURE__ */ jsx("div", {
|
|
10541
|
+
className: "wd-scrub-ex",
|
|
10542
|
+
children: item.text
|
|
10543
|
+
}) : null, turn?.kind === "turn_result" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
10544
|
+
"data-tone": turn.isError ? "danger" : "muted",
|
|
10545
|
+
children: doneLine(turn)
|
|
10546
|
+
}), turn.errors?.map((message, index) => /* @__PURE__ */ jsx("div", {
|
|
10547
|
+
"data-tone": "danger",
|
|
10548
|
+
children: message
|
|
10549
|
+
}, index))] }) : null] });
|
|
10550
|
+
} else if (item) {
|
|
10551
|
+
const failure = first.kind === "toolFailed" && item.kind === "tool_call" ? item.result?.text.split("\n").find((line) => line.trim() !== "") : void 0;
|
|
10552
|
+
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
10553
|
+
className: "wd-scrub-ex",
|
|
10554
|
+
"data-tone": first.kind === "error" || first.kind === "toolFailed" ? "danger" : void 0,
|
|
10555
|
+
children: [first.kind === "user" ? /* @__PURE__ */ jsx("span", {
|
|
10556
|
+
"data-tone": "muted",
|
|
10557
|
+
children: "❯ "
|
|
10558
|
+
}) : null, excerpt(item)]
|
|
10559
|
+
}), failure ? /* @__PURE__ */ jsx("div", {
|
|
10560
|
+
className: "wd-scrub-ex",
|
|
10561
|
+
"data-tone": "danger",
|
|
10562
|
+
children: failure
|
|
10563
|
+
}) : null] });
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
10567
|
+
"data-tone": "muted",
|
|
10568
|
+
children: [KIND_NAME[first?.kind ?? cluster.kind], more]
|
|
10569
|
+
}), body] });
|
|
10570
|
+
}
|
|
10571
|
+
function Scrubber({ items, pendingApprovals, recapItemIndex, bookmarks, frameParentId, interactive = false, onJumpToItem, className }) {
|
|
10572
|
+
const railRef = useRef(null);
|
|
10573
|
+
const peekRef = useRef(null);
|
|
10574
|
+
const [railH, setRailH] = useState(0);
|
|
10575
|
+
const [peek, setPeek] = useState(null);
|
|
10576
|
+
useEffect(() => {
|
|
10577
|
+
const element = railRef.current;
|
|
10578
|
+
if (!element) return;
|
|
10579
|
+
const observer = new ResizeObserver(() => setRailH(element.clientHeight));
|
|
10580
|
+
observer.observe(element);
|
|
10581
|
+
setRailH(element.clientHeight);
|
|
10582
|
+
return () => observer.disconnect();
|
|
10583
|
+
}, []);
|
|
10584
|
+
useEffect(() => {
|
|
10585
|
+
setPeek(null);
|
|
10586
|
+
}, [items]);
|
|
10587
|
+
useLayoutEffect(() => {
|
|
10588
|
+
const element = peekRef.current;
|
|
10589
|
+
if (!element || !peek) return;
|
|
10590
|
+
const height = element.offsetHeight;
|
|
10591
|
+
const railHeight = railRef.current?.clientHeight ?? 0;
|
|
10592
|
+
element.style.top = `${Math.max(4, Math.min(railHeight - height - 4, peek.y - height / 2))}px`;
|
|
10593
|
+
}, [peek]);
|
|
10594
|
+
const clusters = useMemo(() => {
|
|
10595
|
+
if (railH <= 0) return [];
|
|
10596
|
+
const built = clusterMarks(buildMarks(items, {
|
|
10597
|
+
frameParentId,
|
|
10598
|
+
bookmarks,
|
|
10599
|
+
recapItemIndex
|
|
10600
|
+
}), railH, items.length);
|
|
10601
|
+
if (pendingApprovals.length > 0) built.push(approvalCluster(railH));
|
|
10602
|
+
return built;
|
|
10603
|
+
}, [
|
|
10604
|
+
items,
|
|
10605
|
+
frameParentId,
|
|
10606
|
+
bookmarks,
|
|
10607
|
+
recapItemIndex,
|
|
10608
|
+
pendingApprovals,
|
|
10609
|
+
railH
|
|
10610
|
+
]);
|
|
10611
|
+
/** A pointer's y in rail space. */
|
|
10612
|
+
const railY = (clientY) => clientY - (railRef.current?.getBoundingClientRect().top ?? 0);
|
|
10613
|
+
const activate = (cluster, clientY) => {
|
|
10614
|
+
if (cluster.kind === "approval" && cluster.marks.length === 0) {
|
|
10615
|
+
if (items.length > 0) onJumpToItem?.(items.length - 1);
|
|
10616
|
+
return;
|
|
10617
|
+
}
|
|
10618
|
+
const mark = nearestMember(cluster, railY(clientY));
|
|
10619
|
+
if (mark) onJumpToItem?.(mark.itemIndex);
|
|
10620
|
+
};
|
|
10621
|
+
const showPeek = (cluster, clientY) => {
|
|
10622
|
+
const y = railY(clientY);
|
|
10623
|
+
const mark = nearestMember(cluster, y);
|
|
10624
|
+
setPeek((previous) => previous && previous.cluster === cluster && previous.mark === mark ? previous : {
|
|
10625
|
+
cluster,
|
|
10626
|
+
mark,
|
|
10627
|
+
y: Math.min(Math.max(y, cluster.y), cluster.y + cluster.h)
|
|
10628
|
+
});
|
|
10629
|
+
};
|
|
10630
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
10631
|
+
ref: railRef,
|
|
10632
|
+
className: cn("wd-scrubber", className),
|
|
10633
|
+
"data-interactive": interactive || void 0,
|
|
10634
|
+
"aria-hidden": true,
|
|
10635
|
+
children: [clusters.map((cluster, index) => /* @__PURE__ */ jsx("div", {
|
|
10636
|
+
className: "wd-scrub-mark",
|
|
10637
|
+
"data-lane": cluster.lane,
|
|
10638
|
+
"data-kind": cluster.kind,
|
|
10639
|
+
style: {
|
|
10640
|
+
top: cluster.y,
|
|
10641
|
+
height: cluster.h
|
|
10642
|
+
},
|
|
10643
|
+
...interactive ? {
|
|
10644
|
+
onClick: (event) => activate(cluster, event.clientY),
|
|
10645
|
+
onPointerEnter: (event) => showPeek(cluster, event.clientY),
|
|
10646
|
+
onPointerMove: (event) => showPeek(cluster, event.clientY),
|
|
10647
|
+
onPointerLeave: () => setPeek(null)
|
|
10648
|
+
} : null
|
|
10649
|
+
}, index)), peek ? /* @__PURE__ */ jsx("div", {
|
|
10650
|
+
ref: peekRef,
|
|
10651
|
+
className: "wd-scrub-peek",
|
|
10652
|
+
style: { top: peek.y },
|
|
10653
|
+
children: peekContent(peek.cluster, peek.mark, items, pendingApprovals)
|
|
10654
|
+
}) : null]
|
|
10655
|
+
});
|
|
10656
|
+
}
|
|
10657
|
+
//#endregion
|
|
10298
10658
|
//#region src/components/agent/transcript-rows.ts
|
|
10299
10659
|
/** The item a row is spaced *as*. A run stands for the calls it folded, and a
|
|
10300
10660
|
* task block for the `Task` call it absorbed into — all tool calls, so a run,
|
|
@@ -10962,36 +11322,69 @@ function nestedClass(item, frameParentId) {
|
|
|
10962
11322
|
const parent = "parentToolUseId" in item ? item.parentToolUseId : void 0;
|
|
10963
11323
|
return parent != null && parent !== frameParentId ? "border-l-2 border-border pl-3" : void 0;
|
|
10964
11324
|
}
|
|
11325
|
+
/** The cards head's one line: the prompt as a plain run of text. Deliberately
|
|
11326
|
+
* not the Message component — a proportional card clipped by height is a
|
|
11327
|
+
* sliced bubble, and un-styling one from CSS is a fight (see theme.css's
|
|
11328
|
+
* sticky-prompt block for the other half of this decision). Prompt syntax
|
|
11329
|
+
* stays literal — a 28px bar is a reminder of what was asked, not a rendering
|
|
11330
|
+
* surface — and newlines collapse under the bar's `nowrap`. Attachment-only
|
|
11331
|
+
* prompts fall back to the attachments' names so the bar is never blank. */
|
|
11332
|
+
function promptHeadText(item) {
|
|
11333
|
+
return item.text || (item.attachments ?? []).map((attachment) => attachment.name).join(", ");
|
|
11334
|
+
}
|
|
10965
11335
|
/**
|
|
10966
11336
|
* A prompt row's sticky lane — the strip spanning its turn, leading with the
|
|
10967
11337
|
* one-line pinned **head** (see the pinned-prompt comment in
|
|
10968
11338
|
* {@link TranscriptRows}).
|
|
10969
11339
|
*
|
|
11340
|
+
* The head's content is the variant's: the terminal passes the row again
|
|
11341
|
+
* (clipping it to one line is exact under a monospace grid), cards passes the
|
|
11342
|
+
* prompt as plain text for theme.css to draw as a compact bar. Only the
|
|
11343
|
+
* terminal head carries the row's gap class — its stuck geometry parks that
|
|
11344
|
+
* padding above the viewport edge so the visible line docks at zero
|
|
11345
|
+
* (terminal.css); the cards bar never aligns with the row in flow, so the gap
|
|
11346
|
+
* stays off it entirely and the 1st prompt and the Nth share one geometry.
|
|
11347
|
+
*
|
|
10970
11348
|
* The head starts `visibility: hidden` and shows only while actually stuck —
|
|
10971
11349
|
* an overlay that is visible in flow would sit on the real row's first line
|
|
10972
11350
|
* and swallow its selection highlight, which reads as "the first line cannot
|
|
10973
11351
|
* be selected". CSS cannot ask "am I stuck?", so a 1px sentinel at the head's
|
|
10974
|
-
* engage threshold (the line's own y)
|
|
10975
|
-
*
|
|
10976
|
-
*
|
|
10977
|
-
|
|
10978
|
-
|
|
11352
|
+
* engage threshold (the line's own y) answers it: sentinel above the
|
|
11353
|
+
* scrollport top → stuck, read by a passive scroll listener. It was an
|
|
11354
|
+
* IntersectionObserver once, for the "no per-scroll work" purity — and that
|
|
11355
|
+
* was a real bug: IO is edge-triggered, and an *instant* jump (the open-at-
|
|
11356
|
+
* bottom pin, `jumpToRow`, a reveal) teleports the sentinel from below the
|
|
11357
|
+
* viewport to above it between two observations — ratio 0 → 0, no threshold
|
|
11358
|
+
* crossed, `isIntersecting` unchanged — so no entry is ever queued and the
|
|
11359
|
+
* flag strands, in whichever direction the jump left it (observed: a session
|
|
11360
|
+
* opened at the bottom, its prompt bar missing; the stale-true twin paints a
|
|
11361
|
+
* bar over the real bubble). The flag needs level-triggered truth. The cost
|
|
11362
|
+
* is two rect reads per scroll event per mounted lane — layout is clean
|
|
11363
|
+
* during scrolling, and the pin itself is still the compositor's; only the
|
|
11364
|
+
* bar's visibility rides the listener.
|
|
11365
|
+
*/
|
|
11366
|
+
function StickyPromptLane({ top, height, gapClass, gapPx, terminal, scrollRoot, index, measureRef, head, content }) {
|
|
10979
11367
|
const headRef = useRef(null);
|
|
10980
11368
|
const sentinelRef = useRef(null);
|
|
10981
11369
|
useEffect(() => {
|
|
10982
|
-
const
|
|
11370
|
+
const headElement = headRef.current;
|
|
10983
11371
|
const sentinel = sentinelRef.current;
|
|
10984
|
-
if (!
|
|
10985
|
-
const
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
return () =>
|
|
10992
|
-
}, [
|
|
11372
|
+
if (!headElement || !sentinel || !scrollRoot) return;
|
|
11373
|
+
const evaluate = () => {
|
|
11374
|
+
const stuck = sentinel.getBoundingClientRect().top < scrollRoot.getBoundingClientRect().top;
|
|
11375
|
+
headElement.toggleAttribute("data-stuck", stuck);
|
|
11376
|
+
};
|
|
11377
|
+
evaluate();
|
|
11378
|
+
scrollRoot.addEventListener("scroll", evaluate, { passive: true });
|
|
11379
|
+
return () => scrollRoot.removeEventListener("scroll", evaluate);
|
|
11380
|
+
}, [
|
|
11381
|
+
scrollRoot,
|
|
11382
|
+
top,
|
|
11383
|
+
height,
|
|
11384
|
+
gapClass
|
|
11385
|
+
]);
|
|
10993
11386
|
return /* @__PURE__ */ jsxs("div", {
|
|
10994
|
-
"data-sticky-lane": "",
|
|
11387
|
+
"data-sticky-lane": terminal ? "terminal" : "cards",
|
|
10995
11388
|
className: "absolute inset-x-0",
|
|
10996
11389
|
style: {
|
|
10997
11390
|
top,
|
|
@@ -11004,8 +11397,8 @@ function StickyPromptLane({ top, height, gapClass, scrollRoot, index, measureRef
|
|
|
11004
11397
|
children: /* @__PURE__ */ jsx("div", {
|
|
11005
11398
|
ref: headRef,
|
|
11006
11399
|
"data-sticky-head": "",
|
|
11007
|
-
className: gapClass || void 0,
|
|
11008
|
-
children:
|
|
11400
|
+
className: terminal && gapClass || void 0,
|
|
11401
|
+
children: head
|
|
11009
11402
|
})
|
|
11010
11403
|
}),
|
|
11011
11404
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -11013,7 +11406,7 @@ function StickyPromptLane({ top, height, gapClass, scrollRoot, index, measureRef
|
|
|
11013
11406
|
"aria-hidden": true,
|
|
11014
11407
|
className: "absolute left-0 w-px",
|
|
11015
11408
|
style: {
|
|
11016
|
-
top: gapClass ? "var(--term-line)" : 0,
|
|
11409
|
+
top: gapClass ? terminal ? "var(--term-line)" : gapPx : 0,
|
|
11017
11410
|
height: 1
|
|
11018
11411
|
}
|
|
11019
11412
|
}),
|
|
@@ -11069,7 +11462,7 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
11069
11462
|
promptRows: []
|
|
11070
11463
|
});
|
|
11071
11464
|
pinRef.current = {
|
|
11072
|
-
enabled:
|
|
11465
|
+
enabled: stickyPrompt,
|
|
11073
11466
|
promptRows
|
|
11074
11467
|
};
|
|
11075
11468
|
useEffect(() => {
|
|
@@ -11265,16 +11658,19 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
11265
11658
|
onOpenSubagent
|
|
11266
11659
|
})
|
|
11267
11660
|
});
|
|
11268
|
-
if (
|
|
11661
|
+
if (stickyPrompt && "item" in row && row.item.kind === "user" && parentOf(row.item) === void 0) {
|
|
11269
11662
|
const next = promptRows.find((index) => index > virtualRow.index);
|
|
11270
11663
|
const laneEnd = next === void 0 ? virtualizer.getTotalSize() : measurements[next]?.start ?? virtualRow.start;
|
|
11271
11664
|
return /* @__PURE__ */ jsx(StickyPromptLane, {
|
|
11272
11665
|
top: virtualRow.start,
|
|
11273
11666
|
height: Math.max(laneEnd - virtualRow.start, 0),
|
|
11274
11667
|
gapClass,
|
|
11668
|
+
gapPx: gap.px,
|
|
11669
|
+
terminal,
|
|
11275
11670
|
scrollRoot: scrollElement,
|
|
11276
11671
|
index: virtualRow.index,
|
|
11277
11672
|
measureRef: virtualizer.measureElement,
|
|
11673
|
+
head: terminal ? content : promptHeadText(row.item),
|
|
11278
11674
|
content
|
|
11279
11675
|
}, row.key);
|
|
11280
11676
|
}
|
|
@@ -11285,7 +11681,7 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
11285
11681
|
style: { transform: `translateY(${virtualRow.start}px)` },
|
|
11286
11682
|
children: content
|
|
11287
11683
|
}, row.key);
|
|
11288
|
-
}),
|
|
11684
|
+
}), scrubber && scrollElement?.parentElement ? createPortal(terminal ? /* @__PURE__ */ jsx(TerminalScrubber, {
|
|
11289
11685
|
items,
|
|
11290
11686
|
pendingApprovals,
|
|
11291
11687
|
recapRow,
|
|
@@ -11302,10 +11698,18 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
11302
11698
|
interactive: scrubInteractive,
|
|
11303
11699
|
fontSize,
|
|
11304
11700
|
lineHeight
|
|
11701
|
+
}) : /* @__PURE__ */ jsx(Scrubber, {
|
|
11702
|
+
items,
|
|
11703
|
+
pendingApprovals,
|
|
11704
|
+
recapItemIndex: recapIndex >= 0 ? boundary : void 0,
|
|
11705
|
+
bookmarks: scrubberMarks,
|
|
11706
|
+
frameParentId,
|
|
11707
|
+
interactive: scrubInteractive,
|
|
11708
|
+
onJumpToItem: (itemIndex) => jumpToRow(rowIndexForItem(rows, itemIndex), "start")
|
|
11305
11709
|
}), scrollElement.parentElement) : null]
|
|
11306
11710
|
});
|
|
11307
11711
|
}
|
|
11308
|
-
function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage, variant = "cards", density = "comfortable", fontSize, lineHeight, affordances, stickyPrompt = false, scrubber, scrubberMarks, replaying = false, catchUp, jumpToRecapRef, repinRef, reveal, frame, onOpenSubagent, className }) {
|
|
11712
|
+
function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage, variant = "cards", density = "comfortable", fontSize, lineHeight, affordances, stickyPrompt = false, scrubber, scrubberMarks, replaying = false, catchUp, jumpToRecapRef, repinRef, reveal, frame, onOpenSubagent, emptyState, className }) {
|
|
11309
11713
|
const terminal = variant === "terminal";
|
|
11310
11714
|
const items = useMemo(() => frame ? subagentItems(state.items, frame.parentToolUseId) : state.items, [state.items, frame]);
|
|
11311
11715
|
const frameTask = useMemo(() => frame ? state.items.find((item) => item.kind === "tool_call" && item.id === frame.parentToolUseId) : void 0, [state.items, frame]);
|
|
@@ -11356,7 +11760,7 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
11356
11760
|
frame ? frameTask === void 0 && !replaying ? /* @__PURE__ */ jsx("div", {
|
|
11357
11761
|
className: cn(terminal ? "term-row text-fg-4" : "p-4 text-body-sm text-fg-4"),
|
|
11358
11762
|
children: "This sub-agent's work is not in this transcript."
|
|
11359
|
-
}) : null : items.length === 0 && state.status !== "starting" ? /* @__PURE__ */ jsx(SessionEmptyState, {
|
|
11763
|
+
}) : null : items.length === 0 && state.status !== "starting" ? emptyState !== void 0 ? emptyState : /* @__PURE__ */ jsx(SessionEmptyState, {
|
|
11360
11764
|
cwd: state.cwd,
|
|
11361
11765
|
hasCommands: !!state.commands?.length,
|
|
11362
11766
|
hasSkills: !!state.skills?.some((s) => s.enabled),
|
|
@@ -11407,7 +11811,7 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
11407
11811
|
"aria-hidden": true,
|
|
11408
11812
|
className: "wd-hold-appear visible pointer-events-none absolute inset-0 overflow-hidden",
|
|
11409
11813
|
children: /* @__PURE__ */ jsx("div", {
|
|
11410
|
-
className: cn("mx-auto w-full max-w-[var(--wd-
|
|
11814
|
+
className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)]", !terminal && "px-4 py-4"),
|
|
11411
11815
|
children: terminal ? /* @__PURE__ */ jsx(TerminalSurface, {
|
|
11412
11816
|
fontSize,
|
|
11413
11817
|
lineHeight,
|
|
@@ -11531,42 +11935,45 @@ function UsageMeter({ window, now }) {
|
|
|
11531
11935
|
* The session's view of the plan: every window as a meter (see
|
|
11532
11936
|
* {@link UsageMeters}), the plan tier, and what this session itself has cost.
|
|
11533
11937
|
*/
|
|
11534
|
-
function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updatedAt, open, onOpenChange }) {
|
|
11938
|
+
function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updatedAt, open, onOpenChange, className }) {
|
|
11535
11939
|
const now = useMinuteClock(open);
|
|
11536
11940
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
11537
11941
|
open,
|
|
11538
11942
|
onOpenChange,
|
|
11539
|
-
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
className: "
|
|
11559
|
-
children:
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11943
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
11944
|
+
className,
|
|
11945
|
+
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
11946
|
+
title: "Usage",
|
|
11947
|
+
description: engine === "claude" ? "Claude Code" : engine,
|
|
11948
|
+
actions: subscriptionType ? /* @__PURE__ */ jsx(Badge, {
|
|
11949
|
+
variant: "accent",
|
|
11950
|
+
className: "mt-0.5 shrink-0 capitalize",
|
|
11951
|
+
children: subscriptionType
|
|
11952
|
+
}) : null
|
|
11953
|
+
}), /* @__PURE__ */ jsxs(DialogBody, { children: [
|
|
11954
|
+
rateLimits.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
11955
|
+
className: "py-6 text-center text-body-sm text-fg-4",
|
|
11956
|
+
children: engine === "claude" ? "This session reports no plan windows — API-key sessions have none, and a subscription session reports them once a turn has run." : `Plan windows are a claude.ai subscription thing; this session runs on the ${engine} engine.`
|
|
11957
|
+
}) : /* @__PURE__ */ jsx(UsageMeters, {
|
|
11958
|
+
windows: rateLimits,
|
|
11959
|
+
now
|
|
11960
|
+
}),
|
|
11961
|
+
/* @__PURE__ */ jsxs("div", {
|
|
11962
|
+
className: "mt-5 flex items-baseline justify-between gap-4 border-t border-border pt-3",
|
|
11963
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
11964
|
+
className: "text-label text-fg-3",
|
|
11965
|
+
children: "This session has cost"
|
|
11966
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
11967
|
+
className: "font-mono text-body-sm text-fg-1",
|
|
11968
|
+
children: formatCost(totalCostUsd)
|
|
11969
|
+
})]
|
|
11970
|
+
}),
|
|
11971
|
+
updatedAt ? /* @__PURE__ */ jsxs("p", {
|
|
11972
|
+
className: "mt-2 text-label text-fg-4",
|
|
11973
|
+
children: ["Updated ", formatAgoPrecise(updatedAt, now)]
|
|
11974
|
+
}) : null
|
|
11975
|
+
] })]
|
|
11976
|
+
})
|
|
11570
11977
|
});
|
|
11571
11978
|
}
|
|
11572
11979
|
//#endregion
|
|
@@ -11581,7 +11988,7 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updat
|
|
|
11581
11988
|
*/
|
|
11582
11989
|
function PromptSurface({ terminal, metrics, affordances, children }) {
|
|
11583
11990
|
if (!terminal) return /* @__PURE__ */ jsx("div", {
|
|
11584
|
-
className: "mx-auto flex w-full max-w-[var(--wd-
|
|
11991
|
+
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] flex-col gap-2",
|
|
11585
11992
|
children
|
|
11586
11993
|
});
|
|
11587
11994
|
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
@@ -11620,7 +12027,9 @@ const INTERACTIVE = [
|
|
|
11620
12027
|
* the engine name — an absent capability hides the control instead of offering
|
|
11621
12028
|
* one that can only fail.
|
|
11622
12029
|
*/
|
|
11623
|
-
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, scrubberMarks, reveal, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, toolHost, cacheTranscript, className }) {
|
|
12030
|
+
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, scrubberMarks, reveal, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, fontSize, className }) {
|
|
12031
|
+
const effectiveTermFontSize = terminalMetrics?.fontSize ?? fontSize;
|
|
12032
|
+
const effectiveTermLineHeight = terminalMetrics?.lineHeight ?? (fontSize !== void 0 ? Math.round(fontSize * (18 / 13)) : void 0);
|
|
11624
12033
|
const external = panelSurface === "external";
|
|
11625
12034
|
const statusExternal = statusSurface === "external";
|
|
11626
12035
|
const controlsInStatus = controlsSurface === "status" && !statusExternal;
|
|
@@ -11711,7 +12120,13 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11711
12120
|
document.addEventListener("visibilitychange", onVisible);
|
|
11712
12121
|
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
11713
12122
|
}, [reconnectNow]);
|
|
11714
|
-
useToolCallHost(handle, toolHost === false ? { enabled: false } :
|
|
12123
|
+
useToolCallHost(handle, toolHost === false ? { enabled: false } : clientTools ? {
|
|
12124
|
+
...toolHost,
|
|
12125
|
+
clientTools: {
|
|
12126
|
+
...toolHost?.clientTools,
|
|
12127
|
+
...clientTools
|
|
12128
|
+
}
|
|
12129
|
+
} : toolHost);
|
|
11715
12130
|
const terminal = transcriptVariant === "terminal";
|
|
11716
12131
|
const subagentFrameItems = useMemo(() => subagentId === void 0 ? [] : subagentItems(state.items, subagentId), [state.items, subagentId]);
|
|
11717
12132
|
const subagentTask = useMemo(() => subagentId === void 0 ? void 0 : state.items.find((item) => item.kind === "tool_call" && item.id === subagentId), [state.items, subagentId]);
|
|
@@ -11751,7 +12166,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11751
12166
|
cwd: state.cwd,
|
|
11752
12167
|
contextUsage: state.contextUsage,
|
|
11753
12168
|
rateLimits,
|
|
11754
|
-
itemCount: state.items.length
|
|
12169
|
+
itemCount: state.items.length,
|
|
12170
|
+
totalCostUsd: state.totalCostUsd
|
|
11755
12171
|
});
|
|
11756
12172
|
}, [
|
|
11757
12173
|
state.status,
|
|
@@ -11765,7 +12181,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11765
12181
|
state.cwd,
|
|
11766
12182
|
state.contextUsage,
|
|
11767
12183
|
rateLimits,
|
|
11768
|
-
state.items.length
|
|
12184
|
+
state.items.length,
|
|
12185
|
+
state.totalCostUsd
|
|
11769
12186
|
]);
|
|
11770
12187
|
const onControlsRef = useRef(onControls);
|
|
11771
12188
|
onControlsRef.current = onControls;
|
|
@@ -11886,6 +12303,24 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11886
12303
|
onOpenUsage: external && !onOpenPanel ? void 0 : () => openPanel("usage"),
|
|
11887
12304
|
actions: headerTakesActions ? void 0 : menu
|
|
11888
12305
|
});
|
|
12306
|
+
const panelRef = useRef(null);
|
|
12307
|
+
useEffect(() => {
|
|
12308
|
+
if (!onLinkClick) return;
|
|
12309
|
+
const el = panelRef.current;
|
|
12310
|
+
if (!el) return;
|
|
12311
|
+
const handler = (e) => {
|
|
12312
|
+
const anchor = e.target?.closest?.("a[href]");
|
|
12313
|
+
if (!anchor) return;
|
|
12314
|
+
const href = anchor.getAttribute("href");
|
|
12315
|
+
if (!href) return;
|
|
12316
|
+
if (onLinkClick(href)) {
|
|
12317
|
+
e.preventDefault();
|
|
12318
|
+
e.stopPropagation();
|
|
12319
|
+
}
|
|
12320
|
+
};
|
|
12321
|
+
el.addEventListener("click", handler, true);
|
|
12322
|
+
return () => el.removeEventListener("click", handler, true);
|
|
12323
|
+
}, [onLinkClick]);
|
|
11889
12324
|
const handleClick = (event) => {
|
|
11890
12325
|
if (!focusComposerOnClick || readOnly) return;
|
|
11891
12326
|
if (event.target?.closest(INTERACTIVE)) return;
|
|
@@ -11901,10 +12336,12 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11901
12336
|
children: /* @__PURE__ */ jsx(ToolResultImageProvider, {
|
|
11902
12337
|
value: resultImages,
|
|
11903
12338
|
children: /* @__PURE__ */ jsxs("div", {
|
|
12339
|
+
ref: panelRef,
|
|
11904
12340
|
"data-slot": "session-panel",
|
|
11905
12341
|
"data-agent-font": transcriptFont,
|
|
11906
12342
|
onClick: handleClick,
|
|
11907
12343
|
className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
|
|
12344
|
+
style: fontSize !== void 0 ? { "--wd-font-size": `${Math.round(fontSize)}px` } : void 0,
|
|
11908
12345
|
children: [
|
|
11909
12346
|
headerTakesActions ? header({ actions: menu }) : header,
|
|
11910
12347
|
statusPlacement === "top" ? statusBar : null,
|
|
@@ -11929,8 +12366,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11929
12366
|
label: subagentFallbackLabel,
|
|
11930
12367
|
onBack: leaveSubagent,
|
|
11931
12368
|
terminal,
|
|
11932
|
-
fontSize:
|
|
11933
|
-
lineHeight:
|
|
12369
|
+
fontSize: effectiveTermFontSize,
|
|
12370
|
+
lineHeight: effectiveTermLineHeight
|
|
11934
12371
|
}) : null,
|
|
11935
12372
|
/* @__PURE__ */ jsx(Transcript, {
|
|
11936
12373
|
state,
|
|
@@ -11940,8 +12377,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11940
12377
|
hostImage,
|
|
11941
12378
|
variant: transcriptVariant,
|
|
11942
12379
|
density: transcriptDensity,
|
|
11943
|
-
fontSize:
|
|
11944
|
-
lineHeight:
|
|
12380
|
+
fontSize: effectiveTermFontSize,
|
|
12381
|
+
lineHeight: effectiveTermLineHeight,
|
|
11945
12382
|
affordances,
|
|
11946
12383
|
stickyPrompt,
|
|
11947
12384
|
scrubber,
|
|
@@ -11954,6 +12391,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11954
12391
|
reveal: returnReveal ?? reveal,
|
|
11955
12392
|
frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
|
|
11956
12393
|
onOpenSubagent: setSubagentId,
|
|
12394
|
+
emptyState,
|
|
11957
12395
|
jumpToRecapRef: jumpToRecap,
|
|
11958
12396
|
repinRef: repinTranscript
|
|
11959
12397
|
}, subagentId ?? "session"),
|
|
@@ -11961,7 +12399,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11961
12399
|
className: "px-3 pb-1",
|
|
11962
12400
|
children: /* @__PURE__ */ jsxs("div", {
|
|
11963
12401
|
"data-slot": "catch-up",
|
|
11964
|
-
className: "mx-auto flex w-full max-w-[var(--wd-
|
|
12402
|
+
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
|
|
11965
12403
|
children: [
|
|
11966
12404
|
/* @__PURE__ */ jsx("span", {
|
|
11967
12405
|
"aria-hidden": true,
|
|
@@ -11996,7 +12434,10 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11996
12434
|
className: cn(terminal ? "pb-2" : "px-3 pb-2"),
|
|
11997
12435
|
children: /* @__PURE__ */ jsx(PromptSurface, {
|
|
11998
12436
|
terminal,
|
|
11999
|
-
metrics:
|
|
12437
|
+
metrics: {
|
|
12438
|
+
fontSize: effectiveTermFontSize,
|
|
12439
|
+
lineHeight: effectiveTermLineHeight
|
|
12440
|
+
},
|
|
12000
12441
|
affordances,
|
|
12001
12442
|
children: state.pendingApprovals.map((request) => {
|
|
12002
12443
|
const isQuestion = request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0;
|
|
@@ -12036,8 +12477,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
12036
12477
|
}) : void 0,
|
|
12037
12478
|
layout: controlsExternal ? "inline" : "stacked",
|
|
12038
12479
|
toolbar: controlsExternal ? void 0 : sessionControls,
|
|
12039
|
-
fontSize:
|
|
12040
|
-
lineHeight:
|
|
12480
|
+
fontSize: effectiveTermFontSize,
|
|
12481
|
+
lineHeight: effectiveTermLineHeight,
|
|
12041
12482
|
affordances
|
|
12042
12483
|
}),
|
|
12043
12484
|
statusPlacement === "bottom" ? statusBar : null,
|
|
@@ -12159,7 +12600,7 @@ function Notice({ level, onDismiss, children }) {
|
|
|
12159
12600
|
className: "px-3 pt-2",
|
|
12160
12601
|
children: /* @__PURE__ */ jsxs("div", {
|
|
12161
12602
|
role: "alert",
|
|
12162
|
-
className: cn("mx-auto flex w-full max-w-[var(--wd-
|
|
12603
|
+
className: cn("mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-start gap-2 rounded-md border px-3 py-2 text-body-sm", level === "error" ? "border-danger/40 bg-danger-bg text-danger" : "border-warning/40 bg-warning-bg text-warning"),
|
|
12163
12604
|
children: [
|
|
12164
12605
|
/* @__PURE__ */ jsx(TriangleAlert, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
12165
12606
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -12178,6 +12619,6 @@ function Notice({ level, onDismiss, children }) {
|
|
|
12178
12619
|
});
|
|
12179
12620
|
}
|
|
12180
12621
|
//#endregion
|
|
12181
|
-
export { toolIcon as $, PERMISSION_MODES as A, MenuSeparator as At, skillPrompt as B,
|
|
12622
|
+
export { toolIcon as $, PERMISSION_MODES as A, MenuSeparator as At, skillPrompt as B, Badge as Bt, TerminalQuestionPrompt as C, DialogContent as Ct, parseUserQuestions as D, Menu$1 as Dt, QuestionPrompt as E, DialogTrigger as Et, SkillsDialog as F, SelectItemText as Ft, Band as G, TerminalMarkdown as H, Button as Ht, McpDialog as I, SelectTrigger as It, Row as J, Blank as K, HostFilesDialog as L, SelectValue as Lt, permissionModeChoices as M, Select$1 as Mt, permissionModeMeta as N, SelectContent as Nt, SubagentStrip as O, MenuContent as Ot, ModelSelect as P, SelectItem as Pt, isMutatingTool as Q, ContextDialog as R, PortalScope as Rt, SessionInfoDialog as S, DialogClose as St, QUESTION_BEHAVIORS as T, DialogRow as Tt, TerminalDiff as U, buttonVariants as Ut, TerminalSurface as V, badgeVariants as Vt, previewPatch as W, cn as Wt, WithActions as X, CopyAction as Y, useAffordances as Z, Conversation as _, Tip as _t, Transcript as a, hashtagTrigger as at, StatusBar as b, Dialog$1 as bt, ToolCallCard as c, PromptArea as ct, Response as d, ProgressRing as dt, TranscriptDensityProvider as et, PromptTokenText as f, Splitter as ft, FileCard as g, copyText as gt, Loader as h, CopyButton as ht, useMinuteClock as i, commandTrigger as it, PermissionModeSelect as j, MenuTrigger as jt, PermissionPrompt as k, MenuItem as kt, SessionEmptyState as l, plainTextToSegments as lt, MessageContent as m, Spinner as mt, UsageDialog as n, useTranscriptDensity as nt, TerminalItemView as o, mentionTrigger as ot, Message as p, CodeBlock as pt, Ink as q, UsageMeters as r, useTranscriptVariant as rt, TerminalTranscript as s, usePromptAreaState as st, SessionPanel as t, TranscriptVariantProvider as tt, Reasoning as u, segmentsToPlainText as ut, ConversationContent as v, TooltipContent as vt, TerminalPermissionPrompt as w, DialogHeader as wt, STATUS_META as x, DialogBody as xt, ConversationScrollButton as y, TooltipProvider as yt, Composer as z, Input as zt };
|
|
12182
12623
|
|
|
12183
|
-
//# sourceMappingURL=SessionPanel-
|
|
12624
|
+
//# sourceMappingURL=SessionPanel-DUt2VzXG.mjs.map
|