@workerdeck/ui 2.9.0 → 2.10.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 (34) hide show
  1. package/build/index.d.mts +52 -6
  2. package/build/index.mjs +23 -9
  3. package/build/index.mjs.map +1 -1
  4. package/build/scoped.css +20 -0
  5. package/build/{SessionPanel-BClL7zUS.mjs → use-path-links-CvcxdUXL.mjs} +437 -135
  6. package/build/use-path-links-CvcxdUXL.mjs.map +1 -0
  7. package/build/workspace.mjs +3 -83
  8. package/build/workspace.mjs.map +1 -1
  9. package/package.json +4 -4
  10. package/src/components/agent/Composer.tsx +7 -4
  11. package/src/components/agent/PromptTokenText.tsx +11 -3
  12. package/src/components/agent/SessionInfoDialog.tsx +1 -1
  13. package/src/components/agent/SessionItem.tsx +9 -5
  14. package/src/components/agent/SessionList.tsx +1 -1
  15. package/src/components/agent/SessionPanel.tsx +4 -1
  16. package/src/components/agent/StatusBar.tsx +1 -1
  17. package/src/components/agent/Transcript.tsx +83 -79
  18. package/src/components/agent/TranscriptItemView.tsx +1 -1
  19. package/src/components/agent/UsageDialog.tsx +87 -6
  20. package/src/components/agent/composer-commands.ts +14 -2
  21. package/src/components/agent/use-path-links.ts +5 -19
  22. package/src/components/prompt-area/clipboard-helpers.ts +13 -4
  23. package/src/components/prompt-area/dom-helpers.ts +10 -1
  24. package/src/components/prompt-area/index.ts +10 -1
  25. package/src/components/prompt-area/prompt-area-engine.ts +23 -14
  26. package/src/components/prompt-area/types.ts +20 -0
  27. package/src/components/prompt-area/use-prompt-area-keydown.ts +2 -1
  28. package/src/components/prompt-area/use-prompt-area.ts +8 -2
  29. package/src/components/terminal/StatusLine.tsx +3 -2
  30. package/src/components/terminal/items.tsx +3 -2
  31. package/src/index.ts +3 -1
  32. package/src/lib/path-match.ts +51 -0
  33. package/src/lib/session-cost.ts +65 -0
  34. package/build/SessionPanel-BClL7zUS.mjs.map +0 -1
