@workerdeck/ui 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +4 -0
  2. package/build/{SessionPanel-yNO60Tzw.d.mts → SessionPanel-BSwUJDwg.d.mts} +3 -8
  3. package/build/{SessionPanel-I5QSLLb0.mjs → SessionPanel-DQp2oStr.mjs} +409 -267
  4. package/build/SessionPanel-DQp2oStr.mjs.map +1 -0
  5. package/build/{format-C_lpFq0l.d.mts → format-TVRJzYUj.d.mts} +3 -2
  6. package/build/format.d.mts +2 -7
  7. package/build/format.mjs +2 -2
  8. package/build/index.d.mts +34 -9
  9. package/build/index.mjs +38 -12
  10. package/build/index.mjs.map +1 -1
  11. package/build/scoped.css +11 -0
  12. package/build/{status-Dm9INVTt.mjs → status-C4TAgVSc.mjs} +3 -7
  13. package/build/status-C4TAgVSc.mjs.map +1 -0
  14. package/build/workspace.d.mts +3 -2
  15. package/build/workspace.mjs +4 -3
  16. package/build/workspace.mjs.map +1 -1
  17. package/package.json +4 -4
  18. package/src/components/agent/Composer.tsx +2 -4
  19. package/src/components/agent/ContextDialog.tsx +17 -2
  20. package/src/components/agent/ContextRing.tsx +36 -7
  21. package/src/components/agent/EntryIcon.tsx +2 -4
  22. package/src/components/agent/McpDialog.tsx +2 -0
  23. package/src/components/agent/SessionItem.tsx +1 -1
  24. package/src/components/agent/SessionPanel.tsx +198 -186
  25. package/src/components/agent/SessionWorkspace.tsx +3 -0
  26. package/src/components/agent/StatusBar.tsx +12 -4
  27. package/src/components/agent/ToolCallCard.tsx +6 -1
  28. package/src/components/agent/TranscriptItemView.tsx +15 -2
  29. package/src/components/agent/TranscriptRows.tsx +4 -6
  30. package/src/components/agent/held-sends.tsx +73 -0
  31. package/src/components/agent/tool-titles.tsx +12 -0
  32. package/src/components/agent/use-subagent-frame.ts +8 -10
  33. package/src/components/agent/use-transcript-jumps.ts +7 -9
  34. package/src/components/terminal/TerminalTranscript.tsx +15 -1
  35. package/src/components/terminal/height.ts +4 -1
  36. package/src/components/terminal/items.tsx +14 -3
  37. package/src/index.ts +2 -0
  38. package/src/lib/context-note.ts +24 -0
  39. package/src/lib/css.ts +3 -5
  40. package/src/lib/format.ts +3 -0
  41. package/src/lib/status.ts +3 -5
  42. package/build/SessionPanel-I5QSLLb0.mjs.map +0 -1
  43. package/build/status-Dm9INVTt.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { S as toolInputPreview, _ as formatRateLimitWindowLong, a as meterTintClass, d as formatAgoPrecise, f as formatBytes, h as formatDuration, m as formatCountdown, p as formatCost, r as meterColorClass, v as formatRelativeTime, x as rateLimitWindowSeconds, y as formatTokens } from "./status-Dm9INVTt.mjs";
