@workerdeck/ui 2.8.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/{SessionPanel-_lQLhWOw.d.mts → SessionPanel-BVbau2eR.d.mts} +68 -4
- package/build/index.d.mts +62 -9
- package/build/index.mjs +24 -10
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +44 -0
- package/build/{SessionPanel-Dg4xf-ql.mjs → use-path-links-CvcxdUXL.mjs} +1080 -497
- package/build/use-path-links-CvcxdUXL.mjs.map +1 -0
- package/build/workspace.d.mts +3 -2
- package/build/workspace.mjs +5 -86
- package/build/workspace.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/agent/Composer.tsx +88 -83
- package/src/components/agent/PromptTokenText.tsx +11 -3
- package/src/components/agent/SessionInfoDialog.tsx +1 -1
- package/src/components/agent/SessionItem.tsx +12 -6
- package/src/components/agent/SessionList.tsx +1 -1
- package/src/components/agent/SessionPanel.tsx +308 -225
- package/src/components/agent/SessionWorkspace.tsx +3 -0
- 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/UsageMeters.tsx +17 -4
- package/src/components/agent/composer-commands.ts +154 -0
- package/src/components/agent/use-path-links.ts +7 -26
- 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/file-link.tsx +20 -0
- package/src/components/terminal/items.tsx +3 -2
- package/src/components/terminal/markdown.tsx +31 -5
- package/src/index.ts +14 -2
- package/src/lib/file-link.ts +70 -0
- package/src/lib/path-match.ts +51 -0
- package/src/lib/session-cost.ts +65 -0
- package/src/styles/terminal.css +15 -0
- package/build/SessionPanel-Dg4xf-ql.mjs.map +0 -1
|
@@ -5,11 +5,11 @@ import { clsx } from "clsx";
|
|
|
5
5
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
6
6
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { Select } from "@base-ui/react/select";
|
|
8
|
-
import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowRight, ArrowUp, AtSign, Brain, ChartPie, Check, CheckSquare, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, Circle, CircleAlert, ClipboardList, Clock, Code, Copy, Download, File, FileDiff, FileText, Folder, FolderSearch, FolderTree, Gauge, Globe, Hand, Image, Info, Link2, LoaderCircle, MessageCircleQuestion, MessageSquareText, MoreHorizontal, Paperclip, PencilLine, Plug, Power, PowerOff, Puzzle, RefreshCw, RotateCcw, RotateCw, Search, ShieldCheck, SlashSquare, Sparkles, Square, SquarePen, Terminal, TriangleAlert, UsersRound, WifiOff, Wrench, X, Zap } from "lucide-react";
|
|
8
|
+
import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowRight, ArrowUp, AtSign, Brain, ChartPie, Check, CheckSquare, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, Circle, CircleAlert, ClipboardList, Clock, Code, Copy, Download, File, FileDiff, FileText, Folder, FolderSearch, FolderTree, Gauge, Globe, Hand, Image, Info, Link2, LoaderCircle, MessageCircleQuestion, MessageSquareText, MoreHorizontal, Paperclip, PencilLine, Plug, Power, PowerOff, Puzzle, RefreshCw, RotateCcw, RotateCw, Search, ShieldCheck, SlashSquare, SlidersHorizontal, Sparkles, Square, SquarePen, Terminal, TriangleAlert, UsersRound, WifiOff, Wrench, X, Zap } from "lucide-react";
|
|
9
9
|
import { Menu } from "@base-ui/react/menu";
|
|
10
10
|
import { Dialog } from "@base-ui/react/dialog";
|
|
11
11
|
import { Tooltip } from "@base-ui/react/tooltip";
|
|
12
|
-
import { PROTOCOL_VERSION, mergeUsage, orderUsageWindows, parseTodoWriteInput, parseUserQuestions, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, usageInfos, 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?.({
|
|
@@ -4411,6 +4428,123 @@ function launchTrigger(opts) {
|
|
|
4411
4428
|
};
|
|
4412
4429
|
}
|
|
4413
4430
|
//#endregion
|
|
4431
|
+
//#region src/components/agent/composer-commands.ts
|
|
4432
|
+
const KIND_ORDER = {
|
|
4433
|
+
command: 0,
|
|
4434
|
+
client: 1,
|
|
4435
|
+
skill: 2
|
|
4436
|
+
};
|
|
4437
|
+
function cleanCommandName(name) {
|
|
4438
|
+
return name.replace(/\s*\(MCP\)$/i, "");
|
|
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
|
+
}
|
|
4448
|
+
function skillPrompt(skill) {
|
|
4449
|
+
return skillToken(skill) + skillTrailingText(skill);
|
|
4450
|
+
}
|
|
4451
|
+
function mergeComposerRows(sources) {
|
|
4452
|
+
const rows = [];
|
|
4453
|
+
const engineNames = /* @__PURE__ */ new Set();
|
|
4454
|
+
for (const command of sources.commands ?? []) {
|
|
4455
|
+
const name = cleanCommandName(command.name);
|
|
4456
|
+
if (engineNames.has(name)) continue;
|
|
4457
|
+
engineNames.add(name);
|
|
4458
|
+
for (const alias of command.aliases ?? []) engineNames.add(cleanCommandName(alias));
|
|
4459
|
+
rows.push({
|
|
4460
|
+
kind: "command",
|
|
4461
|
+
name,
|
|
4462
|
+
description: command.description,
|
|
4463
|
+
argumentHint: command.argumentHint,
|
|
4464
|
+
aliases: command.aliases
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
for (const command of sources.clientCommands ?? []) {
|
|
4468
|
+
if (engineNames.has(command.name)) continue;
|
|
4469
|
+
rows.push({
|
|
4470
|
+
kind: "client",
|
|
4471
|
+
name: command.name,
|
|
4472
|
+
description: command.description,
|
|
4473
|
+
argumentHint: command.argumentHint,
|
|
4474
|
+
command
|
|
4475
|
+
});
|
|
4476
|
+
}
|
|
4477
|
+
for (const skill of sources.skills ?? []) rows.push({
|
|
4478
|
+
kind: "skill",
|
|
4479
|
+
name: skill.name,
|
|
4480
|
+
label: skill.displayName ?? skill.name,
|
|
4481
|
+
description: skill.shortDescription ?? skill.description,
|
|
4482
|
+
enabled: skill.enabled,
|
|
4483
|
+
scope: skill.scope,
|
|
4484
|
+
skill
|
|
4485
|
+
});
|
|
4486
|
+
return rows;
|
|
4487
|
+
}
|
|
4488
|
+
function haystacks(row) {
|
|
4489
|
+
if (row.kind === "skill") return [
|
|
4490
|
+
row.name,
|
|
4491
|
+
row.label,
|
|
4492
|
+
...row.name.split(/[-:_]/)
|
|
4493
|
+
];
|
|
4494
|
+
return [
|
|
4495
|
+
row.name,
|
|
4496
|
+
...row.kind === "command" ? row.aliases ?? [] : [],
|
|
4497
|
+
...row.name.split(":")
|
|
4498
|
+
];
|
|
4499
|
+
}
|
|
4500
|
+
function matchScore(query, candidates) {
|
|
4501
|
+
const needle = query.toLowerCase();
|
|
4502
|
+
const lowered = candidates.map((s) => s.toLowerCase());
|
|
4503
|
+
if (lowered.some((h) => h.startsWith(needle))) return 2;
|
|
4504
|
+
return lowered.some((h) => h.includes(needle)) ? 1 : 0;
|
|
4505
|
+
}
|
|
4506
|
+
function rankComposerRows(query, rows) {
|
|
4507
|
+
const scored = [];
|
|
4508
|
+
rows.forEach((row, index) => {
|
|
4509
|
+
if (row.kind === "skill" && !row.enabled) return;
|
|
4510
|
+
const score = matchScore(query, haystacks(row));
|
|
4511
|
+
if (score > 0) scored.push({
|
|
4512
|
+
score,
|
|
4513
|
+
index,
|
|
4514
|
+
row
|
|
4515
|
+
});
|
|
4516
|
+
});
|
|
4517
|
+
scored.sort((a, b) => b.score - a.score || KIND_ORDER[a.row.kind] - KIND_ORDER[b.row.kind] || a.index - b.index);
|
|
4518
|
+
return scored.map(({ row }) => row);
|
|
4519
|
+
}
|
|
4520
|
+
function matchClientCommand(text, commands) {
|
|
4521
|
+
const match = /^\/([\w:-]+)[ \t]*([\s\S]*)$/.exec(text.trim());
|
|
4522
|
+
if (!match) return;
|
|
4523
|
+
const command = commands.find((c) => c.name === match[1]);
|
|
4524
|
+
return command ? {
|
|
4525
|
+
command,
|
|
4526
|
+
args: match[2].trim()
|
|
4527
|
+
} : void 0;
|
|
4528
|
+
}
|
|
4529
|
+
function composerCommandRows(rows) {
|
|
4530
|
+
return rows.map((row) => row.kind === "skill" ? {
|
|
4531
|
+
kind: row.kind,
|
|
4532
|
+
name: row.name,
|
|
4533
|
+
label: row.label,
|
|
4534
|
+
description: row.description,
|
|
4535
|
+
scope: row.scope,
|
|
4536
|
+
enabled: row.enabled,
|
|
4537
|
+
insertText: skillPrompt(row.skill)
|
|
4538
|
+
} : {
|
|
4539
|
+
kind: row.kind,
|
|
4540
|
+
name: row.name,
|
|
4541
|
+
label: `/${row.name}`,
|
|
4542
|
+
description: row.description,
|
|
4543
|
+
enabled: true,
|
|
4544
|
+
insertText: `/${row.name} `
|
|
4545
|
+
});
|
|
4546
|
+
}
|
|
4547
|
+
//#endregion
|
|
4414
4548
|
//#region src/components/agent/transcript-variant.tsx
|
|
4415
4549
|
const VariantContext = createContext("cards");
|
|
4416
4550
|
function TranscriptVariantProvider({ value, children }) {
|
|
@@ -4531,6 +4665,38 @@ function usePulse(animated) {
|
|
|
4531
4665
|
return PULSE_FRAMES[frame % PULSE_FRAMES.length];
|
|
4532
4666
|
}
|
|
4533
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
|
|
4534
4700
|
//#region src/components/terminal/affordances.tsx
|
|
4535
4701
|
const DEFAULTS = {
|
|
4536
4702
|
hover: true,
|
|
@@ -4749,6 +4915,69 @@ function TerminalDiff({ patch }) {
|
|
|
4749
4915
|
});
|
|
4750
4916
|
}
|
|
4751
4917
|
//#endregion
|
|
4918
|
+
//#region src/lib/file-link.ts
|
|
4919
|
+
const SCHEME = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
4920
|
+
const TRAILING_LINE = /^(.*?):(\d+)(?::\d+)?$/;
|
|
4921
|
+
const FRAGMENT_LINE = /^L(\d+)/;
|
|
4922
|
+
function parseFileLink(href, cwd) {
|
|
4923
|
+
const raw = href?.trim();
|
|
4924
|
+
if (!raw || raw.startsWith("#") || raw.startsWith("//")) return;
|
|
4925
|
+
let target = raw;
|
|
4926
|
+
if (SCHEME.test(target)) {
|
|
4927
|
+
if (!target.startsWith("file:")) return;
|
|
4928
|
+
try {
|
|
4929
|
+
target = decodeURIComponent(new URL(target).pathname);
|
|
4930
|
+
} catch {
|
|
4931
|
+
return;
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
let line;
|
|
4935
|
+
const hash = target.indexOf("#");
|
|
4936
|
+
if (hash !== -1) {
|
|
4937
|
+
line = readLine(FRAGMENT_LINE.exec(target.slice(hash + 1))?.[1]);
|
|
4938
|
+
target = target.slice(0, hash);
|
|
4939
|
+
}
|
|
4940
|
+
const suffix = TRAILING_LINE.exec(target);
|
|
4941
|
+
if (suffix) {
|
|
4942
|
+
target = suffix[1];
|
|
4943
|
+
line ??= readLine(suffix[2]);
|
|
4944
|
+
}
|
|
4945
|
+
if (!target) return;
|
|
4946
|
+
const path = target.startsWith("/") ? normalize(target) : cwd ? normalize(`${cwd}/${target}`) : void 0;
|
|
4947
|
+
return path ? {
|
|
4948
|
+
path,
|
|
4949
|
+
...line === void 0 ? {} : { line }
|
|
4950
|
+
} : void 0;
|
|
4951
|
+
}
|
|
4952
|
+
function readLine(value) {
|
|
4953
|
+
const parsed = value === void 0 ? NaN : Number(value);
|
|
4954
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
4955
|
+
}
|
|
4956
|
+
function normalize(path) {
|
|
4957
|
+
const out = [];
|
|
4958
|
+
for (const part of path.split("/")) {
|
|
4959
|
+
if (part === "" || part === ".") continue;
|
|
4960
|
+
if (part === "..") {
|
|
4961
|
+
out.pop();
|
|
4962
|
+
continue;
|
|
4963
|
+
}
|
|
4964
|
+
out.push(part);
|
|
4965
|
+
}
|
|
4966
|
+
return `/${out.join("/")}`;
|
|
4967
|
+
}
|
|
4968
|
+
//#endregion
|
|
4969
|
+
//#region src/components/terminal/file-link.tsx
|
|
4970
|
+
const FileLinkContext = createContext(void 0);
|
|
4971
|
+
function FileLinkProvider({ value, children }) {
|
|
4972
|
+
return /* @__PURE__ */ jsx(FileLinkContext.Provider, {
|
|
4973
|
+
value,
|
|
4974
|
+
children
|
|
4975
|
+
});
|
|
4976
|
+
}
|
|
4977
|
+
function useFileLinks() {
|
|
4978
|
+
return useContext(FileLinkContext);
|
|
4979
|
+
}
|
|
4980
|
+
//#endregion
|
|
4752
4981
|
//#region src/components/terminal/markdown.tsx
|
|
4753
4982
|
function codeText(node) {
|
|
4754
4983
|
if (node === null || node === void 0 || typeof node === "boolean") return "";
|
|
@@ -4788,6 +5017,29 @@ function heading(tone) {
|
|
|
4788
5017
|
});
|
|
4789
5018
|
};
|
|
4790
5019
|
}
|
|
5020
|
+
function Link({ href, children }) {
|
|
5021
|
+
const links = useFileLinks();
|
|
5022
|
+
const file = links ? parseFileLink(href, links.cwd) : void 0;
|
|
5023
|
+
if (file) return /* @__PURE__ */ jsx("button", {
|
|
5024
|
+
type: "button",
|
|
5025
|
+
className: "term-link",
|
|
5026
|
+
"data-tone": "blue",
|
|
5027
|
+
title: file.line === void 0 ? file.path : `${file.path}:${file.line}`,
|
|
5028
|
+
onClick: (event) => {
|
|
5029
|
+
event.stopPropagation();
|
|
5030
|
+
links?.open(file.path, file.line);
|
|
5031
|
+
},
|
|
5032
|
+
children
|
|
5033
|
+
});
|
|
5034
|
+
return /* @__PURE__ */ jsx("a", {
|
|
5035
|
+
className: "term-link",
|
|
5036
|
+
"data-tone": "blue",
|
|
5037
|
+
href,
|
|
5038
|
+
target: "_blank",
|
|
5039
|
+
rel: "noreferrer",
|
|
5040
|
+
children
|
|
5041
|
+
});
|
|
5042
|
+
}
|
|
4791
5043
|
const TERMINAL_COMPONENTS = {
|
|
4792
5044
|
p: ({ children }) => /* @__PURE__ */ jsx("div", {
|
|
4793
5045
|
className: "term-block",
|
|
@@ -4844,12 +5096,8 @@ const TERMINAL_COMPONENTS = {
|
|
|
4844
5096
|
className: "term-em",
|
|
4845
5097
|
children
|
|
4846
5098
|
}),
|
|
4847
|
-
a: ({ children, href }) => /* @__PURE__ */ jsx(
|
|
4848
|
-
className: "term-link",
|
|
4849
|
-
"data-tone": "blue",
|
|
5099
|
+
a: ({ children, href }) => /* @__PURE__ */ jsx(Link, {
|
|
4850
5100
|
href,
|
|
4851
|
-
target: "_blank",
|
|
4852
|
-
rel: "noreferrer",
|
|
4853
5101
|
children
|
|
4854
5102
|
}),
|
|
4855
5103
|
table: ({ children }) => /* @__PURE__ */ jsx("div", {
|
|
@@ -5221,7 +5469,7 @@ function UserRow({ item }) {
|
|
|
5221
5469
|
glyph: index === 0 ? "❯" : void 0,
|
|
5222
5470
|
glyphTone: "dim",
|
|
5223
5471
|
tone: "fg",
|
|
5224
|
-
children: line
|
|
5472
|
+
children: line ? /* @__PURE__ */ jsx(PromptTokenText, { text: line }) : "\xA0"
|
|
5225
5473
|
}, index)) : null]
|
|
5226
5474
|
})
|
|
5227
5475
|
});
|
|
@@ -5453,7 +5701,7 @@ function TurnResultRow$1({ item }) {
|
|
|
5453
5701
|
" · ",
|
|
5454
5702
|
formatDuration(item.durationMs),
|
|
5455
5703
|
" · ",
|
|
5456
|
-
formatCost(item.totalCostUsd)
|
|
5704
|
+
formatCost(item.costUsd ?? item.totalCostUsd)
|
|
5457
5705
|
]
|
|
5458
5706
|
}), item.errors?.map((message, index) => /* @__PURE__ */ jsx(Row, {
|
|
5459
5707
|
tone: "red",
|
|
@@ -5557,20 +5805,7 @@ function TerminalSurface({ fontSize, lineHeight, bleed, affordances, className,
|
|
|
5557
5805
|
//#region src/components/agent/Composer.tsx
|
|
5558
5806
|
const SHELL_PLACEHOLDER = "Run a command on the host…";
|
|
5559
5807
|
const SHELL_HINT = "! shell mode · esc to exit";
|
|
5560
|
-
function
|
|
5561
|
-
return name.replace(/\s*\(MCP\)$/i, "");
|
|
5562
|
-
}
|
|
5563
|
-
function skillPrompt(skill) {
|
|
5564
|
-
const base = skill.defaultPrompt?.trim() || `$${skill.name}`;
|
|
5565
|
-
return /\s$/.test(base) ? base : base + " ";
|
|
5566
|
-
}
|
|
5567
|
-
function matchScore(query, haystacks) {
|
|
5568
|
-
const needle = query.toLowerCase();
|
|
5569
|
-
const lowered = haystacks.map((s) => s.toLowerCase());
|
|
5570
|
-
if (lowered.some((h) => h.startsWith(needle))) return 2;
|
|
5571
|
-
return lowered.some((h) => h.includes(needle)) ? 1 : 0;
|
|
5572
|
-
}
|
|
5573
|
-
function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message the agent…", commands, skills, onSearchFiles, onShellCommand, attachments, toolbar, layout = "stacked", fontSize, lineHeight, affordances, draft, className, ref }) {
|
|
5808
|
+
function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message the agent…", commands, skills, clientCommands, onSearchFiles, onShellCommand, attachments, toolbar, layout = "stacked", fontSize, lineHeight, affordances, draft, className, ref }) {
|
|
5574
5809
|
const inline = layout === "inline";
|
|
5575
5810
|
const terminal = useTranscriptVariant() === "terminal";
|
|
5576
5811
|
const [initialDraft] = useState(() => draft?.initialText ?? "");
|
|
@@ -5578,6 +5813,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5578
5813
|
const fileInput = useRef(null);
|
|
5579
5814
|
const [dragging, setDragging] = useState(false);
|
|
5580
5815
|
const [shellMode, setShellMode] = useState(false);
|
|
5816
|
+
const [helpOpen, setHelpOpen] = useState(false);
|
|
5581
5817
|
useImperativeHandle(ref, () => ({
|
|
5582
5818
|
insertText: (text) => {
|
|
5583
5819
|
const prefix = plainText.length > 0 && !/\s$/.test(plainText) ? " " : "";
|
|
@@ -5592,71 +5828,42 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5592
5828
|
]);
|
|
5593
5829
|
const triggers = useMemo(() => {
|
|
5594
5830
|
const configured = [];
|
|
5595
|
-
const
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
return [{
|
|
5603
|
-
...c,
|
|
5604
|
-
name
|
|
5605
|
-
}];
|
|
5606
|
-
});
|
|
5831
|
+
const rows = mergeComposerRows({
|
|
5832
|
+
commands,
|
|
5833
|
+
clientCommands,
|
|
5834
|
+
skills
|
|
5835
|
+
});
|
|
5836
|
+
if (rows.length > 0) {
|
|
5837
|
+
const byTag = new Map(rows.map((row) => [`${row.kind}:${row.name}`, row]));
|
|
5607
5838
|
configured.push(commandTrigger({
|
|
5608
|
-
onSearch: (query) => {
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
return
|
|
5839
|
+
onSearch: (query) => rankComposerRows(query, rows).map((row) => row.kind === "skill" ? {
|
|
5840
|
+
value: row.name,
|
|
5841
|
+
label: row.label,
|
|
5842
|
+
description: row.description ? `Skill · ${row.description}` : "Skill · inserts a message you can edit",
|
|
5843
|
+
icon: /* @__PURE__ */ jsx(Sparkles, { className: "size-3.5 text-fg-3" }),
|
|
5844
|
+
data: `${row.kind}:${row.name}`
|
|
5845
|
+
} : {
|
|
5846
|
+
value: row.name,
|
|
5847
|
+
label: `/${row.name}${row.argumentHint ? ` ${row.argumentHint}` : ""}`,
|
|
5848
|
+
description: row.description,
|
|
5849
|
+
icon: row.kind === "client" ? /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-3.5 text-fg-3" }) : void 0,
|
|
5850
|
+
data: `${row.kind}:${row.name}`
|
|
5851
|
+
}),
|
|
5852
|
+
insertAsText: (suggestion) => {
|
|
5853
|
+
const row = byTag.get(String(suggestion.data));
|
|
5854
|
+
return row?.kind === "client" && row.command.requiresArgs ? `/${row.name} ` : void 0;
|
|
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;
|
|
5628
5862
|
},
|
|
5629
5863
|
onSelect: (suggestion) => suggestion.value,
|
|
5630
5864
|
chipClassName: "font-mono"
|
|
5631
5865
|
}));
|
|
5632
5866
|
}
|
|
5633
|
-
if (usableSkills.length > 0) configured.push(commandTrigger({
|
|
5634
|
-
char: "$",
|
|
5635
|
-
accessibilityLabel: "skill",
|
|
5636
|
-
onSearch: (query) => {
|
|
5637
|
-
const scored = [];
|
|
5638
|
-
for (const skill of usableSkills) {
|
|
5639
|
-
const score = matchScore(query, [skill.name, ...skill.name.split(/[-:_]/)]);
|
|
5640
|
-
if (score === 0) continue;
|
|
5641
|
-
const summary = skill.shortDescription ?? skill.description;
|
|
5642
|
-
scored.push({
|
|
5643
|
-
score,
|
|
5644
|
-
suggestion: {
|
|
5645
|
-
value: skill.name,
|
|
5646
|
-
label: skill.displayName ?? skill.name,
|
|
5647
|
-
description: summary ? `Skill · ${summary}` : "Skill · inserts a message you can edit",
|
|
5648
|
-
icon: /* @__PURE__ */ jsx(Sparkles, { className: "size-3.5 text-fg-3" })
|
|
5649
|
-
}
|
|
5650
|
-
});
|
|
5651
|
-
}
|
|
5652
|
-
scored.sort((a, b) => b.score - a.score);
|
|
5653
|
-
return scored.map(({ suggestion }) => suggestion);
|
|
5654
|
-
},
|
|
5655
|
-
insertAsText: (suggestion) => {
|
|
5656
|
-
const skill = usableSkills.find((s) => s.name === suggestion.value);
|
|
5657
|
-
return skill ? skillPrompt(skill) : `$${suggestion.value} `;
|
|
5658
|
-
}
|
|
5659
|
-
}));
|
|
5660
5867
|
if (onSearchFiles) configured.push(mentionTrigger({
|
|
5661
5868
|
searchDebounceMs: 150,
|
|
5662
5869
|
onSearch: async (query, options) => {
|
|
@@ -5680,6 +5887,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5680
5887
|
}, [
|
|
5681
5888
|
commands,
|
|
5682
5889
|
skills,
|
|
5890
|
+
clientCommands,
|
|
5683
5891
|
onSearchFiles,
|
|
5684
5892
|
onShellCommand
|
|
5685
5893
|
]);
|
|
@@ -5711,6 +5919,24 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5711
5919
|
setShellMode(false);
|
|
5712
5920
|
focus();
|
|
5713
5921
|
};
|
|
5922
|
+
const hints = [
|
|
5923
|
+
triggers?.some((t) => t.char === "/") ? {
|
|
5924
|
+
key: "/",
|
|
5925
|
+
what: "commands and skills"
|
|
5926
|
+
} : void 0,
|
|
5927
|
+
onSearchFiles ? {
|
|
5928
|
+
key: "@",
|
|
5929
|
+
what: "mention a file"
|
|
5930
|
+
} : void 0,
|
|
5931
|
+
onShellCommand ? {
|
|
5932
|
+
key: "!",
|
|
5933
|
+
what: "run a shell command"
|
|
5934
|
+
} : void 0,
|
|
5935
|
+
{
|
|
5936
|
+
key: "?",
|
|
5937
|
+
what: "this list, on an empty composer"
|
|
5938
|
+
}
|
|
5939
|
+
].filter((h) => h !== void 0);
|
|
5714
5940
|
const shellKeys = shellMode ? {
|
|
5715
5941
|
onEscape: leaveShellMode,
|
|
5716
5942
|
onKeyDown: (e) => {
|
|
@@ -5719,7 +5945,30 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5719
5945
|
leaveShellMode();
|
|
5720
5946
|
}
|
|
5721
5947
|
}
|
|
5722
|
-
} : {
|
|
5948
|
+
} : {
|
|
5949
|
+
onEscape: helpOpen ? () => setHelpOpen(false) : void 0,
|
|
5950
|
+
onKeyDown: (e) => {
|
|
5951
|
+
if (e.key === "?" && isEmpty && !e.metaKey && !e.ctrlKey) {
|
|
5952
|
+
e.preventDefault();
|
|
5953
|
+
setHelpOpen(true);
|
|
5954
|
+
return;
|
|
5955
|
+
}
|
|
5956
|
+
if (helpOpen) setHelpOpen(false);
|
|
5957
|
+
}
|
|
5958
|
+
};
|
|
5959
|
+
const helpHints = helpOpen ? /* @__PURE__ */ jsx(Fragment$1, { children: hints.map((hint) => /* @__PURE__ */ jsxs("span", {
|
|
5960
|
+
className: "flex items-center gap-1",
|
|
5961
|
+
children: [/* @__PURE__ */ jsx("kbd", {
|
|
5962
|
+
className: "font-mono text-text",
|
|
5963
|
+
children: hint.key
|
|
5964
|
+
}), hint.what]
|
|
5965
|
+
}, hint.key)) }) : null;
|
|
5966
|
+
const helpRow = helpOpen ? /* @__PURE__ */ jsx("div", {
|
|
5967
|
+
role: "note",
|
|
5968
|
+
"aria-label": "Composer shortcuts",
|
|
5969
|
+
className: "mx-auto mb-1 flex w-full max-w-[var(--wd-transcript-max-width)] flex-wrap items-center gap-x-3 gap-y-1 text-label text-fg-3",
|
|
5970
|
+
children: helpHints
|
|
5971
|
+
}) : null;
|
|
5723
5972
|
const pick = (files) => {
|
|
5724
5973
|
if (files && files.length > 0) attachments?.add(files);
|
|
5725
5974
|
};
|
|
@@ -5862,6 +6111,18 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5862
6111
|
})
|
|
5863
6112
|
]
|
|
5864
6113
|
}),
|
|
6114
|
+
helpOpen ? /* @__PURE__ */ jsxs("div", {
|
|
6115
|
+
role: "note",
|
|
6116
|
+
"aria-label": "Composer shortcuts",
|
|
6117
|
+
className: "term-row",
|
|
6118
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
6119
|
+
"aria-hidden": true,
|
|
6120
|
+
className: "term-gutter"
|
|
6121
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
6122
|
+
className: "flex min-w-0 flex-wrap items-center gap-x-[2ch] text-fg-3",
|
|
6123
|
+
children: helpHints
|
|
6124
|
+
})]
|
|
6125
|
+
}) : null,
|
|
5865
6126
|
shellMode ? /* @__PURE__ */ jsxs("div", {
|
|
5866
6127
|
className: "term-row",
|
|
5867
6128
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -5889,55 +6150,59 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
5889
6150
|
return /* @__PURE__ */ jsxs("div", {
|
|
5890
6151
|
"data-slot": "composer",
|
|
5891
6152
|
className: cn("px-[var(--wd-composer-padding)] pb-[var(--wd-composer-padding)]", className),
|
|
5892
|
-
children: [
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
className: "
|
|
5897
|
-
children: [
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
className: "flex
|
|
5934
|
-
children: [
|
|
5935
|
-
className: "
|
|
5936
|
-
children:
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
6153
|
+
children: [
|
|
6154
|
+
helpRow,
|
|
6155
|
+
/* @__PURE__ */ jsxs("div", {
|
|
6156
|
+
...dropHandlers,
|
|
6157
|
+
className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)] overflow-hidden border border-border bg-bg", "transition-colors rounded-lg shadow-(--shadow-xs)", "focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/30", dragging && "border-ring ring-2 ring-ring/30", shellMode && "border-[var(--wd-shell-accent)] focus-within:border-[var(--wd-shell-accent)] focus-within:ring-[var(--wd-shell-accent)]/30", disabled && "opacity-60"),
|
|
6158
|
+
children: [staged.length > 0 && attachments ? /* @__PURE__ */ jsx(AttachmentStrip, { attachments }) : null, inline ? /* @__PURE__ */ jsxs("div", {
|
|
6159
|
+
className: "flex items-end gap-1 p-1",
|
|
6160
|
+
children: [
|
|
6161
|
+
shellMode ? /* @__PURE__ */ jsx(ShellBadge, { onLeave: leaveShellMode }) : attach,
|
|
6162
|
+
/* @__PURE__ */ jsx(PromptArea, {
|
|
6163
|
+
...bind,
|
|
6164
|
+
triggers,
|
|
6165
|
+
markdown: false,
|
|
6166
|
+
normalizeBullets: false,
|
|
6167
|
+
onSubmit: submit,
|
|
6168
|
+
disabled,
|
|
6169
|
+
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
6170
|
+
minHeight: 20,
|
|
6171
|
+
maxHeight: 192,
|
|
6172
|
+
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
6173
|
+
className: "min-w-0 flex-1 py-1 text-body-sm text-text",
|
|
6174
|
+
onImagePaste: (file) => attachments?.add([file]),
|
|
6175
|
+
...shellKeys
|
|
6176
|
+
}),
|
|
6177
|
+
submitButton
|
|
6178
|
+
]
|
|
6179
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(PromptArea, {
|
|
6180
|
+
...bind,
|
|
6181
|
+
triggers,
|
|
6182
|
+
markdown: false,
|
|
6183
|
+
normalizeBullets: false,
|
|
6184
|
+
onSubmit: submit,
|
|
6185
|
+
disabled,
|
|
6186
|
+
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
6187
|
+
minHeight: 28,
|
|
6188
|
+
maxHeight: 192,
|
|
6189
|
+
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
6190
|
+
className: "px-3 pt-2.5 pb-0 text-body-sm text-text",
|
|
6191
|
+
onImagePaste: (file) => attachments?.add([file]),
|
|
6192
|
+
...shellKeys
|
|
6193
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
6194
|
+
className: "flex items-center justify-between gap-2 px-2 pb-2",
|
|
6195
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
6196
|
+
className: "flex min-w-0 items-center gap-1",
|
|
6197
|
+
children: [shellMode ? /* @__PURE__ */ jsx(ShellBadge, { onLeave: leaveShellMode }) : attach, shellMode ? /* @__PURE__ */ jsx("span", {
|
|
6198
|
+
className: "text-label text-text-muted",
|
|
6199
|
+
children: SHELL_HINT
|
|
6200
|
+
}) : toolbar]
|
|
6201
|
+
}), submitButton]
|
|
6202
|
+
})] })]
|
|
6203
|
+
}),
|
|
6204
|
+
errorRow
|
|
6205
|
+
]
|
|
5941
6206
|
});
|
|
5942
6207
|
}
|
|
5943
6208
|
function GlyphButton({ tone, label, disabled, onClick, gutter, className, children }) {
|
|
@@ -8015,7 +8280,7 @@ function SessionInfoDialog({ state, client, sessionId, open, onOpenChange }) {
|
|
|
8015
8280
|
/* @__PURE__ */ jsx(DialogRow, {
|
|
8016
8281
|
label: "Cost",
|
|
8017
8282
|
mono: true,
|
|
8018
|
-
children: formatCost(state.totalCostUsd)
|
|
8283
|
+
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
8019
8284
|
})
|
|
8020
8285
|
]
|
|
8021
8286
|
}),
|
|
@@ -8325,7 +8590,7 @@ function StatusBar({ state, rateLimits, connected, connection, onOpenStatus, onO
|
|
|
8325
8590
|
/* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
8326
8591
|
/* @__PURE__ */ jsx("span", {
|
|
8327
8592
|
className: "font-mono text-label text-fg-3",
|
|
8328
|
-
children: formatCost(state.totalCostUsd)
|
|
8593
|
+
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
8329
8594
|
}),
|
|
8330
8595
|
actions ? /* @__PURE__ */ jsx("span", {
|
|
8331
8596
|
className: "self-center",
|
|
@@ -10101,30 +10366,6 @@ function MessageContent({ className, ...props }) {
|
|
|
10101
10366
|
});
|
|
10102
10367
|
}
|
|
10103
10368
|
//#endregion
|
|
10104
|
-
//#region src/components/agent/PromptTokenText.tsx
|
|
10105
|
-
function PromptTokenText({ text, className }) {
|
|
10106
|
-
const tokens = scanPromptTokens(text);
|
|
10107
|
-
if (tokens.length === 0) return /* @__PURE__ */ jsx("span", {
|
|
10108
|
-
className,
|
|
10109
|
-
children: text
|
|
10110
|
-
});
|
|
10111
|
-
const parts = [];
|
|
10112
|
-
let cursor = 0;
|
|
10113
|
-
for (const [index, token] of tokens.entries()) {
|
|
10114
|
-
if (token.start > cursor) parts.push(text.slice(cursor, token.start));
|
|
10115
|
-
parts.push(/* @__PURE__ */ jsx("span", {
|
|
10116
|
-
className: cn("font-mono", token.kind === "file" ? "text-accent" : "text-info"),
|
|
10117
|
-
children: token.text
|
|
10118
|
-
}, `${token.start}-${index}`));
|
|
10119
|
-
cursor = token.end;
|
|
10120
|
-
}
|
|
10121
|
-
if (cursor < text.length) parts.push(text.slice(cursor));
|
|
10122
|
-
return /* @__PURE__ */ jsx("span", {
|
|
10123
|
-
className,
|
|
10124
|
-
children: parts.map((part, index) => /* @__PURE__ */ jsx(Fragment, { children: part }, index))
|
|
10125
|
-
});
|
|
10126
|
-
}
|
|
10127
|
-
//#endregion
|
|
10128
10369
|
//#region src/components/agent/Reasoning.tsx
|
|
10129
10370
|
function Reasoning({ children, isStreaming = false, defaultOpen, className }) {
|
|
10130
10371
|
const [open, setOpen] = useState(defaultOpen ?? isStreaming);
|
|
@@ -10432,7 +10673,7 @@ function TurnResultRow({ item }) {
|
|
|
10432
10673
|
" · ",
|
|
10433
10674
|
formatDuration(item.durationMs),
|
|
10434
10675
|
" · ",
|
|
10435
|
-
formatCost(item.totalCostUsd)
|
|
10676
|
+
formatCost(item.costUsd ?? item.totalCostUsd)
|
|
10436
10677
|
]
|
|
10437
10678
|
}),
|
|
10438
10679
|
/* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
|
|
@@ -10905,85 +11146,116 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
10905
11146
|
terminal,
|
|
10906
11147
|
brief
|
|
10907
11148
|
]);
|
|
11149
|
+
const skillNames = useMemo(() => state.skills?.map((skill) => skill.name), [state.skills]);
|
|
10908
11150
|
return /* @__PURE__ */ jsx(TranscriptVariantProvider, {
|
|
10909
11151
|
value: variant,
|
|
10910
|
-
children: /* @__PURE__ */
|
|
10911
|
-
|
|
10912
|
-
children:
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
affordances,
|
|
10920
|
-
children: [
|
|
10921
|
-
frame ? frameTask === void 0 && !replaying ? /* @__PURE__ */ jsx("div", {
|
|
10922
|
-
className: cn(terminal ? "term-row text-fg-4" : "p-4 text-body-sm text-fg-4"),
|
|
10923
|
-
children: "This sub-agent's work is not in this transcript."
|
|
10924
|
-
}) : null : items.length === 0 && state.status !== "starting" ? emptyState !== void 0 ? emptyState : /* @__PURE__ */ jsx(SessionEmptyState, {
|
|
10925
|
-
cwd: state.cwd,
|
|
10926
|
-
hasCommands: !!state.commands?.length,
|
|
10927
|
-
hasSkills: !!state.skills?.some((s) => s.enabled),
|
|
10928
|
-
canBrowseFiles
|
|
10929
|
-
}) : null,
|
|
10930
|
-
frame && frameTask === void 0 && !replaying ? null : /* @__PURE__ */ jsx(TranscriptRows, {
|
|
10931
|
-
rows,
|
|
10932
|
-
boundary,
|
|
10933
|
-
since: catchUp?.since,
|
|
10934
|
-
terminal,
|
|
10935
|
-
replaying,
|
|
10936
|
-
stickyPrompt: !frame && stickyPrompt,
|
|
10937
|
-
gap,
|
|
10938
|
-
fontSize,
|
|
10939
|
-
lineHeight,
|
|
10940
|
-
items,
|
|
10941
|
-
pendingApprovals: state.pendingApprovals,
|
|
10942
|
-
scrubber,
|
|
10943
|
-
bookmarks: frame ? void 0 : bookmarks,
|
|
10944
|
-
affordances,
|
|
10945
|
-
fileUrl,
|
|
10946
|
-
attachmentUrl,
|
|
10947
|
-
hostImage,
|
|
10948
|
-
jumpToRecapRef,
|
|
10949
|
-
repinRef,
|
|
10950
|
-
reveal: frame ? void 0 : reveal,
|
|
10951
|
-
frameParentId: frame?.parentToolUseId,
|
|
10952
|
-
onOpenSubagent: frame ? void 0 : onOpenSubagent
|
|
10953
|
-
}),
|
|
10954
|
-
(frame ? frameTask !== void 0 && taskBusy(frameTask, items) : showLoader(state)) ? terminal ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
10955
|
-
className: "term-blank",
|
|
10956
|
-
"aria-hidden": true
|
|
10957
|
-
}) : null, /* @__PURE__ */ jsx(WorkingRow, {
|
|
10958
|
-
label: state.status === "starting" ? "Starting…" : "Working…",
|
|
10959
|
-
startedAt: runStartedAt,
|
|
10960
|
-
tokens: state.contextUsage?.totalTokens
|
|
10961
|
-
})] }) : /* @__PURE__ */ jsx(Loader, { label: state.status === "starting" ? "Starting session…" : void 0 }) : null
|
|
10962
|
-
]
|
|
10963
|
-
})
|
|
10964
|
-
}),
|
|
10965
|
-
/* @__PURE__ */ jsx(ConversationScrollButton, {}),
|
|
10966
|
-
replaying ? /* @__PURE__ */ jsx("div", {
|
|
10967
|
-
"data-slot": "transcript-hold",
|
|
10968
|
-
"aria-hidden": true,
|
|
10969
|
-
className: "wd-hold-appear visible pointer-events-none absolute inset-0 overflow-hidden",
|
|
10970
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
10971
|
-
className: cn("mx-auto w-full max-w-[var(--wd-transcript-max-width)]", !terminal && "px-4 py-4"),
|
|
10972
|
-
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,
|
|
10973
11161
|
fontSize,
|
|
10974
11162
|
lineHeight,
|
|
10975
|
-
affordances
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
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
|
+
})
|
|
10983
11228
|
})
|
|
10984
11229
|
});
|
|
10985
11230
|
}
|
|
10986
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
|
|
10987
11259
|
//#region src/components/agent/UsageMeters.tsx
|
|
10988
11260
|
function useMinuteClock(active = true) {
|
|
10989
11261
|
const [now, setNow] = useState(() => Date.now());
|
|
@@ -11009,6 +11281,7 @@ function UsageMeters({ windows, now, className }) {
|
|
|
11009
11281
|
function UsageMeter({ window, now }) {
|
|
11010
11282
|
const { key: windowKey, info, updatedAt, inferredReset } = window;
|
|
11011
11283
|
const utilization = info.utilization ?? 0;
|
|
11284
|
+
const stale = usageIsStale(window, now);
|
|
11012
11285
|
const resetsAtMs = info.resetsAt !== void 0 ? info.resetsAt * 1e3 : void 0;
|
|
11013
11286
|
const duration = rateLimitWindowSeconds(windowKey);
|
|
11014
11287
|
const remaining = resetsAtMs !== void 0 ? (resetsAtMs - now) / 1e3 : void 0;
|
|
@@ -11020,14 +11293,14 @@ function UsageMeter({ window, now }) {
|
|
|
11020
11293
|
className: "truncate text-body-sm text-fg-1",
|
|
11021
11294
|
children: formatRateLimitWindowLong(windowKey)
|
|
11022
11295
|
}), /* @__PURE__ */ jsxs("span", {
|
|
11023
|
-
className: cn("shrink-0 font-mono text-body-sm font-medium", info.status === "rejected" ? "text-danger" : "text-fg-1"),
|
|
11296
|
+
className: cn("shrink-0 font-mono text-body-sm font-medium", info.status === "rejected" ? "text-danger" : stale ? "text-fg-4" : "text-fg-1"),
|
|
11024
11297
|
children: [utilization.toFixed(0), "% used"]
|
|
11025
11298
|
})]
|
|
11026
11299
|
}),
|
|
11027
11300
|
/* @__PURE__ */ jsxs("div", {
|
|
11028
11301
|
className: "relative mt-2 h-2 rounded-full bg-border",
|
|
11029
11302
|
children: [/* @__PURE__ */ jsx("div", {
|
|
11030
|
-
className: cn("h-full rounded-full", meterTintClass(utilization)),
|
|
11303
|
+
className: cn("h-full rounded-full", meterTintClass(utilization), stale && "opacity-40"),
|
|
11031
11304
|
style: { width: `${Math.min(100, Math.max(2, utilization))}%` }
|
|
11032
11305
|
}), pace !== void 0 ? /* @__PURE__ */ jsx("span", {
|
|
11033
11306
|
"aria-hidden": true,
|
|
@@ -11056,15 +11329,144 @@ function UsageMeter({ window, now }) {
|
|
|
11056
11329
|
children: "limit reached"
|
|
11057
11330
|
}) : null,
|
|
11058
11331
|
inferredReset ? /* @__PURE__ */ jsx("span", { children: "window reset · nothing reported since" }) : null,
|
|
11059
|
-
updatedAt && !inferredReset ? /* @__PURE__ */
|
|
11332
|
+
updatedAt && !inferredReset ? /* @__PURE__ */ jsxs("span", {
|
|
11333
|
+
className: cn(stale && "text-warning"),
|
|
11334
|
+
children: [stale ? "last reported " : "", formatAgoPrecise(updatedAt, now)]
|
|
11335
|
+
}) : null
|
|
11060
11336
|
]
|
|
11061
11337
|
})
|
|
11062
11338
|
] });
|
|
11063
11339
|
}
|
|
11064
11340
|
//#endregion
|
|
11065
11341
|
//#region src/components/agent/UsageDialog.tsx
|
|
11066
|
-
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 }) {
|
|
11067
11464
|
const now = useMinuteClock(open);
|
|
11465
|
+
const cost = sessionCost({
|
|
11466
|
+
costUsd,
|
|
11467
|
+
totalCostUsd,
|
|
11468
|
+
usageByModel
|
|
11469
|
+
});
|
|
11068
11470
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
11069
11471
|
open,
|
|
11070
11472
|
onOpenChange,
|
|
@@ -11086,15 +11488,17 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, updat
|
|
|
11086
11488
|
windows: rateLimits,
|
|
11087
11489
|
now
|
|
11088
11490
|
}),
|
|
11089
|
-
/* @__PURE__ */
|
|
11090
|
-
className: "mt-5
|
|
11091
|
-
children:
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
})
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
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
|
|
11098
11502
|
}),
|
|
11099
11503
|
updatedAt ? /* @__PURE__ */ jsxs("p", {
|
|
11100
11504
|
className: "mt-2 text-label text-fg-4",
|
|
@@ -11135,7 +11539,7 @@ const INTERACTIVE = [
|
|
|
11135
11539
|
"[role=\"radio\"]",
|
|
11136
11540
|
"[role=\"tab\"]"
|
|
11137
11541
|
].join(",");
|
|
11138
|
-
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, bookmarks, onToggleBookmark, reveal, subagents, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, approvalPrompts, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, fontSize, className }) {
|
|
11542
|
+
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, bookmarks, onToggleBookmark, reveal, subagents, openSubagent, onSubagentChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, approvalPrompts, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, onOpenFile, fontSize, className }) {
|
|
11139
11543
|
const effectiveTermFontSize = terminalMetrics?.fontSize ?? fontSize;
|
|
11140
11544
|
const effectiveTermLineHeight = terminalMetrics?.lineHeight ?? (fontSize !== void 0 ? Math.round(fontSize * (18 / 13)) : void 0);
|
|
11141
11545
|
const external = panelSurface === "external";
|
|
@@ -11146,7 +11550,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11146
11550
|
const [panel, setPanel] = useState();
|
|
11147
11551
|
const [showCompletedTasks, setShowCompletedTasks] = useState(false);
|
|
11148
11552
|
const [taskReveal, setTaskReveal] = useState();
|
|
11149
|
-
const { state, connection, replaying, protocolMismatch, shell, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, setModel, setPermissionMode, reconnectNow, loadFullResult } = useClaudeSession(client, sessionId, {
|
|
11553
|
+
const { state, connection, replaying, protocolMismatch, shell, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, clearContext, setModel, setPermissionMode, reconnectNow, loadFullResult } = useClaudeSession(client, sessionId, {
|
|
11150
11554
|
onProtocolError: setProtocolError,
|
|
11151
11555
|
cacheTranscript
|
|
11152
11556
|
});
|
|
@@ -11186,7 +11590,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11186
11590
|
} : toolHost);
|
|
11187
11591
|
const terminal = transcriptVariant === "terminal";
|
|
11188
11592
|
const capabilities = state.capabilities;
|
|
11189
|
-
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 });
|
|
11190
11594
|
const usage = useMemo(() => mergeUsage({
|
|
11191
11595
|
rateLimits: state.rateLimits,
|
|
11192
11596
|
updatedAt: state.rateLimitsUpdatedAt
|
|
@@ -11208,6 +11612,86 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11208
11612
|
subagents,
|
|
11209
11613
|
state.session?.subagents
|
|
11210
11614
|
]);
|
|
11615
|
+
const clientCommands = useMemo(() => {
|
|
11616
|
+
const modes = capabilities.permissionModes;
|
|
11617
|
+
const built = [];
|
|
11618
|
+
if (models.length > 0) built.push({
|
|
11619
|
+
name: "model",
|
|
11620
|
+
description: "Switch the model for this session",
|
|
11621
|
+
argumentHint: "<model>",
|
|
11622
|
+
requiresArgs: true,
|
|
11623
|
+
run: (args) => {
|
|
11624
|
+
const wanted = args.split(/\s+/)[0];
|
|
11625
|
+
if (!wanted) return false;
|
|
11626
|
+
setModel(wanted);
|
|
11627
|
+
return true;
|
|
11628
|
+
}
|
|
11629
|
+
});
|
|
11630
|
+
if (modes.length > 1) built.push({
|
|
11631
|
+
name: "permissions",
|
|
11632
|
+
description: `Set the permission mode (${modes.join(", ")})`,
|
|
11633
|
+
argumentHint: "<mode>",
|
|
11634
|
+
requiresArgs: true,
|
|
11635
|
+
run: (args) => {
|
|
11636
|
+
const wanted = args.split(/\s+/)[0];
|
|
11637
|
+
if (!modes.includes(wanted)) return false;
|
|
11638
|
+
setPermissionMode(wanted);
|
|
11639
|
+
return true;
|
|
11640
|
+
}
|
|
11641
|
+
});
|
|
11642
|
+
if (capabilities.clearContext) built.push({
|
|
11643
|
+
name: "clear",
|
|
11644
|
+
description: "Clear the conversation - the session keeps running and the old one stays resumable",
|
|
11645
|
+
run: () => {
|
|
11646
|
+
clearContext();
|
|
11647
|
+
return true;
|
|
11648
|
+
}
|
|
11649
|
+
});
|
|
11650
|
+
if (capabilities.mcpStatus) built.push({
|
|
11651
|
+
name: "mcp",
|
|
11652
|
+
description: "MCP servers and their status",
|
|
11653
|
+
run: () => (openPanel("mcp"), true)
|
|
11654
|
+
});
|
|
11655
|
+
if (capabilities.contextUsage) built.push({
|
|
11656
|
+
name: "context",
|
|
11657
|
+
description: "Context window usage",
|
|
11658
|
+
run: () => (openPanel("context"), true)
|
|
11659
|
+
});
|
|
11660
|
+
built.push({
|
|
11661
|
+
name: "status",
|
|
11662
|
+
description: "Session details",
|
|
11663
|
+
run: () => (openPanel("info"), true)
|
|
11664
|
+
});
|
|
11665
|
+
if (capabilities.rateLimits) built.push({
|
|
11666
|
+
name: "usage",
|
|
11667
|
+
description: "Rate limits and spend",
|
|
11668
|
+
run: () => (openPanel("usage"), true)
|
|
11669
|
+
});
|
|
11670
|
+
if (capabilities.skillsList) built.push({
|
|
11671
|
+
name: "skills",
|
|
11672
|
+
description: "Browse the skills this session can use",
|
|
11673
|
+
run: () => (openPanel("skills"), true)
|
|
11674
|
+
});
|
|
11675
|
+
return built;
|
|
11676
|
+
}, [
|
|
11677
|
+
capabilities,
|
|
11678
|
+
models.length,
|
|
11679
|
+
openPanel,
|
|
11680
|
+
clearContext,
|
|
11681
|
+
setModel,
|
|
11682
|
+
setPermissionMode
|
|
11683
|
+
]);
|
|
11684
|
+
const composerCommands = useMemo(() => composerCommandRows(mergeComposerRows({
|
|
11685
|
+
commands: capabilities.slashCommands ? state.commands : void 0,
|
|
11686
|
+
clientCommands,
|
|
11687
|
+
skills: capabilities.skillsList ? state.skills : void 0
|
|
11688
|
+
})), [
|
|
11689
|
+
capabilities.slashCommands,
|
|
11690
|
+
capabilities.skillsList,
|
|
11691
|
+
state.commands,
|
|
11692
|
+
state.skills,
|
|
11693
|
+
clientCommands
|
|
11694
|
+
]);
|
|
11211
11695
|
const onVitalsRef = useRef(onVitals);
|
|
11212
11696
|
onVitalsRef.current = onVitals;
|
|
11213
11697
|
const vitalsModel = effectiveModel ?? state.model;
|
|
@@ -11223,6 +11707,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11223
11707
|
permissionMode: state.permissionMode,
|
|
11224
11708
|
permissionModes,
|
|
11225
11709
|
skills: state.skills,
|
|
11710
|
+
composerCommands,
|
|
11226
11711
|
cwd: state.cwd,
|
|
11227
11712
|
contextUsage: state.contextUsage,
|
|
11228
11713
|
tasks,
|
|
@@ -11241,6 +11726,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11241
11726
|
state.permissionMode,
|
|
11242
11727
|
permissionModes,
|
|
11243
11728
|
state.skills,
|
|
11729
|
+
composerCommands,
|
|
11244
11730
|
state.cwd,
|
|
11245
11731
|
state.contextUsage,
|
|
11246
11732
|
tasks,
|
|
@@ -11296,26 +11782,10 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11296
11782
|
const composerRef = useRef(null);
|
|
11297
11783
|
const jumpToRecap = useRef(null);
|
|
11298
11784
|
const repinTranscript = useRef(null);
|
|
11299
|
-
const commands = useMemo(() => {
|
|
11300
|
-
if (!state.commands) return;
|
|
11301
|
-
if (state.commands.some((c) => c.name === "model")) return state.commands;
|
|
11302
|
-
return [{
|
|
11303
|
-
name: "model",
|
|
11304
|
-
description: "Switch the model for this session",
|
|
11305
|
-
argumentHint: "<model>"
|
|
11306
|
-
}, ...state.commands];
|
|
11307
|
-
}, [state.commands]);
|
|
11308
11785
|
const handleSend = (text, attachmentIds) => {
|
|
11309
11786
|
if (attachmentIds.length === 0) {
|
|
11310
|
-
const
|
|
11311
|
-
if (
|
|
11312
|
-
setModel(modelCommand[1]);
|
|
11313
|
-
return;
|
|
11314
|
-
}
|
|
11315
|
-
if (capabilities.mcpStatus && text.trim() === "/mcp") {
|
|
11316
|
-
openPanel("mcp");
|
|
11317
|
-
return;
|
|
11318
|
-
}
|
|
11787
|
+
const local = matchClientCommand(text, clientCommands);
|
|
11788
|
+
if (local && local.command.run(local.args)) return;
|
|
11319
11789
|
}
|
|
11320
11790
|
setCaughtUp(true);
|
|
11321
11791
|
repinTranscript.current?.();
|
|
@@ -11381,6 +11851,10 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11381
11851
|
onOpenTasks: external && !onOpenPanel ? void 0 : () => openPanel("tasks"),
|
|
11382
11852
|
actions: headerTakesActions ? void 0 : menu
|
|
11383
11853
|
});
|
|
11854
|
+
const fileLinks = useMemo(() => onOpenFile ? {
|
|
11855
|
+
cwd: state.cwd,
|
|
11856
|
+
open: onOpenFile
|
|
11857
|
+
} : void 0, [onOpenFile, state.cwd]);
|
|
11384
11858
|
const panelRef = useRef(null);
|
|
11385
11859
|
useEffect(() => {
|
|
11386
11860
|
if (!onLinkClick) return;
|
|
@@ -11409,224 +11883,231 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
11409
11883
|
value: transcriptVariant,
|
|
11410
11884
|
children: /* @__PURE__ */ jsx(TranscriptDensityProvider, {
|
|
11411
11885
|
value: transcriptDensity,
|
|
11412
|
-
children: /* @__PURE__ */ jsx(
|
|
11413
|
-
value:
|
|
11414
|
-
children: /* @__PURE__ */ jsx(
|
|
11415
|
-
value:
|
|
11416
|
-
children: /* @__PURE__ */ jsx(
|
|
11417
|
-
value:
|
|
11418
|
-
children: /* @__PURE__ */
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
|
|
11431
|
-
|
|
11432
|
-
protocolMismatch,
|
|
11433
|
-
", this build renders v",
|
|
11434
|
-
PROTOCOL_VERSION,
|
|
11435
|
-
". Some events may not render."
|
|
11436
|
-
]
|
|
11437
|
-
}) : null,
|
|
11438
|
-
protocolError ? /* @__PURE__ */ jsx(Notice, {
|
|
11439
|
-
level: "error",
|
|
11440
|
-
onDismiss: () => setProtocolError(void 0),
|
|
11441
|
-
children: protocolError
|
|
11442
|
-
}) : null,
|
|
11443
|
-
subagentId !== void 0 ? /* @__PURE__ */ jsx(SubagentStrip, {
|
|
11444
|
-
task: subagentTask,
|
|
11445
|
-
items: subagentFrameItems,
|
|
11446
|
-
label: subagentFallbackLabel,
|
|
11447
|
-
onBack: leaveSubagent,
|
|
11448
|
-
terminal,
|
|
11449
|
-
fontSize: effectiveTermFontSize,
|
|
11450
|
-
lineHeight: effectiveTermLineHeight
|
|
11451
|
-
}) : null,
|
|
11452
|
-
/* @__PURE__ */ jsx(BookmarkProvider, {
|
|
11453
|
-
value: bookmarkHandle,
|
|
11454
|
-
children: /* @__PURE__ */ jsx(Transcript, {
|
|
11455
|
-
state,
|
|
11456
|
-
fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
|
|
11457
|
-
attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
|
|
11458
|
-
canBrowseFiles: hostFiles.available,
|
|
11459
|
-
hostImage,
|
|
11460
|
-
variant: transcriptVariant,
|
|
11461
|
-
density: transcriptDensity,
|
|
11462
|
-
fontSize: effectiveTermFontSize,
|
|
11463
|
-
lineHeight: effectiveTermLineHeight,
|
|
11464
|
-
affordances,
|
|
11465
|
-
stickyPrompt,
|
|
11466
|
-
scrubber,
|
|
11467
|
-
bookmarks,
|
|
11468
|
-
replaying,
|
|
11469
|
-
catchUp: catchUp && newCount > 0 ? {
|
|
11470
|
-
from: catchUp.itemCount,
|
|
11471
|
-
since: catchUp.since
|
|
11472
|
-
} : void 0,
|
|
11473
|
-
reveal: taskReveal ?? returnReveal ?? reveal,
|
|
11474
|
-
frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
|
|
11475
|
-
onOpenSubagent: enterSubagent,
|
|
11476
|
-
emptyState,
|
|
11477
|
-
jumpToRecapRef: jumpToRecap,
|
|
11478
|
-
repinRef: repinTranscript
|
|
11479
|
-
}, subagentId ?? "session")
|
|
11480
|
-
}),
|
|
11481
|
-
catchUp && newCount > 0 && !replaying && subagentId === void 0 ? /* @__PURE__ */ jsx("div", {
|
|
11482
|
-
className: "px-3 pb-1",
|
|
11483
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
11484
|
-
"data-slot": "catch-up",
|
|
11485
|
-
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
|
|
11886
|
+
children: /* @__PURE__ */ jsx(FileLinkProvider, {
|
|
11887
|
+
value: fileLinks,
|
|
11888
|
+
children: /* @__PURE__ */ jsx(ToolResultFetchProvider, {
|
|
11889
|
+
value: loadFullResult,
|
|
11890
|
+
children: /* @__PURE__ */ jsx(ToolTitleProvider, {
|
|
11891
|
+
value: state.toolTitles,
|
|
11892
|
+
children: /* @__PURE__ */ jsx(ToolResultImageProvider, {
|
|
11893
|
+
value: resultImages,
|
|
11894
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
11895
|
+
ref: panelRef,
|
|
11896
|
+
"data-slot": "session-panel",
|
|
11897
|
+
"data-agent-font": transcriptFont,
|
|
11898
|
+
onClick: handleClick,
|
|
11899
|
+
className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
|
|
11900
|
+
style: fontSize !== void 0 ? { "--wd-font-size": `${Math.round(fontSize)}px` } : void 0,
|
|
11901
|
+
children: [
|
|
11902
|
+
headerTakesActions ? header({ actions: menu }) : header,
|
|
11903
|
+
statusPlacement === "top" ? statusBar : null,
|
|
11904
|
+
protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
|
|
11905
|
+
level: "warning",
|
|
11486
11906
|
children: [
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
/* @__PURE__ */ jsxs("span", {
|
|
11493
|
-
className: "min-w-0 flex-1 truncate",
|
|
11494
|
-
children: [
|
|
11495
|
-
newCount,
|
|
11496
|
-
" new ",
|
|
11497
|
-
newCount === 1 ? "row" : "rows",
|
|
11498
|
-
catchUp.since !== void 0 ? ` since you were last here` : ""
|
|
11499
|
-
]
|
|
11500
|
-
}),
|
|
11501
|
-
/* @__PURE__ */ jsx("button", {
|
|
11502
|
-
type: "button",
|
|
11503
|
-
onClick: () => jumpToRecap.current?.(),
|
|
11504
|
-
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
11505
|
-
children: "jump"
|
|
11506
|
-
}),
|
|
11507
|
-
/* @__PURE__ */ jsx("button", {
|
|
11508
|
-
type: "button",
|
|
11509
|
-
onClick: () => setCaughtUp(true),
|
|
11510
|
-
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
11511
|
-
children: "dismiss"
|
|
11512
|
-
})
|
|
11907
|
+
"Server speaks protocol v",
|
|
11908
|
+
protocolMismatch,
|
|
11909
|
+
", this build renders v",
|
|
11910
|
+
PROTOCOL_VERSION,
|
|
11911
|
+
". Some events may not render."
|
|
11513
11912
|
]
|
|
11514
|
-
})
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11913
|
+
}) : null,
|
|
11914
|
+
protocolError ? /* @__PURE__ */ jsx(Notice, {
|
|
11915
|
+
level: "error",
|
|
11916
|
+
onDismiss: () => setProtocolError(void 0),
|
|
11917
|
+
children: protocolError
|
|
11918
|
+
}) : null,
|
|
11919
|
+
subagentId !== void 0 ? /* @__PURE__ */ jsx(SubagentStrip, {
|
|
11920
|
+
task: subagentTask,
|
|
11921
|
+
items: subagentFrameItems,
|
|
11922
|
+
label: subagentFallbackLabel,
|
|
11923
|
+
onBack: leaveSubagent,
|
|
11519
11924
|
terminal,
|
|
11520
|
-
|
|
11925
|
+
fontSize: effectiveTermFontSize,
|
|
11926
|
+
lineHeight: effectiveTermLineHeight
|
|
11927
|
+
}) : null,
|
|
11928
|
+
/* @__PURE__ */ jsx(BookmarkProvider, {
|
|
11929
|
+
value: bookmarkHandle,
|
|
11930
|
+
children: /* @__PURE__ */ jsx(Transcript, {
|
|
11931
|
+
state,
|
|
11932
|
+
fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
|
|
11933
|
+
attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
|
|
11934
|
+
canBrowseFiles: hostFiles.available,
|
|
11935
|
+
hostImage,
|
|
11936
|
+
variant: transcriptVariant,
|
|
11937
|
+
density: transcriptDensity,
|
|
11521
11938
|
fontSize: effectiveTermFontSize,
|
|
11522
|
-
lineHeight: effectiveTermLineHeight
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
},
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
onApprove: approve,
|
|
11540
|
-
onDeny: deny
|
|
11541
|
-
}, request.id);
|
|
11542
|
-
return isQuestion ? /* @__PURE__ */ jsx(QuestionPrompt, {
|
|
11543
|
-
request,
|
|
11544
|
-
onAnswer: approve,
|
|
11545
|
-
onDismiss: (id) => deny(id, "Question dismissed by user")
|
|
11546
|
-
}, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
11547
|
-
request,
|
|
11548
|
-
onApprove: approve,
|
|
11549
|
-
onDeny: deny
|
|
11550
|
-
}, request.id);
|
|
11551
|
-
})
|
|
11552
|
-
})
|
|
11553
|
-
}) : null,
|
|
11554
|
-
readOnly || subagentId !== void 0 ? null : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Composer, {
|
|
11555
|
-
ref: composerRef,
|
|
11556
|
-
onSend: handleSend,
|
|
11557
|
-
onInterrupt: interrupt,
|
|
11558
|
-
busy,
|
|
11559
|
-
disabled: ended || !sessionId,
|
|
11560
|
-
commands: capabilities.slashCommands ? commands : void 0,
|
|
11561
|
-
skills: capabilities.skillsList ? state.skills : void 0,
|
|
11562
|
-
attachments,
|
|
11563
|
-
draft,
|
|
11564
|
-
onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
|
|
11565
|
-
onShellCommand: shell ? runShell : void 0,
|
|
11566
|
-
layout: controlsExternal ? "inline" : "stacked",
|
|
11567
|
-
toolbar: controlsExternal ? void 0 : sessionControls,
|
|
11568
|
-
fontSize: effectiveTermFontSize,
|
|
11569
|
-
lineHeight: effectiveTermLineHeight,
|
|
11570
|
-
affordances
|
|
11571
|
-
}) }),
|
|
11572
|
-
statusPlacement === "bottom" ? statusBar : null,
|
|
11573
|
-
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
11574
|
-
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
11575
|
-
state,
|
|
11576
|
-
client,
|
|
11577
|
-
sessionId,
|
|
11578
|
-
open: panel === "info",
|
|
11579
|
-
onOpenChange: (next) => setPanel(next ? "info" : void 0)
|
|
11580
|
-
}),
|
|
11581
|
-
/* @__PURE__ */ jsx(ContextDialog, {
|
|
11582
|
-
usage: state.contextUsage,
|
|
11583
|
-
engine: state.engine ?? "claude",
|
|
11584
|
-
open: panel === "context",
|
|
11585
|
-
onOpenChange: (next) => setPanel(next ? "context" : void 0)
|
|
11586
|
-
}),
|
|
11587
|
-
/* @__PURE__ */ jsx(UsageDialog, {
|
|
11588
|
-
rateLimits: windows,
|
|
11589
|
-
subscriptionType: state.subscriptionType,
|
|
11590
|
-
engine: state.engine ?? "claude",
|
|
11591
|
-
totalCostUsd: state.totalCostUsd,
|
|
11592
|
-
updatedAt: usageUpdatedAt,
|
|
11593
|
-
open: panel === "usage",
|
|
11594
|
-
onOpenChange: (next) => setPanel(next ? "usage" : void 0)
|
|
11939
|
+
lineHeight: effectiveTermLineHeight,
|
|
11940
|
+
affordances,
|
|
11941
|
+
stickyPrompt,
|
|
11942
|
+
scrubber,
|
|
11943
|
+
bookmarks,
|
|
11944
|
+
replaying,
|
|
11945
|
+
catchUp: catchUp && newCount > 0 ? {
|
|
11946
|
+
from: catchUp.itemCount,
|
|
11947
|
+
since: catchUp.since
|
|
11948
|
+
} : void 0,
|
|
11949
|
+
reveal: taskReveal ?? returnReveal ?? reveal,
|
|
11950
|
+
frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
|
|
11951
|
+
onOpenSubagent: enterSubagent,
|
|
11952
|
+
emptyState,
|
|
11953
|
+
jumpToRecapRef: jumpToRecap,
|
|
11954
|
+
repinRef: repinTranscript
|
|
11955
|
+
}, subagentId ?? "session")
|
|
11595
11956
|
}),
|
|
11596
|
-
/* @__PURE__ */ jsx(
|
|
11597
|
-
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11627
|
-
|
|
11628
|
-
|
|
11629
|
-
|
|
11957
|
+
catchUp && newCount > 0 && !replaying && subagentId === void 0 ? /* @__PURE__ */ jsx("div", {
|
|
11958
|
+
className: "px-3 pb-1",
|
|
11959
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
11960
|
+
"data-slot": "catch-up",
|
|
11961
|
+
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
|
|
11962
|
+
children: [
|
|
11963
|
+
/* @__PURE__ */ jsx("span", {
|
|
11964
|
+
"aria-hidden": true,
|
|
11965
|
+
className: cn("select-none", terminal ? "text-fg-3" : "text-accent"),
|
|
11966
|
+
children: "※"
|
|
11967
|
+
}),
|
|
11968
|
+
/* @__PURE__ */ jsxs("span", {
|
|
11969
|
+
className: "min-w-0 flex-1 truncate",
|
|
11970
|
+
children: [
|
|
11971
|
+
newCount,
|
|
11972
|
+
" new ",
|
|
11973
|
+
newCount === 1 ? "row" : "rows",
|
|
11974
|
+
catchUp.since !== void 0 ? ` since you were last here` : ""
|
|
11975
|
+
]
|
|
11976
|
+
}),
|
|
11977
|
+
/* @__PURE__ */ jsx("button", {
|
|
11978
|
+
type: "button",
|
|
11979
|
+
onClick: () => jumpToRecap.current?.(),
|
|
11980
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
11981
|
+
children: "jump"
|
|
11982
|
+
}),
|
|
11983
|
+
/* @__PURE__ */ jsx("button", {
|
|
11984
|
+
type: "button",
|
|
11985
|
+
onClick: () => setCaughtUp(true),
|
|
11986
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
11987
|
+
children: "dismiss"
|
|
11988
|
+
})
|
|
11989
|
+
]
|
|
11990
|
+
})
|
|
11991
|
+
}) : null,
|
|
11992
|
+
!readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
11993
|
+
className: cn(terminal ? "pb-2" : "px-3 pb-2"),
|
|
11994
|
+
children: /* @__PURE__ */ jsx(PromptSurface, {
|
|
11995
|
+
terminal,
|
|
11996
|
+
metrics: {
|
|
11997
|
+
fontSize: effectiveTermFontSize,
|
|
11998
|
+
lineHeight: effectiveTermLineHeight
|
|
11999
|
+
},
|
|
12000
|
+
affordances,
|
|
12001
|
+
children: state.pendingApprovals.map((request) => {
|
|
12002
|
+
const HostPrompt = approvalPrompts?.[request.toolName];
|
|
12003
|
+
if (HostPrompt) return /* @__PURE__ */ jsx(HostPrompt, {
|
|
12004
|
+
request,
|
|
12005
|
+
onApprove: approve,
|
|
12006
|
+
onDeny: deny
|
|
12007
|
+
}, request.id);
|
|
12008
|
+
const isQuestion = request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0;
|
|
12009
|
+
if (terminal) return isQuestion ? /* @__PURE__ */ jsx(TerminalQuestionPrompt, {
|
|
12010
|
+
request,
|
|
12011
|
+
onAnswer: approve,
|
|
12012
|
+
onDismiss: (id) => deny(id, "Question dismissed by user")
|
|
12013
|
+
}, request.id) : /* @__PURE__ */ jsx(TerminalPermissionPrompt, {
|
|
12014
|
+
request,
|
|
12015
|
+
onApprove: approve,
|
|
12016
|
+
onDeny: deny
|
|
12017
|
+
}, request.id);
|
|
12018
|
+
return isQuestion ? /* @__PURE__ */ jsx(QuestionPrompt, {
|
|
12019
|
+
request,
|
|
12020
|
+
onAnswer: approve,
|
|
12021
|
+
onDismiss: (id) => deny(id, "Question dismissed by user")
|
|
12022
|
+
}, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
12023
|
+
request,
|
|
12024
|
+
onApprove: approve,
|
|
12025
|
+
onDeny: deny
|
|
12026
|
+
}, request.id);
|
|
12027
|
+
})
|
|
12028
|
+
})
|
|
12029
|
+
}) : null,
|
|
12030
|
+
readOnly || subagentId !== void 0 ? null : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Composer, {
|
|
12031
|
+
ref: composerRef,
|
|
12032
|
+
onSend: handleSend,
|
|
12033
|
+
onInterrupt: interrupt,
|
|
12034
|
+
busy,
|
|
12035
|
+
disabled: ended || !sessionId,
|
|
12036
|
+
commands: capabilities.slashCommands ? state.commands : void 0,
|
|
12037
|
+
skills: capabilities.skillsList ? state.skills : void 0,
|
|
12038
|
+
clientCommands,
|
|
12039
|
+
attachments,
|
|
12040
|
+
draft,
|
|
12041
|
+
onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
|
|
12042
|
+
onShellCommand: shell ? runShell : void 0,
|
|
12043
|
+
layout: controlsExternal ? "inline" : "stacked",
|
|
12044
|
+
toolbar: controlsExternal ? void 0 : sessionControls,
|
|
12045
|
+
fontSize: effectiveTermFontSize,
|
|
12046
|
+
lineHeight: effectiveTermLineHeight,
|
|
12047
|
+
affordances
|
|
12048
|
+
}) }),
|
|
12049
|
+
statusPlacement === "bottom" ? statusBar : null,
|
|
12050
|
+
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
12051
|
+
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
12052
|
+
state,
|
|
12053
|
+
client,
|
|
12054
|
+
sessionId,
|
|
12055
|
+
open: panel === "info",
|
|
12056
|
+
onOpenChange: (next) => setPanel(next ? "info" : void 0)
|
|
12057
|
+
}),
|
|
12058
|
+
/* @__PURE__ */ jsx(ContextDialog, {
|
|
12059
|
+
usage: state.contextUsage,
|
|
12060
|
+
engine: state.engine ?? "claude",
|
|
12061
|
+
open: panel === "context",
|
|
12062
|
+
onOpenChange: (next) => setPanel(next ? "context" : void 0)
|
|
12063
|
+
}),
|
|
12064
|
+
/* @__PURE__ */ jsx(UsageDialog, {
|
|
12065
|
+
rateLimits: windows,
|
|
12066
|
+
subscriptionType: state.subscriptionType,
|
|
12067
|
+
engine: state.engine ?? "claude",
|
|
12068
|
+
totalCostUsd: state.totalCostUsd,
|
|
12069
|
+
costUsd: state.costUsd,
|
|
12070
|
+
usageByModel: state.usageByModel,
|
|
12071
|
+
spend: profileSpend,
|
|
12072
|
+
updatedAt: usageUpdatedAt,
|
|
12073
|
+
open: panel === "usage",
|
|
12074
|
+
onOpenChange: (next) => setPanel(next ? "usage" : void 0)
|
|
12075
|
+
}),
|
|
12076
|
+
/* @__PURE__ */ jsx(McpDialog, {
|
|
12077
|
+
client,
|
|
12078
|
+
sessionId,
|
|
12079
|
+
canManageServers: capabilities.mcpServerActions,
|
|
12080
|
+
open: panel === "mcp",
|
|
12081
|
+
onOpenChange: (next) => setPanel(next ? "mcp" : void 0)
|
|
12082
|
+
}),
|
|
12083
|
+
/* @__PURE__ */ jsx(TasksDialog, {
|
|
12084
|
+
tasks,
|
|
12085
|
+
showCompleted: showCompletedTasks,
|
|
12086
|
+
onShowCompletedChange: setShowCompletedTasks,
|
|
12087
|
+
onSelectTask: (task) => {
|
|
12088
|
+
if (task.toolUseId) setTaskReveal({
|
|
12089
|
+
toolUseId: task.toolUseId,
|
|
12090
|
+
nonce: Date.now()
|
|
12091
|
+
});
|
|
12092
|
+
},
|
|
12093
|
+
open: panel === "tasks",
|
|
12094
|
+
onOpenChange: (next) => setPanel(next ? "tasks" : void 0)
|
|
12095
|
+
}),
|
|
12096
|
+
/* @__PURE__ */ jsx(SkillsDialog, {
|
|
12097
|
+
skills: state.skills,
|
|
12098
|
+
open: panel === "skills",
|
|
12099
|
+
onOpenChange: (next) => setPanel(next ? "skills" : void 0),
|
|
12100
|
+
onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
|
|
12101
|
+
}),
|
|
12102
|
+
/* @__PURE__ */ jsx(HostFilesDialog, {
|
|
12103
|
+
client,
|
|
12104
|
+
cwd: state.cwd,
|
|
12105
|
+
open: panel === "files",
|
|
12106
|
+
onOpenChange: (next) => setPanel(next ? "files" : void 0)
|
|
12107
|
+
})
|
|
12108
|
+
] }) : null
|
|
12109
|
+
]
|
|
12110
|
+
})
|
|
11630
12111
|
})
|
|
11631
12112
|
})
|
|
11632
12113
|
})
|
|
@@ -11696,6 +12177,108 @@ function Notice({ level, onDismiss, children }) {
|
|
|
11696
12177
|
});
|
|
11697
12178
|
}
|
|
11698
12179
|
//#endregion
|
|
11699
|
-
|
|
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 };
|
|
11700
12283
|
|
|
11701
|
-
//# sourceMappingURL=
|
|
12284
|
+
//# sourceMappingURL=use-path-links-CvcxdUXL.mjs.map
|