@@ -9,7 +9,7 @@ import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowRight, ArrowUp, AtSign, Bra
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, parseTodoWriteInput, parseUserQuestions, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, usageInfos, usageIsStale, visibleTasks } from "@workerdeck/protocol";
12
+ import { PRICING_NOTE, PROTOCOL_VERSION, UNPRICED_WARN_SHARE, canonicalModel, costOf, costOfByModel, mergeUsage, orderUsageWindows, parseTodoWriteInput, parseUserQuestions, rateFor, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, totalTokens, usageInfos, usageIsStale, visibleTasks } 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";
@@ -464,13 +464,19 @@ function ProgressRing({ value, size = 13, strokeWidth = 2, className }) {
464
464
  //#endregion
465
465
  //#region src/components/prompt-area/prompt-area-engine.ts
466
466
  /**
467
+ * A chip's plain-text form: `{sigil ?? trigger}{displayText}` (e.g., "@Alice").
468
+ */
469
+ function chipPlainText(seg) {
470
+ return `${seg.sigil ?? seg.trigger}${seg.displayText}`;
471
+ }
472
+ /**
467
473
  * Converts an array of segments to a plain text string.
468
- * Chips are represented as `{trigger}{displayText}` (e.g., "@Alice").
474
+ * Chips are represented by {@link chipPlainText}.
469
475
  */
470
476
  function segmentsToPlainText(segments) {
471
477
  return segments.map((seg) => {
472
478
  if (seg.type === "text") return seg.text;
473
- return `${seg.trigger}${seg.displayText}`;
479
+ return chipPlainText(seg);
474
480
  }).join("");
475
481
  }
476
482
  /**
@@ -495,7 +501,7 @@ function truncateSegmentsToLength(segments, maxLength) {
495
501
  const result = [];
496
502
  let length = 0;
497
503
  for (const seg of segments) {
498
- const segLength = seg.type === "text" ? seg.text.length : seg.trigger.length + seg.displayText.length;
504
+ const segLength = seg.type === "text" ? seg.text.length : chipPlainText(seg).length;
499
505
  if (length + segLength <= maxLength) {
500
506
  result.push(seg);
501
507
  length += segLength;
@@ -597,13 +603,13 @@ function detectActiveTrigger(text, cursorPos, triggers) {
597
603
  * @param chip - The chip data (value, displayText, optional data)
598
604
  * @returns New segments array with the chip inserted, and the new cursor position
599
605
  */
600
- function resolveChip(segments, activeTrigger, chip) {
606
+ function resolveChip(segments, activeTrigger, chip, trailingText = " ") {
601
607
  const triggerStart = activeTrigger.startOffset;
602
608
  const triggerEnd = triggerStart + 1 + activeTrigger.query.length;
603
609
  const newSegments = [];
604
610
  let offset = 0;
605
611
  for (const seg of segments) if (seg.type === "chip") {
606
- const chipText = `${seg.trigger}${seg.displayText}`;
612
+ const chipText = chipPlainText(seg);
607
613
  const chipStart = offset;
608
614
  const chipEnd = offset + chipText.length;
609
615
  if (chipEnd <= triggerStart || chipStart >= triggerEnd) newSegments.push(seg);
@@ -625,17 +631,18 @@ function resolveChip(segments, activeTrigger, chip) {
625
631
  trigger: activeTrigger.config.char,
626
632
  value: chip.value,
627
633
  displayText: chip.displayText,
634
+ ...chip.sigil !== void 0 ? { sigil: chip.sigil } : {},
628
635
  ...chip.data !== void 0 ? { data: chip.data } : {},
629
636
  ...chip.autoResolved ? { autoResolved: true } : {}
630
637
  };
631
638
  newSegments.push(newChip);
632
639
  if (afterText) newSegments.push({
633
640
  type: "text",
634
- text: " " + afterText.replace(/^\s/, "")
641
+ text: trailingText + afterText.replace(/^\s/, "")
635
642
  });
636
643
  else newSegments.push({
637
644
  type: "text",
638
- text: " "
645
+ text: trailingText
639
646
  });
640
647
  }
641
648
  offset = textEnd;
@@ -645,12 +652,12 @@ function resolveChip(segments, activeTrigger, chip) {
645
652
  let runningOffset = 0;
646
653
  for (const seg of merged) if (seg.type === "text") runningOffset += seg.text.length;
647
654
  else {
648
- runningOffset += seg.trigger.length + seg.displayText.length;
655
+ runningOffset += chipPlainText(seg).length;
649
656
  if (seg.value === chip.value && seg.displayText === chip.displayText && seg.trigger === activeTrigger.config.char) lastChipEndOffset = runningOffset;
650
657
  }
651
658
  return {
652
659
  segments: merged,
653
- cursorOffset: lastChipEndOffset === -1 ? runningOffset : lastChipEndOffset + 1
660
+ cursorOffset: lastChipEndOffset === -1 ? runningOffset : lastChipEndOffset + trailingText.length
654
661
  };
655
662
  }
656
663
  /**
@@ -671,7 +678,7 @@ function resolveText(segments, activeTrigger, text) {
671
678
  let cursorOffset = triggerStart + text.length;
672
679
  for (const seg of segments) {
673
680
  if (seg.type === "chip") {
674
- const chipEnd = offset + `${seg.trigger}${seg.displayText}`.length;
681
+ const chipEnd = offset + chipPlainText(seg).length;
675
682
  if (chipEnd <= triggerStart || offset >= triggerEnd) newSegments.push(seg);
676
683
  offset = chipEnd;
677
684
  continue;
@@ -729,7 +736,7 @@ function revertChipAtIndex(segments, index) {
729
736
  if (index < 0 || index >= segments.length) return null;
730
737
  const seg = segments[index];
731
738
  if (seg.type !== "chip" || !seg.autoResolved) return null;
732
- const revertedText = `${seg.trigger}${seg.displayText}`;
739
+ const revertedText = chipPlainText(seg);
733
740
  return {
734
741
  segments: mergeAdjacentTextSegments([
735
742
  ...segments.slice(0, index),
@@ -826,7 +833,7 @@ function replaceTextRange(segments, start, end, replacement) {
826
833
  let offset = 0;
827
834
  let inserted = false;
828
835
  for (const seg of segments) if (seg.type === "chip") {
829
- const chipText = `${seg.trigger}${seg.displayText}`;
836
+ const chipText = chipPlainText(seg);
830
837
  const chipStart = offset;
831
838
  const chipEnd = offset + chipText.length;
832
839
  if (!inserted && start === end && chipStart === start) {
@@ -1388,6 +1395,10 @@ function getChipData(node) {
1388
1395
  if (!raw) return;
1389
1396
  return safeJsonParse(raw);
1390
1397
  }
1398
+ function getChipSigil(node) {
1399
+ if (!isChipElement(node)) return;
1400
+ return node.dataset.chipSigil;
1401
+ }
1391
1402
  /**
1392
1403
  * Length of a chip's plain-text representation (`trigger + displayText`).
1393
1404
  *
@@ -1397,7 +1408,7 @@ function getChipData(node) {
1397
1408
  * `textContent` for resilience against externally-mutated nodes.
1398
1409
  */
1399
1410
  function chipNodeTextLength(node) {
1400
- const trigger = node.dataset.chipTrigger ?? "";
1411
+ const trigger = node.dataset.chipSigil ?? node.dataset.chipTrigger ?? "";
1401
1412
  const display = node.dataset.chipDisplay ?? node.textContent ?? "";
1402
1413
  return trigger.length + display.length;
1403
1414
  }
@@ -1416,6 +1427,7 @@ function chipNodeToSegment(node) {
1416
1427
  const value = getChipValue(node);
1417
1428
  const displayText = getChipDisplay(node);
1418
1429
  if (!trigger || value === void 0 || !displayText) return null;
1430
+ const sigil = getChipSigil(node);
1419
1431
  const data = getChipData(node);
1420
1432
  const autoResolved = getChipAutoResolved(node);
1421
1433
  return {
@@ -1423,6 +1435,7 @@ function chipNodeToSegment(node) {
1423
1435
  trigger,
1424
1436
  value,
1425
1437
  displayText,
1438
+ ...sigil !== void 0 ? { sigil } : {},
1426
1439
  ...data !== void 0 ? { data } : {},
1427
1440
  ...autoResolved ? { autoResolved: true } : {}
1428
1441
  };
@@ -2052,7 +2065,7 @@ function serializeFragmentToPlainText(fragment) {
2052
2065
  text += value;
2053
2066
  },
2054
2067
  onChip: (node) => {
2055
- text += (getChipTrigger(node) ?? "") + (getChipDisplay(node) ?? "");
2068
+ text += (getChipSigil(node) ?? getChipTrigger(node) ?? "") + (getChipDisplay(node) ?? "");
2056
2069
  },
2057
2070
  onBreak: () => {
2058
2071
  text += "\n";
@@ -2106,6 +2119,7 @@ function parseSegmentsFromClipboard(json) {
2106
2119
  trigger: item.trigger,
2107
2120
  value: item.value,
2108
2121
  displayText: item.displayText,
2122
+ ...typeof item.sigil === "string" ? { sigil: item.sigil } : {},
2109
2123
  ...item.data !== void 0 ? { data: item.data } : {},
2110
2124
  ...item.autoResolved ? { autoResolved: true } : {}
2111
2125
  };
@@ -2140,7 +2154,7 @@ function insertSegmentsAtCursor(currentSegments, pastedSegments, editor) {
2140
2154
  };
2141
2155
  for (const seg of currentSegments) {
2142
2156
  if (seg.type === "chip") {
2143
- const chipLen = seg.trigger.length + seg.displayText.length;
2157
+ const chipLen = chipPlainText(seg).length;
2144
2158
  if (offset >= cursorOffset) insertOnce();
2145
2159
  result.push(seg);
2146
2160
  offset += chipLen;
@@ -2618,7 +2632,7 @@ function usePromptAreaKeydown({ editorRef, triggers, markdownEnabled, submitOnEn
2618
2632
  for (let i = 0; i < segIdx; i++) {
2619
2633
  const s = segments[i];
2620
2634
  if (s.type === "text") targetOffset += s.text.length;
2621
- else targetOffset += s.trigger.length + s.displayText.length;
2635
+ else targetOffset += chipPlainText(s).length;
2622
2636
  }
2623
2637
  targetOffset += result.revertedText.length;
2624
2638
  onChange(result.segments);
@@ -3229,6 +3243,7 @@ function usePromptArea({ value, onChange, triggers = NO_TRIGGERS, disabled = fal
3229
3243
  chip.dataset.chipTrigger = seg.trigger;
3230
3244
  chip.dataset.chipValue = seg.value;
3231
3245
  chip.dataset.chipDisplay = seg.displayText;
3246
+ if (seg.sigil !== void 0) chip.dataset.chipSigil = seg.sigil;
3232
3247
  if (seg.data !== void 0) {
3233
3248
  const json = safeJsonStringify(seg.data);
3234
3249
  if (json) chip.dataset.chipData = json;
@@ -3238,7 +3253,7 @@ function usePromptArea({ value, onChange, triggers = NO_TRIGGERS, disabled = fal
3238
3253
  const chipStyle = triggerConfig?.chipStyle ?? "pill";
3239
3254
  chip.dataset.chipStyle = chipStyle;
3240
3255
  chip.className = cn("prompt-area-chip", chipStyle === "inline" && "prompt-area-chip--inline", triggerConfig?.chipClassName);
3241
- chip.textContent = `${seg.trigger}${seg.displayText}`;
3256
+ chip.textContent = chipPlainText(seg);
3242
3257
  chip.setAttribute("role", "button");
3243
3258
  chip.setAttribute("tabindex", "-1");
3244
3259
  editor.appendChild(chip);
@@ -3483,9 +3498,11 @@ function usePromptArea({ value, onChange, triggers = NO_TRIGGERS, disabled = fal
3483
3498
  return;
3484
3499
  }
3485
3500
  const displayText = activeTrigger.config.onSelect?.(suggestion) ?? suggestion.label;
3501
+ const options = activeTrigger.config.chipOptions?.(suggestion);
3486
3502
  const chipData = {
3487
3503
  value: suggestion.value,
3488
3504
  displayText: displayText || suggestion.label,
3505
+ ...options?.sigil !== void 0 ? { sigil: options.sigil } : {},
3489
3506
  data: suggestion.data
3490
3507
  };
3491
3508
  if (chipEditing.trySelectEditingChip(segments, chipData, activeTrigger.config.char, events.pushUndo)) {
@@ -3495,7 +3512,7 @@ function usePromptArea({ value, onChange, triggers = NO_TRIGGERS, disabled = fal
3495
3512
  }, 0);
3496
3513
  return;
3497
3514
  }
3498
- const result = resolveChip(segments, activeTrigger, chipData);
3515
+ const result = resolveChip(segments, activeTrigger, chipData, options?.trailingText);
3499
3516
  onChange(result.segments);
3500
3517
  renderSegmentsToDOM(result.segments);
3501
3518
  onChipAdd?.({
@@ -4420,9 +4437,16 @@ const KIND_ORDER = {
4420
4437
  function cleanCommandName(name) {
4421
4438
  return name.replace(/\s*\(MCP\)$/i, "");
4422
4439
  }
4440
+ function skillToken(skill) {
4441
+ return `$${skill.name}`;
4442
+ }
4443
+ function skillTrailingText(skill) {
4444
+ const token = skillToken(skill);
4445
+ const rest = (skill.defaultPrompt ?? "").split(token).join(" ").replace(/\s+/g, " ").trim();
4446
+ return rest ? ` ${rest} ` : " ";
4447
+ }
4423
4448
  function skillPrompt(skill) {
4424
- const base = skill.defaultPrompt?.trim() || `Use the ${skill.displayName ?? skill.name} skill:`;
4425
- return /\s$/.test(base) ? base : base + " ";
4449
+ return skillToken(skill) + skillTrailingText(skill);
4426
4450
  }
4427
4451
  function mergeComposerRows(sources) {
4428
4452
  const rows = [];
@@ -4641,6 +4665,38 @@ function usePulse(animated) {
4641
4665
  return PULSE_FRAMES[frame % PULSE_FRAMES.length];
4642
4666
  }
4643
4667
  //#endregion
4668
+ //#region src/components/agent/PromptTokenText.tsx
4669
+ const SkillNamesContext = createContext(void 0);
4670
+ function SkillNamesProvider({ names, children }) {
4671
+ return /* @__PURE__ */ jsx(SkillNamesContext.Provider, {
4672
+ value: names,
4673
+ children
4674
+ });
4675
+ }
4676
+ function PromptTokenText({ text, className }) {
4677
+ const skills = useContext(SkillNamesContext);
4678
+ const tokens = scanPromptTokens(text, { skills });
4679
+ if (tokens.length === 0) return /* @__PURE__ */ jsx("span", {
4680
+ className,
4681
+ children: text
4682
+ });
4683
+ const parts = [];
4684
+ let cursor = 0;
4685
+ for (const [index, token] of tokens.entries()) {
4686
+ if (token.start > cursor) parts.push(text.slice(cursor, token.start));
4687
+ parts.push(/* @__PURE__ */ jsx("span", {
4688
+ className: cn("font-mono", token.kind === "file" ? "text-accent" : "text-info"),
4689
+ children: token.text
4690
+ }, `${token.start}-${index}`));
4691
+ cursor = token.end;
4692
+ }
4693
+ if (cursor < text.length) parts.push(text.slice(cursor));
4694
+ return /* @__PURE__ */ jsx("span", {
4695
+ className,
4696
+ children: parts.map((part, index) => /* @__PURE__ */ jsx(Fragment, { children: part }, index))
4697
+ });
4698
+ }
4699
+ //#endregion
4644
4700
  //#region src/components/terminal/affordances.tsx
4645
4701
  const DEFAULTS = {
4646
4702
  hover: true,
@@ -5413,7 +5469,7 @@ function UserRow({ item }) {
5413
5469
  glyph: index === 0 ? "❯" : void 0,
5414
5470
  glyphTone: "dim",
5415
5471
  tone: "fg",
5416
- children: line || "\xA0"
5472
+ children: line ? /* @__PURE__ */ jsx(PromptTokenText, { text: line }) : "\xA0"
5417
5473
  }, index)) : null]
5418
5474
  })
5419
5475
  });
@@ -5645,7 +5701,7 @@ function TurnResultRow$1({ item }) {
5645
5701
  " · ",
5646
5702
  formatDuration(item.durationMs),
5647
5703
  " · ",
5648
- formatCost(item.totalCostUsd)
5704
+ formatCost(item.costUsd ?? item.totalCostUsd)
5649
5705
  ]
5650
5706
  }), item.errors?.map((message, index) => /* @__PURE__ */ jsx(Row, {
5651
5707
  tone: "red",
@@ -5795,9 +5851,15 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
5795
5851
  }),
5796
5852
  insertAsText: (suggestion) => {
5797
5853
  const row = byTag.get(String(suggestion.data));
5798
- if (row?.kind === "skill") return skillPrompt(row.skill);
5799
5854
  return row?.kind === "client" && row.command.requiresArgs ? `/${row.name} ` : void 0;
5800
5855
  },
5856
+ chipOptions: (suggestion) => {
5857
+ const row = byTag.get(String(suggestion.data));
5858
+ return row?.kind === "skill" ? {
5859
+ sigil: "$",
5860
+ trailingText: skillTrailingText(row.skill)
5861
+ } : void 0;
5862
+ },
5801
5863
  onSelect: (suggestion) => suggestion.value,
5802
5864
  chipClassName: "font-mono"
5803
5865
  }));
@@ -8218,7 +8280,7 @@ function SessionInfoDialog({ state, client, sessionId, open, onOpenChange }) {
8218
8280
  /* @__PURE__ */ jsx(DialogRow, {
8219
8281
  label: "Cost",
8220
8282
  mono: true,
8221
- children: formatCost(state.totalCostUsd)
8283
+ children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
8222
8284
  })
8223
8285
  ]
8224
8286
  }),
@@ -8528,7 +8590,7 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
8528
8590
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
8529
8591
  /* @__PURE__ */ jsx("span", {
8530
8592
  className: "font-mono text-label text-fg-3",
8531
- children: formatCost(state.totalCostUsd)
8593
+ children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
8532
8594
  }),
8533
8595
  actions ? /* @__PURE__ */ jsx("span", {
8534
8596
  className: "self-center",
@@ -10304,30 +10366,6 @@ function MessageContent({ className, ...props }) {
10304
10366
  });
10305
10367
  }
10306
10368
  //#endregion
10307
- //#region src/components/agent/PromptTokenText.tsx
10308
- function PromptTokenText({ text, className }) {
10309
- const tokens = scanPromptTokens(text);
10310
- if (tokens.length === 0) return /* @__PURE__ */ jsx("span", {
10311
- className,
10312
- children: text
10313
- });
10314
- const parts = [];
10315
- let cursor = 0;
10316
- for (const [index, token] of tokens.entries()) {
10317
- if (token.start > cursor) parts.push(text.slice(cursor, token.start));
10318
- parts.push(/* @__PURE__ */ jsx("span", {
10319
- className: cn("font-mono", token.kind === "file" ? "text-accent" : "text-info"),
10320
- children: token.text
10321
- }, `${token.start}-${index}`));
10322
- cursor = token.end;
10323
- }
10324
- if (cursor < text.length) parts.push(text.slice(cursor));
10325
- return /* @__PURE__ */ jsx("span", {
10326
- className,
10327
- children: parts.map((part, index) => /* @__PURE__ */ jsx(Fragment, { children: part }, index))
10328
- });
10329
- }
10330
- //#endregion
10331
10369
  //#region src/components/agent/Reasoning.tsx
10332
10370
  function Reasoning({ children, isStreaming = false, defaultOpen, className }) {
10333
10371
  const [open, setOpen] = useState(defaultOpen ?? isStreaming);
@@ -10635,7 +10673,7 @@ function TurnResultRow({ item }) {
10635
10673
  " · ",
10636
10674
  formatDuration(item.durationMs),
10637
10675
  " · ",
10638
- formatCost(item.totalCostUsd)
10676
+ formatCost(item.costUsd ?? item.totalCostUsd)
10639
10677
  ]
10640
10678
  }),
10641
10679
  /* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
@@ -11108,85 +11146,116 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
11108
11146
  terminal,
11109
11147
  brief
11110
11148
  ]);
11149
+ const skillNames = useMemo(() => state.skills?.map((skill) => skill.name), [state.skills]);
11111
11150
  return /* @__PURE__ */ jsx(TranscriptVariantProvider, {
11112
11151
  value: variant,
11113
- children: /* @__PURE__ */ jsxs(Conversation, {
11114
- className: cn(replaying && "invisible", className),
11115
- children: [
11116
- /* @__PURE__ */ jsx(ConversationContent, {
11117
- className: cn(terminal && "gap-0 p-0"),
11118
- children: /* @__PURE__ */ jsxs(TerminalShell, {
11119
- active: terminal,
11120
- fontSize,
11121
- lineHeight,
11122
- affordances,
11123
- children: [
11124
- frame ? frameTask === void 0 && !replaying ? /* @__PURE__ */ jsx("div", {
11125
- className: cn(terminal ? "term-row text-fg-4" : "p-4 text-body-sm text-fg-4"),
11126
- children: "This sub-agent's work is not in this transcript."
11127
- }) : null : items.length === 0 && state.status !== "starting" ? emptyState !== void 0 ? emptyState : /* @__PURE__ */ jsx(SessionEmptyState, {
11128
- cwd: state.cwd,
11129
- hasCommands: !!state.commands?.length,
11130
- hasSkills: !!state.skills?.some((s) => s.enabled),
11131
- canBrowseFiles
11132
- }) : null,
11133
- frame && frameTask === void 0 && !replaying ? null : /* @__PURE__ */ jsx(TranscriptRows, {
11134
- rows,
11135
- boundary,
11136
- since: catchUp?.since,
11137
- terminal,
11138
- replaying,
11139
- stickyPrompt: !frame && stickyPrompt,
11140
- gap,
11141
- fontSize,
11142
- lineHeight,
11143
- items,
11144
- pendingApprovals: state.pendingApprovals,
11145
- scrubber,
11146
- bookmarks: frame ? void 0 : bookmarks,
11147
- affordances,
11148
- fileUrl,
11149
- attachmentUrl,
11150
- hostImage,
11151
- jumpToRecapRef,
11152
- repinRef,
11153
- reveal: frame ? void 0 : reveal,
11154
- frameParentId: frame?.parentToolUseId,
11155
- onOpenSubagent: frame ? void 0 : onOpenSubagent
11156
- }),
11157
- (frame ? frameTask !== void 0 && taskBusy(frameTask, items) : showLoader(state)) ? terminal ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx("div", {
11158
- className: "term-blank",
11159
- "aria-hidden": true
11160
- }) : null, /* @__PURE__ */ jsx(WorkingRow, {
11161
- label: state.status === "starting" ? "Starting…" : "Working…",
11162
- startedAt: runStartedAt,
11163
- tokens: state.contextUsage?.totalTokens
11164
- })] }) : /* @__PURE__ */ jsx(Loader, { label: state.status === "starting" ? "Starting session…" : void 0 }) : null
11165
- ]
11166
- })
11167
- }),
11168
- /* @__PURE__ */ jsx(ConversationScrollButton, {}),
11169
- replaying ? /* @__PURE__ */ jsx("div", {
11170
- "data-slot": "transcript-hold",
11171
- "aria-hidden": true,
11172
- className: "wd-hold-appear visible pointer-events-none absolute inset-0 overflow-hidden",
11173
- children: /* @__PURE__ */ jsx("div", {
11174
- className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)]", !terminal && "px-4 py-4"),
11175
- children: terminal ? /* @__PURE__ */ jsx(TerminalSurface, {
11152
+ children: /* @__PURE__ */ jsx(SkillNamesProvider, {
11153
+ names: skillNames,
11154
+ children: /* @__PURE__ */ jsxs(Conversation, {
11155
+ className: cn(replaying && "invisible", className),
11156
+ children: [
11157
+ /* @__PURE__ */ jsx(ConversationContent, {
11158
+ className: cn(terminal && "gap-0 p-0"),
11159
+ children: /* @__PURE__ */ jsxs(TerminalShell, {
11160
+ active: terminal,
11176
11161
  fontSize,
11177
11162
  lineHeight,
11178
- affordances: false,
11179
- bleed: "1ch",
11180
- className: "term-transcript",
11181
- children: /* @__PURE__ */ jsx(WorkingRow, { label: "Loading…" })
11182
- }) : /* @__PURE__ */ jsx(Loader, { label: "Loading session…" })
11183
- })
11184
- }) : null
11185
- ]
11163
+ affordances,
11164
+ children: [
11165
+ frame ? frameTask === void 0 && !replaying ? /* @__PURE__ */ jsx("div", {
11166
+ className: cn(terminal ? "term-row text-fg-4" : "p-4 text-body-sm text-fg-4"),
11167
+ children: "This sub-agent's work is not in this transcript."
11168
+ }) : null : items.length === 0 && state.status !== "starting" ? emptyState !== void 0 ? emptyState : /* @__PURE__ */ jsx(SessionEmptyState, {
11169
+ cwd: state.cwd,
11170
+ hasCommands: !!state.commands?.length,
11171
+ hasSkills: !!state.skills?.some((s) => s.enabled),
11172
+ canBrowseFiles
11173
+ }) : null,
11174
+ frame && frameTask === void 0 && !replaying ? null : /* @__PURE__ */ jsx(TranscriptRows, {
11175
+ rows,
11176
+ boundary,
11177
+ since: catchUp?.since,
11178
+ terminal,
11179
+ replaying,
11180
+ stickyPrompt: !frame && stickyPrompt,
11181
+ gap,
11182
+ fontSize,
11183
+ lineHeight,
11184
+ items,
11185
+ pendingApprovals: state.pendingApprovals,
11186
+ scrubber,
11187
+ bookmarks: frame ? void 0 : bookmarks,
11188
+ affordances,
11189
+ fileUrl,
11190
+ attachmentUrl,
11191
+ hostImage,
11192
+ jumpToRecapRef,
11193
+ repinRef,
11194
+ reveal: frame ? void 0 : reveal,
11195
+ frameParentId: frame?.parentToolUseId,
11196
+ onOpenSubagent: frame ? void 0 : onOpenSubagent
11197
+ }),
11198
+ (frame ? frameTask !== void 0 && taskBusy(frameTask, items) : showLoader(state)) ? terminal ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx("div", {
11199
+ className: "term-blank",
11200
+ "aria-hidden": true
11201
+ }) : null, /* @__PURE__ */ jsx(WorkingRow, {
11202
+ label: state.status === "starting" ? "Starting…" : "Working…",
11203
+ startedAt: runStartedAt,
11204
+ tokens: state.contextUsage?.totalTokens
11205
+ })] }) : /* @__PURE__ */ jsx(Loader, { label: state.status === "starting" ? "Starting session…" : void 0 }) : null
11206
+ ]
11207
+ })
11208
+ }),
11209
+ /* @__PURE__ */ jsx(ConversationScrollButton, {}),
11210
+ replaying ? /* @__PURE__ */ jsx("div", {
11211
+ "data-slot": "transcript-hold",
11212
+ "aria-hidden": true,
11213
+ className: "wd-hold-appear visible pointer-events-none absolute inset-0 overflow-hidden",
11214
+ children: /* @__PURE__ */ jsx("div", {
11215
+ className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)]", !terminal && "px-4 py-4"),
11216
+ children: terminal ? /* @__PURE__ */ jsx(TerminalSurface, {
11217
+ fontSize,
11218
+ lineHeight,
11219
+ affordances: false,
11220
+ bleed: "1ch",
11221
+ className: "term-transcript",
11222
+ children: /* @__PURE__ */ jsx(WorkingRow, { label: "Loading…" })
11223
+ }) : /* @__PURE__ */ jsx(Loader, { label: "Loading session…" })
11224
+ })
11225
+ }) : null
11226
+ ]
11227
+ })
11186
11228
  })
11187
11229
  });