1
+ import { C as toolInputPreview, S as rateLimitWindowSeconds, a as meterTintClass, b as formatTokens, d as COMPACTION_TEXT, f as formatAgoPrecise, g as formatDuration, h as formatCountdown, m as formatCost, p as formatBytes, r as meterColorClass, v as formatRateLimitWindowLong, y as formatRelativeTime } from "./status-C4TAgVSc.mjs";
2
2
  import { Fragment, createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import { cva } from "class-variance-authority";
4
4
  import { clsx } from "clsx";
@@ -9,7 +9,7 @@ import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowUp, AtSign, Brain, ChartPie
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";
12
- import { PROTOCOL_VERSION, mergeUsage, orderUsageWindows, subagentLabel, usageInfos } from "@workerdeck/protocol";
12
+ import { PROTOCOL_VERSION, mergeUsage, orderUsageWindows, subagentLabel, toolTitle, usageInfos } from "@workerdeck/protocol";
13
13
  import { recapLine, scanPromptTokens, summarizeSince, useAttachments, useClaudeSession, useDraft, useHostFileSearch, useProfileUsage, useToolCallHost } from "@workerdeck/react";
14
14
  import { Streamdown } from "streamdown";
15
15
  import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
@@ -4974,6 +4974,18 @@ function useToolResultFetcher() {
4974
4974
  return useContext(FetchContext);
4975
4975
  }
4976
4976
  //#endregion
4977
+ //#region src/components/agent/tool-titles.tsx
4978
+ const TitlesContext = createContext(void 0);
4979
+ function ToolTitleProvider({ value, children }) {
4980
+ return /* @__PURE__ */ jsx(TitlesContext.Provider, {
4981
+ value,
4982
+ children
4983
+ });
4984
+ }
4985
+ function useToolTitle(name) {
4986
+ return toolTitle(name, useContext(TitlesContext));
4987
+ }
4988
+ //#endregion
4977
4989
  //#region src/components/agent/tool-result-image.tsx
4978
4990
  const noop = async () => void 0;
4979
4991
  const ImageContext = createContext(noop);
@@ -5270,6 +5282,7 @@ function ToolRow({ item }) {
5270
5282
  const command = item.input?.command;
5271
5283
  const copyable = typeof command === "string" ? command : text;
5272
5284
  const todos = todoPreview(item.name, item.input);
5285
+ const title = useToolTitle(item.name);
5273
5286
  return /* @__PURE__ */ jsx("div", {
5274
5287
  ref: reveal,
5275
5288
  className: open ? "term-open" : void 0,
@@ -5286,11 +5299,12 @@ function ToolRow({ item }) {
5286
5299
  glyph: busy ? pulse : "●",
5287
5300
  glyphTone: tone,
5288
5301
  tone: "fg",
5302
+ title: title ? item.name : void 0,
5289
5303
  children: [
5290
5304
  /* @__PURE__ */ jsx(Ink, {
5291
5305
  bold: true,
5292
5306
  tone: "bright",
5293
- children: item.name
5307
+ children: title ?? item.name
5294
5308
  }),
5295
5309
  /* @__PURE__ */ jsxs(Ink, {
5296
5310
  tone: "dim",
@@ -5300,6 +5314,10 @@ function ToolRow({ item }) {
5300
5314
  ")"
5301
5315
  ]
5302
5316
  }),
5317
+ title && open ? /* @__PURE__ */ jsxs(Ink, {
5318
+ tone: "faint",
5319
+ children: [" · ", item.name]
5320
+ }) : null,
5303
5321
  item.backend && item.backend !== "server" ? /* @__PURE__ */ jsxs(Ink, {
5304
5322
  tone: "faint",
5305
5323
  children: [" · ", item.backend]
@@ -5441,6 +5459,14 @@ function TurnResultRow$1({ item }) {
5441
5459
  children: message
5442
5460
  }, index))] });
5443
5461
  }
5462
+ function CompactionRow$1() {
5463
+ return /* @__PURE__ */ jsx(Row, {
5464
+ glyph: "≡",
5465
+ glyphTone: "yellow",
5466
+ tone: "faint",
5467
+ children: COMPACTION_TEXT
5468
+ });
5469
+ }
5444
5470
  function NoticeRow$1({ item }) {
5445
5471
  const error = item.level === "error";
5446
5472
  return /* @__PURE__ */ jsx(Row, {
@@ -5933,17 +5959,24 @@ function extensionOf(name) {
5933
5959
  }
5934
5960
  //#endregion
5935
5961
  //#region src/lib/css.ts
5936
- /**
5937
- * Pass a colour through only if this engine can actually parse it. Category colours arrive
5938
- * from the CLI as untrusted strings, and an unparseable one must fall back to the token
5939
- * colour rather than reaching the DOM.
5940
- */
5941
5962
  function cssColor(color) {
5942
5963
  return typeof CSS !== "undefined" && CSS.supports("color", color) ? color : void 0;
5943
5964
  }
5944
5965
  //#endregion
5966
+ //#region src/lib/context-note.ts
5967
+ const CODEX_CONTEXT_NOTE = {
5968
+ summary: "Codex budgets 272K input by default and reports 95% of it, so a 1M-class model reads ~258k. That is codex’s price tier, not the model’s ceiling — and it is the number auto-compaction fires on, so the meter is honest.",
5969
+ hint: "Raising it is yours to set: model_context_window in ~/.codex/config.toml — and watch for auto-compaction failing afterwards.",
5970
+ detail: ["To raise it, set model_context_window in ~/.codex/config.toml, up to 872000 (reported as 828400). Codex clamps to its own max_context_window, itself below OpenAI’s stated 922,000 max input.", "Above 272K input, a request bills at 2x input / 1.5x output for the whole request. WorkerDeck never writes this setting — it is a cost decision on your account."],
5971
+ caveat: "Raise it and watch for auto-compaction failing: openai/codex #16068 reports it stops firing after the first overflow. Unverified here on 0.149.0."
5972
+ };
5973
+ function contextNote(engine) {
5974
+ return (engine ?? "claude") === "codex" ? CODEX_CONTEXT_NOTE : void 0;
5975
+ }
5976
+ //#endregion
5945
5977
  //#region src/components/agent/ContextDialog.tsx
5946
- function ContextDialog({ usage, open, onOpenChange, className }) {
5978
+ function ContextDialog({ usage, engine, open, onOpenChange, className }) {
5979
+ const note = contextNote(engine);
5947
5980
  return /* @__PURE__ */ jsx(Dialog$1, {
5948
5981
  open,
5949
5982
  onOpenChange,
@@ -5952,7 +5985,7 @@ function ContextDialog({ usage, open, onOpenChange, className }) {
5952
5985
  children: [/* @__PURE__ */ jsx(DialogHeader, {
5953
5986
  title: "Context",
5954
5987
  description: usage?.model
5955
- }), /* @__PURE__ */ jsx(DialogBody, { children: !usage ? /* @__PURE__ */ jsx("p", {
5988
+ }), /* @__PURE__ */ jsxs(DialogBody, { children: [!usage ? /* @__PURE__ */ jsx("p", {
5956
5989
  className: "py-6 text-center text-body-sm text-fg-4",
5957
5990
  children: "No reading yet — the context window is measured after a turn completes."
5958
5991
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
@@ -6018,16 +6051,32 @@ function ContextDialog({ usage, open, onOpenChange, className }) {
6018
6051
  })
6019
6052
  })]
6020
6053
  }) : null
6021
- ] }) })]
6054
+ ] }), note ? /* @__PURE__ */ jsxs("div", {
6055
+ className: "mt-5 border-t border-border pt-4",
6056
+ children: [
6057
+ /* @__PURE__ */ jsx("h3", {
6058
+ className: "text-label font-medium text-fg-3",
6059
+ children: "Why this window is 272K"
6060
+ }),
6061
+ /* @__PURE__ */ jsx("p", {
6062
+ className: "mt-2 text-body-sm text-fg-2",
6063
+ children: note.summary
6064
+ }),
6065
+ note.detail.map((line) => /* @__PURE__ */ jsx("p", {
6066
+ className: "mt-2 text-body-sm text-fg-3",
6067
+ children: line
6068
+ }, line)),
6069
+ /* @__PURE__ */ jsx("p", {
6070
+ className: "mt-2 text-body-sm text-warning",
6071
+ children: note.caveat
6072
+ })
6073
+ ]
6074
+ }) : null] })]
6022
6075
  })
6023
6076
  });
6024
6077
  }
6025
6078
  //#endregion
6026
6079
  //#region src/components/agent/EntryIcon.tsx
6027
- /**
6028
- * The icon for one host directory entry. A symlink is drawn as a link and never silently
6029
- * resolved — the caller decides what a symlink means, the tree only says it is one.
6030
- */
6031
6080
  function EntryIcon({ type }) {
6032
6081
  if (type === "dir") return /* @__PURE__ */ jsx(Folder, { className: "size-3.5 shrink-0 text-accent" });
6033
6082
  if (type === "symlink") return /* @__PURE__ */ jsx(Link2, { className: "size-3.5 shrink-0 text-fg-4" });
@@ -6389,10 +6438,17 @@ function ServerView({ server, busy, canManage, onAct, onSelectTool }) {
6389
6438
  type: "button",
6390
6439
  onClick: () => onSelectTool(t.name),
6391
6440
  className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-surface-hover",
6392
- children: [/* @__PURE__ */ jsx("span", {
6393
- className: "min-w-0 flex-1 truncate font-mono text-label text-fg-1",
6394
- children: t.name
6395
- }), /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0 text-fg-4" })]
6441
+ children: [
6442
+ /* @__PURE__ */ jsx("span", {
6443
+ className: "min-w-0 flex-1 truncate font-mono text-label text-fg-1",
6444
+ children: t.name
6445
+ }),
6446
+ t.title ? /* @__PURE__ */ jsx("span", {
6447
+ className: "min-w-0 shrink truncate text-label text-fg-4",
6448
+ children: t.title
6449
+ }) : null,
6450
+ /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0 text-fg-4" })
6451
+ ]
6396
6452
  }) }, t.name))
6397
6453
  })] })
6398
6454
  ]
