@workerdeck/ui 3.3.0 → 3.4.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.
@@ -5,7 +5,7 @@ import { clsx } from "clsx";
5
5
  import { extendTailwindMerge } from "tailwind-merge";
6
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  import { Select } from "@base-ui/react/select";
8
- import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowUp, AtSign, Bot, BotOff, Brain, ChartPie, Check, CheckSquare, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, ClipboardList, Clock, Code, Copy, Download, File, FileDiff, FileText, Folder, FolderSearch, FolderTree, Gauge, Globe, Hand, Image, Info, Link2, LoaderCircle, Maximize, Maximize2, MessageCircleQuestion, MessageSquareText, Minus, MoreHorizontal, Paperclip, PencilLine, Plug, Plus, Power, PowerOff, Puzzle, RefreshCw, RotateCcw, RotateCw, Search, ShieldCheck, SlashSquare, SlidersHorizontal, Sparkles, Square, SquarePen, SquareTerminal, Star, Terminal, TriangleAlert, Users, UsersRound, WifiOff, Wrench, X, Zap } from "lucide-react";
8
+ import { ArrowDown, ArrowDownCircle, ArrowDownToLine, ArrowLeft, ArrowUp, AtSign, Bot, BotOff, Brain, ChartPie, Check, CheckSquare, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, ClipboardList, Clock, Code, Copy, Download, File, FileDiff, FileText, Folder, FolderSearch, FolderTree, Gauge, Globe, Hand, Image, Info, Link2, LoaderCircle, Maximize, Maximize2, MessageCircleQuestion, MessageSquareText, Minus, MoreHorizontal, Paperclip, PencilLine, Plug, Plus, Power, PowerOff, Puzzle, RefreshCw, RotateCcw, RotateCw, Search, ShieldCheck, SlashSquare, SlidersHorizontal, Sparkles, Square, SquarePen, SquareTerminal, Star, Terminal, TriangleAlert, Users, UsersRound, WifiOff, Wrench, X, Zap } from "lucide-react";
9
9
  import { Menu } from "@base-ui/react/menu";
10
10
  import { Dialog } from "@base-ui/react/dialog";
11
11
  import { Tooltip } from "@base-ui/react/tooltip";
@@ -4588,7 +4588,7 @@ function composerCommandRows(rows) {
4588
4588
  insertText: `/${row.name} `
4589
4589
  });
4590
4590
  }
