@workerdeck/ui 2.9.0 → 2.11.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 +54 -7
- package/build/index.mjs +34 -16
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +76 -1
- package/build/{SessionPanel-BClL7zUS.mjs → use-path-links-DO_79-wX.mjs} +834 -303
- package/build/use-path-links-DO_79-wX.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 +13 -8
- package/src/components/agent/SessionList.tsx +1 -1
- package/src/components/agent/SessionPanel.tsx +6 -1
- package/src/components/agent/StatusBar.tsx +1 -1
- package/src/components/agent/Transcript.tsx +83 -79
- package/src/components/agent/TranscriptItemView.tsx +3 -1
- package/src/components/agent/TranscriptRows.tsx +60 -56
- package/src/components/agent/UsageDialog.tsx +101 -7
- package/src/components/agent/composer-commands.ts +14 -2
- package/src/components/agent/pulse.tsx +53 -16
- package/src/components/agent/use-path-links.ts +5 -19
- package/src/components/agent/use-transcript-jumps.ts +25 -0
- 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/TerminalTranscript.tsx +31 -27
- package/src/components/terminal/blocks.ts +15 -7
- package/src/components/terminal/height.ts +14 -5
- package/src/components/terminal/items.tsx +99 -12
- package/src/components/terminal/peer-names.tsx +16 -0
- package/src/components/terminal/row.tsx +1 -1
- package/src/components/terminal/tool-run.ts +68 -0
- package/src/index.ts +3 -1
- package/src/lib/path-match.ts +51 -0
- package/src/lib/session-cost.ts +75 -0
- package/src/lib/tool-icon.ts +5 -1
- package/src/styles/terminal.css +93 -0
- package/src/styles/theme.css +1 -1
- package/build/SessionPanel-BClL7zUS.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as rateLimitWindowSeconds, _ as formatDuration, a as meterTintClass, b as formatRelativeTime, f as compactionText, g as formatCountdown, h as formatCost, m as formatBytes, p as formatAgoPrecise, r as meterColorClass, w as toolInputPreview, x as formatTokens, y as formatRateLimitWindowLong } from "./status-kmsBhuFG.mjs";
|
|
2
|
-
import { Fragment, createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { Fragment, createContext, forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { clsx } from "clsx";
|
|
5
5
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
@@ -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, isPeerSendTool, mergeUsage, orderUsageWindows, parseTodoWriteInput, parseUserQuestions, peerDeliveredTo, pricingAgeNote, rateFor, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, totalTokens, unknownBasisModels, 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 = [];
|
|
@@ -4582,7 +4606,11 @@ function toolIcon(toolName) {
|
|
|
4582
4606
|
case "WebSearch": return Globe;
|
|
4583
4607
|
case "Task":
|
|
4584
4608
|
case "Agent": return UsersRound;
|
|
4585
|
-
case "TodoWrite":
|
|
4609
|
+
case "TodoWrite":
|
|
4610
|
+
case "TaskCreate":
|
|
4611
|
+
case "TaskUpdate":
|
|
4612
|
+
case "TaskGet":
|
|
4613
|
+
case "TaskList": return CheckSquare;
|
|
4586
4614
|
case "Skill": return Sparkles;
|
|
4587
4615
|
case "AskUserQuestion": return MessageCircleQuestion;
|
|
4588
4616
|
case "CodexCommand": return Terminal;
|
|
@@ -4610,12 +4638,53 @@ function isMutatingTool(toolName) {
|
|
|
4610
4638
|
//#endregion
|
|
4611
4639
|
//#region src/components/agent/pulse.tsx
|
|
4612
4640
|
const PULSE_FRAMES = [
|
|
4613
|
-
"
|
|
4614
|
-
"
|
|
4615
|
-
"
|
|
4616
|
-
"
|
|
4641
|
+
"⠋",
|
|
4642
|
+
"⠙",
|
|
4643
|
+
"⠹",
|
|
4644
|
+
"⠸",
|
|
4645
|
+
"⠼",
|
|
4646
|
+
"⠴",
|
|
4647
|
+
"⠦",
|
|
4648
|
+
"⠧",
|
|
4649
|
+
"⠇",
|
|
4650
|
+
"⠏"
|
|
4617
4651
|
];
|
|
4618
|
-
const
|
|
4652
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4653
|
+
let ticker;
|
|
4654
|
+
let current = "⠿";
|
|
4655
|
+
function pulseFrameAt(now) {
|
|
4656
|
+
return PULSE_FRAMES[Math.floor(now / 90) % PULSE_FRAMES.length];
|
|
4657
|
+
}
|
|
4658
|
+
function tick() {
|
|
4659
|
+
const next = pulseFrameAt(Date.now());
|
|
4660
|
+
if (next === current) return;
|
|
4661
|
+
current = next;
|
|
4662
|
+
for (const listener of listeners) listener();
|
|
4663
|
+
}
|
|
4664
|
+
function subscribe(listener) {
|
|
4665
|
+
listeners.add(listener);
|
|
4666
|
+
if (ticker === void 0) {
|
|
4667
|
+
current = pulseFrameAt(Date.now());
|
|
4668
|
+
ticker = setInterval(tick, 90);
|
|
4669
|
+
}
|
|
4670
|
+
return () => {
|
|
4671
|
+
listeners.delete(listener);
|
|
4672
|
+
if (listeners.size === 0 && ticker !== void 0) {
|
|
4673
|
+
clearInterval(ticker);
|
|
4674
|
+
ticker = void 0;
|
|
4675
|
+
}
|
|
4676
|
+
};
|
|
4677
|
+
}
|
|
4678
|
+
function subscribeRest() {
|
|
4679
|
+
return unsubscribeRest;
|
|
4680
|
+
}
|
|
4681
|
+
function unsubscribeRest() {}
|
|
4682
|
+
function readFrame() {
|
|
4683
|
+
return current;
|
|
4684
|
+
}
|
|
4685
|
+
function readRest() {
|
|
4686
|
+
return "⠿";
|
|
4687
|
+
}
|
|
4619
4688
|
function usePrefersReducedMotion() {
|
|
4620
4689
|
const [reduced, setReduced] = useState(false);
|
|
4621
4690
|
useEffect(() => {
|
|
@@ -4631,14 +4700,39 @@ function usePrefersReducedMotion() {
|
|
|
4631
4700
|
function usePulse(animated) {
|
|
4632
4701
|
const reduced = usePrefersReducedMotion();
|
|
4633
4702
|
const running = animated && !reduced;
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4703
|
+
return useSyncExternalStore(running ? subscribe : subscribeRest, running ? readFrame : readRest, readRest);
|
|
4704
|
+
}
|
|
4705
|
+
//#endregion
|
|
4706
|
+
//#region src/components/agent/PromptTokenText.tsx
|
|
4707
|
+
const SkillNamesContext = createContext(void 0);
|
|
4708
|
+
function SkillNamesProvider({ names, children }) {
|
|
4709
|
+
return /* @__PURE__ */ jsx(SkillNamesContext.Provider, {
|
|
4710
|
+
value: names,
|
|
4711
|
+
children
|
|
4712
|
+
});
|
|
4713
|
+
}
|
|
4714
|
+
function PromptTokenText({ text, className }) {
|
|
4715
|
+
const skills = useContext(SkillNamesContext);
|
|
4716
|
+
const tokens = scanPromptTokens(text, { skills });
|
|
4717
|
+
if (tokens.length === 0) return /* @__PURE__ */ jsx("span", {
|
|
4718
|
+
className,
|
|
4719
|
+
children: text
|
|
4720
|
+
});
|
|
4721
|
+
const parts = [];
|
|
4722
|
+
let cursor = 0;
|
|
4723
|
+
for (const [index, token] of tokens.entries()) {
|
|
4724
|
+
if (token.start > cursor) parts.push(text.slice(cursor, token.start));
|
|
4725
|
+
parts.push(/* @__PURE__ */ jsx("span", {
|
|
4726
|
+
className: cn("font-mono", token.kind === "file" ? "text-accent" : "text-info"),
|
|
4727
|
+
children: token.text
|
|
4728
|
+
}, `${token.start}-${index}`));
|
|
4729
|
+
cursor = token.end;
|
|
4730
|
+
}
|
|
4731
|
+
if (cursor < text.length) parts.push(text.slice(cursor));
|
|
4732
|
+
return /* @__PURE__ */ jsx("span", {
|
|
4733
|
+
className,
|
|
4734
|
+
children: parts.map((part, index) => /* @__PURE__ */ jsx(Fragment, { children: part }, index))
|
|
4735
|
+
});
|
|
4642
4736
|
}
|
|
4643
4737
|
//#endregion
|
|
4644
4738
|
//#region src/components/terminal/affordances.tsx
|
|
@@ -5075,6 +5169,129 @@ const TerminalMarkdown = memo(function TerminalMarkdown({ children, streaming, c
|
|
|
5075
5169
|
});
|
|
5076
5170
|
}, (prev, next) => prev.children === next.children && prev.streaming === next.streaming && prev.className === next.className);
|
|
5077
5171
|
//#endregion
|
|
5172
|
+
//#region src/components/terminal/tool-run.ts
|
|
5173
|
+
function isPeerSend(item) {
|
|
5174
|
+
return item.kind === "tool_call" && isPeerSendTool(item.name);
|
|
5175
|
+
}
|
|
5176
|
+
function peerName(origin) {
|
|
5177
|
+
return origin.name ?? origin.sessionId.slice(0, 8);
|
|
5178
|
+
}
|
|
5179
|
+
function peerNamesOf(items) {
|
|
5180
|
+
const names = /* @__PURE__ */ new Map();
|
|
5181
|
+
for (const item of items) {
|
|
5182
|
+
if (item.kind === "user") {
|
|
5183
|
+
if (item.origin?.name) names.set(item.origin.sessionId, item.origin.name);
|
|
5184
|
+
continue;
|
|
5185
|
+
}
|
|
5186
|
+
if (item.kind === "tool_call" && isPeerSendTool(item.name) && item.result && !item.result.isError) {
|
|
5187
|
+
const delivered = peerDeliveredTo(item.result.text);
|
|
5188
|
+
if (delivered?.name) names.set(delivered.sessionId, delivered.name);
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
return names;
|
|
5192
|
+
}
|
|
5193
|
+
function peerSendTarget(item, names) {
|
|
5194
|
+
const delivered = item.result && !item.result.isError ? peerDeliveredTo(item.result.text) : void 0;
|
|
5195
|
+
const addressed = item.input?.sessionId;
|
|
5196
|
+
const sessionId = delivered?.sessionId ?? (typeof addressed === "string" ? addressed : void 0);
|
|
5197
|
+
if (sessionId === void 0) return "peer";
|
|
5198
|
+
return delivered?.name ?? names?.get(sessionId) ?? sessionId.slice(0, 8);
|
|
5199
|
+
}
|
|
5200
|
+
function peerSendText(item) {
|
|
5201
|
+
const text = item.input?.text;
|
|
5202
|
+
return typeof text === "string" ? text : "";
|
|
5203
|
+
}
|
|
5204
|
+
function peerOneLine(text) {
|
|
5205
|
+
return text.replace(/\s+/g, " ").trim();
|
|
5206
|
+
}
|
|
5207
|
+
function foldsTogether(a, b) {
|
|
5208
|
+
if (isPeerSend(a) || isPeerSend(b)) return false;
|
|
5209
|
+
return a.parentToolUseId === b.parentToolUseId;
|
|
5210
|
+
}
|
|
5211
|
+
function toolFamily(name) {
|
|
5212
|
+
if (isShellTool(name)) return "shell";
|
|
5213
|
+
const mcp = /^mcp__([^_]+(?:_[^_]+)*?)__/.exec(name);
|
|
5214
|
+
if (mcp?.[1]) return mcp[1].replace(/_/g, "-");
|
|
5215
|
+
return name.toLowerCase();
|
|
5216
|
+
}
|
|
5217
|
+
function planRun(items) {
|
|
5218
|
+
return items.length === 1 ? {
|
|
5219
|
+
kind: "call",
|
|
5220
|
+
item: items[0]
|
|
5221
|
+
} : {
|
|
5222
|
+
kind: "summary",
|
|
5223
|
+
items
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
function runSummary(items, busy) {
|
|
5227
|
+
const verb = busy ? "Running " : "Ran ";
|
|
5228
|
+
const tail = busy ? "…" : "";
|
|
5229
|
+
const n = items.length;
|
|
5230
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5231
|
+
for (const item of items) {
|
|
5232
|
+
const family = toolFamily(item.name);
|
|
5233
|
+
counts.set(family, (counts.get(family) ?? 0) + 1);
|
|
5234
|
+
}
|
|
5235
|
+
if (counts.size === 1 && counts.has("shell")) return `${verb}${n} shell command${n === 1 ? "" : "s"}${tail}`;
|
|
5236
|
+
const breakdown = [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([family, count]) => `${count} ${family}`).join(", ");
|
|
5237
|
+
return `${verb}${n} tool${n === 1 ? "" : "s"} · ${breakdown}${tail}`;
|
|
5238
|
+
}
|
|
5239
|
+
function clip(text, max = 80) {
|
|
5240
|
+
return text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
5241
|
+
}
|
|
5242
|
+
function trimmed(value) {
|
|
5243
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
5244
|
+
}
|
|
5245
|
+
function taskLabel(task) {
|
|
5246
|
+
return `${task.name}(${taskIdentity(task)})`;
|
|
5247
|
+
}
|
|
5248
|
+
function taskIdentity(task) {
|
|
5249
|
+
const input = task.input;
|
|
5250
|
+
const description = trimmed(input?.description);
|
|
5251
|
+
const agent = trimmed(input?.subagent_type);
|
|
5252
|
+
return agent && description ? `${agent} · ${clip(description)}` : agent ?? (description ? clip(description) : toolInputPreview(task.input));
|
|
5253
|
+
}
|
|
5254
|
+
function taskBrief(task) {
|
|
5255
|
+
const input = task.input;
|
|
5256
|
+
return trimmed(input?.prompt);
|
|
5257
|
+
}
|
|
5258
|
+
function callBusy(call) {
|
|
5259
|
+
return call.status === "running" || call.status === "pending";
|
|
5260
|
+
}
|
|
5261
|
+
function callFailed(call) {
|
|
5262
|
+
return call.status === "failed" || call.result?.isError === true;
|
|
5263
|
+
}
|
|
5264
|
+
function runFailed(items) {
|
|
5265
|
+
const last = items[items.length - 1];
|
|
5266
|
+
return last !== void 0 && callFailed(last);
|
|
5267
|
+
}
|
|
5268
|
+
function taskBusy(task, children) {
|
|
5269
|
+
return callBusy(task) || children.some((child) => child.kind === "tool_call" && callBusy(child));
|
|
5270
|
+
}
|
|
5271
|
+
function taskFailed(task) {
|
|
5272
|
+
return callFailed(task);
|
|
5273
|
+
}
|
|
5274
|
+
function taskSummary$1(task, children) {
|
|
5275
|
+
const busy = taskBusy(task, children);
|
|
5276
|
+
const calls = children.reduce((n, child) => n + (child.kind === "tool_call" ? 1 : 0), 0);
|
|
5277
|
+
const label = taskLabel(task);
|
|
5278
|
+
if (calls === 0) return busy ? `${label} · working…` : `${label} · done`;
|
|
5279
|
+
return `${label} · ${calls} tool${calls === 1 ? "" : "s"}${busy ? "…" : ""}`;
|
|
5280
|
+
}
|
|
5281
|
+
//#endregion
|
|
5282
|
+
//#region src/components/terminal/peer-names.tsx
|
|
5283
|
+
const PeerNamesContext = createContext(/* @__PURE__ */ new Map());
|
|
5284
|
+
function PeerNamesProvider({ items, children }) {
|
|
5285
|
+
const names = useMemo(() => peerNamesOf(items), [items]);
|
|
5286
|
+
return /* @__PURE__ */ jsx(PeerNamesContext.Provider, {
|
|
5287
|
+
value: names,
|
|
5288
|
+
children
|
|
5289
|
+
});
|
|
5290
|
+
}
|
|
5291
|
+
function usePeerNames() {
|
|
5292
|
+
return useContext(PeerNamesContext);
|
|
5293
|
+
}
|
|
5294
|
+
//#endregion
|
|
5078
5295
|
//#region src/components/terminal/press.tsx
|
|
5079
5296
|
const DRAG_SLOP = 4;
|
|
5080
5297
|
function Pressable({ onPress, expanded, className, children }) {
|
|
@@ -5299,72 +5516,6 @@ function evict(cache, keep) {
|
|
|
5299
5516
|
}
|
|
5300
5517
|
}
|
|
5301
5518
|
//#endregion
|
|
5302
|
-
//#region src/components/terminal/tool-run.ts
|
|
5303
|
-
function foldsTogether(a, b) {
|
|
5304
|
-
return a.parentToolUseId === b.parentToolUseId;
|
|
5305
|
-
}
|
|
5306
|
-
function toolFamily(name) {
|
|
5307
|
-
if (isShellTool(name)) return "shell";
|
|
5308
|
-
const mcp = /^mcp__([^_]+(?:_[^_]+)*?)__/.exec(name);
|
|
5309
|
-
if (mcp?.[1]) return mcp[1].replace(/_/g, "-");
|
|
5310
|
-
return name.toLowerCase();
|
|
5311
|
-
}
|
|
5312
|
-
function runSummary(items, busy) {
|
|
5313
|
-
const verb = busy ? "Running " : "Ran ";
|
|
5314
|
-
const tail = busy ? "…" : "";
|
|
5315
|
-
const n = items.length;
|
|
5316
|
-
const counts = /* @__PURE__ */ new Map();
|
|
5317
|
-
for (const item of items) {
|
|
5318
|
-
const family = toolFamily(item.name);
|
|
5319
|
-
counts.set(family, (counts.get(family) ?? 0) + 1);
|
|
5320
|
-
}
|
|
5321
|
-
if (counts.size === 1 && counts.has("shell")) return `${verb}${n} shell command${n === 1 ? "" : "s"}${tail}`;
|
|
5322
|
-
const breakdown = [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([family, count]) => `${count} ${family}`).join(", ");
|
|
5323
|
-
return `${verb}${n} tool${n === 1 ? "" : "s"} · ${breakdown}${tail}`;
|
|
5324
|
-
}
|
|
5325
|
-
function clip(text, max = 80) {
|
|
5326
|
-
return text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
5327
|
-
}
|
|
5328
|
-
function trimmed(value) {
|
|
5329
|
-
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
5330
|
-
}
|
|
5331
|
-
function taskLabel(task) {
|
|
5332
|
-
return `${task.name}(${taskIdentity(task)})`;
|
|
5333
|
-
}
|
|
5334
|
-
function taskIdentity(task) {
|
|
5335
|
-
const input = task.input;
|
|
5336
|
-
const description = trimmed(input?.description);
|
|
5337
|
-
const agent = trimmed(input?.subagent_type);
|
|
5338
|
-
return agent && description ? `${agent} · ${clip(description)}` : agent ?? (description ? clip(description) : toolInputPreview(task.input));
|
|
5339
|
-
}
|
|
5340
|
-
function taskBrief(task) {
|
|
5341
|
-
const input = task.input;
|
|
5342
|
-
return trimmed(input?.prompt);
|
|
5343
|
-
}
|
|
5344
|
-
function callBusy(call) {
|
|
5345
|
-
return call.status === "running" || call.status === "pending";
|
|
5346
|
-
}
|
|
5347
|
-
function callFailed(call) {
|
|
5348
|
-
return call.status === "failed" || call.result?.isError === true;
|
|
5349
|
-
}
|
|
5350
|
-
function runFailed(items) {
|
|
5351
|
-
const last = items[items.length - 1];
|
|
5352
|
-
return last !== void 0 && callFailed(last);
|
|
5353
|
-
}
|
|
5354
|
-
function taskBusy(task, children) {
|
|
5355
|
-
return callBusy(task) || children.some((child) => child.kind === "tool_call" && callBusy(child));
|
|
5356
|
-
}
|
|
5357
|
-
function taskFailed(task) {
|
|
5358
|
-
return callFailed(task);
|
|
5359
|
-
}
|
|
5360
|
-
function taskSummary$1(task, children) {
|
|
5361
|
-
const busy = taskBusy(task, children);
|
|
5362
|
-
const calls = children.reduce((n, child) => n + (child.kind === "tool_call" ? 1 : 0), 0);
|
|
5363
|
-
const label = taskLabel(task);
|
|
5364
|
-
if (calls === 0) return busy ? `${label} · working…` : `${label} · done`;
|
|
5365
|
-
return `${label} · ${calls} tool${calls === 1 ? "" : "s"}${busy ? "…" : ""}`;
|
|
5366
|
-
}
|
|
5367
|
-
//#endregion
|
|
5368
5519
|
//#region src/components/terminal/todos.ts
|
|
5369
5520
|
const PREVIEW_TODOS = 8;
|
|
5370
5521
|
const GLYPH = {
|
|
@@ -5399,21 +5550,81 @@ function clipToChars(lines, maxChars) {
|
|
|
5399
5550
|
}
|
|
5400
5551
|
return out;
|
|
5401
5552
|
}
|
|
5553
|
+
function peerLabel(origin) {
|
|
5554
|
+
const who = origin.name ? `${origin.name} (${origin.sessionId.slice(0, 8)})` : origin.sessionId.slice(0, 8);
|
|
5555
|
+
return `message from ${origin.engine ? `${origin.engine} session ` : "session "}${who}`;
|
|
5556
|
+
}
|
|
5557
|
+
function PeerRow({ glyph, who, body, tone = "peer", clip }) {
|
|
5558
|
+
const line = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
5559
|
+
/* @__PURE__ */ jsx(Ink, {
|
|
5560
|
+
tone,
|
|
5561
|
+
bold: true,
|
|
5562
|
+
children: who
|
|
5563
|
+
}),
|
|
5564
|
+
": ",
|
|
5565
|
+
body
|
|
5566
|
+
] });
|
|
5567
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
5568
|
+
glyph,
|
|
5569
|
+
glyphTone: tone,
|
|
5570
|
+
tone,
|
|
5571
|
+
children: clip ? /* @__PURE__ */ jsx("span", {
|
|
5572
|
+
className: "term-clip-1",
|
|
5573
|
+
children: line
|
|
5574
|
+
}) : line
|
|
5575
|
+
});
|
|
5576
|
+
}
|
|
5577
|
+
function PeerSendRow({ item }) {
|
|
5578
|
+
const [open, setOpen] = useState(false);
|
|
5579
|
+
const names = usePeerNames();
|
|
5580
|
+
const reveal = useRevealOnOpen(open);
|
|
5581
|
+
const lines = peerSendText(item).split("\n");
|
|
5582
|
+
const tone = item.status === "failed" || item.result?.isError === true ? "red" : "peer";
|
|
5583
|
+
return /* @__PURE__ */ jsx(WithActions, {
|
|
5584
|
+
actions: /* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
|
|
5585
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
5586
|
+
ref: reveal,
|
|
5587
|
+
className: open ? "term-open" : void 0,
|
|
5588
|
+
children: [/* @__PURE__ */ jsx(Pressable, {
|
|
5589
|
+
onPress: () => setOpen((v) => !v),
|
|
5590
|
+
expanded: open,
|
|
5591
|
+
children: /* @__PURE__ */ jsx(PeerRow, {
|
|
5592
|
+
glyph: "↤",
|
|
5593
|
+
who: peerSendTarget(item, names),
|
|
5594
|
+
tone,
|
|
5595
|
+
clip: !open,
|
|
5596
|
+
body: open ? lines[0] || "\xA0" : peerOneLine(lines.join(" "))
|
|
5597
|
+
})
|
|
5598
|
+
}), open ? /* @__PURE__ */ jsxs("div", { children: [lines.slice(1).map((line, index) => /* @__PURE__ */ jsx(Row, {
|
|
5599
|
+
tone,
|
|
5600
|
+
children: line || "\xA0"
|
|
5601
|
+
}, index)), item.result ? /* @__PURE__ */ jsx(Row, {
|
|
5602
|
+
tone: "faint",
|
|
5603
|
+
children: peerOneLine(item.result.text)
|
|
5604
|
+
}) : null] }) : null]
|
|
5605
|
+
})
|
|
5606
|
+
});
|
|
5607
|
+
}
|
|
5402
5608
|
function UserRow({ item }) {
|
|
5403
5609
|
return /* @__PURE__ */ jsx(WithActions, {
|
|
5404
5610
|
actions: /* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
|
|
5405
5611
|
children: /* @__PURE__ */ jsxs("div", {
|
|
5406
5612
|
className: "term-user",
|
|
5613
|
+
"data-peer": item.origin ? "" : void 0,
|
|
5407
5614
|
children: [item.attachments?.length ? /* @__PURE__ */ jsx(Row, {
|
|
5408
5615
|
glyph: "❯",
|
|
5409
5616
|
glyphTone: "dim",
|
|
5410
5617
|
tone: "dim",
|
|
5411
5618
|
children: item.attachments.map((attachment) => attachment.name).join(", ")
|
|
5412
|
-
}) : null, item.text ? item.text.split("\n").map((line, index) => /* @__PURE__ */ jsx(
|
|
5413
|
-
glyph:
|
|
5619
|
+
}) : null, item.text ? item.text.split("\n").map((line, index) => item.origin && index === 0 ? /* @__PURE__ */ jsx(PeerRow, {
|
|
5620
|
+
glyph: "↦",
|
|
5621
|
+
who: peerName(item.origin),
|
|
5622
|
+
body: line ? /* @__PURE__ */ jsx(PromptTokenText, { text: line }) : "\xA0"
|
|
5623
|
+
}, index) : /* @__PURE__ */ jsx(Row, {
|
|
5624
|
+
glyph: !item.origin && index === 0 ? "❯" : void 0,
|
|
5414
5625
|
glyphTone: "dim",
|
|
5415
|
-
tone: "fg",
|
|
5416
|
-
children: line
|
|
5626
|
+
tone: item.origin ? "peer" : "fg",
|
|
5627
|
+
children: line ? /* @__PURE__ */ jsx(PromptTokenText, { text: line }) : "\xA0"
|
|
5417
5628
|
}, index)) : null]
|
|
5418
5629
|
})
|
|
5419
5630
|
});
|
|
@@ -5497,6 +5708,7 @@ function ToolRow({ item }) {
|
|
|
5497
5708
|
/* @__PURE__ */ jsx(Ink, {
|
|
5498
5709
|
bold: true,
|
|
5499
5710
|
tone: "bright",
|
|
5711
|
+
className: busy ? "term-shimmer" : void 0,
|
|
5500
5712
|
children: title ?? item.name
|
|
5501
5713
|
}),
|
|
5502
5714
|
/* @__PURE__ */ jsxs(Ink, {
|
|
@@ -5632,11 +5844,19 @@ function ToolRunRow({ items }) {
|
|
|
5632
5844
|
glyph: busy ? pulse : void 0,
|
|
5633
5845
|
glyphTone: busy ? "mark" : void 0,
|
|
5634
5846
|
tone: failed ? "red" : "dim",
|
|
5635
|
-
children:
|
|
5847
|
+
children: busy ? /* @__PURE__ */ jsx("span", {
|
|
5848
|
+
className: "term-shimmer",
|
|
5849
|
+
children: runSummary(items, busy)
|
|
5850
|
+
}) : runSummary(items, busy)
|
|
5636
5851
|
})
|
|
5637
5852
|
}), open ? /* @__PURE__ */ jsx("div", { children: items.map((item) => /* @__PURE__ */ jsx(ToolRow, { item }, item.id)) }) : null]
|
|
5638
5853
|
});
|
|
5639
5854
|
}
|
|
5855
|
+
function RunRow({ items }) {
|
|
5856
|
+
const plan = planRun(items);
|
|
5857
|
+
if (plan.kind === "summary") return /* @__PURE__ */ jsx(ToolRunRow, { items: plan.items });
|
|
5858
|
+
return isPeerSend(plan.item) ? /* @__PURE__ */ jsx(PeerSendRow, { item: plan.item }) : /* @__PURE__ */ jsx(ToolRow, { item: plan.item });
|
|
5859
|
+
}
|
|
5640
5860
|
function TurnResultRow$1({ item }) {
|
|
5641
5861
|
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(Row, {
|
|
5642
5862
|
tone: item.isError ? "red" : "faint",
|
|
@@ -5645,7 +5865,7 @@ function TurnResultRow$1({ item }) {
|
|
|
5645
5865
|
" · ",
|
|
5646
5866
|
formatDuration(item.durationMs),
|
|
5647
5867
|
" · ",
|
|
5648
|
-
formatCost(item.totalCostUsd)
|
|
5868
|
+
formatCost(item.costUsd ?? item.totalCostUsd)
|
|
5649
5869
|
]
|
|
5650
5870
|
}), item.errors?.map((message, index) => /* @__PURE__ */ jsx(Row, {
|
|
5651
5871
|
tone: "red",
|
|
@@ -5714,7 +5934,10 @@ function WorkingRow({ label, startedAt, tokens }) {
|
|
|
5714
5934
|
glyph: pulse,
|
|
5715
5935
|
glyphTone: "mark",
|
|
5716
5936
|
tone: "mark",
|
|
5717
|
-
children: [
|
|
5937
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
5938
|
+
className: "term-shimmer",
|
|
5939
|
+
children: label
|
|
5940
|
+
}), readings.length ? /* @__PURE__ */ jsxs(Ink, {
|
|
5718
5941
|
tone: "faint",
|
|
5719
5942
|
children: [
|
|
5720
5943
|
" (",
|
|
@@ -5795,9 +6018,15 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5795
6018
|
}),
|
|
5796
6019
|
insertAsText: (suggestion) => {
|
|
5797
6020
|
const row = byTag.get(String(suggestion.data));
|
|
5798
|
-
if (row?.kind === "skill") return skillPrompt(row.skill);
|
|
5799
6021
|
return row?.kind === "client" && row.command.requiresArgs ? `/${row.name} ` : void 0;
|
|
5800
6022
|
},
|
|
6023
|
+
chipOptions: (suggestion) => {
|
|
6024
|
+
const row = byTag.get(String(suggestion.data));
|
|
6025
|
+
return row?.kind === "skill" ? {
|
|
6026
|
+
sigil: "$",
|
|
6027
|
+
trailingText: skillTrailingText(row.skill)
|
|
6028
|
+
} : void 0;
|
|
6029
|
+
},
|
|
5801
6030
|
onSelect: (suggestion) => suggestion.value,
|
|
5802
6031
|
chipClassName: "font-mono"
|
|
5803
6032
|
}));
|
|
@@ -7384,7 +7613,7 @@ function taskChildItems(block) {
|
|
|
7384
7613
|
}
|
|
7385
7614
|
function pushLeaf(out, item, index) {
|
|
7386
7615
|
const previous = out.at(-1);
|
|
7387
|
-
if (isRunCall(item)) {
|
|
7616
|
+
if (isRunCall(item) && !isPeerSend(item)) {
|
|
7388
7617
|
if (previous && "run" in previous && foldsTogether(previous.run[0], item)) {
|
|
7389
7618
|
previous.run.push(item);
|
|
7390
7619
|
previous.indices.push(index);
|
|
@@ -7450,12 +7679,15 @@ function terminalBlocks(items, offset = 0, fold = true) {
|
|
|
7450
7679
|
return out;
|
|
7451
7680
|
}
|
|
7452
7681
|
function needsBlank(previous, next) {
|
|
7453
|
-
if (previous
|
|
7454
|
-
return
|
|
7682
|
+
if (isPeerSend(previous) || isPeerSend(next)) return true;
|
|
7683
|
+
return !(previous.kind === "tool_call" && next.kind === "tool_call");
|
|
7684
|
+
}
|
|
7685
|
+
function blockKind(block) {
|
|
7686
|
+
if (!("item" in block)) return "tool_call";
|
|
7687
|
+
return isPeerSend(block.item) ? "peer_send" : block.item.kind;
|
|
7455
7688
|
}
|
|
7456
7689
|
function blockNeedsBlank(previous, next) {
|
|
7457
|
-
|
|
7458
|
-
return !(kind(previous) === "tool_call" && kind(next) === "tool_call");
|
|
7690
|
+
return !(blockKind(previous) === "tool_call" && blockKind(next) === "tool_call");
|
|
7459
7691
|
}
|
|
7460
7692
|
//#endregion
|
|
7461
7693
|
//#region src/components/agent/use-subagent-frame.ts
|
|
@@ -8218,7 +8450,7 @@ function SessionInfoDialog({ state, client, sessionId, open, onOpenChange }) {
|
|
|
8218
8450
|
/* @__PURE__ */ jsx(DialogRow, {
|
|
8219
8451
|
label: "Cost",
|
|
8220
8452
|
mono: true,
|
|
8221
|
-
children: formatCost(state.totalCostUsd)
|
|
8453
|
+
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
8222
8454
|
})
|
|
8223
8455
|
]
|
|
8224
8456
|
}),
|
|
@@ -8528,7 +8760,7 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
|
|
|
8528
8760
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
8529
8761
|
/* @__PURE__ */ jsx("span", {
|
|
8530
8762
|
className: "font-mono text-label text-fg-3",
|
|
8531
|
-
children: formatCost(state.totalCostUsd)
|
|
8763
|
+
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
8532
8764
|
}),
|
|
8533
8765
|
actions ? /* @__PURE__ */ jsx("span", {
|
|
8534
8766
|
className: "self-center",
|
|
@@ -9210,12 +9442,20 @@ function itemHeight(item, m) {
|
|
|
9210
9442
|
exact: true
|
|
9211
9443
|
};
|
|
9212
9444
|
if (item.attachments?.length) acc = add(acc, rowH(item.attachments.map((a) => a.name).join(", "), m, { extraPx }));
|
|
9213
|
-
if (item.text)
|
|
9445
|
+
if (item.text) {
|
|
9446
|
+
const who = item.origin ? `${peerName(item.origin)}: ` : "";
|
|
9447
|
+
for (const [index, line] of item.text.split("\n").entries()) acc = add(acc, rowH((index === 0 ? who : "") + (line || " "), m, { extraPx }));
|
|
9448
|
+
}
|
|
9214
9449
|
return acc;
|
|
9215
9450
|
}
|
|
9216
9451
|
case "assistant_text": return markdownHeight(item.text, m, extraPx);
|
|
9217
9452
|
case "thinking": return rowH(item.text, m, { extraPx });
|
|
9218
|
-
case "tool_call":
|
|
9453
|
+
case "tool_call":
|
|
9454
|
+
if (isPeerSend(item)) return {
|
|
9455
|
+
px: m.line + extraPx,
|
|
9456
|
+
exact: true
|
|
9457
|
+
};
|
|
9458
|
+
return toolRowHeight(item, m, extraPx);
|
|
9219
9459
|
case "turn_result": {
|
|
9220
9460
|
let acc = rowH(`${item.isError ? item.subtype : "done"} · ${formatDuration(item.durationMs)} · ${formatCost(item.totalCostUsd)}`, m, { extraPx });
|
|
9221
9461
|
for (const message of item.errors ?? []) acc = add(acc, rowH(message, m, { extraPx }));
|
|
@@ -9233,8 +9473,10 @@ function itemHeight(item, m) {
|
|
|
9233
9473
|
function blockHeight(block, m) {
|
|
9234
9474
|
if ("task" in block) return rowH(taskSummary$1(block.task, taskChildItems(block)), m);
|
|
9235
9475
|
if ("run" in block) {
|
|
9236
|
-
const
|
|
9237
|
-
|
|
9476
|
+
const plan = planRun(block.run);
|
|
9477
|
+
if (plan.kind === "call") return itemHeight(plan.item, m);
|
|
9478
|
+
const busy = plan.items.some((item) => item.status === "running" || item.status === "pending");
|
|
9479
|
+
return rowH(runSummary(plan.items, busy), m);
|
|
9238
9480
|
}
|
|
9239
9481
|
return itemHeight(block.item, m);
|
|
9240
9482
|
}
|
|
@@ -10070,6 +10312,20 @@ function repinToBottom(stick) {
|
|
|
10070
10312
|
};
|
|
10071
10313
|
state.scrollTop = state.calculatedTargetScrollTop;
|
|
10072
10314
|
}
|
|
10315
|
+
function absorbScrollerResize(stick, difference) {
|
|
10316
|
+
const { state } = stick;
|
|
10317
|
+
state.resizeDifference = difference;
|
|
10318
|
+
requestAnimationFrame(() => {
|
|
10319
|
+
setTimeout(() => {
|
|
10320
|
+
if (state.resizeDifference === difference) state.resizeDifference = 0;
|
|
10321
|
+
}, 1);
|
|
10322
|
+
});
|
|
10323
|
+
if (state.animation?.ignoreEscapes) {
|
|
10324
|
+
state.scrollTop = state.calculatedTargetScrollTop;
|
|
10325
|
+
return;
|
|
10326
|
+
}
|
|
10327
|
+
stick.scrollToBottom("instant");
|
|
10328
|
+
}
|
|
10073
10329
|
function useTranscriptJumps(options) {
|
|
10074
10330
|
const { rows, terminal, stickyPrompt, epoch, promptRows, scrollElement, rowsRef, virtualizer, stick, jumpToRecapRef, repinRef } = options;
|
|
10075
10331
|
const aimTimer = useRef(void 0);
|
|
@@ -10147,7 +10403,7 @@ function TerminalItemView({ item, fileUrl }) {
|
|
|
10147
10403
|
case "user": return /* @__PURE__ */ jsx(UserRow, { item });
|
|
10148
10404
|
case "assistant_text": return /* @__PURE__ */ jsx(AssistantRow, { item });
|
|
10149
10405
|
case "thinking": return /* @__PURE__ */ jsx(ThinkingRow, { item });
|
|
10150
|
-
case "tool_call": return /* @__PURE__ */ jsx(ToolRow, { item });
|
|
10406
|
+
case "tool_call": return isPeerSend(item) ? /* @__PURE__ */ jsx(PeerSendRow, { item }) : /* @__PURE__ */ jsx(ToolRow, { item });
|
|
10151
10407
|
case "turn_result": return /* @__PURE__ */ jsx(TurnResultRow$1, { item });
|
|
10152
10408
|
case "notice": return /* @__PURE__ */ jsx(NoticeRow$1, { item });
|
|
10153
10409
|
case "compaction": return /* @__PURE__ */ jsx(CompactionRow$1, { item });
|
|
@@ -10201,14 +10457,17 @@ function TaskRow({ block, fileUrl, onOpenSubagent }) {
|
|
|
10201
10457
|
glyph: busy ? pulse : "●",
|
|
10202
10458
|
glyphTone: failed ? "red" : busy ? "mark" : "dim",
|
|
10203
10459
|
tone: failed ? "red" : "green",
|
|
10204
|
-
children:
|
|
10460
|
+
children: busy ? /* @__PURE__ */ jsx("span", {
|
|
10461
|
+
className: "term-shimmer",
|
|
10462
|
+
children: taskSummary$1(block.task, children)
|
|
10463
|
+
}) : taskSummary$1(block.task, children)
|
|
10205
10464
|
})
|
|
10206
10465
|
}), open ? /* @__PURE__ */ jsxs("div", {
|
|
10207
10466
|
className: "term-nested",
|
|
10208
10467
|
children: [brief ? /* @__PURE__ */ jsx(BriefRow, {
|
|
10209
10468
|
text: brief,
|
|
10210
10469
|
terminal: true
|
|
10211
|
-
}) : null, block.children.map((leaf, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && blockNeedsBlank(block.children[index - 1], leaf) ? /* @__PURE__ */ jsx(Blank, {}) : null, "run" in leaf ? /* @__PURE__ */ jsx(
|
|
10470
|
+
}) : null, block.children.map((leaf, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && blockNeedsBlank(block.children[index - 1], leaf) ? /* @__PURE__ */ jsx(Blank, {}) : null, "run" in leaf ? /* @__PURE__ */ jsx(RunRow, { items: leaf.run }) : /* @__PURE__ */ jsx(TerminalItemView, {
|
|
10212
10471
|
item: leaf.item,
|
|
10213
10472
|
fileUrl
|
|
10214
10473
|
})] }, leaf.key))]
|
|
@@ -10238,23 +10497,26 @@ function working(state) {
|
|
|
10238
10497
|
function TerminalTranscript({ state, fileUrl, fontSize, lineHeight, affordances, className }) {
|
|
10239
10498
|
const runStartedAt = useRunStart$1(state.status);
|
|
10240
10499
|
const blocks = useMemo(() => terminalBlocks(state.items), [state.items]);
|
|
10241
|
-
return /* @__PURE__ */
|
|
10500
|
+
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
10242
10501
|
fontSize,
|
|
10243
10502
|
lineHeight,
|
|
10244
10503
|
affordances,
|
|
10245
10504
|
bleed: "1ch",
|
|
10246
10505
|
className: cn("term-transcript", className),
|
|
10247
|
-
children:
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10506
|
+
children: /* @__PURE__ */ jsxs(PeerNamesProvider, {
|
|
10507
|
+
items: state.items,
|
|
10508
|
+
children: [blocks.map((block, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && blockNeedsBlank(blocks[index - 1], block) ? /* @__PURE__ */ jsx(Blank, {}) : null, "run" in block ? /* @__PURE__ */ jsx(RunRow, { items: block.run }) : "item" in block ? /* @__PURE__ */ jsx(TerminalItemView, {
|
|
10509
|
+
item: block.item,
|
|
10510
|
+
fileUrl
|
|
10511
|
+
}) : /* @__PURE__ */ jsx(TaskRow, {
|
|
10512
|
+
block,
|
|
10513
|
+
fileUrl
|
|
10514
|
+
})] }, block.key)), working(state) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx(Blank, {}) : null, /* @__PURE__ */ jsx(WorkingRow, {
|
|
10515
|
+
label: state.status === "starting" ? "Starting…" : "Working…",
|
|
10516
|
+
startedAt: runStartedAt,
|
|
10517
|
+
tokens: state.contextUsage?.totalTokens
|
|
10518
|
+
})] }) : null]
|
|
10519
|
+
})
|
|
10258
10520
|
});
|
|
10259
10521
|
}
|
|
10260
10522
|
//#endregion
|
|
@@ -10304,30 +10566,6 @@ function MessageContent({ className, ...props }) {
|
|
|
10304
10566
|
});
|
|
10305
10567
|
}
|
|
10306
10568
|
//#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
10569
|
//#region src/components/agent/Reasoning.tsx
|
|
10332
10570
|
function Reasoning({ children, isStreaming = false, defaultOpen, className }) {
|
|
10333
10571
|
const [open, setOpen] = useState(defaultOpen ?? isStreaming);
|
|
@@ -10635,7 +10873,7 @@ function TurnResultRow({ item }) {
|
|
|
10635
10873
|
" · ",
|
|
10636
10874
|
formatDuration(item.durationMs),
|
|
10637
10875
|
" · ",
|
|
10638
|
-
formatCost(item.totalCostUsd)
|
|
10876
|
+
formatCost(item.costUsd ?? item.totalCostUsd)
|
|
10639
10877
|
]
|
|
10640
10878
|
}),
|
|
10641
10879
|
/* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
|
|
@@ -10664,10 +10902,17 @@ function TranscriptItemView({ item, fileUrl, attachmentUrl, hostImage, terminal
|
|
|
10664
10902
|
switch (item.kind) {
|
|
10665
10903
|
case "user": return /* @__PURE__ */ jsxs(Message, {
|
|
10666
10904
|
from: "user",
|
|
10667
|
-
children: [
|
|
10668
|
-
|
|
10669
|
-
|
|
10670
|
-
|
|
10905
|
+
children: [
|
|
10906
|
+
item.origin ? /* @__PURE__ */ jsx("div", {
|
|
10907
|
+
className: "wd-peer-origin text-xs text-muted-foreground",
|
|
10908
|
+
children: peerLabel(item.origin)
|
|
10909
|
+
}) : null,
|
|
10910
|
+
item.attachments?.length ? /* @__PURE__ */ jsx(SentAttachments, {
|
|
10911
|
+
attachments: item.attachments,
|
|
10912
|
+
attachmentUrl
|
|
10913
|
+
}) : null,
|
|
10914
|
+
item.text ? /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(PromptTokenText, { text: item.text }) }) : null
|
|
10915
|
+
]
|
|
10671
10916
|
});
|
|
10672
10917
|
case "assistant_text": return /* @__PURE__ */ jsx(Message, {
|
|
10673
10918
|
from: "assistant",
|
|
@@ -10842,8 +11087,9 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
10842
11087
|
const observer = new ResizeObserver(() => {
|
|
10843
11088
|
const height = scrollElement.clientHeight;
|
|
10844
11089
|
if (height === last) return;
|
|
11090
|
+
const difference = height - last;
|
|
10845
11091
|
last = height;
|
|
10846
|
-
if (stick.state.isAtBottom) stick
|
|
11092
|
+
if (stick.state.isAtBottom) absorbScrollerResize(stick, difference);
|
|
10847
11093
|
});
|
|
10848
11094
|
observer.observe(scrollElement);
|
|
10849
11095
|
return () => observer.disconnect();
|
|
@@ -10963,59 +11209,62 @@ function TranscriptRows({ rows, boundary, since, terminal, replaying, stickyProm
|
|
|
10963
11209
|
"data-slot": "transcript-rows",
|
|
10964
11210
|
className: "relative w-full",
|
|
10965
11211
|
style: { height: virtualizer.getTotalSize() },
|
|
10966
|
-
children: [
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
11212
|
+
children: [/* @__PURE__ */ jsx(PeerNamesProvider, {
|
|
11213
|
+
items,
|
|
11214
|
+
children: virtualizer.getVirtualItems().map((virtualRow) => {
|
|
11215
|
+
const row = rows[virtualRow.index];
|
|
11216
|
+
const gapClass = virtualRow.index > 0 && (!terminal || gapBefore(rows, virtualRow.index)) ? gap.className : void 0;
|
|
11217
|
+
const content = "run" in row ? /* @__PURE__ */ jsx("div", {
|
|
11218
|
+
className: cn(read(boundary, row.index) && "opacity-45"),
|
|
11219
|
+
children: /* @__PURE__ */ jsx(RunRow, { items: row.run })
|
|
11220
|
+
}) : "item" in row ? /* @__PURE__ */ jsx("div", {
|
|
11221
|
+
className: cn(read(boundary, row.index) && "opacity-45", nestedClass(row.item, frameParentId)),
|
|
11222
|
+
children: /* @__PURE__ */ jsx(TranscriptItemView, {
|
|
11223
|
+
item: row.item,
|
|
11224
|
+
fileUrl,
|
|
11225
|
+
attachmentUrl,
|
|
11226
|
+
hostImage,
|
|
11227
|
+
terminal
|
|
11228
|
+
})
|
|
11229
|
+
}) : "text" in row && row.key === "brief" ? /* @__PURE__ */ jsx(BriefRow, {
|
|
11230
|
+
text: row.text,
|
|
10979
11231
|
terminal
|
|
10980
|
-
})
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
|
|
11001
|
-
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11232
|
+
}) : "line" in row ? /* @__PURE__ */ jsx(RecapRow, {
|
|
11233
|
+
line: row.line,
|
|
11234
|
+
since,
|
|
11235
|
+
terminal
|
|
11236
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
11237
|
+
className: cn(read(boundary, row.index) && "opacity-45"),
|
|
11238
|
+
children: /* @__PURE__ */ jsx(TaskRow, {
|
|
11239
|
+
block: row,
|
|
11240
|
+
fileUrl,
|
|
11241
|
+
onOpenSubagent
|
|
11242
|
+
})
|
|
11243
|
+
});
|
|
11244
|
+
if (stickyPrompt && "item" in row && row.item.kind === "user" && parentOf(row.item) === void 0) {
|
|
11245
|
+
const next = promptRows.find((index) => index > virtualRow.index);
|
|
11246
|
+
const laneEnd = next === void 0 ? virtualizer.getTotalSize() : measurements[next]?.start ?? virtualRow.start;
|
|
11247
|
+
return /* @__PURE__ */ jsx(StickyPromptLane, {
|
|
11248
|
+
top: virtualRow.start,
|
|
11249
|
+
height: Math.max(laneEnd - virtualRow.start, 0),
|
|
11250
|
+
gapClass,
|
|
11251
|
+
gapPx: gap.px,
|
|
11252
|
+
terminal,
|
|
11253
|
+
scrollRoot: scrollElement,
|
|
11254
|
+
index: virtualRow.index,
|
|
11255
|
+
measureRef: virtualizer.measureElement,
|
|
11256
|
+
head: terminal ? content : promptHeadText(row.item),
|
|
11257
|
+
content
|
|
11258
|
+
}, row.key);
|
|
11259
|
+
}
|
|
11260
|
+
return /* @__PURE__ */ jsx("div", {
|
|
11261
|
+
ref: virtualizer.measureElement,
|
|
11262
|
+
"data-index": virtualRow.index,
|
|
11263
|
+
className: cn("absolute inset-x-0 top-0", gapClass),
|
|
11264
|
+
style: { transform: `translateY(${virtualRow.start}px)` },
|
|
11265
|
+
children: content
|
|
11010
11266
|
}, row.key);
|
|
11011
|
-
}
|
|
11012
|
-
return /* @__PURE__ */ jsx("div", {
|
|
11013
|
-
ref: virtualizer.measureElement,
|
|
11014
|
-
"data-index": virtualRow.index,
|
|
11015
|
-
className: cn("absolute inset-x-0 top-0", gapClass),
|
|
11016
|
-
style: { transform: `translateY(${virtualRow.start}px)` },
|
|
11017
|
-
children: content
|
|
11018
|
-
}, row.key);
|
|
11267
|
+
})
|
|
11019
11268
|
}), scrubber && scrollElement?.parentElement ? createPortal(terminal ? /* @__PURE__ */ jsx(TerminalScrubber, {
|
|
11020
11269
|
items,
|
|
11021
11270
|
pendingApprovals,
|
|
@@ -11108,85 +11357,119 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
11108
11357
|
terminal,
|
|
11109
11358
|
brief
|
|
11110
11359
|
]);
|
|
11360
|
+
const skillNames = useMemo(() => state.skills?.map((skill) => skill.name), [state.skills]);
|
|
11111
11361
|
return /* @__PURE__ */ jsx(TranscriptVariantProvider, {
|
|
11112
11362
|
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, {
|
|
11363
|
+
children: /* @__PURE__ */ jsx(SkillNamesProvider, {
|
|
11364
|
+
names: skillNames,
|
|
11365
|
+
children: /* @__PURE__ */ jsxs(Conversation, {
|
|
11366
|
+
className: cn(replaying && "invisible", className),
|
|
11367
|
+
children: [
|
|
11368
|
+
/* @__PURE__ */ jsx(ConversationContent, {
|
|
11369
|
+
className: cn(terminal && "gap-0 p-0"),
|
|
11370
|
+
children: /* @__PURE__ */ jsxs(TerminalShell, {
|
|
11371
|
+
active: terminal,
|
|
11176
11372
|
fontSize,
|
|
11177
11373
|
lineHeight,
|
|
11178
|
-
affordances
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11374
|
+
affordances,
|
|
11375
|
+
children: [
|
|
11376
|
+
frame ? frameTask === void 0 && !replaying ? /* @__PURE__ */ jsx("div", {
|
|
11377
|
+
className: cn(terminal ? "term-row text-fg-4" : "p-4 text-body-sm text-fg-4"),
|
|
11378
|
+
children: "This sub-agent's work is not in this transcript."
|
|
11379
|
+
}) : null : items.length === 0 && state.status !== "starting" ? emptyState !== void 0 ? emptyState : /* @__PURE__ */ jsx(SessionEmptyState, {
|
|
11380
|
+
cwd: state.cwd,
|
|
11381
|
+
hasCommands: !!state.commands?.length,
|
|
11382
|
+
hasSkills: !!state.skills?.some((s) => s.enabled),
|
|
11383
|
+
canBrowseFiles
|
|
11384
|
+
}) : null,
|
|
11385
|
+
frame && frameTask === void 0 && !replaying ? null : /* @__PURE__ */ jsx(TranscriptRows, {
|
|
11386
|
+
rows,
|
|
11387
|
+
boundary,
|
|
11388
|
+
since: catchUp?.since,
|
|
11389
|
+
terminal,
|
|
11390
|
+
replaying,
|
|
11391
|
+
stickyPrompt: !frame && stickyPrompt,
|
|
11392
|
+
gap,
|
|
11393
|
+
fontSize,
|
|
11394
|
+
lineHeight,
|
|
11395
|
+
items,
|
|
11396
|
+
pendingApprovals: state.pendingApprovals,
|
|
11397
|
+
scrubber,
|
|
11398
|
+
bookmarks: frame ? void 0 : bookmarks,
|
|
11399
|
+
affordances,
|
|
11400
|
+
fileUrl,
|
|
11401
|
+
attachmentUrl,
|
|
11402
|
+
hostImage,
|
|
11403
|
+
jumpToRecapRef,
|
|
11404
|
+
repinRef,
|
|
11405
|
+
reveal: frame ? void 0 : reveal,
|
|
11406
|
+
frameParentId: frame?.parentToolUseId,
|
|
11407
|
+
onOpenSubagent: frame ? void 0 : onOpenSubagent
|
|
11408
|
+
}),
|
|
11409
|
+
(frame ? frameTask !== void 0 && taskBusy(frameTask, items) : showLoader(state)) ? terminal ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
11410
|
+
className: "term-blank",
|
|
11411
|
+
"aria-hidden": true
|
|
11412
|
+
}) : null, /* @__PURE__ */ jsx(WorkingRow, {
|
|
11413
|
+
label: state.status === "starting" ? "Starting…" : "Working…",
|
|
11414
|
+
startedAt: runStartedAt,
|
|
11415
|
+
tokens: state.contextUsage?.totalTokens
|
|
11416
|
+
})] }) : /* @__PURE__ */ jsx(Loader, { label: state.status === "starting" ? "Starting session…" : void 0 }) : null
|
|
11417
|
+
]
|
|
11418
|
+
})
|
|
11419
|
+
}),
|
|
11420
|
+
/* @__PURE__ */ jsx(ConversationScrollButton, {}),
|
|
11421
|
+
replaying ? /* @__PURE__ */ jsx("div", {
|
|
11422
|
+
"data-slot": "transcript-hold",
|
|
11423
|
+
"aria-hidden": true,
|
|
11424
|
+
className: "wd-hold-appear visible pointer-events-none absolute inset-0 overflow-hidden",
|
|
11425
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
11426
|
+
className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)]", !terminal && "px-4 py-4"),
|
|
11427
|
+
children: terminal ? /* @__PURE__ */ jsx(TerminalSurface, {
|
|
11428
|
+
fontSize,
|
|
11429
|
+
lineHeight,
|
|
11430
|
+
affordances: false,
|
|
11431
|
+
bleed: "1ch",
|
|
11432
|
+
className: "term-transcript",
|
|
11433
|
+
children: /* @__PURE__ */ jsx(WorkingRow, { label: "Loading…" })
|
|
11434
|
+
}) : /* @__PURE__ */ jsx(Loader, { label: "Loading session…" })
|
|
11435
|
+
})
|
|
11436
|
+
}) : null
|
|
11437
|
+
]
|
|
11438
|
+
})
|
|
11186
11439
|
})
|
|
11187
11440
|
});
|
|
11188
11441
|
}
|
|
11189
11442
|
//#endregion
|
|
11443
|
+
//#region src/lib/session-cost.ts
|
|
11444
|
+
const GAP_SHARE = .02;
|
|
11445
|
+
function sessionCost(input) {
|
|
11446
|
+
const byModel = input.usageByModel ?? {};
|
|
11447
|
+
const pricing = input.pricing;
|
|
11448
|
+
const breakdown = costOfByModel(byModel, pricing);
|
|
11449
|
+
const computedUsd = input.costUsd ?? (breakdown.unpriced || Object.keys(byModel).length === 0 ? void 0 : breakdown.total);
|
|
11450
|
+
const reportedUsd = input.totalCostUsd;
|
|
11451
|
+
const rows = Object.entries(byModel).map(([model, usage]) => ({
|
|
11452
|
+
model: canonicalModel(model),
|
|
11453
|
+
usage,
|
|
11454
|
+
tokens: totalTokens(usage),
|
|
11455
|
+
costUsd: rateFor(model, pricing) ? costOf(usage, model, pricing).total : void 0,
|
|
11456
|
+
costBasis: usage.costBasis
|
|
11457
|
+
})).sort((a, b) => b.tokens - a.tokens);
|
|
11458
|
+
const gap = computedUsd !== void 0 && reportedUsd !== void 0 ? reportedUsd - computedUsd : void 0;
|
|
11459
|
+
const worthShowing = gap !== void 0 && Math.abs(gap) > Math.max(.01, GAP_SHARE * Math.max(computedUsd ?? 0, reportedUsd ?? 0));
|
|
11460
|
+
return {
|
|
11461
|
+
displayUsd: computedUsd ?? reportedUsd,
|
|
11462
|
+
computedUsd,
|
|
11463
|
+
reportedUsd,
|
|
11464
|
+
breakdown,
|
|
11465
|
+
rows,
|
|
11466
|
+
unpricedShare: breakdown.unpricedShare,
|
|
11467
|
+
showUnpricedWarning: breakdown.unpricedShare > UNPRICED_WARN_SHARE,
|
|
11468
|
+
unknownBasisModels: unknownBasisModels(byModel),
|
|
11469
|
+
gapUsd: worthShowing ? gap : void 0
|
|
11470
|
+
};
|
|
11471
|
+
}
|
|
11472
|
+
//#endregion
|
|
11190
11473
|
//#region src/components/agent/UsageMeters.tsx
|
|
11191
11474
|
function useMinuteClock(active = true) {
|
|
11192
11475
|
const [now, setNow] = useState(() => Date.now());
|
|
@@ -11270,8 +11553,148 @@ function UsageMeter({ window, now }) {
|
|
|
11270
11553
|
}
|
|
11271
11554
|
//#endregion
|
|
11272
11555
|
//#region src/components/agent/UsageDialog.tsx
|
|
11273
|
-
function
|
|
11556
|
+
function engineLabel(engine) {
|
|
11557
|
+
return engine === "claude" ? "Claude Code" : engine;
|
|
11558
|
+
}
|
|
11559
|
+
function Line({ label, value, tone }) {
|
|
11560
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11561
|
+
className: "flex items-baseline justify-between gap-4",
|
|
11562
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
11563
|
+
className: tone === "muted" ? "text-label text-fg-4" : "text-label text-fg-3",
|
|
11564
|
+
children: label
|
|
11565
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
11566
|
+
className: `font-mono text-body-sm ${tone === "muted" ? "text-fg-4" : "text-fg-1"}`,
|
|
11567
|
+
children: value
|
|
11568
|
+
})]
|
|
11569
|
+
});
|
|
11570
|
+
}
|
|
11571
|
+
function CostEvidence({ cost, engine }) {
|
|
11572
|
+
const { breakdown, rows } = cost;
|
|
11573
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx(Line, {
|
|
11574
|
+
label: "This session has cost",
|
|
11575
|
+
value: formatCost(cost.displayUsd)
|
|
11576
|
+
});
|
|
11577
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11578
|
+
className: "space-y-3",
|
|
11579
|
+
children: [
|
|
11580
|
+
/* @__PURE__ */ jsxs("div", {
|
|
11581
|
+
className: "flex items-baseline justify-between gap-4",
|
|
11582
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
11583
|
+
className: "text-label text-fg-3",
|
|
11584
|
+
children: "This session has cost"
|
|
11585
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
11586
|
+
className: "font-mono text-body text-fg-1",
|
|
11587
|
+
children: formatCost(cost.displayUsd)
|
|
11588
|
+
})]
|
|
11589
|
+
}),
|
|
11590
|
+
/* @__PURE__ */ jsxs("div", {
|
|
11591
|
+
className: "space-y-1 border-t border-border pt-2",
|
|
11592
|
+
children: [
|
|
11593
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11594
|
+
label: "input",
|
|
11595
|
+
value: formatCost(breakdown.input),
|
|
11596
|
+
tone: "muted"
|
|
11597
|
+
}),
|
|
11598
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11599
|
+
label: "output",
|
|
11600
|
+
value: formatCost(breakdown.output),
|
|
11601
|
+
tone: "muted"
|
|
11602
|
+
}),
|
|
11603
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11604
|
+
label: "cache write",
|
|
11605
|
+
value: formatCost(breakdown.cacheWrite),
|
|
11606
|
+
tone: "muted"
|
|
11607
|
+
}),
|
|
11608
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11609
|
+
label: "cache read",
|
|
11610
|
+
value: formatCost(breakdown.cacheRead),
|
|
11611
|
+
tone: "muted"
|
|
11612
|
+
})
|
|
11613
|
+
]
|
|
11614
|
+
}),
|
|
11615
|
+
/* @__PURE__ */ jsx("div", {
|
|
11616
|
+
className: "space-y-1 border-t border-border pt-2",
|
|
11617
|
+
children: rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
11618
|
+
className: "flex items-baseline justify-between gap-4",
|
|
11619
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
11620
|
+
className: "truncate text-label text-fg-4",
|
|
11621
|
+
children: row.model
|
|
11622
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
11623
|
+
className: "shrink-0 font-mono text-label text-fg-4",
|
|
11624
|
+
children: [
|
|
11625
|
+
formatTokens(row.tokens),
|
|
11626
|
+
" · ",
|
|
11627
|
+
row.costUsd === void 0 ? "no rate" : formatCost(row.costUsd)
|
|
11628
|
+
]
|
|
11629
|
+
})]
|
|
11630
|
+
}, row.model))
|
|
11631
|
+
}),
|
|
11632
|
+
cost.showUnpricedWarning ? /* @__PURE__ */ jsxs("p", {
|
|
11633
|
+
className: "text-label text-warning",
|
|
11634
|
+
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."]
|
|
11635
|
+
}) : null,
|
|
11636
|
+
cost.unknownBasisModels.length > 0 ? /* @__PURE__ */ jsxs("p", {
|
|
11637
|
+
className: "text-label text-warning",
|
|
11638
|
+
children: [
|
|
11639
|
+
engineLabel(engine),
|
|
11640
|
+
" matched no rate table of its own to ",
|
|
11641
|
+
cost.unknownBasisModels.join(", "),
|
|
11642
|
+
", so the figure it reports for those tokens is a guess rather than a rate."
|
|
11643
|
+
]
|
|
11644
|
+
}) : null,
|
|
11645
|
+
cost.gapUsd !== void 0 ? /* @__PURE__ */ jsxs("p", {
|
|
11646
|
+
className: "text-label text-fg-4",
|
|
11647
|
+
children: [
|
|
11648
|
+
engineLabel(engine),
|
|
11649
|
+
" reports ",
|
|
11650
|
+
formatCost(cost.reportedUsd),
|
|
11651
|
+
" for the same tokens."
|
|
11652
|
+
]
|
|
11653
|
+
}) : null
|
|
11654
|
+
]
|
|
11655
|
+
});
|
|
11656
|
+
}
|
|
11657
|
+
function ProfileSpendSection({ spend }) {
|
|
11658
|
+
const { subscription } = spend;
|
|
11659
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11660
|
+
className: "mt-4 space-y-1 border-t border-border pt-3",
|
|
11661
|
+
children: [
|
|
11662
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11663
|
+
label: "This profile, last 7 days",
|
|
11664
|
+
value: formatCost(spend.weekUsd)
|
|
11665
|
+
}),
|
|
11666
|
+
/* @__PURE__ */ jsx(Line, {
|
|
11667
|
+
label: "Last 30 days",
|
|
11668
|
+
value: formatCost(spend.monthUsd),
|
|
11669
|
+
tone: "muted"
|
|
11670
|
+
}),
|
|
11671
|
+
subscription ? /* @__PURE__ */ jsxs("p", {
|
|
11672
|
+
className: "pt-1 text-label text-fg-4",
|
|
11673
|
+
children: [
|
|
11674
|
+
formatMultiple(subscription.ratio),
|
|
11675
|
+
" the ",
|
|
11676
|
+
formatCost(subscription.weeklyShareUsd),
|
|
11677
|
+
" weekly share of your",
|
|
11678
|
+
" ",
|
|
11679
|
+
formatCost(subscription.monthlyUsd),
|
|
11680
|
+
" a month. A subscription is a flat fee, so this is leverage, not a bill."
|
|
11681
|
+
]
|
|
11682
|
+
}) : null
|
|
11683
|
+
]
|
|
11684
|
+
});
|
|
11685
|
+
}
|
|
11686
|
+
function formatMultiple(ratio) {
|
|
11687
|
+
return ratio >= 10 ? `${Math.round(ratio)}x` : `${ratio.toFixed(1)}x`;
|
|
11688
|
+
}
|
|
11689
|
+
function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, costUsd, usageByModel, pricing, spend, updatedAt, open, onOpenChange, className }) {
|
|
11274
11690
|
const now = useMinuteClock(open);
|
|
11691
|
+
const cost = sessionCost({
|
|
11692
|
+
costUsd,
|
|
11693
|
+
totalCostUsd,
|
|
11694
|
+
usageByModel,
|
|
11695
|
+
pricing
|
|
11696
|
+
});
|
|
11697
|
+
const ageNote = pricingAgeNote(now);
|
|
11275
11698
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
11276
11699
|
open,
|
|
11277
11700
|
onOpenChange,
|
|
@@ -11279,7 +11702,7 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updat
|
|
|
11279
11702
|
className,
|
|
11280
11703
|
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
11281
11704
|
title: "Usage",
|
|
11282
|
-
description: engine
|
|
11705
|
+
description: engineLabel(engine),
|
|
11283
11706
|
actions: subscriptionType ? /* @__PURE__ */ jsx(Badge, {
|
|
11284
11707
|
variant: "accent",
|
|
11285
11708
|
className: "mt-0.5 shrink-0 capitalize",
|
|
@@ -11293,15 +11716,17 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updat
|
|
|
11293
11716
|
windows: rateLimits,
|
|
11294
11717
|
now
|
|
11295
11718
|
}),
|
|
11296
|
-
/* @__PURE__ */
|
|
11297
|
-
className: "mt-5
|
|
11298
|
-
children:
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
})
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11719
|
+
/* @__PURE__ */ jsx("div", {
|
|
11720
|
+
className: "mt-5 border-t border-border pt-3",
|
|
11721
|
+
children: /* @__PURE__ */ jsx(CostEvidence, {
|
|
11722
|
+
cost,
|
|
11723
|
+
engine
|
|
11724
|
+
})
|
|
11725
|
+
}),
|
|
11726
|
+
spend ? /* @__PURE__ */ jsx(ProfileSpendSection, { spend }) : null,
|
|
11727
|
+
/* @__PURE__ */ jsx("p", {
|
|
11728
|
+
className: "mt-3 text-label text-fg-4",
|
|
11729
|
+
children: ageNote ? `${PRICING_NOTE} ${ageNote}` : PRICING_NOTE
|
|
11305
11730
|
}),
|
|
11306
11731
|
updatedAt ? /* @__PURE__ */ jsxs("p", {
|
|
11307
11732
|
className: "mt-2 text-label text-fg-4",
|
|
@@ -11353,7 +11778,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11353
11778
|
const [panel, setPanel] = useState();
|
|
11354
11779
|
const [showCompletedTasks, setShowCompletedTasks] = useState(false);
|
|
11355
11780
|
const [taskReveal, setTaskReveal] = useState();
|
|
11356
|
-
const { state, connection, replaying, protocolMismatch, shell, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, clearContext, setModel, setPermissionMode, reconnectNow, loadFullResult } = useClaudeSession(client, sessionId, {
|
|
11781
|
+
const { state, connection, replaying, protocolMismatch, shell, pricing, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, clearContext, setModel, setPermissionMode, reconnectNow, loadFullResult } = useClaudeSession(client, sessionId, {
|
|
11357
11782
|
onProtocolError: setProtocolError,
|
|
11358
11783
|
cacheTranscript
|
|
11359
11784
|
});
|
|
@@ -11393,7 +11818,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11393
11818
|
} : toolHost);
|
|
11394
11819
|
const terminal = transcriptVariant === "terminal";
|
|
11395
11820
|
const capabilities = state.capabilities;
|
|
11396
|
-
const { usage: profileUsage } = useProfileUsage(client, state.session?.profile, { enabled: capabilities.rateLimits });
|
|
11821
|
+
const { usage: profileUsage, spend: profileSpend } = useProfileUsage(client, state.session?.profile, { enabled: capabilities.rateLimits });
|
|
11397
11822
|
const usage = useMemo(() => mergeUsage({
|
|
11398
11823
|
rateLimits: state.rateLimits,
|
|
11399
11824
|
updatedAt: state.rateLimitsUpdatedAt
|
|
@@ -11869,6 +12294,10 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11869
12294
|
subscriptionType: state.subscriptionType,
|
|
11870
12295
|
engine: state.engine ?? "claude",
|
|
11871
12296
|
totalCostUsd: state.totalCostUsd,
|
|
12297
|
+
costUsd: state.costUsd,
|
|
12298
|
+
usageByModel: state.usageByModel,
|
|
12299
|
+
pricing,
|
|
12300
|
+
spend: profileSpend,
|
|
11872
12301
|
updatedAt: usageUpdatedAt,
|
|
11873
12302
|
open: panel === "usage",
|
|
11874
12303
|
onOpenChange: (next) => setPanel(next ? "usage" : void 0)
|
|
@@ -11977,6 +12406,108 @@ function Notice({ level, onDismiss, children }) {
|
|
|
11977
12406
|
});
|
|
11978
12407
|
}
|
|
11979
12408
|
//#endregion
|
|
11980
|
-
|
|
12409
|
+
//#region src/lib/path-match.ts
|
|
12410
|
+
const SEG = "[^\\s:'\"`()\\[\\]{}<>|]+";
|
|
12411
|
+
const PATH_PATTERN = new RegExp(`(?:^|[\\s'"\`([{<@,])((?:\\.\\.?)?(?:/${SEG})+|[^\\s:'"\`()\\[\\]{}<>|@,]+(?:/${SEG})+)(?::(\\d+))?`);
|
|
12412
|
+
const FILE_PATTERN = /^([\w.@-]+\.[A-Za-z0-9]{1,10})(?::(\d+))?$/;
|
|
12413
|
+
const TRAILING = /[.,;:!?)\]}'"`]+$/;
|
|
12414
|
+
const FILENAME = /\.[A-Za-z0-9]{1,10}$/;
|
|
12415
|
+
function matchPath(text, inCode = false) {
|
|
12416
|
+
const source = text ?? "";
|
|
12417
|
+
const match = PATH_PATTERN.exec(source);
|
|
12418
|
+
if (!match) return inCode ? matchFilename(source) : void 0;
|
|
12419
|
+
const path = match[1].replace(TRAILING, "");
|
|
12420
|
+
if (!path.includes("/") || path.endsWith("/")) return;
|
|
12421
|
+
if (!(path.startsWith("/") || path.startsWith("./") || path.startsWith("../")) && !FILENAME.test(path)) return;
|
|
12422
|
+
return {
|
|
12423
|
+
path,
|
|
12424
|
+
line: match[2] ? Number(match[2]) : void 0,
|
|
12425
|
+
length: path.length + (match[2] ? match[2].length + 1 : 0)
|
|
12426
|
+
};
|
|
12427
|
+
}
|
|
12428
|
+
function matchFilename(text) {
|
|
12429
|
+
const hit = FILE_PATTERN.exec(text.trim());
|
|
12430
|
+
if (!hit) return;
|
|
12431
|
+
const line = hit[2] ? Number(hit[2]) : void 0;
|
|
12432
|
+
return {
|
|
12433
|
+
path: hit[1],
|
|
12434
|
+
line,
|
|
12435
|
+
length: hit[0].length
|
|
12436
|
+
};
|
|
12437
|
+
}
|
|
12438
|
+
//#endregion
|
|
12439
|
+
//#region src/components/agent/use-path-links.ts
|
|
12440
|
+
const LINKISH = "wd-path-link";
|
|
12441
|
+
const COVERAGE = .6;
|
|
12442
|
+
function hitFor(element) {
|
|
12443
|
+
if (!element) return;
|
|
12444
|
+
const inCode = element.closest("code") !== null;
|
|
12445
|
+
const text = element.textContent?.trim() ?? "";
|
|
12446
|
+
const hit = matchPath(text, inCode);
|
|
12447
|
+
if (!hit) return;
|
|
12448
|
+
if (!inCode && hit.length < text.length * COVERAGE) return;
|
|
12449
|
+
return {
|
|
12450
|
+
path: hit.path,
|
|
12451
|
+
line: hit.line
|
|
12452
|
+
};
|
|
12453
|
+
}
|
|
12454
|
+
function usePathLinks({ container, onOpen, enabled = true, ignore }) {
|
|
12455
|
+
useEffect(() => {
|
|
12456
|
+
const root = container.current;
|
|
12457
|
+
if (!root || !enabled) return;
|
|
12458
|
+
const excluded = (element) => ignore !== void 0 && element?.closest(ignore) !== null && element !== void 0;
|
|
12459
|
+
let marked;
|
|
12460
|
+
const unmark = () => {
|
|
12461
|
+
marked?.classList.remove(LINKISH);
|
|
12462
|
+
marked = void 0;
|
|
12463
|
+
};
|
|
12464
|
+
const onClick = (event) => {
|
|
12465
|
+
if (!event.metaKey && !event.ctrlKey) return;
|
|
12466
|
+
const target = event.target instanceof HTMLElement ? event.target : void 0;
|
|
12467
|
+
if (excluded(target)) return;
|
|
12468
|
+
const hit = hitFor(target);
|
|
12469
|
+
if (!hit) return;
|
|
12470
|
+
event.preventDefault();
|
|
12471
|
+
event.stopPropagation();
|
|
12472
|
+
unmark();
|
|
12473
|
+
onOpen(hit);
|
|
12474
|
+
};
|
|
12475
|
+
const onMove = (event) => {
|
|
12476
|
+
if (!event.metaKey && !event.ctrlKey) return unmark();
|
|
12477
|
+
const element = event.target instanceof HTMLElement ? event.target : void 0;
|
|
12478
|
+
if (element === marked) return;
|
|
12479
|
+
unmark();
|
|
12480
|
+
if (!element || excluded(element) || !hitFor(element)) return;
|
|
12481
|
+
marked = element;
|
|
12482
|
+
element.classList.add(LINKISH);
|
|
12483
|
+
};
|
|
12484
|
+
const onKey = (event) => {
|
|
12485
|
+
if (!event.metaKey && !event.ctrlKey) unmark();
|
|
12486
|
+
};
|
|
12487
|
+
root.addEventListener("click", onClick, true);
|
|
12488
|
+
root.addEventListener("mousemove", onMove);
|
|
12489
|
+
document.addEventListener("keydown", onKey);
|
|
12490
|
+
document.addEventListener("keyup", onKey);
|
|
12491
|
+
window.addEventListener("blur", unmark);
|
|
12492
|
+
return () => {
|
|
12493
|
+
unmark();
|
|
12494
|
+
root.removeEventListener("click", onClick, true);
|
|
12495
|
+
root.removeEventListener("mousemove", onMove);
|
|
12496
|
+
document.removeEventListener("keydown", onKey);
|
|
12497
|
+
document.removeEventListener("keyup", onKey);
|
|
12498
|
+
window.removeEventListener("blur", unmark);
|
|
12499
|
+
};
|
|
12500
|
+
}, [
|
|
12501
|
+
container,
|
|
12502
|
+
onOpen,
|
|
12503
|
+
enabled,
|
|
12504
|
+
ignore
|
|
12505
|
+
]);
|
|
12506
|
+
}
|
|
12507
|
+
function resolveAgainstCwd(path, cwd) {
|
|
12508
|
+
return parseFileLink(path, cwd)?.path ?? path;
|
|
12509
|
+
}
|
|
12510
|
+
//#endregion
|
|
12511
|
+
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
12512
|
|
|
11982
|
-
//# sourceMappingURL=
|
|
12513
|
+
//# sourceMappingURL=use-path-links-DO_79-wX.mjs.map
|