@@ -6403,6 +6459,10 @@ function ToolView({ tool }) {
6403
6459
  return /* @__PURE__ */ jsxs("div", {
6404
6460
  className: "flex flex-col gap-3",
6405
6461
  children: [
6462
+ tool.title ? /* @__PURE__ */ jsx("p", {
6463
+ className: "text-body-sm font-medium text-fg-1",
6464
+ children: tool.title
6465
+ }) : null,
6406
6466
  tool.description ? /* @__PURE__ */ jsx("p", {
6407
6467
  className: "text-body-sm whitespace-pre-wrap text-fg-2",
6408
6468
  children: tool.description
@@ -7035,14 +7095,6 @@ function blockNeedsBlank(previous, next) {
7035
7095
  }
7036
7096
  //#endregion
7037
7097
  //#region src/components/agent/use-subagent-frame.ts
7038
- /**
7039
- * The sub-agent frame machine: which agent frame is on screen, how it is entered (a host
7040
- * `openSubagent` request or a Task row in the transcript), how it is left (Escape, the strip's
7041
- * Back, or the host withdrawing), and what the transcript reveals on the way out. The frame
7042
- * round-trips through the host's URL — the anti-loop rules live in GOTCHAS ("The sub-agent
7043
- * frame round-trips through the URL"); here they mean: entry keys on the nonce alone, and the
7044
- * report is deduped through a ref, so an echo of our own report is inert on arrival.
7045
- */
7046
7098
  function useSubagentFrame(options) {
7047
7099
  const { sessionId, items, session, reveal, openSubagent, onSubagentChange } = options;
7048
7100
  const [subagentId, setSubagentId] = useState(void 0);
@@ -7947,40 +7999,48 @@ function useNow(intervalMs = 3e4) {
7947
7999
  }, [intervalMs]);
7948
8000
  return now;
7949
8001
  }
7950
- function ContextMeter({ usage }) {
8002
+ function ContextMeter({ usage, engine }) {
8003
+ const note = contextNote(engine);
7951
8004
  return /* @__PURE__ */ jsx(Tip, {
7952
8005
  content: /* @__PURE__ */ jsxs("div", {
7953
- className: "flex min-w-44 flex-col gap-1 py-0.5",
7954
- children: [usage.categories.map((c) => /* @__PURE__ */ jsxs("div", {
7955
- className: "flex items-center gap-2",
7956
- children: [
7957
- /* @__PURE__ */ jsx("span", {
7958
- className: "size-2 shrink-0 rounded-full bg-fg-4",
7959
- style: cssColor(c.color) ? { backgroundColor: c.color } : void 0
7960
- }),
7961
- /* @__PURE__ */ jsx("span", {
7962
- className: "flex-1",
7963
- children: c.name
7964
- }),
7965
- /* @__PURE__ */ jsx("span", {
7966
- className: "font-mono text-fg-3",
7967
- children: formatTokens(c.tokens)
7968
- })
7969
- ]
7970
- }, c.name)), /* @__PURE__ */ jsxs("div", {
7971
- className: "mt-0.5 flex items-center justify-between gap-2 border-t border-border pt-1",
7972
- children: [/* @__PURE__ */ jsx("span", { children: "Total" }), /* @__PURE__ */ jsxs("span", {
7973
- className: "font-mono text-fg-3",
8006
+ className: "flex max-w-64 min-w-44 flex-col gap-1 py-0.5",
8007
+ children: [
8008
+ usage.categories.map((c) => /* @__PURE__ */ jsxs("div", {
8009
+ className: "flex items-center gap-2",
7974
8010
  children: [
7975
- formatTokens(usage.totalTokens),
7976
- " / ",
7977
- formatTokens(usage.maxTokens),
7978
- " (",
7979
- usage.percentage.toFixed(0),
7980
- "%)"
8011
+ /* @__PURE__ */ jsx("span", {
8012
+ className: "size-2 shrink-0 rounded-full bg-fg-4",
8013
+ style: cssColor(c.color) ? { backgroundColor: c.color } : void 0
8014
+ }),
8015
+ /* @__PURE__ */ jsx("span", {
8016
+ className: "flex-1",
8017
+ children: c.name
8018
+ }),
8019
+ /* @__PURE__ */ jsx("span", {
8020
+ className: "font-mono text-fg-3",
8021
+ children: formatTokens(c.tokens)
8022
+ })
7981
8023
  ]
7982
- })]
7983
- })]
8024
+ }, c.name)),
8025
+ /* @__PURE__ */ jsxs("div", {
8026
+ className: "mt-0.5 flex items-center justify-between gap-2 border-t border-border pt-1",
8027
+ children: [/* @__PURE__ */ jsx("span", { children: "Total" }), /* @__PURE__ */ jsxs("span", {
8028
+ className: "font-mono text-fg-3",
8029
+ children: [
8030
+ formatTokens(usage.totalTokens),
8031
+ " / ",
8032
+ formatTokens(usage.maxTokens),
8033
+ " (",
8034
+ usage.percentage.toFixed(0),
8035
+ "%)"
8036
+ ]
8037
+ })]
8038
+ }),
8039
+ note ? /* @__PURE__ */ jsxs("div", {
8040
+ className: "mt-0.5 flex flex-col gap-1 border-t border-border pt-1 text-fg-3",
8041
+ children: [/* @__PURE__ */ jsx("span", { children: note.summary }), /* @__PURE__ */ jsx("span", { children: note.hint })]
8042
+ }) : null
8043
+ ]
7984
8044
  }),
7985
8045
  children: /* @__PURE__ */ jsxs("span", {
7986
8046
  className: cn("inline-flex cursor-default items-center gap-1 font-mono text-label", meterColorClass(usage.percentage)),
@@ -8076,7 +8136,10 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
8076
8136
  state.capabilities.contextUsage && state.contextUsage ? /* @__PURE__ */ jsx(Slot, {
8077
8137
  onClick: onOpenContext,
8078
8138
  hint: "Context breakdown",
8079
- children: /* @__PURE__ */ jsx(ContextMeter, { usage: state.contextUsage })
8139
+ children: /* @__PURE__ */ jsx(ContextMeter, {
8140
+ usage: state.contextUsage,
8141
+ engine: state.engine
8142
+ })
8080
8143
  }) : null,
8081
8144
  session || weekly ? /* @__PURE__ */ jsx(Slot, {
8082
8145
  onClick: onOpenUsage,
@@ -8795,6 +8858,7 @@ function itemHeight(item, m) {
8795
8858
  return acc;
8796
8859
  }
8797
8860
  case "notice": return rowH(item.text, m, { extraPx });
8861
+ case "compaction": return rowH(COMPACTION_TEXT, m, { extraPx });
8798
8862
  case "file_delivered": return rowH(`${item.path} · ${formatBytes(item.bytes)}` + (item.description ? ` · ${item.description}` : ""), m, { extraPx });
8799
8863
  default: return {
8800
8864
  px: 0,
@@ -9627,14 +9691,6 @@ function useHeightEpoch(options) {
9627
9691
  //#region src/components/agent/use-transcript-jumps.ts
9628
9692
  const AIM_PASSES = 4;
9629
9693
  const AIM_SETTLE_MS = 50;
9630
- /**
9631
- * The send re-pin: a held, escape-proof pin, not one `scrollToBottom('instant')` — a trackpad's
9632
- * trailing momentum tick reads as escape intent and aborts the one-shot before its first frame
9633
- * (GOTCHAS "The send re-pin is a held pin"). Every line is load-bearing: clear the stale escape
9634
- * flag, hold through the momentum tail, seed the `ignoreEscapes` record the library only
9635
- * installs one rAF too late, and press the first scroll synchronously. Deliberate detach
9636
- * (`stopScroll`, drag-selection) still wins immediately.
9637
- */
9638
9694
  function repinToBottom(stick) {
9639
9695
  const { state } = stick;
9640
9696
  state.escapedFromLock = false;
@@ -9730,6 +9786,7 @@ function TerminalItemView({ item, fileUrl }) {
9730
9786
  case "tool_call": return /* @__PURE__ */ jsx(ToolRow, { item });
9731
9787
  case "turn_result": return /* @__PURE__ */ jsx(TurnResultRow$1, { item });
9732
9788
  case "notice": return /* @__PURE__ */ jsx(NoticeRow$1, { item });
9789
+ case "compaction": return /* @__PURE__ */ jsx(CompactionRow$1, {});
9733
9790
  case "file_delivered": return /* @__PURE__ */ jsx(FileRow, {
9734
9791
  item,
9735
9792
  href: fileUrl?.(item.path)
@@ -10044,6 +10101,7 @@ function ToolCallCard({ item, hostImage, className }) {
10044
10101
  const badge = STATE_BADGE[status];
10045
10102
  const isError = status === "failed" || item.result?.isError === true;
10046
10103
  const Icon = toolIcon(item.name);
10104
+ const title = useToolTitle(item.name);
10047
10105
  const resultText = item.result?.text ?? "";
10048
10106
  const clipped = !fullResult && resultText.length > RESULT_PREVIEW_CHARS;
10049
10107
  const shownResult = clipped ? resultText.slice(0, RESULT_PREVIEW_CHARS) : resultText;
@@ -10052,6 +10110,10 @@ function ToolCallCard({ item, hostImage, className }) {
10052
10110
  const details = open ? /* @__PURE__ */ jsxs("div", {
10053
10111
  className: "flex flex-col gap-2 border-t border-border p-2.5",
10054
10112
  children: [
10113
+ title ? /* @__PURE__ */ jsx("p", {
10114
+ className: "font-mono text-label text-fg-4",
10115
+ children: item.name
10116
+ }) : null,
10055
10117
  /* @__PURE__ */ jsx(PlainPayload, {
10056
10118
  code: JSON.stringify(item.input, null, 2),
10057
10119
  language: "json",
@@ -10113,8 +10175,9 @@ function ToolCallCard({ item, hostImage, className }) {
10113
10175
  children: [
10114
10176
  /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0 text-fg-3" }),
10115
10177
  /* @__PURE__ */ jsx("span", {
10116
- className: "shrink-0 font-mono text-body-sm font-medium text-fg-1",
10117
- children: item.name
10178
+ className: cn("shrink-0 text-body-sm font-medium text-fg-1", title === void 0 && "font-mono"),
10179
+ title: item.name,
10180
+ children: title ?? item.name
10118
10181
  }),
10119
10182
  item.backend && item.backend !== "server" ? /* @__PURE__ */ jsx(Badge, {
10120
10183
  variant: "neutral",
@@ -10229,7 +10292,6 @@ function NoticeRow({ item }) {
10229
10292
  children: item.text
10230
10293
  });
10231
10294
  }
10232
- /** The item-view switch: one transcript item, drawn for the active variant. */
10233
10295
  function TranscriptItemView({ item, fileUrl, attachmentUrl, hostImage, terminal }) {
10234
10296
  if (terminal) return /* @__PURE__ */ jsx(TerminalItemView, {
10235
10297
  item,
@@ -10260,6 +10322,7 @@ function TranscriptItemView({ item, fileUrl, attachmentUrl, hostImage, terminal
10260
10322
  });
10261
10323
  case "turn_result": return /* @__PURE__ */ jsx(TurnResultRow, { item });
10262
10324
  case "notice": return /* @__PURE__ */ jsx(NoticeRow, { item });
10325
+ case "compaction": return /* @__PURE__ */ jsx(CompactionRow, {});
10263
10326
  case "file_delivered": return /* @__PURE__ */ jsx(FileCard, {
10264
10327
  item,
10265
10328
  href: fileUrl?.(item.path)
@@ -10267,6 +10330,20 @@ function TranscriptItemView({ item, fileUrl, attachmentUrl, hostImage, terminal
10267
10330
  default: return null;
10268
10331
  }
10269
10332
  }
10333
+ function CompactionRow() {
10334
+ return /* @__PURE__ */ jsxs("div", {
10335
+ "data-slot": "compaction",
10336
+ className: "flex items-center gap-2 py-1",
10337
+ children: [
10338
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" }),
10339
+ /* @__PURE__ */ jsxs("span", {
10340
+ className: "font-mono text-label text-fg-3",
10341
+ children: ["≡ ", COMPACTION_TEXT]
10342
+ }),
10343
+ /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
10344
+ ]
10345
+ });
10346
+ }
10270
10347
  function RecapRow({ line, since, terminal }) {
10271
10348
  const away = since === void 0 ? void 0 : formatRelativeTime(since);
10272
10349
  const text = away ? `${line} · last here ${away}` : line;
@@ -10376,12 +10453,6 @@ function StickyPromptLane({ top, height, gapClass, gapPx, terminal, scrollRoot,
10376
10453
  ]
10377
10454
  });
10378
10455
  }
10379
- /**
10380
- * The virtualized row lane and its scroll-ownership regime. Two things want to write
10381
- * `scrollTop` — the follow spring and the virtualizer's size-change corrections — and they are
10382
- * split by regime here: pinned, corrections are suppressed outright; escaped, the virtualizer
10383
- * corrects so the scrollback holds still (GOTCHAS "The transcript is virtualized").
10384
- */
10385
10456
  function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyPrompt, frameParentId, onOpenSubagent, gap, fontSize, lineHeight, items, pendingApprovals, scrubber, bookmarks, affordances, fileUrl, attachmentUrl, hostImage, jumpToRecapRef, repinRef, reveal }) {
10386
10457
  const stick = useStickToBottomContext();
10387
10458
  const [scrollElement, setScrollElement] = useState(null);
@@ -10752,6 +10823,65 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
10752
10823
  });
10753
10824
  }
10754
10825
  //#endregion
10826
+ //#region src/components/agent/held-sends.tsx
10827
+ function useHeldSends(options) {
10828
+ const [held, setHeld] = useState([]);
10829
+ const queue = useRef([]);
10830
+ const sendRef = useRef(options.send);
10831
+ sendRef.current = options.send;
10832
+ const flush = useCallback(() => {
10833
+ const queued = queue.current;
10834
+ if (queued.length === 0) return;
10835
+ queue.current = [];
10836
+ setHeld([]);
10837
+ for (const item of queued) sendRef.current(item.text, item.attachmentIds);
10838
+ }, []);
10839
+ useEffect(() => {
10840
+ if (!options.busy) flush();
10841
+ }, [options.busy, flush]);
10842
+ return {
10843
+ held,
10844
+ submit: useCallback((text, attachmentIds) => {
10845
+ if (!options.hold || !options.busy) {
10846
+ sendRef.current(text, attachmentIds);
10847
+ return;
10848
+ }
10849
+ queue.current = [...queue.current, {
10850
+ text,
10851
+ attachmentIds
10852
+ }];
10853
+ setHeld(queue.current);
10854
+ }, [options.hold, options.busy]),
10855
+ flush
10856
+ };
10857
+ }
10858
+ function HeldSendsBar({ held, onSendNow }) {
10859
+ if (held.length === 0) return null;
10860
+ return /* @__PURE__ */ jsx("div", {
10861
+ className: "px-3 pt-2",
10862
+ children: /* @__PURE__ */ jsxs("div", {
10863
+ className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 rounded-md border border-border bg-surface px-3 py-1.5 text-label text-fg-3",
10864
+ children: [
10865
+ /* @__PURE__ */ jsx(Clock, { className: "size-3.5 shrink-0" }),
10866
+ /* @__PURE__ */ jsxs("span", {
10867
+ className: "min-w-0 flex-1 truncate",
10868
+ children: [
10869
+ held.length === 1 ? "1 message" : `${held.length} messages`,
10870
+ " waiting for this turn to end — ",
10871
+ held[held.length - 1].text
10872
+ ]
10873
+ }),
10874
+ /* @__PURE__ */ jsx("button", {
10875
+ type: "button",
10876
+ onClick: onSendNow,
10877
+ className: "shrink-0 underline-offset-2 hover:underline",
10878
+ children: "Send now"
10879
+ })
10880
+ ]
10881
+ })
10882
+ });
10883
+ }
10884
+ //#endregion
10755
10885
  //#region src/components/agent/UsageMeters.tsx
10756
10886
  function useMinuteClock(active = true) {
10757
10887
  const [now, setNow] = useState(() => Date.now());
@@ -10903,7 +11033,7 @@ const INTERACTIVE = [
10903
11033
  "[role=\"radio\"]",
10904
11034
  "[role=\"tab\"]"
10905
11035
  ].join(",");
10906
- function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, bookmarks, onToggleBookmark, reveal, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, fontSize, className }) {
11036
+ function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", midTurnSend = "fold", affordances, terminalMetrics, scrubber = false, bookmarks, onToggleBookmark, reveal, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, fontSize, className }) {
10907
11037
  const effectiveTermFontSize = terminalMetrics?.fontSize ?? fontSize;
10908
11038
  const effectiveTermLineHeight = terminalMetrics?.lineHeight ?? (fontSize !== void 0 ? Math.round(fontSize * (18 / 13)) : void 0);
10909
11039
  const external = panelSurface === "external";
@@ -11061,6 +11191,11 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
11061
11191
  argumentHint: "<model>"
11062
11192
  }, ...state.commands];
11063
11193
  }, [state.commands]);
11194
+ const heldSends = useHeldSends({
11195
+ hold: midTurnSend === "hold",
11196
+ busy: busy && !ended,
11197
+ send
11198
+ });
11064
11199
  const handleSend = (text, attachmentIds) => {
11065
11200
  if (attachmentIds.length === 0) {
11066
11201
  const modelCommand = /^\/model\s+(\S+)$/.exec(text);
@@ -11075,7 +11210,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
11075
11210
  }
11076
11211
  setCaughtUp(true);
11077
11212
  repinTranscript.current?.();
11078
- send(text, attachmentIds);
11213
+ heldSends.submit(text, attachmentIds);
11079
11214
  };
11080
11215
  const actionsMenu = /* @__PURE__ */ jsxs(Menu$1, { children: [/* @__PURE__ */ jsx(MenuTrigger, { render: /* @__PURE__ */ jsx(Button, {
11081
11216
  variant: "ghost",
@@ -11165,199 +11300,206 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
11165
11300
  value: transcriptDensity,
11166
11301
  children: /* @__PURE__ */ jsx(ToolResultFetchProvider, {
11167
11302
  value: loadFullResult,
11168
- children: /* @__PURE__ */ jsx(ToolResultImageProvider, {
11169
- value: resultImages,
11170
- children: /* @__PURE__ */ jsxs("div", {
11171
- ref: panelRef,
11172
- "data-slot": "session-panel",
11173
- "data-agent-font": transcriptFont,
11174
- onClick: handleClick,
11175
- className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
11176
- style: fontSize !== void 0 ? { "--wd-font-size": `${Math.round(fontSize)}px` } : void 0,
11177
- children: [
11178
- headerTakesActions ? header({ actions: menu }) : header,
11179
- statusPlacement === "top" ? statusBar : null,
11180
- protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
11181
- level: "warning",
11182
- children: [
11183
- "Server speaks protocol v",
11184
- protocolMismatch,
11185
- ", this build renders v",
11186
- PROTOCOL_VERSION,
11187
- ". Some events may not render."
11188
- ]
11189
- }) : null,
11190
- protocolError ? /* @__PURE__ */ jsx(Notice, {
11191
- level: "error",
11192
- onDismiss: () => setProtocolError(void 0),
11193
- children: protocolError
11194
- }) : null,
11195
- subagentId !== void 0 ? /* @__PURE__ */ jsx(SubagentStrip, {
11196
- task: subagentTask,
11197
- items: subagentFrameItems,
11198
- label: subagentFallbackLabel,
11199
- onBack: leaveSubagent,
11200
- terminal,
11201
- fontSize: effectiveTermFontSize,
11202
- lineHeight: effectiveTermLineHeight
11203
- }) : null,
11204
- /* @__PURE__ */ jsx(BookmarkProvider, {
11205
- value: bookmarkHandle,
11206
- children: /* @__PURE__ */ jsx(Transcript, {
11207
- state,
11208
- fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
11209
- attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
11210
- canBrowseFiles: hostFiles.available,
11211
- hostImage,
11212
- variant: transcriptVariant,
11213
- density: transcriptDensity,
11214
- fontSize: effectiveTermFontSize,
11215
- lineHeight: effectiveTermLineHeight,
11216
- affordances,
11217
- stickyPrompt,
11218
- scrubber,
11219
- bookmarks,
11220
- replaying,
11221
- catchUp: catchUp && newCount > 0 ? {
11222
- from: catchUp.itemCount,
11223
- since: catchUp.since
11224
- } : void 0,
11225
- reveal: returnReveal ?? reveal,
11226
- frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
11227
- onOpenSubagent: enterSubagent,
11228
- emptyState,
11229
- jumpToRecapRef: jumpToRecap,
11230
- repinRef: repinTranscript
11231
- }, subagentId ?? "session")
11232
- }),
11233
- catchUp && newCount > 0 && !replaying && subagentId === void 0 ? /* @__PURE__ */ jsx("div", {
11234
- className: "px-3 pb-1",
11235
- children: /* @__PURE__ */ jsxs("div", {
11236
- "data-slot": "catch-up",
11237
- className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
11303
+ children: /* @__PURE__ */ jsx(ToolTitleProvider, {
11304
+ value: state.toolTitles,
11305
+ children: /* @__PURE__ */ jsx(ToolResultImageProvider, {
11306
+ value: resultImages,
11307
+ children: /* @__PURE__ */ jsxs("div", {
11308
+ ref: panelRef,
11309
+ "data-slot": "session-panel",
11310
+ "data-agent-font": transcriptFont,
11311
+ onClick: handleClick,
11312
+ className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
11313
+ style: fontSize !== void 0 ? { "--wd-font-size": `${Math.round(fontSize)}px` } : void 0,
11314
+ children: [
11315
+ headerTakesActions ? header({ actions: menu }) : header,
11316
+ statusPlacement === "top" ? statusBar : null,
11317
+ protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
11318
+ level: "warning",
11238
11319
  children: [
11239
- /* @__PURE__ */ jsx("span", {
11240
- "aria-hidden": true,
11241
- className: cn("select-none", terminal ? "text-fg-3" : "text-accent"),
11242
- children: "※"
11243
- }),
11244
- /* @__PURE__ */ jsxs("span", {
11245
- className: "min-w-0 flex-1 truncate",
11246
- children: [
11247
- newCount,
11248
- " new ",
11249
- newCount === 1 ? "row" : "rows",
11250
- catchUp.since !== void 0 ? ` since you were last here` : ""
11251
- ]
11252
- }),
11253
- /* @__PURE__ */ jsx("button", {
11254
- type: "button",
11255
- onClick: () => jumpToRecap.current?.(),
11256
- className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
11257
- children: "jump"
11258
- }),
11259
- /* @__PURE__ */ jsx("button", {
11260
- type: "button",
11261
- onClick: () => setCaughtUp(true),
11262
- className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
11263
- children: "dismiss"
11264
- })
11320
+ "Server speaks protocol v",
11321
+ protocolMismatch,
11322
+ ", this build renders v",
11323
+ PROTOCOL_VERSION,
11324
+ ". Some events may not render."
11265
11325
  ]
11266
- })
11267
- }) : null,
11268
- !readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx("div", {
11269
- className: cn(terminal ? "pb-2" : "px-3 pb-2"),
11270
- children: /* @__PURE__ */ jsx(PromptSurface, {
11326
+ }) : null,
11327
+ protocolError ? /* @__PURE__ */ jsx(Notice, {
11328
+ level: "error",
11329
+ onDismiss: () => setProtocolError(void 0),
11330
+ children: protocolError
11331
+ }) : null,
11332
+ subagentId !== void 0 ? /* @__PURE__ */ jsx(SubagentStrip, {
11333
+ task: subagentTask,
11334
+ items: subagentFrameItems,
11335
+ label: subagentFallbackLabel,
11336
+ onBack: leaveSubagent,
11271
11337
  terminal,
11272
- metrics: {
11338
+ fontSize: effectiveTermFontSize,
11339
+ lineHeight: effectiveTermLineHeight
11340
+ }) : null,
11341
+ /* @__PURE__ */ jsx(BookmarkProvider, {
11342
+ value: bookmarkHandle,
11343
+ children: /* @__PURE__ */ jsx(Transcript, {
11344
+ state,
11345
+ fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
11346
+ attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
11347
+ canBrowseFiles: hostFiles.available,
11348
+ hostImage,
11349
+ variant: transcriptVariant,
11350
+ density: transcriptDensity,
11273
11351
  fontSize: effectiveTermFontSize,
11274
- lineHeight: effectiveTermLineHeight
11275
- },
11276
- affordances,
11277
- children: state.pendingApprovals.map((request) => {
11278
- const isQuestion = request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0;
11279
- if (terminal) return isQuestion ? /* @__PURE__ */ jsx(TerminalQuestionPrompt, {
11280
- request,
11281
- onAnswer: approve,
11282
- onDismiss: (id) => deny(id, "Question dismissed by user")
11283
- }, request.id) : /* @__PURE__ */ jsx(TerminalPermissionPrompt, {
11284
- request,
11285
- onApprove: approve,
11286
- onDeny: deny
11287
- }, request.id);
11288
- return isQuestion ? /* @__PURE__ */ jsx(QuestionPrompt, {
11289
- request,
11290
- onAnswer: approve,
11291
- onDismiss: (id) => deny(id, "Question dismissed by user")
11292
- }, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
11293
- request,
11294
- onApprove: approve,
11295
- onDeny: deny
11296
- }, request.id);
11297
- })
11298
- })
11299
- }) : null,
11300
- readOnly || subagentId !== void 0 ? null : /* @__PURE__ */ jsx(Composer, {
11301
- ref: composerRef,
11302
- onSend: handleSend,
11303
- onInterrupt: interrupt,
11304
- busy,
11305
- disabled: ended || !sessionId,
11306
- commands: capabilities.slashCommands ? commands : void 0,
11307
- skills: capabilities.skillsList ? state.skills : void 0,
11308
- attachments,
11309
- draft,
11310
- onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
11311
- layout: controlsExternal ? "inline" : "stacked",
11312
- toolbar: controlsExternal ? void 0 : sessionControls,
11313
- fontSize: effectiveTermFontSize,
11314
- lineHeight: effectiveTermLineHeight,
11315
- affordances
11316
- }),
11317
- statusPlacement === "bottom" ? statusBar : null,
11318
- !external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
11319
- /* @__PURE__ */ jsx(SessionInfoDialog, {
11320
- state,
11321
- client,
11322
- sessionId,
11323
- open: panel === "info",
11324
- onOpenChange: (next) => setPanel(next ? "info" : void 0)
11325
- }),
11326
- /* @__PURE__ */ jsx(ContextDialog, {
11327
- usage: state.contextUsage,
11328
- open: panel === "context",
11329
- onOpenChange: (next) => setPanel(next ? "context" : void 0)
11330
- }),
11331
- /* @__PURE__ */ jsx(UsageDialog, {
11332
- rateLimits: windows,
11333
- subscriptionType: state.subscriptionType,
11334
- engine: state.engine ?? "claude",
11335
- totalCostUsd: state.totalCostUsd,
11336
- updatedAt: usageUpdatedAt,
11337
- open: panel === "usage",
11338
- onOpenChange: (next) => setPanel(next ? "usage" : void 0)
11339
- }),
11340
- /* @__PURE__ */ jsx(McpDialog, {
11341
- client,
11342
- sessionId,
11343
- canManageServers: capabilities.mcpServerActions,
11344
- open: panel === "mcp",
11345
- onOpenChange: (next) => setPanel(next ? "mcp" : void 0)
11352
+ lineHeight: effectiveTermLineHeight,
11353
+ affordances,
11354
+ stickyPrompt,
11355
+ scrubber,
11356
+ bookmarks,
11357
+ replaying,
11358
+ catchUp: catchUp && newCount > 0 ? {
11359
+ from: catchUp.itemCount,
11360
+ since: catchUp.since
11361
+ } : void 0,
11362
+ reveal: returnReveal ?? reveal,
11363
+ frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
11364
+ onOpenSubagent: enterSubagent,
11365
+ emptyState,
11366
+ jumpToRecapRef: jumpToRecap,
11367
+ repinRef: repinTranscript
11368
+ }, subagentId ?? "session")
11346
11369
  }),
11347
- /* @__PURE__ */ jsx(SkillsDialog, {
11348
- skills: state.skills,
11349
- open: panel === "skills",
11350
- onOpenChange: (next) => setPanel(next ? "skills" : void 0),
11351
- onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
11352
- }),
11353
- /* @__PURE__ */ jsx(HostFilesDialog, {
11354
- client,
11355
- cwd: state.cwd,
11356
- open: panel === "files",
11357
- onOpenChange: (next) => setPanel(next ? "files" : void 0)
11358
- })
11359
- ] }) : null
11360
- ]
11370
+ catchUp && newCount > 0 && !replaying && subagentId === void 0 ? /* @__PURE__ */ jsx("div", {
11371
+ className: "px-3 pb-1",
11372
+ children: /* @__PURE__ */ jsxs("div", {
11373
+ "data-slot": "catch-up",
11374
+ className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
11375
+ children: [
11376
+ /* @__PURE__ */ jsx("span", {
11377
+ "aria-hidden": true,
11378
+ className: cn("select-none", terminal ? "text-fg-3" : "text-accent"),
11379
+ children: "※"
11380
+ }),
11381
+ /* @__PURE__ */ jsxs("span", {
11382
+ className: "min-w-0 flex-1 truncate",
11383
+ children: [
11384
+ newCount,
11385
+ " new ",
11386
+ newCount === 1 ? "row" : "rows",
11387
+ catchUp.since !== void 0 ? ` since you were last here` : ""
11388
+ ]
11389
+ }),
11390
+ /* @__PURE__ */ jsx("button", {
11391
+ type: "button",
11392
+ onClick: () => jumpToRecap.current?.(),
11393
+ className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
11394
+ children: "jump"
11395
+ }),
11396
+ /* @__PURE__ */ jsx("button", {
11397
+ type: "button",
11398
+ onClick: () => setCaughtUp(true),
11399
+ className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
11400
+ children: "dismiss"
11401
+ })
11402
+ ]
11403
+ })
11404
+ }) : null,
11405
+ !readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx("div", {
11406
+ className: cn(terminal ? "pb-2" : "px-3 pb-2"),
11407
+ children: /* @__PURE__ */ jsx(PromptSurface, {
11408
+ terminal,
11409
+ metrics: {
11410
+ fontSize: effectiveTermFontSize,
11411
+ lineHeight: effectiveTermLineHeight
11412
+ },
11413
+ affordances,
11414
+ children: state.pendingApprovals.map((request) => {
11415
+ const isQuestion = request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0;
11416
+ if (terminal) return isQuestion ? /* @__PURE__ */ jsx(TerminalQuestionPrompt, {
11417
+ request,
11418
+ onAnswer: approve,
11419
+ onDismiss: (id) => deny(id, "Question dismissed by user")
11420
+ }, request.id) : /* @__PURE__ */ jsx(TerminalPermissionPrompt, {
11421
+ request,
11422
+ onApprove: approve,
11423
+ onDeny: deny
11424
+ }, request.id);
11425
+ return isQuestion ? /* @__PURE__ */ jsx(QuestionPrompt, {
11426
+ request,
11427
+ onAnswer: approve,
11428
+ onDismiss: (id) => deny(id, "Question dismissed by user")
11429
+ }, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
11430
+ request,
11431
+ onApprove: approve,
11432
+ onDeny: deny
11433
+ }, request.id);
11434
+ })
11435
+ })
11436
+ }) : null,
11437
+ readOnly || subagentId !== void 0 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(HeldSendsBar, {
11438
+ held: heldSends.held,
11439
+ onSendNow: heldSends.flush
11440
+ }), /* @__PURE__ */ jsx(Composer, {
11441
+ ref: composerRef,
11442
+ onSend: handleSend,
11443
+ onInterrupt: interrupt,
11444
+ busy,
11445
+ disabled: ended || !sessionId,
11446
+ commands: capabilities.slashCommands ? commands : void 0,
11447
+ skills: capabilities.skillsList ? state.skills : void 0,
11448
+ attachments,
11449
+ draft,
11450
+ onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
11451
+ layout: controlsExternal ? "inline" : "stacked",
11452
+ toolbar: controlsExternal ? void 0 : sessionControls,
11453
+ fontSize: effectiveTermFontSize,
11454
+ lineHeight: effectiveTermLineHeight,
11455
+ affordances
11456
+ })] }),
11457
+ statusPlacement === "bottom" ? statusBar : null,
11458
+ !external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
11459
+ /* @__PURE__ */ jsx(SessionInfoDialog, {
11460
+ state,
11461
+ client,
11462
+ sessionId,
11463
+ open: panel === "info",
11464
+ onOpenChange: (next) => setPanel(next ? "info" : void 0)
11465
+ }),
11466
+ /* @__PURE__ */ jsx(ContextDialog, {
11467
+ usage: state.contextUsage,
11468
+ engine: state.engine ?? "claude",
11469
+ open: panel === "context",
11470
+ onOpenChange: (next) => setPanel(next ? "context" : void 0)
11471
+ }),
11472
+ /* @__PURE__ */ jsx(UsageDialog, {
11473
+ rateLimits: windows,
11474
+ subscriptionType: state.subscriptionType,
11475
+ engine: state.engine ?? "claude",
11476
+ totalCostUsd: state.totalCostUsd,
11477
+ updatedAt: usageUpdatedAt,
11478
+ open: panel === "usage",
11479
+ onOpenChange: (next) => setPanel(next ? "usage" : void 0)
11480
+ }),
11481
+ /* @__PURE__ */ jsx(McpDialog, {
11482
+ client,
11483
+ sessionId,
11484
+ canManageServers: capabilities.mcpServerActions,
11485
+ open: panel === "mcp",
11486
+ onOpenChange: (next) => setPanel(next ? "mcp" : void 0)
11487
+ }),
11488
+ /* @__PURE__ */ jsx(SkillsDialog, {
11489
+ skills: state.skills,
11490
+ open: panel === "skills",
11491
+ onOpenChange: (next) => setPanel(next ? "skills" : void 0),
11492
+ onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
11493
+ }),
11494
+ /* @__PURE__ */ jsx(HostFilesDialog, {
11495
+ client,
11496
+ cwd: state.cwd,
11497
+ open: panel === "files",
11498
+ onOpenChange: (next) => setPanel(next ? "files" : void 0)
11499
+ })
11500
+ ] }) : null
11501
+ ]
11502
+ })
11361
11503
  })
11362
11504
  })
11363
11505
  })
@@ -11426,6 +11568,6 @@ function Notice({ level, onDismiss, children }) {
11426
11568
  });
11427
11569
  }
11428
11570
  //#endregion
11429
- export { isMutatingTool as $, PERMISSION_MODES as A, MenuItem as At, Composer as B, Input as Bt, TerminalPermissionPrompt as C, DialogClose as Ct, SubagentStrip as D, DialogTrigger as Dt, parseUserQuestions as E, DialogRow as Et, SkillsDialog as F, SelectItem as Ft, previewPatch as G, cn as Gt, TerminalSurface as H, badgeVariants as Ht, McpDialog as I, SelectItemText as It, Ink as J, Band as K, HostFilesDialog as L, SelectTrigger as Lt, permissionModeChoices as M, MenuTrigger as Mt, permissionModeMeta as N, Select$1 as Nt, PermissionPrompt as O, Menu$1 as Ot, ModelSelect as P, SelectContent as Pt, useAffordances as Q, EntryIcon as R, SelectValue as Rt, TerminalQuestionPrompt as S, DialogBody as St, QuestionPrompt as T, DialogHeader as Tt, TerminalMarkdown as U, Button as Ut, skillPrompt as V, Badge as Vt, TerminalDiff as W, buttonVariants as Wt, CopyAction as X, Row as Y, WithActions as Z, ConversationContent as _, copyText as _t, Transcript as a, commandTrigger as at, STATUS_META as b, TooltipProvider as bt, PromptTokenText as c, usePromptAreaState as ct, FileCard as d, segmentsToPlainText as dt, toolIcon as et, TerminalItemView as f, ProgressRing as ft, Conversation as g, CopyButton as gt, Loader as h, Spinner as ht, useMinuteClock as i, useTranscriptVariant as it, PermissionModeSelect as j, MenuSeparator as jt, Response as k, MenuContent as kt, Message as l, PromptArea as lt, SessionEmptyState as m, CodeBlock as mt, UsageDialog as n, TranscriptVariantProvider as nt, ToolCallCard as o, hashtagTrigger as ot, TerminalTranscript as p, Splitter as pt, Blank as q, UsageMeters as r, useTranscriptDensity as rt, Reasoning as s, mentionTrigger as st, SessionPanel as t, TranscriptDensityProvider as tt, MessageContent as u, plainTextToSegments as ut, ConversationScrollButton as v, Tip as vt, QUESTION_BEHAVIORS as w, DialogContent as wt, SessionInfoDialog as x, Dialog$1 as xt, StatusBar as y, TooltipContent as yt, ContextDialog as z, PortalScope as zt };
11571
+ export { Ink as $, PermissionPrompt as A, DialogHeader as At, EntryIcon as B, SelectItem as Bt, SessionInfoDialog as C, Tip as Ct, QuestionPrompt as D, DialogBody as Dt, QUESTION_BEHAVIORS as E, Dialog$1 as Et, permissionModeMeta as F, MenuItem as Ft, TerminalSurface as G, Input as Gt, contextNote as H, SelectTrigger as Ht, ModelSelect as I, MenuSeparator as It, TerminalMarkdown as J, Button as Jt, ToolTitleProvider as K, Badge as Kt, SkillsDialog as L, MenuTrigger as Lt, PERMISSION_MODES as M, DialogTrigger as Mt, PermissionModeSelect as N, Menu$1 as Nt, parseUserQuestions as O, DialogClose as Ot, permissionModeChoices as P, MenuContent as Pt, Blank as Q, McpDialog as R, Select$1 as Rt, STATUS_META as S, copyText as St, TerminalPermissionPrompt as T, TooltipProvider as Tt, Composer as U, SelectValue as Ut, ContextDialog as V, SelectItemText as Vt, skillPrompt as W, PortalScope as Wt, previewPatch as X, cn as Xt, TerminalDiff as Y, buttonVariants as Yt, Band as Z, Loader as _, ProgressRing as _t, HeldSendsBar as a, toolIcon as at, ConversationScrollButton as b, Spinner as bt, ToolCallCard as c, useTranscriptDensity as ct, Message as d, hashtagTrigger as dt, Row as et, MessageContent as f, mentionTrigger as ft, SessionEmptyState as g, segmentsToPlainText as gt, TerminalTranscript as h, plainTextToSegments as ht, useMinuteClock as i, isMutatingTool as it, Response as j, DialogRow as jt, SubagentStrip as k, DialogContent as kt, Reasoning as l, useTranscriptVariant as lt, TerminalItemView as m, PromptArea as mt, UsageDialog as n, WithActions as nt, useHeldSends as o, TranscriptDensityProvider as ot, FileCard as p, usePromptAreaState as pt, useToolTitle as q, badgeVariants as qt, UsageMeters as r, useAffordances as rt, Transcript as s, TranscriptVariantProvider as st, SessionPanel as t, CopyAction as tt, PromptTokenText as u, commandTrigger as ut, Conversation as v, Splitter as vt, TerminalQuestionPrompt as w, TooltipContent as wt, StatusBar as x, CopyButton as xt, ConversationContent as y, CodeBlock as yt, HostFilesDialog as z, SelectContent as zt };
11430
11572
 
11431
- //# sourceMappingURL=SessionPanel-I5QSLLb0.mjs.map
11573
+ //# sourceMappingURL=SessionPanel-DQp2oStr.mjs.map