4591
- function buildClientCommands({ capabilities, hasModels, setModel, setPermissionMode, clearContext, openPanel }) {
4591
+ function buildClientCommands({ capabilities, hasModels, efforts = [], setModel, setEffort, setPermissionMode, clearContext, openPanel }) {
4592
4592
  const modes = capabilities.permissionModes;
4593
4593
  const built = [];
4594
4594
  if (hasModels) built.push({
@@ -4603,6 +4603,22 @@ function buildClientCommands({ capabilities, hasModels, setModel, setPermissionM
4603
4603
  return true;
4604
4604
  }
4605
4605
  });
4606
+ if (efforts.length && setEffort) built.push({
4607
+ name: "effort",
4608
+ description: `Set the reasoning effort (${efforts.join(", ")}, default)`,
4609
+ argumentHint: "<level>",
4610
+ requiresArgs: true,
4611
+ run: (args) => {
4612
+ const wanted = args.split(/\s+/)[0];
4613
+ if (wanted === "default") {
4614
+ setEffort(void 0);
4615
+ return true;
4616
+ }
4617
+ if (!wanted || !efforts.includes(wanted)) return false;
4618
+ setEffort(wanted);
4619
+ return true;
4620
+ }
4621
+ });
4606
4622
  if (modes.length > 1) built.push({
4607
4623
  name: "permissions",
4608
4624
  description: `Set the permission mode (${modes.join(", ")})`,
@@ -4937,6 +4953,23 @@ function BookmarkAction({ id }) {
4937
4953
  onPress: () => handle.toggle(id)
4938
4954
  });
4939
4955
  }
4956
+ const TaskControlContext = createContext(void 0);
4957
+ function TaskControlProvider({ value, children }) {
4958
+ return /* @__PURE__ */ jsx(TaskControlContext.Provider, {
4959
+ value,
4960
+ children
4961
+ });
4962
+ }
4963
+ function BackgroundAction({ toolUseId }) {
4964
+ const handle = useContext(TaskControlContext);
4965
+ if (!handle) return null;
4966
+ return /* @__PURE__ */ jsx(ActionButton, {
4967
+ icon: ArrowDownToLine,
4968
+ word: "background",
4969
+ label: "Move to background (the command keeps running, the agent continues)",
4970
+ onPress: () => handle.background(toolUseId)
4971
+ });
4972
+ }
4940
4973
  function OpenSubagentAction({ onOpen, label = "Open sub-agent" }) {
4941
4974
  return /* @__PURE__ */ jsx(ActionButton, {
4942
4975
  icon: Maximize2,
@@ -4994,6 +5027,51 @@ function AgentWriteIcon({ granted, className }) {
4994
5027
  className
4995
5028
  });
4996
5029
  }
5030
+ const ELAPSED_WIDEST = " ·\xA059m\xA059s";
5031
+ const BACKGROUNDABLE = /* @__PURE__ */ new Set([
5032
+ "Bash",
5033
+ "Task",
5034
+ "Agent"
5035
+ ]);
5036
+ function toolBusy(item) {
5037
+ const status = item.status ?? (item.result === void 0 ? "running" : "settled");
5038
+ return status === "running" || status === "pending";
5039
+ }
5040
+ function liveTailLines(item) {
5041
+ if (!item.liveTail || !toolBusy(item)) return [];
5042
+ return item.liveTail.split("\n").slice(-5);
5043
+ }
5044
+ function elapsedLabel(startedAt, now) {
5045
+ if (startedAt === void 0 || now - startedAt < 5e3) return;
5046
+ return formatDuration(Math.floor((now - startedAt) / 1e3) * 1e3).replace(" ", "\xA0");
5047
+ }
5048
+ function runStartedAt(items) {
5049
+ let earliest;
5050
+ for (const item of items) if (toolBusy(item) && item.ts !== void 0 && (earliest === void 0 || item.ts < earliest)) earliest = item.ts;
5051
+ return earliest;
5052
+ }
5053
+ function canBackground(item) {
5054
+ return BACKGROUNDABLE.has(item.name) && item.parentToolUseId == null && toolBusy(item);
5055
+ }
5056
+ function runTailLines(items) {
5057
+ for (let index = items.length - 1; index >= 0; index--) {
5058
+ const lines = liveTailLines(items[index]);
5059
+ if (lines.length > 0) return lines;
5060
+ }
5061
+ return [];
5062
+ }
5063
+ function backgroundableSince(items) {
5064
+ let since;
5065
+ for (let index = items.length - 1; index >= 0; index--) {
5066
+ const item = items[index];
5067
+ if (item.kind === "user" && item.parentToolUseId == null) break;
5068
+ if (item.kind === "tool_call" && canBackground(item)) {
5069
+ const ts = item.ts ?? 0;
5070
+ since = since === void 0 ? ts : Math.min(since, ts);
5071
+ }
5072
+ }
5073
+ return since;
5074
+ }
4997
5075
  //#endregion
4998
5076
  //#region src/components/terminal/row.tsx
4999
5077
  function Row({ glyph, glyphTone, tone, bold, indent, columns, className, children, style, ...props }) {
@@ -6432,6 +6510,9 @@ function ToolRow({ item }) {
6432
6510
  const busy = status === "running" || status === "pending";
6433
6511
  const isError = status === "failed" || item.result?.isError === true;
6434
6512
  const pulse = usePulse(busy);
6513
+ const now = useTicker(busy && item.ts !== void 0);
6514
+ const elapsed = busy ? elapsedLabel(item.ts, now) : void 0;
6515
+ const tail = liveTailLines(item);
6435
6516
  const text = item.result?.text ?? "";
6436
6517
  const lines = text.trimEnd().split("\n");
6437
6518
  const collapsed = collapsedResult(lines, item.result?.totalChars);
@@ -6450,10 +6531,14 @@ function ToolRow({ item }) {
6450
6531
  ref: reveal,
6451
6532
  className: open ? "term-open" : void 0,
6452
6533
  children: /* @__PURE__ */ jsxs(WithActions, {
6453
- actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(BookmarkAction, { id: item.id }), copyable ? /* @__PURE__ */ jsx(CopyAction, {
6454
- text: copyable,
6455
- label: "Copy"
6456
- }) : null] }),
6534
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [
6535
+ canBackground(item) ? /* @__PURE__ */ jsx(BackgroundAction, { toolUseId: item.id }) : null,
6536
+ /* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
6537
+ copyable ? /* @__PURE__ */ jsx(CopyAction, {
6538
+ text: copyable,
6539
+ label: "Copy"
6540
+ }) : null
6541
+ ] }),
6457
6542
  children: [
6458
6543
  /* @__PURE__ */ jsx(Pressable, {
6459
6544
  onPress: () => setOpen((v) => !v),
@@ -6478,6 +6563,15 @@ function ToolRow({ item }) {
6478
6563
  ")"
6479
6564
  ]
6480
6565
  }),
6566
+ elapsed ? /* @__PURE__ */ jsxs(Ink, {
6567
+ tone: "faint",
6568
+ children: [
6569
+ " ",
6570
+ "·",
6571
+ "\xA0",
6572
+ elapsed
6573
+ ]
6574
+ }) : null,
6481
6575
  title && open ? /* @__PURE__ */ jsxs(Ink, {
6482
6576
  tone: "faint",
6483
6577
  children: [" · ", item.name]
@@ -6489,6 +6583,7 @@ function ToolRow({ item }) {
6489
6583
  ]
6490
6584
  })
6491
6585
  }),
6586
+ /* @__PURE__ */ jsx(LiveTail, { lines: tail }),
6492
6587
  hostPath !== void 0 ? /* @__PURE__ */ jsx(TerminalHostImage, { path: hostPath }) : null,
6493
6588
  item.result?.images?.map((image) => /* @__PURE__ */ jsx(TerminalImage, {
6494
6589
  toolUseId: item.id,
@@ -6633,25 +6728,39 @@ function ToolRunRow({ items }) {
6633
6728
  });
6634
6729
  const failed = runFailed(items);
6635
6730
  const pulse = usePulse(busy);
6731
+ const startedAt = runStartedAt(items);
6732
+ const elapsed = elapsedLabel(startedAt, useTicker(startedAt !== void 0));
6636
6733
  return /* @__PURE__ */ jsxs("div", {
6637
6734
  ref: reveal,
6638
6735
  className: open ? "term-open" : void 0,
6639
- children: [/* @__PURE__ */ jsx(Pressable, {
6640
- onPress: () => setOpen((v) => !v),
6641
- expanded: open,
6642
- children: /* @__PURE__ */ jsx(Row, {
6643
- glyph: busy ? pulse : void 0,
6644
- glyphTone: busy ? "mark" : void 0,
6645
- tone: failed ? "red" : "dim",
6646
- children: busy ? /* @__PURE__ */ jsx("span", {
6647
- className: "term-shimmer",
6648
- children: runSummary(items, busy)
6649
- }) : runSummary(items, busy)
6650
- })
6651
- }), open ? /* @__PURE__ */ jsx("div", { children: items.map((item, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? /* @__PURE__ */ jsx(Blank, {}) : null, index < items.length - 1 ? /* @__PURE__ */ jsx(ActionPlacementProvider, {
6652
- value: "below",
6653
- children: /* @__PURE__ */ jsx(ToolRow, { item })
6654
- }) : /* @__PURE__ */ jsx(ToolRow, { item })] }, item.id)) }) : null]
6736
+ children: [
6737
+ /* @__PURE__ */ jsx(Pressable, {
6738
+ onPress: () => setOpen((v) => !v),
6739
+ expanded: open,
6740
+ children: /* @__PURE__ */ jsxs(Row, {
6741
+ glyph: busy ? pulse : void 0,
6742
+ glyphTone: busy ? "mark" : void 0,
6743
+ tone: failed ? "red" : "dim",
6744
+ children: [busy ? /* @__PURE__ */ jsx("span", {
6745
+ className: "term-shimmer",
6746
+ children: runSummary(items, busy)
6747
+ }) : runSummary(items, busy), elapsed ? /* @__PURE__ */ jsxs(Ink, {
6748
+ tone: "faint",
6749
+ children: [
6750
+ " ",
6751
+ "·",
6752
+ "\xA0",
6753
+ elapsed
6754
+ ]
6755
+ }) : null]
6756
+ })
6757
+ }),
6758
+ open ? null : /* @__PURE__ */ jsx(LiveTail, { lines: runTailLines(items) }),
6759
+ open ? /* @__PURE__ */ jsx("div", { children: items.map((item, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 ? /* @__PURE__ */ jsx(Blank, {}) : null, index < items.length - 1 ? /* @__PURE__ */ jsx(ActionPlacementProvider, {
6760
+ value: "below",
6761
+ children: /* @__PURE__ */ jsx(ToolRow, { item })
6762
+ }) : /* @__PURE__ */ jsx(ToolRow, { item })] }, item.id)) }) : null
6763
+ ]
6655
6764
  });
6656
6765
  }
