@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.
- package/build/index.d.mts +52 -6
- package/build/index.mjs +23 -9
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +20 -0
- package/build/{SessionPanel-BClL7zUS.mjs → use-path-links-CvcxdUXL.mjs} +437 -135
- package/build/use-path-links-CvcxdUXL.mjs.map +1 -0
- package/build/workspace.mjs +3 -83
- package/build/workspace.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/agent/Composer.tsx +7 -4
- package/src/components/agent/PromptTokenText.tsx +11 -3
- package/src/components/agent/SessionInfoDialog.tsx +1 -1
- package/src/components/agent/SessionItem.tsx +9 -5
- package/src/components/agent/SessionList.tsx +1 -1
- package/src/components/agent/SessionPanel.tsx +4 -1
- package/src/components/agent/StatusBar.tsx +1 -1
- package/src/components/agent/Transcript.tsx +83 -79
- package/src/components/agent/TranscriptItemView.tsx +1 -1
- package/src/components/agent/UsageDialog.tsx +87 -6
- package/src/components/agent/composer-commands.ts +14 -2
- package/src/components/agent/use-path-links.ts +5 -19
- package/src/components/prompt-area/clipboard-helpers.ts +13 -4
- package/src/components/prompt-area/dom-helpers.ts +10 -1
- package/src/components/prompt-area/index.ts +10 -1
- package/src/components/prompt-area/prompt-area-engine.ts +23 -14
- package/src/components/prompt-area/types.ts +20 -0
- package/src/components/prompt-area/use-prompt-area-keydown.ts +2 -1
- package/src/components/prompt-area/use-prompt-area.ts +8 -2
- package/src/components/terminal/StatusLine.tsx +3 -2
- package/src/components/terminal/items.tsx +3 -2
- package/src/index.ts +3 -1
- package/src/lib/path-match.ts +51 -0
- package/src/lib/session-cost.ts +65 -0
- 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
|
|
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
|
|
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.
|
|
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 =
|
|
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:
|
|
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.
|
|
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 +
|
|
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 +
|
|
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 =
|
|
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 =
|
|
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.
|
|
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.
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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__ */
|
|
11114
|
-
|
|
11115
|
-
children:
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
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
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
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
|
|
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__ */
|
|
11297
|
-
className: "mt-5
|
|
11298
|
-
children:
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
})
|
|
11302
|
-
|
|
11303
|
-
|
|
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
|
-
|
|
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=
|
|
12284
|
+
//# sourceMappingURL=use-path-links-CvcxdUXL.mjs.map
|