11188
11230
  }
11189
11231
  //#endregion
11232
+ //#region src/lib/session-cost.ts
11233
+ const GAP_SHARE = .02;
11234
+ function sessionCost(input) {
11235
+ const byModel = input.usageByModel ?? {};
11236
+ const breakdown = costOfByModel(byModel);
11237
+ const computedUsd = input.costUsd ?? (breakdown.unpriced || Object.keys(byModel).length === 0 ? void 0 : breakdown.total);
11238
+ const reportedUsd = input.totalCostUsd;
11239
+ const rows = Object.entries(byModel).map(([model, usage]) => ({
11240
+ model: canonicalModel(model),
11241
+ usage,
11242
+ tokens: totalTokens(usage),
11243
+ costUsd: rateFor(model) ? costOf(usage, model).total : void 0
11244
+ })).sort((a, b) => b.tokens - a.tokens);
11245
+ const gap = computedUsd !== void 0 && reportedUsd !== void 0 ? reportedUsd - computedUsd : void 0;
11246
+ const worthShowing = gap !== void 0 && Math.abs(gap) > Math.max(.01, GAP_SHARE * Math.max(computedUsd ?? 0, reportedUsd ?? 0));
11247
+ return {
11248
+ displayUsd: computedUsd ?? reportedUsd,
11249
+ computedUsd,
11250
+ reportedUsd,
11251
+ breakdown,
11252
+ rows,
11253
+ unpricedShare: breakdown.unpricedShare,
11254
+ showUnpricedWarning: breakdown.unpricedShare > UNPRICED_WARN_SHARE,
11255
+ gapUsd: worthShowing ? gap : void 0
11256
+ };
11257
+ }
11258
+ //#endregion
11190
11259
  //#region src/components/agent/UsageMeters.tsx