6657
6766
  function RunRow({ items }) {
@@ -6777,6 +6886,15 @@ function FileRow({ item, href }) {
6777
6886
  ]
6778
6887
  });
6779
6888
  }
6889
+ function LiveTail({ lines }) {
6890
+ return lines.map((line, index) => /* @__PURE__ */ jsx(Row, {
6891
+ indent: 1,
6892
+ columns: 3,
6893
+ glyph: index === 0 ? "⎿" : void 0,
6894
+ tone: "faint",
6895
+ children: line || " "
6896
+ }, index));
6897
+ }
6780
6898
  function useTicker(on) {
6781
6899
  const [now, setNow] = useState(() => Date.now());
6782
6900
  useEffect(() => {
@@ -6832,7 +6950,7 @@ function TerminalSurface({ fontSize, lineHeight, bleed, affordances, className,
6832
6950
  //#region src/components/agent/Composer.tsx
6833
6951
  const SHELL_PLACEHOLDER = "Run a command on the host…";
6834
6952
  const SHELL_HINT = "$ shell mode · esc to exit";
6835
- function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message the agent…", commands, skills, clientCommands, onSearchFiles, peers, onShellCommand, attachments, toolbar, layout = "stacked", fontSize, lineHeight, affordances, draft, className, ref }) {
6953
+ function Composer({ onSend, onSendNow, onInterrupt, busy, disabled, placeholder = "Message the agent…", commands, skills, clientCommands, onSearchFiles, peers, onShellCommand, attachments, toolbar, layout = "stacked", fontSize, lineHeight, affordances, draft, className, ref }) {
6836
6954
  const inline = layout === "inline";
6837
6955
  const terminal = useTranscriptVariant() === "terminal";
6838
6956
  const [initialDraft] = useState(() => draft?.initialText ?? "");
@@ -6911,6 +7029,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
6911
7029
  value: peer.slug,
6912
7030
  label: peer.label,
6913
7031
  description: [
7032
+ peer.gateway,
6914
7033
  peer.engine,
6915
7034
  peer.project,
6916
7035
  peer.status
@@ -6942,7 +7061,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
6942
7061
  }, [plainText, saveDraft]);
6943
7062
  const staged = attachments?.items ?? [];
6944
7063
  const canSend = !disabled && (!isEmpty || staged.length > 0) && !attachments?.uploading && !attachments?.hasFailure;
6945
- const submit = () => {
7064
+ const submit = (now = false) => {
6946
7065
  if (!canSend) return;
6947
7066
  if (shellMode) {
6948
7067
  const command = plainText.trim();
@@ -6954,7 +7073,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
6954
7073
  focus();
6955
7074
  return;
6956
7075
  }
6957
- onSend(plainText.trim(), attachments?.readyIds ?? []);
7076
+ (now && onSendNow ? onSendNow : onSend)(plainText.trim(), attachments?.readyIds ?? []);
6958
7077
  attachments?.clear();
6959
7078
  draft?.clear();
6960
7079
  clear();
@@ -7003,6 +7122,11 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7003
7122
  setHelpOpen(true);
7004
7123
  return;
7005
7124
  }
7125
+ if (e.key === "Enter" && e.altKey && onSendNow && canSend) {
7126
+ e.preventDefault();
7127
+ submit(true);
7128
+ return;
7129
+ }
7006
7130
  if (helpOpen) setHelpOpen(false);
7007
7131
  }
7008
7132
  };
@@ -7066,10 +7190,16 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7066
7190
  "data-tone": "blue",
7067
7191
  children: "❯"
7068
7192
  });
7193
+ const sendNow = onSendNow && canSend && !shellMode ? /* @__PURE__ */ jsx("button", {
7194
+ type: "button",
7195
+ className: "term-press term-link text-label",
7196
+ onClick: () => submit(true),
7197
+ children: "⌥↵ send now - moves the running command to the background"
7198
+ }) : null;
7069
7199
  const submitButton = terminal ? /* @__PURE__ */ jsx(GlyphButton, {
7070
7200
  label: "Send",
7071
7201
  disabled: !canSend,
7072
- onClick: submit,
7202
+ onClick: () => submit(),
7073
7203
  tone: canSend ? "blue" : void 0,
7074
7204
  children: "↵"
7075
7205
  }) : busy && !canSend ? /* @__PURE__ */ jsx(Button, {
@@ -7084,7 +7214,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7084
7214
  "aria-label": "Send",
7085
7215
  className: "rounded-full",
7086
7216
  disabled: !canSend,
7087
- onClick: submit,
7217
+ onClick: () => submit(),
7088
7218
  children: /* @__PURE__ */ jsx(ArrowUp, { className: "size-4" })
7089
7219
  });
7090
7220
  const dropHandlers = {
@@ -7125,7 +7255,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7125
7255
  triggers,
7126
7256
  markdown: false,
7127
7257
  normalizeBullets: false,
7128
- onSubmit: submit,
7258
+ onSubmit: () => submit(),
7129
7259
  disabled,
7130
7260
  placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
7131
7261
  minHeight,
@@ -7151,6 +7281,13 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7151
7281
  children: /* @__PURE__ */ jsxs("div", {
7152
7282
  className: "term-composer-body",
7153
7283
  children: [
7284
+ sendNow ? /* @__PURE__ */ jsxs("div", {
7285
+ className: "term-row",
7286
+ children: [/* @__PURE__ */ jsx("span", {
7287
+ "aria-hidden": true,
7288
+ className: "term-gutter"
7289
+ }), sendNow]
7290
+ }) : null,
7154
7291
  stagedStrip,
7155
7292
  /* @__PURE__ */ jsxs("div", {
7156
7293
  className: "term-row",
@@ -7204,6 +7341,10 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
7204
7341
  className: cn("px-[var(--wd-composer-padding)] pb-[var(--wd-composer-padding)]", className),
7205
7342
  children: [
7206
7343
  helpRow,
7344
+ sendNow ? /* @__PURE__ */ jsx("div", {
7345
+ className: "mx-auto mb-1 w-full max-w-[var(--wd-transcript-max-width)] text-text-muted",
7346
+ children: sendNow
7347
+ }) : null,
7207
7348
  /* @__PURE__ */ jsxs("div", {
7208
7349
  ...dropHandlers,
7209
7350
  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", shellMode && "border-[var(--wd-shell-accent)] focus-within:border-[var(--wd-shell-accent)] focus-within:ring-[var(--wd-shell-accent)]/30", disabled && "opacity-60"),
@@ -8072,6 +8213,50 @@ function ModelSelect({ models, model, onModelChange, variant = "toolbar", disabl
8072
8213
  });
8073
8214
  }
8074
8215
  //#endregion
8216
+ //#region src/components/agent/EffortSelect.tsx
8217
+ const DEFAULT_VALUE = "default";
8218
+ function effortChoices(models, model, capabilities) {
8219
+ return matchModel(models, model)?.reasoningEfforts ?? capabilities.reasoningEfforts ?? [];
8220
+ }
8221
+ function EffortSelect({ efforts, effort, onEffortChange, variant = "toolbar", disabled, className }) {
8222
+ const items = [{
8223
+ value: DEFAULT_VALUE,
8224
+ label: "Default"
8225
+ }, ...efforts.map((value) => ({
8226
+ value,
8227
+ label: value
8228
+ }))];
8229
+ return /* @__PURE__ */ jsxs(Select$1, {
8230
+ items,
8231
+ value: effort ?? null,
8232
+ onValueChange: (value) => {
8233
+ if (typeof value !== "string" || value === effort) return;
8234
+ onEffortChange(value === DEFAULT_VALUE ? void 0 : value);
8235
+ },
8236
+ disabled,
8237
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
8238
+ "aria-label": "Reasoning effort",
8239
+ className: cn(variant === "toolbar" && "h-6 max-w-32 border-transparent bg-transparent text-fg-3 hover:bg-surface-hover", className),
8240
+ children: /* @__PURE__ */ jsxs("span", {
8241
+ className: cn("flex items-center gap-1 truncate", variant === "toolbar" && "font-mono text-label"),
8242
+ children: [/* @__PURE__ */ jsx(Brain, { className: "size-3 shrink-0" }), /* @__PURE__ */ jsx(SelectValue, { placeholder: "effort" })]
8243
+ })
8244
+ }), /* @__PURE__ */ jsx(SelectContent, {
8245
+ className: "min-w-40",
8246
+ children: items.map((item) => /* @__PURE__ */ jsxs(SelectItem, {
8247
+ value: item.value,
8248
+ children: [/* @__PURE__ */ jsx(SelectItemText, { children: /* @__PURE__ */ jsx("span", {
8249
+ className: "font-medium",
8250
+ children: item.label
8251
+ }) }), item.value === DEFAULT_VALUE ? /* @__PURE__ */ jsx("span", {
8252
+ className: "text-label text-fg-4",
8253
+ children: "The model's configured default"
8254
+ }) : null]
8255
+ }, item.value))
8256
+ })]
8257
+ });
8258
+ }
8259
+ //#endregion
8075
8260
  //#region src/components/agent/PermissionModeSelect.tsx
8076
8261
  const PERMISSION_MODES = [
8077
8262
  {
@@ -10781,10 +10966,16 @@ function toolRowHeight(item, m, extraPx) {
10781
10966
  const todos = todoPreview(item.name, item.input);
10782
10967
  const preview = todos ? todos.summary : toolInputPreview(item.input);
10783
10968
  const backend = item.backend && item.backend !== "server" ? ` · ${item.backend}` : "";
10784
- let acc = rowH(`${item.name}(${preview})${backend}`, m, {
10969
+ const elapsed = toolBusy(item) && item.ts !== void 0 ? ELAPSED_WIDEST : "";
10970
+ let acc = rowH(`${item.name}(${preview})${backend}${elapsed}`, m, {
10785
10971
  gutterCells: 2,
10786
10972
  extraPx
10787
10973
  });
10974
+ for (const line of liveTailLines(item)) acc = add(acc, rowH(line || " ", m, {
10975
+ indentCells: 3,
10976
+ gutterCells: 3,
10977
+ extraPx
10978
+ }));
10788
10979
  const boxes = (item.result?.images?.length ?? 0) + (hostImagePathOf(item) === void 0 ? 0 : 1);
10789
10980
  if (boxes > 0) acc = add(acc, {
10790
10981
  px: boxes * 12 * m.line,
@@ -10873,7 +11064,13 @@ function blockHeight(block, m) {
10873
11064
  const plan = planRun(block.run);
10874
11065
  if (plan.kind === "call") return itemHeight(plan.item, m);
10875
11066
  const busy = plan.items.some((item) => item.status === "running" || item.status === "pending");
10876
- return rowH(runSummary(plan.items, busy), m);
11067
+ const elapsed = runStartedAt(plan.items) === void 0 ? "" : ELAPSED_WIDEST;
11068
+ let acc = rowH(runSummary(plan.items, busy) + elapsed, m);
11069
+ for (const line of runTailLines(plan.items)) acc = add(acc, rowH(line || " ", m, {
11070
+ indentCells: 3,
11071
+ gutterCells: 3
11072
+ }));
11073
+ return acc;
10877
11074
  }
10878
11075
  return itemHeight(block.item, m);
10879
11076
  }
@@ -12180,15 +12377,33 @@ function TranscriptItemView({ item, fileUrl, attachmentUrl, hostImage, terminal
12180
12377
  function ToolCard({ item, hostImage }) {
12181
12378
  const command = item.input?.command;
12182
12379
  const copyable = typeof command === "string" ? command : item.result?.text ?? "";
12183
- return /* @__PURE__ */ jsx(WithActions, {
12184
- actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(BookmarkAction, { id: item.id }), copyable ? /* @__PURE__ */ jsx(CopyAction, {
12185
- text: copyable,
12186
- label: "Copy"
12187
- }) : null] }),
12188
- children: /* @__PURE__ */ jsx(ToolCallCard, {
12380
+ return /* @__PURE__ */ jsxs(WithActions, {
12381
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [
12382
+ canBackground(item) ? /* @__PURE__ */ jsx(BackgroundAction, { toolUseId: item.id }) : null,
12383
+ /* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
12384
+ copyable ? /* @__PURE__ */ jsx(CopyAction, {
12385
+ text: copyable,
12386
+ label: "Copy"
12387
+ }) : null
12388
+ ] }),
12389
+ children: [/* @__PURE__ */ jsx(ToolCallCard, {
12189
12390
  item,
12190
12391
  hostImage
12191
- })
12392
+ }), toolBusy(item) ? /* @__PURE__ */ jsx(LiveToolStrip, { item }) : null]
12393
+ });
12394
+ }
12395
+ function LiveToolStrip({ item }) {
12396
+ const now = useTicker(item.ts !== void 0);
12397
+ const elapsed = elapsedLabel(item.ts, now);
12398
+ const tail = liveTailLines(item);
12399
+ if (!elapsed && tail.length === 0) return null;
12400
+ return /* @__PURE__ */ jsxs("div", {
12401
+ "data-slot": "tool-live",
12402
+ className: "mt-1 text-label text-fg-4",
12403
+ children: [elapsed ? /* @__PURE__ */ jsxs("div", { children: ["running ", elapsed] }) : null, tail.length > 0 ? /* @__PURE__ */ jsx("pre", {
12404
+ className: "overflow-x-auto font-mono whitespace-pre-wrap text-fg-3",
12405
+ children: tail.join("\n")
12406
+ }) : null]
12192
12407
  });
12193
12408
  }
12194
12409
  function ShellCard({ item }) {
@@ -13129,7 +13344,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13129
13344
  const controlsExternal = controlsSurface === "external" || controlsInStatus;
13130
13345
  const [protocolError, setProtocolError] = useState(void 0);
13131
13346
  const [panel, setPanel] = useState();
13132
- const { state, connection, replaying, protocolMismatch, shell, pricing, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, clearContext, setModel, setPermissionMode, reconnectNow, loadFullResult, loadShellOutput, verifyShell, killShell, setShellAgentWrite } = useClaudeSession(client, sessionId, {
13347
+ const { state, connection, replaying, protocolMismatch, shell, pricing, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, backgroundTask, clearContext, setModel, setEffort, setPermissionMode, reconnectNow, loadFullResult, loadShellOutput, verifyShell, killShell, setShellAgentWrite } = useClaudeSession(client, sessionId, {
13133
13348
  onProtocolError: setProtocolError,
13134
13349
  cacheTranscript
13135
13350
  });
@@ -13214,19 +13429,29 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13214
13429
  state.session?.subagents
13215
13430
  ]);
13216
13431
  const hasModels = models.length > 0;
13432
+ const efforts = useMemo(() => effortChoices(models, effectiveModel ?? state.model, capabilities), [
13433
+ models,
13434
+ effectiveModel,
13435
+ state.model,
13436
+ capabilities
13437
+ ]);
13217
13438
  const clientCommands = useMemo(() => buildClientCommands({
13218
13439
  capabilities,
13219
13440
  hasModels,
13441
+ efforts,
13220
13442
  setModel,
13443
+ setEffort,
13221
13444
  setPermissionMode,
13222
13445
  clearContext,
13223
13446
  openPanel
13224
13447
  }), [
13225
13448
  capabilities,
13226
13449
  hasModels,
13450
+ efforts,
13227
13451
  openPanel,
13228
13452
  clearContext,
13229
13453
  setModel,
13454
+ setEffort,
13230
13455
  setPermissionMode
13231
13456
  ]);
13232
13457
  const composerCommands = useMemo(() => composerCommandRows(mergeComposerRows({
@@ -13251,6 +13476,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13251
13476
  capabilities: state.capabilities,
13252
13477
  model: vitalsModel,
13253
13478
  models,
13479
+ effort: state.effort,
13480
+ efforts,
13254
13481
  permissionMode: state.permissionMode,
13255
13482
  permissionModes,
13256
13483
  skills: state.skills,
@@ -13273,16 +13500,19 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13273
13500
  onControlsRef.current = onControls;
13274
13501
  const setters = useRef({
13275
13502
  setModel,
13503
+ setEffort,
13276
13504
  setPermissionMode,
13277
13505
  interrupt
13278
13506
  });
13279
13507
  setters.current = {
13280
13508
  setModel,
13509
+ setEffort,
13281
13510
  setPermissionMode,
13282
13511
  interrupt
13283
13512
  };
13284
13513
  const controls = useRef({
13285
13514
  setModel: (model) => setters.current.setModel(model),
13515
+ setEffort: (effort) => setters.current.setEffort(effort),
13286
13516
  setPermissionMode: (mode) => setters.current.setPermissionMode(mode),
13287
13517
  interrupt: () => setters.current.interrupt(),
13288
13518
  focusComposer: () => composerRef.current?.focus(),
@@ -13298,6 +13528,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13298
13528
  has: (id) => bookmarkSet.has(id),
13299
13529
  toggle: onToggleBookmark
13300
13530
  } : void 0, [bookmarkSet, onToggleBookmark]);
13531
+ const canBackgroundTasks = !readOnly && capabilities.backgroundTasks === true;
13532
+ const taskControl = useMemo(() => canBackgroundTasks ? { background: backgroundTask } : void 0, [canBackgroundTasks, backgroundTask]);
13301
13533
  const busy = state.status === "running" || state.status === "awaiting_approval";
13302
13534
  const ended = state.status === "failed" || state.status === "closed";
13303
13535
  const attachments = useAttachments(client, sessionId, {
@@ -13326,6 +13558,13 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13326
13558
  repinTranscript.current?.();
13327
13559
  send(text, attachmentIds);
13328
13560
  };
13561
+ const foregroundSince = canBackgroundTasks ? backgroundableSince(state.items) : void 0;
13562
+ const tick = useTicker(foregroundSince !== void 0);
13563
+ const runningForeground = foregroundSince !== void 0 && tick - foregroundSince >= 5e3;
13564
+ const handleSendNow = (text, attachmentIds) => {
13565
+ handleSend(text, attachmentIds);
13566
+ backgroundTask();
13567
+ };
13329
13568
  const menuShows = {
13330
13569
  context: capabilities.contextUsage,
13331
13570
  usage: capabilities.rateLimits,
@@ -13353,20 +13592,30 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13353
13592
  onOpenChange: (next) => setPanel(next ? target : void 0)
13354
13593
  });
13355
13594
  const headerTakesActions = typeof header === "function";
13356
- const sessionControls = /* @__PURE__ */ jsxs(Fragment$1, { children: [models.length ? /* @__PURE__ */ jsx(ModelSelect, {
13357
- models,
13358
- model: effectiveModel,
13359
- onModelChange: setModel,
13360
- disabled: ended,
13361
- className: controlsInStatus ? "h-5" : void 0
13362
- }) : null, state.permissionMode ? /* @__PURE__ */ jsx(PermissionModeSelect, {
13363
- mode: state.permissionMode,
13364
- onModeChange: setPermissionMode,
13365
- modes: capabilities.permissionModes,
13366
- canBypass: state.session?.canBypassPermissions,
13367
- disabled: ended,
13368
- className: controlsInStatus ? "h-5" : void 0
13369
- }) : null] });
13595
+ const sessionControls = /* @__PURE__ */ jsxs(Fragment$1, { children: [
13596
+ models.length ? /* @__PURE__ */ jsx(ModelSelect, {
13597
+ models,
13598
+ model: effectiveModel,
13599
+ onModelChange: setModel,
13600
+ disabled: ended,
13601
+ className: controlsInStatus ? "h-5" : void 0
13602
+ }) : null,
13603
+ efforts.length && state.effort !== null ? /* @__PURE__ */ jsx(EffortSelect, {
13604
+ efforts,
13605
+ effort: state.effort,
13606
+ onEffortChange: setEffort,
13607
+ disabled: ended,
13608
+ className: controlsInStatus ? "h-5" : void 0
13609
+ }) : null,
13610
+ state.permissionMode ? /* @__PURE__ */ jsx(PermissionModeSelect, {
13611
+ mode: state.permissionMode,
13612
+ onModeChange: setPermissionMode,
13613
+ modes: capabilities.permissionModes,
13614
+ canBypass: state.session?.canBypassPermissions,
13615
+ disabled: ended,
13616
+ className: controlsInStatus ? "h-5" : void 0
13617
+ }) : null
13618
+ ] });
13370
13619
  const statusBar = statusExternal ? null : /* @__PURE__ */ jsx(StatusBar, {
13371
13620
  state,
13372
13621
  rateLimits,
@@ -13461,31 +13710,34 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13461
13710
  fontSize: cell.fontSize
13462
13711
  }, framedShellId) : /* @__PURE__ */ jsx(BookmarkProvider, {
13463
13712
  value: bookmarkHandle,
13464
- children: /* @__PURE__ */ jsx(Transcript, {
13465
- state,
13466
- fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
13467
- attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
13468
- canBrowseFiles: hostFiles.available,
13469
- sessionNames: peers.names,
13470
- hostImage,
13471
- variant: transcriptVariant,
13472
- ...cell,
13473
- affordances,
13474
- stickyPrompt,
13475
- scrubber,
13476
- bookmarks,
13477
- replaying,
13478
- catchUp: catchUp && newCount > 0 ? {
13479
- from: catchUp.itemCount,
13480
- since: catchUp.since
13481
- } : void 0,
13482
- reveal: frameReturnReveal ?? reveal,
13483
- frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
13484
- onOpenSubagent: enterSubagent,
13485
- emptyState,
13486
- jumpToRecapRef: jumpToRecap,
13487
- repinRef: repinTranscript
13488
- }, subagentId ?? "session")
13713
+ children: /* @__PURE__ */ jsx(TaskControlProvider, {
13714
+ value: taskControl,
13715
+ children: /* @__PURE__ */ jsx(Transcript, {
13716
+ state,
13717
+ fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
13718
+ attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
13719
+ canBrowseFiles: hostFiles.available,
13720
+ sessionNames: peers.names,
13721
+ hostImage,
13722
+ variant: transcriptVariant,
13723
+ ...cell,
13724
+ affordances,
13725
+ stickyPrompt,
13726
+ scrubber,
13727
+ bookmarks,
13728
+ replaying,
13729
+ catchUp: catchUp && newCount > 0 ? {
13730
+ from: catchUp.itemCount,
13731
+ since: catchUp.since
13732
+ } : void 0,
13733
+ reveal: frameReturnReveal ?? reveal,
13734
+ frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
13735
+ onOpenSubagent: enterSubagent,
13736
+ emptyState,
13737
+ jumpToRecapRef: jumpToRecap,
13738
+ repinRef: repinTranscript
13739
+ }, subagentId ?? "session")
13740
+ })
13489
13741
  }),
13490
13742
  catchUp && newCount > 0 && !replaying && subagentId === void 0 && framedShellId === void 0 ? /* @__PURE__ */ jsx(CatchUpBanner, {
13491
13743
  count: newCount,
@@ -13506,6 +13758,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
13506
13758
  readOnly || subagentId !== void 0 || framedShellId !== void 0 ? null : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Composer, {
13507
13759
  ref: composerRef,
13508
13760
  onSend: handleSend,
13761
+ onSendNow: runningForeground ? handleSendNow : void 0,
13509
13762
  onInterrupt: interrupt,
13510
13763
  busy,
13511
13764
  disabled: ended || !sessionId,
@@ -13734,6 +13987,6 @@ function resolveAgainstCwd(path, cwd) {
13734
13987
  return parseFileLink(path, cwd)?.path ?? path;
13735
13988
  }
13736
13989
  //#endregion
13737
- export { ShellActionsProvider as $, Spinner as $t, PermissionPrompt as A, buttonVariants as An, PromptTokenText as At, ModelSelect as B, rankPeerSessions as Bt, SessionInfoDialog as C, SelectValue as Cn, Blank as Ct, QUESTION_BEHAVIORS as D, Badge as Dn, CopyAction as Dt, TerminalPermissionPrompt as E, Input as En, AgentWriteIcon as Et, SubagentStrip as F, TranscriptVariantProvider as Ft, useMcpPanel as G, mentionTrigger as Gt, McpDialog as H, commandTrigger as Ht, PERMISSION_MODES as I, useTranscriptVariant as It, ContextDialog as J, plainTextToSegments as Jt, HostFilesDialog as K, usePromptAreaState as Kt, PermissionModeSelect as L, matchClientCommand as Lt, useShellFrame as M, SkillNamesProvider as Mt, ShellTerminal as N, isMutatingTool as Nt, QuestionPrompt as O, badgeVariants as On, WithActions as Ot, ShellStrip as P, toolIcon as Pt, TerminalSurface as Q, CodeBlock as Qt, permissionModeChoices as R, mergeComposerRows as Rt, STATUS_META as S, SelectTrigger as Sn, Band as St, TerminalQuestionPrompt as T, Textarea as Tn, Row as Tt, McpPanel as U, hashtagTrigger as Ut, SkillsDialog as V, skillPrompt as Vt, McpPanelActions as W, launchTrigger as Wt, contextNote as X, ProgressRing as Xt, ContextPanel as Y, segmentsToPlainText as Yt, Composer as Z, Splitter as Zt, Loader as _, OptionSelect as _n, FileLinkProvider as _t, UsageDialog as a, Dialog$1 as an, shellGrantable as at, ConversationScrollButton as b, SelectItem as bn, TerminalDiff as bt, TerminalTranscript as c, DialogContent as cn, shellInfoStatusText as ct, Reasoning as d, DialogTrigger as dn, useToolTitle as dt, CopyButton as en, useShellActions as et, Message as f, Menu$1 as fn, TerminalMarkdown as ft, SessionEmptyState as g, MenuTrigger as gn, useOpenImage as gt, TerminalItemView as h, MenuSeparator as hn, ViewableImage as ht, SessionPanel as i, TooltipProvider as in, shellAgentWriteLabel as it, Response as j, cn as jn, SessionNamesProvider as jt, parseUserQuestions as k, Button as kn, useAffordances as kt, Transcript as l, DialogHeader as ln, shellTitle as lt, FileCard as m, MenuItem as mn, ImageViewerProvider as mt, usePathLinks as n, Tip as nn, SHELL_GLYPH as nt, UsageMeters as o, DialogBody as on, shellInfoFailed as ot, MessageContent as p, MenuContent as pn, ImageViewer as pt, EntryIcon as q, PromptArea as qt, matchPath as r, TooltipContent as rn, SHELL_KILL_GLYPH as rt, useMinuteClock as s, DialogClose as sn, shellInfoLabel as st, resolveAgainstCwd as t, copyText as tn, SHELL_AGENT_WRITE_NOTE as tt, ToolCallCard as u, DialogRow as un, ToolTitleProvider as ut, Conversation as v, Select$1 as vn, useFileLinks as vt, SessionInfoPanel as w, PortalScope as wn, Ink as wt, StatusBar as x, SelectItemText as xn, previewPatch as xt, ConversationContent as y, SelectContent as yn, parseFileLink as yt, permissionModeMeta as z, rankComposerRows as zt };
13990
+ export { Composer as $, Splitter as $t, PermissionPrompt as A, badgeVariants as An, WithActions as At, EffortSelect as B, mergeComposerRows as Bt, SessionInfoDialog as C, SelectItemText as Cn, previewPatch as Ct, QUESTION_BEHAVIORS as D, Textarea as Dn, Row as Dt, TerminalPermissionPrompt as E, PortalScope as En, Ink as Et, SubagentStrip as F, isMutatingTool as Ft, McpPanel as G, hashtagTrigger as Gt, ModelSelect as H, rankPeerSessions as Ht, PERMISSION_MODES as I, toolIcon as It, HostFilesDialog as J, usePromptAreaState as Jt, McpPanelActions as K, launchTrigger as Kt, PermissionModeSelect as L, TranscriptVariantProvider as Lt, useShellFrame as M, buttonVariants as Mn, PromptTokenText as Mt, ShellTerminal as N, cn as Nn, SessionNamesProvider as Nt, QuestionPrompt as O, Input as On, AgentWriteIcon as Ot, ShellStrip as P, SkillNamesProvider as Pt, contextNote as Q, ProgressRing as Qt, permissionModeChoices as R, useTranscriptVariant as Rt, STATUS_META as S, SelectItem as Sn, TerminalDiff as St, TerminalQuestionPrompt as T, SelectValue as Tn, Blank as Tt, SkillsDialog as U, skillPrompt as Ut, effortChoices as V, rankComposerRows as Vt, McpDialog as W, commandTrigger as Wt, ContextDialog as X, plainTextToSegments as Xt, EntryIcon as Y, PromptArea as Yt, ContextPanel as Z, segmentsToPlainText as Zt, Loader as _, MenuSeparator as _n, ViewableImage as _t, UsageDialog as a, TooltipContent as an, SHELL_KILL_GLYPH as at, ConversationScrollButton as b, Select$1 as bn, useFileLinks as bt, TerminalTranscript as c, DialogBody as cn, shellInfoFailed as ct, Reasoning as d, DialogHeader as dn, shellTitle as dt, CodeBlock as en, TerminalSurface as et, Message as f, DialogRow as fn, ToolTitleProvider as ft, SessionEmptyState as g, MenuItem as gn, ImageViewerProvider as gt, TerminalItemView as h, MenuContent as hn, ImageViewer as ht, SessionPanel as i, Tip as in, SHELL_GLYPH as it, Response as j, Button as jn, useAffordances as jt, parseUserQuestions as k, Badge as kn, CopyAction as kt, Transcript as l, DialogClose as ln, shellInfoLabel as lt, FileCard as m, Menu$1 as mn, TerminalMarkdown as mt, usePathLinks as n, CopyButton as nn, useShellActions as nt, UsageMeters as o, TooltipProvider as on, shellAgentWriteLabel as ot, MessageContent as p, DialogTrigger as pn, useToolTitle as pt, useMcpPanel as q, mentionTrigger as qt, matchPath as r, copyText as rn, SHELL_AGENT_WRITE_NOTE as rt, useMinuteClock as s, Dialog$1 as sn, shellGrantable as st, resolveAgainstCwd as t, Spinner as tn, ShellActionsProvider as tt, ToolCallCard as u, DialogContent as un, shellInfoStatusText as ut, Conversation as v, MenuTrigger as vn, useOpenImage as vt, SessionInfoPanel as w, SelectTrigger as wn, Band as wt, StatusBar as x, SelectContent as xn, parseFileLink as xt, ConversationContent as y, OptionSelect as yn, FileLinkProvider as yt, permissionModeMeta as z, matchClientCommand as zt };
13738
13991
 
13739
- //# sourceMappingURL=use-path-links-Cby4i_VL.mjs.map
13992
+ //# sourceMappingURL=use-path-links-WCsysQPy.mjs.map