11191
11260
  function useMinuteClock(active = true) {
11192
11261
  const [now, setNow] = useState(() => Date.now());
@@ -11270,8 +11339,134 @@ function UsageMeter({ window, now }) {
11270
11339
  }
11271
11340
  //#endregion
11272
11341
  //#region src/components/agent/UsageDialog.tsx
11273
- function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updatedAt, open, onOpenChange, className }) {
11342
+ function Line({ label, value, tone }) {
11343
+ return /* @__PURE__ */ jsxs("div", {
11344
+ className: "flex items-baseline justify-between gap-4",
11345
+ children: [/* @__PURE__ */ jsx("span", {
11346
+ className: tone === "muted" ? "text-label text-fg-4" : "text-label text-fg-3",
11347
+ children: label
11348
+ }), /* @__PURE__ */ jsx("span", {
11349
+ className: `font-mono text-body-sm ${tone === "muted" ? "text-fg-4" : "text-fg-1"}`,
11350
+ children: value
11351
+ })]
11352
+ });
11353
+ }
11354
+ function CostEvidence({ cost, engine }) {
11355
+ const { breakdown, rows } = cost;
11356
+ if (rows.length === 0) return /* @__PURE__ */ jsx(Line, {
11357
+ label: "This session has cost",
11358
+ value: formatCost(cost.displayUsd)
11359
+ });
11360
+ return /* @__PURE__ */ jsxs("div", {
11361
+ className: "space-y-3",
11362
+ children: [
11363
+ /* @__PURE__ */ jsxs("div", {
11364
+ className: "flex items-baseline justify-between gap-4",
11365
+ children: [/* @__PURE__ */ jsx("span", {
11366
+ className: "text-label text-fg-3",
11367
+ children: "This session has cost"
11368
+ }), /* @__PURE__ */ jsx("span", {
11369
+ className: "font-mono text-body text-fg-1",
11370
+ children: formatCost(cost.displayUsd)
11371
+ })]
11372
+ }),
11373
+ /* @__PURE__ */ jsxs("div", {
11374
+ className: "space-y-1 border-t border-border pt-2",
11375
+ children: [
11376
+ /* @__PURE__ */ jsx(Line, {
11377
+ label: "input",
11378
+ value: formatCost(breakdown.input),
11379
+ tone: "muted"
11380
+ }),
11381
+ /* @__PURE__ */ jsx(Line, {
11382
+ label: "output",
11383
+ value: formatCost(breakdown.output),
11384
+ tone: "muted"
11385
+ }),
11386
+ /* @__PURE__ */ jsx(Line, {
11387
+ label: "cache write",
11388
+ value: formatCost(breakdown.cacheWrite),
11389
+ tone: "muted"
11390
+ }),
11391
+ /* @__PURE__ */ jsx(Line, {
11392
+ label: "cache read",
11393
+ value: formatCost(breakdown.cacheRead),
11394
+ tone: "muted"
11395
+ })
11396
+ ]
11397
+ }),
11398
+ /* @__PURE__ */ jsx("div", {
11399
+ className: "space-y-1 border-t border-border pt-2",
11400
+ children: rows.map((row) => /* @__PURE__ */ jsxs("div", {
11401
+ className: "flex items-baseline justify-between gap-4",
11402
+ children: [/* @__PURE__ */ jsx("span", {
11403
+ className: "truncate text-label text-fg-4",
11404
+ children: row.model
11405
+ }), /* @__PURE__ */ jsxs("span", {
11406
+ className: "shrink-0 font-mono text-label text-fg-4",
11407
+ children: [
11408
+ formatTokens(row.tokens),
11409
+ " · ",
11410
+ row.costUsd === void 0 ? "no rate" : formatCost(row.costUsd)
11411
+ ]
11412
+ })]
11413
+ }, row.model))
11414
+ }),
11415
+ cost.showUnpricedWarning ? /* @__PURE__ */ jsxs("p", {
11416
+ className: "text-label text-warning",
11417
+ children: [Math.round(cost.unpricedShare * 100), "% of these tokens ran on a model with no bundled rate, so the total is an understatement rather than an estimate."]
11418
+ }) : null,
11419
+ cost.gapUsd !== void 0 ? /* @__PURE__ */ jsxs("p", {
11420
+ className: "text-label text-fg-4",
11421
+ children: [
11422
+ engine === "claude" ? "Claude Code" : engine,
11423
+ " reports ",
11424
+ formatCost(cost.reportedUsd),
11425
+ " for the same tokens."
11426
+ ]
11427
+ }) : null
11428
+ ]
11429
+ });
11430
+ }
11431
+ function ProfileSpendSection({ spend }) {
11432
+ const { subscription } = spend;
11433
+ return /* @__PURE__ */ jsxs("div", {
11434
+ className: "mt-4 space-y-1 border-t border-border pt-3",
11435
+ children: [
11436
+ /* @__PURE__ */ jsx(Line, {
11437
+ label: "This profile, last 7 days",
11438
+ value: formatCost(spend.weekUsd)
11439
+ }),
11440
+ /* @__PURE__ */ jsx(Line, {
11441
+ label: "Last 30 days",
11442
+ value: formatCost(spend.monthUsd),
11443
+ tone: "muted"
11444
+ }),
11445
+ subscription ? /* @__PURE__ */ jsxs("p", {
11446
+ className: "pt-1 text-label text-fg-4",
11447
+ children: [
11448
+ formatMultiple(subscription.ratio),
11449
+ " the ",
11450
+ formatCost(subscription.weeklyShareUsd),
11451
+ " weekly share of your",
11452
+ " ",
11453
+ formatCost(subscription.monthlyUsd),
11454
+ " a month. A subscription is a flat fee, so this is leverage, not a bill."
11455
+ ]
11456
+ }) : null
11457
+ ]
11458
+ });
11459
+ }
11460
+ function formatMultiple(ratio) {
11461
+ return ratio >= 10 ? `${Math.round(ratio)}x` : `${ratio.toFixed(1)}x`;
11462
+ }
11463
+ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, costUsd, usageByModel, spend, updatedAt, open, onOpenChange, className }) {
11274
11464
  const now = useMinuteClock(open);
11465
+ const cost = sessionCost({
11466
+ costUsd,
11467
+ totalCostUsd,
11468
+ usageByModel
11469
+ });
11275
11470
  return /* @__PURE__ */ jsx(Dialog$1, {
11276
11471
  open,
11277
11472
  onOpenChange,
@@ -11293,15 +11488,17 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updat
11293
11488
  windows: rateLimits,
11294
11489
  now
11295
11490
  }),
11296
- /* @__PURE__ */ jsxs("div", {
11297
- className: "mt-5 flex items-baseline justify-between gap-4 border-t border-border pt-3",
11298
- children: [/* @__PURE__ */ jsx("span", {
11299
- className: "text-label text-fg-3",
11300
- children: "This session has cost"
11301
- }), /* @__PURE__ */ jsx("span", {
11302
- className: "font-mono text-body-sm text-fg-1",
11303
- children: formatCost(totalCostUsd)
11304
- })]
11491
+ /* @__PURE__ */ jsx("div", {
11492
+ className: "mt-5 border-t border-border pt-3",
11493
+ children: /* @__PURE__ */ jsx(CostEvidence, {
11494
+ cost,
11495
+ engine
11496
+ })
11497
+ }),
11498
+ spend ? /* @__PURE__ */ jsx(ProfileSpendSection, { spend }) : null,
11499
+ /* @__PURE__ */ jsx("p", {
11500
+ className: "mt-3 text-label text-fg-4",
11501
+ children: PRICING_NOTE
11305
11502
  }),
11306
11503
  updatedAt ? /* @__PURE__ */ jsxs("p", {
11307
11504
  className: "mt-2 text-label text-fg-4",
@@ -11393,7 +11590,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
11393
11590
  } : toolHost);
11394
11591
  const terminal = transcriptVariant === "terminal";
11395
11592
  const capabilities = state.capabilities;
11396
- const { usage: profileUsage } = useProfileUsage(client, state.session?.profile, { enabled: capabilities.rateLimits });
11593
+ const { usage: profileUsage, spend: profileSpend } = useProfileUsage(client, state.session?.profile, { enabled: capabilities.rateLimits });
11397
11594
  const usage = useMemo(() => mergeUsage({
11398
11595
  rateLimits: state.rateLimits,
11399
11596
  updatedAt: state.rateLimitsUpdatedAt
@@ -11869,6 +12066,9 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
11869
12066
  subscriptionType: state.subscriptionType,
11870
12067
  engine: state.engine ?? "claude",
11871
12068
  totalCostUsd: state.totalCostUsd,
12069
+ costUsd: state.costUsd,
12070
+ usageByModel: state.usageByModel,
12071
+ spend: profileSpend,
11872
12072
  updatedAt: usageUpdatedAt,
11873
12073
  open: panel === "usage",
11874
12074
  onOpenChange: (next) => setPanel(next ? "usage" : void 0)
@@ -11977,6 +12177,108 @@ function Notice({ level, onDismiss, children }) {
11977
12177
  });
11978
12178
  }
11979
12179
  //#endregion
11980
- export { Band as $, Input as $t, PERMISSION_MODES as A, Tip as At, TaskList as B, Menu$1 as Bt, TerminalPermissionPrompt as C, segmentsToPlainText as Ct, SubagentStrip as D, Spinner as Dt, parseUserQuestions as E, CodeBlock as Et, SkillsDialog as F, DialogClose as Ft, ToolTitleProvider as G, Select$1 as Gt, contextNote as H, MenuItem as Ht, McpDialog as I, DialogContent as It, FileLinkProvider as J, SelectItemText as Jt, useToolTitle as K, SelectContent as Kt, HostFilesDialog as L, DialogHeader as Lt, permissionModeChoices as M, TooltipProvider as Mt, permissionModeMeta as N, Dialog$1 as Nt, PermissionPrompt as O, CopyButton as Ot, ModelSelect as P, DialogBody as Pt, previewPatch as Q, Textarea as Qt, EntryIcon as R, DialogRow as Rt, TerminalQuestionPrompt as S, plainTextToSegments as St, QuestionPrompt as T, Splitter as Tt, Composer as U, MenuSeparator as Ut, ContextDialog as V, MenuContent as Vt, TerminalSurface as W, MenuTrigger as Wt, parseFileLink as X, SelectValue as Xt, useFileLinks as Y, SelectTrigger as Yt, TerminalDiff as Z, PortalScope as Zt, ConversationContent as _, hashtagTrigger as _t, Transcript as a, useAffordances as at, STATUS_META as b, usePromptAreaState as bt, PromptTokenText as c, TranscriptDensityProvider as ct, FileCard as d, useTranscriptVariant as dt, Badge as en, Blank as et, TerminalItemView as f, matchClientCommand as ft, Conversation as g, commandTrigger as gt, Loader as h, skillPrompt as ht, useMinuteClock as i, cn as in, WithActions as it, PermissionModeSelect as j, TooltipContent as jt, Response as k, copyText as kt, Message as l, TranscriptVariantProvider as lt, SessionEmptyState as m, rankComposerRows as mt, UsageDialog as n, Button as nn, Row as nt, ToolCallCard as o, isMutatingTool as ot, TerminalTranscript as p, mergeComposerRows as pt, TerminalMarkdown as q, SelectItem as qt, UsageMeters as r, buttonVariants as rn, CopyAction as rt, Reasoning as s, toolIcon as st, SessionPanel as t, badgeVariants as tn, Ink as tt, MessageContent as u, useTranscriptDensity as ut, ConversationScrollButton as v, launchTrigger as vt, QUESTION_BEHAVIORS as w, ProgressRing as wt, SessionInfoDialog as x, PromptArea as xt, StatusBar as y, mentionTrigger as yt, TasksDialog as z, DialogTrigger as zt };
12180
+ //#region src/lib/path-match.ts
12181
+ const SEG = "[^\\s:'\"`()\\[\\]{}<>|]+";
12182
+ const PATH_PATTERN = new RegExp(`(?:^|[\\s'"\`([{<@,])((?:\\.\\.?)?(?:/${SEG})+|[^\\s:'"\`()\\[\\]{}<>|@,]+(?:/${SEG})+)(?::(\\d+))?`);
12183
+ const FILE_PATTERN = /^([\w.@-]+\.[A-Za-z0-9]{1,10})(?::(\d+))?$/;
12184
+ const TRAILING = /[.,;:!?)\]}'"`]+$/;
12185
+ const FILENAME = /\.[A-Za-z0-9]{1,10}$/;
12186
+ function matchPath(text, inCode = false) {
12187
+ const source = text ?? "";
12188
+ const match = PATH_PATTERN.exec(source);
12189
+ if (!match) return inCode ? matchFilename(source) : void 0;
12190
+ const path = match[1].replace(TRAILING, "");
12191
+ if (!path.includes("/") || path.endsWith("/")) return;
12192
+ if (!(path.startsWith("/") || path.startsWith("./") || path.startsWith("../")) && !FILENAME.test(path)) return;
12193
+ return {
12194
+ path,
12195
+ line: match[2] ? Number(match[2]) : void 0,
12196
+ length: path.length + (match[2] ? match[2].length + 1 : 0)
12197
+ };
12198
+ }
12199
+ function matchFilename(text) {
12200
+ const hit = FILE_PATTERN.exec(text.trim());
12201
+ if (!hit) return;
12202
+ const line = hit[2] ? Number(hit[2]) : void 0;
12203
+ return {
12204
+ path: hit[1],
12205
+ line,
12206
+ length: hit[0].length
12207
+ };
12208
+ }
12209
+ //#endregion
12210
+ //#region src/components/agent/use-path-links.ts
12211
+ const LINKISH = "wd-path-link";
12212
+ const COVERAGE = .6;
12213
+ function hitFor(element) {
12214
+ if (!element) return;
12215
+ const inCode = element.closest("code") !== null;
12216
+ const text = element.textContent?.trim() ?? "";
12217
+ const hit = matchPath(text, inCode);
12218
+ if (!hit) return;
12219
+ if (!inCode && hit.length < text.length * COVERAGE) return;
12220
+ return {
12221
+ path: hit.path,
12222
+ line: hit.line
12223
+ };
12224
+ }
12225
+ function usePathLinks({ container, onOpen, enabled = true, ignore }) {
12226
+ useEffect(() => {
12227
+ const root = container.current;
12228
+ if (!root || !enabled) return;
12229
+ const excluded = (element) => ignore !== void 0 && element?.closest(ignore) !== null && element !== void 0;
12230
+ let marked;
12231
+ const unmark = () => {
12232
+ marked?.classList.remove(LINKISH);
12233
+ marked = void 0;
12234
+ };
12235
+ const onClick = (event) => {
12236
+ if (!event.metaKey && !event.ctrlKey) return;
12237
+ const target = event.target instanceof HTMLElement ? event.target : void 0;
12238
+ if (excluded(target)) return;
12239
+ const hit = hitFor(target);
12240
+ if (!hit) return;
12241
+ event.preventDefault();
12242
+ event.stopPropagation();
12243
+ unmark();
12244
+ onOpen(hit);
12245
+ };
12246
+ const onMove = (event) => {
12247
+ if (!event.metaKey && !event.ctrlKey) return unmark();
12248
+ const element = event.target instanceof HTMLElement ? event.target : void 0;
12249
+ if (element === marked) return;
12250
+ unmark();
12251
+ if (!element || excluded(element) || !hitFor(element)) return;
12252
+ marked = element;
12253
+ element.classList.add(LINKISH);
12254
+ };
12255
+ const onKey = (event) => {
12256
+ if (!event.metaKey && !event.ctrlKey) unmark();
12257
+ };
12258
+ root.addEventListener("click", onClick, true);
12259
+ root.addEventListener("mousemove", onMove);
12260
+ document.addEventListener("keydown", onKey);
12261
+ document.addEventListener("keyup", onKey);
12262
+ window.addEventListener("blur", unmark);
12263
+ return () => {
12264
+ unmark();
12265
+ root.removeEventListener("click", onClick, true);
12266
+ root.removeEventListener("mousemove", onMove);
12267
+ document.removeEventListener("keydown", onKey);
12268
+ document.removeEventListener("keyup", onKey);
12269
+ window.removeEventListener("blur", unmark);
12270
+ };
12271
+ }, [
12272
+ container,
12273
+ onOpen,
12274
+ enabled,
12275
+ ignore
12276
+ ]);
12277
+ }
12278
+ function resolveAgainstCwd(path, cwd) {
12279
+ return parseFileLink(path, cwd)?.path ?? path;
12280
+ }
12281
+ //#endregion
12282
+ export { TerminalDiff as $, SelectValue as $t, PermissionPrompt as A, Spinner as At, EntryIcon as B, DialogHeader as Bt, SessionInfoDialog as C, usePromptAreaState as Ct, QuestionPrompt as D, ProgressRing as Dt, QUESTION_BEHAVIORS as E, segmentsToPlainText as Et, permissionModeMeta as F, TooltipProvider as Ft, Composer as G, MenuItem as Gt, TaskList as H, DialogTrigger as Ht, ModelSelect as I, Dialog$1 as It, useToolTitle as J, Select$1 as Jt, TerminalSurface as K, MenuSeparator as Kt, SkillsDialog as L, DialogBody as Lt, PERMISSION_MODES as M, copyText as Mt, PermissionModeSelect as N, Tip as Nt, parseUserQuestions as O, Splitter as Ot, permissionModeChoices as P, TooltipContent as Pt, parseFileLink as Q, SelectTrigger as Qt, McpDialog as R, DialogClose as Rt, STATUS_META as S, mentionTrigger as St, TerminalPermissionPrompt as T, plainTextToSegments as Tt, ContextDialog as U, Menu$1 as Ut, TasksDialog as V, DialogRow as Vt, contextNote as W, MenuContent as Wt, FileLinkProvider as X, SelectItem as Xt, TerminalMarkdown as Y, SelectContent as Yt, useFileLinks as Z, SelectItemText as Zt, Loader as _, rankComposerRows as _t, UsageDialog as a, Button as an, CopyAction as at, ConversationScrollButton as b, hashtagTrigger as bt, Transcript as c, PromptTokenText as ct, Message as d, TranscriptDensityProvider as dt, PortalScope as en, previewPatch as et, MessageContent as f, TranscriptVariantProvider as ft, SessionEmptyState as g, mergeComposerRows as gt, TerminalTranscript as h, matchClientCommand as ht, SessionPanel as i, badgeVariants as in, Row as it, Response as j, CopyButton as jt, SubagentStrip as k, CodeBlock as kt, ToolCallCard as l, isMutatingTool as lt, TerminalItemView as m, useTranscriptVariant as mt, usePathLinks as n, Input as nn, Blank as nt, UsageMeters as o, buttonVariants as on, WithActions as ot, FileCard as p, useTranscriptDensity as pt, ToolTitleProvider as q, MenuTrigger as qt, matchPath as r, Badge as rn, Ink as rt, useMinuteClock as s, cn as sn, useAffordances as st, resolveAgainstCwd as t, Textarea as tn, Band as tt, Reasoning as u, toolIcon as ut, Conversation as v, skillPrompt as vt, TerminalQuestionPrompt as w, PromptArea as wt, StatusBar as x, launchTrigger as xt, ConversationContent as y, commandTrigger as yt, HostFilesDialog as z, DialogContent as zt };
11981
12283
 
11982
- //# sourceMappingURL=SessionPanel-BClL7zUS.mjs.map
12284
+ //# sourceMappingURL=use-path-links-CvcxdUXL.mjs.map