@workerdeck/ui 3.0.1 → 3.2.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-C1bU4yTM.d.mts → SessionPanel-BNNc8grK.d.mts} +9 -7
- package/build/index.d.mts +153 -45
- package/build/index.mjs +501 -226
- package/build/index.mjs.map +1 -1
- package/build/scoped.css +15 -6
- package/build/{use-path-links-BEWxt0ZM.mjs → use-path-links-C6Fh5zdx.mjs} +1926 -2086
- package/build/use-path-links-C6Fh5zdx.mjs.map +1 -0
- package/build/workspace.d.mts +1 -1
- package/build/workspace.mjs +1 -1
- package/package.json +4 -4
- package/src/components/agent/ApprovalPrompts.tsx +87 -0
- package/src/components/agent/Composer.tsx +25 -47
- package/src/components/agent/ContextDialog.tsx +75 -67
- package/src/components/agent/FrameStrip.tsx +74 -0
- package/src/components/agent/HostFilesDialog.tsx +3 -2
- package/src/components/agent/McpDialog.tsx +112 -78
- package/src/components/agent/PermissionPrompt.tsx +13 -22
- package/src/components/agent/QuestionPrompt.tsx +6 -41
- package/src/components/agent/Scrubber.tsx +6 -75
- package/src/components/agent/SessionBrowser.tsx +125 -214
- package/src/components/agent/SessionFilters.tsx +266 -0
- package/src/components/agent/SessionInfoDialog.tsx +47 -63
- package/src/components/agent/SessionItem.tsx +27 -7
- package/src/components/agent/SessionPanel.tsx +244 -488
- package/src/components/agent/SessionSteps.tsx +54 -11
- package/src/components/agent/ShellStrip.tsx +27 -43
- package/src/components/agent/SubagentStrip.tsx +13 -30
- package/src/components/agent/Transcript.tsx +13 -0
- package/src/components/agent/TranscriptItemView.tsx +6 -36
- package/src/components/agent/composer-commands.ts +80 -1
- package/src/components/agent/markdown-image.tsx +49 -1
- package/src/components/agent/scrubber-marks.ts +33 -11
- package/src/components/agent/scrubber-peek.tsx +122 -0
- package/src/components/agent/session-panel-providers.tsx +41 -0
- package/src/components/agent/shell-actions.tsx +36 -1
- package/src/components/agent/use-catch-up.ts +20 -0
- package/src/components/agent/use-frame.ts +88 -0
- package/src/components/agent/use-host-image.ts +81 -0
- package/src/components/agent/use-shell-frame.ts +12 -70
- package/src/components/agent/use-subagent-frame.ts +19 -75
- package/src/components/prompt-area/prompt-area-engine.ts +21 -20
- package/src/components/prompt-area/prompt-area-list-ops.ts +12 -15
- package/src/components/terminal/PermissionPrompt.tsx +19 -32
- package/src/components/terminal/QuestionPrompt.tsx +10 -46
- package/src/components/terminal/TerminalTranscript.tsx +3 -86
- package/src/components/terminal/items.tsx +5 -43
- package/src/components/terminal/scrubber.tsx +25 -272
- package/src/components/ui/Popover.tsx +29 -0
- package/src/components/ui/Select.tsx +25 -0
- package/src/index.ts +46 -8
- package/src/lib/file-link.ts +3 -16
- package/src/lib/permission-prompt.ts +57 -0
- package/src/lib/question-answers.ts +65 -0
- package/build/use-path-links-BEWxt0ZM.mjs.map +0 -1
- package/src/components/prompt-area/use-markdown-mode.ts +0 -103
|
@@ -5,12 +5,12 @@ 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,
|
|
8
|
+
import { ArrowDown, ArrowDownCircle, ArrowLeft, ArrowUp, AtSign, Bot, BotOff, Brain, ChartPie, Check, CheckSquare, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, ClipboardList, Clock, Code, Copy, Download, File, FileDiff, FileText, Folder, FolderSearch, FolderTree, Gauge, Globe, Hand, Image, Info, Link2, LoaderCircle, Maximize, Maximize2, MessageCircleQuestion, MessageSquareText, Minus, MoreHorizontal, Paperclip, PencilLine, Plug, Plus, Power, PowerOff, Puzzle, RefreshCw, RotateCcw, RotateCw, Search, ShieldCheck, SlashSquare, SlidersHorizontal, Sparkles, Square, SquarePen, SquareTerminal, Star, Terminal, TriangleAlert, Users, 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 { PRICING_NOTE, PROTOCOL_VERSION, SHELL_INTERACTIVE_NOTE, UNPRICED_WARN_SHARE, canonicalModel, costOf, costOfByModel, isPeerSendTool, mergeUsage, orderUsageWindows, parseTodoWriteInput, parseUserQuestions, peerDeliveredTo, pricingAgeNote, rateFor, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, totalTokens, unknownBasisModels, usageInfos, usageIsStale
|
|
13
|
-
import { recapLine, scanPromptTokens, summarizeSince, useAttachments, useClaudeSession, useDraft, useHostFileSearch, usePeerSessions, useProfileUsage, useShellTerminal, useToolCallHost } from "@workerdeck/react";
|
|
12
|
+
import { PRICING_NOTE, PROTOCOL_VERSION, SHELL_INTERACTIVE_NOTE, UNPRICED_WARN_SHARE, canonicalModel, costOf, costOfByModel, errorMessage, isPeerSendTool, mergeUsage, orderUsageWindows, parseTodoWriteInput, parseUserQuestions, peerDeliveredTo, pricingAgeNote, rateFor, resolvePosix, sessionTasks, subagentLabel, taskCountLabel, taskSummary, toolTitle, totalTokens, unknownBasisModels, usageInfos, usageIsStale } from "@workerdeck/protocol";
|
|
13
|
+
import { recapLine, scanPromptTokens, summarizeSince, useAsync, useAttachments, useClaudeSession, useDraft, useHostFileSearch, usePeerSessions, useProfileUsage, useShellTerminal, useToolCallHost } from "@workerdeck/react";
|
|
14
14
|
import { Streamdown, defaultRehypePlugins } from "streamdown";
|
|
15
15
|
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
|
16
16
|
import { createPortal } from "react-dom";
|
|
@@ -170,6 +170,20 @@ const SelectItem = ({ className, children, ...props }) => /* @__PURE__ */ jsxs(S
|
|
|
170
170
|
children: /* @__PURE__ */ jsx(Check, { className: "size-3.5" })
|
|
171
171
|
})]
|
|
172
172
|
});
|
|
173
|
+
function OptionSelect({ label, value, options, onChange, className }) {
|
|
174
|
+
return /* @__PURE__ */ jsxs(Select$1, {
|
|
175
|
+
value,
|
|
176
|
+
onValueChange: (next) => onChange(next),
|
|
177
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
178
|
+
"aria-label": label,
|
|
179
|
+
className,
|
|
180
|
+
children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
|
|
181
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
|
|
182
|
+
value: option.value,
|
|
183
|
+
children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
|
|
184
|
+
}, option.value)) })]
|
|
185
|
+
});
|
|
186
|
+
}
|
|
173
187
|
//#endregion
|
|
174
188
|
//#region src/components/ui/Menu.tsx
|
|
175
189
|
const Menu$1 = Menu.Root;
|
|
@@ -608,7 +622,8 @@ function resolveChip(segments, activeTrigger, chip, trailingText = " ") {
|
|
|
608
622
|
const triggerEnd = triggerStart + 1 + activeTrigger.query.length;
|
|
609
623
|
const newSegments = [];
|
|
610
624
|
let offset = 0;
|
|
611
|
-
|
|
625
|
+
let insertedChip;
|
|
626
|
+
for (const seg of mergeAdjacentTextSegments(segments)) if (seg.type === "chip") {
|
|
612
627
|
const chipText = chipPlainText(seg);
|
|
613
628
|
const chipStart = offset;
|
|
614
629
|
const chipEnd = offset + chipText.length;
|
|
@@ -636,6 +651,7 @@ function resolveChip(segments, activeTrigger, chip, trailingText = " ") {
|
|
|
636
651
|
...chip.autoResolved ? { autoResolved: true } : {}
|
|
637
652
|
};
|
|
638
653
|
newSegments.push(newChip);
|
|
654
|
+
insertedChip = newChip;
|
|
639
655
|
if (afterText) newSegments.push({
|
|
640
656
|
type: "text",
|
|
641
657
|
text: trailingText + afterText.replace(/^\s/, "")
|
|
@@ -648,16 +664,9 @@ function resolveChip(segments, activeTrigger, chip, trailingText = " ") {
|
|
|
648
664
|
offset = textEnd;
|
|
649
665
|
}
|
|
650
666
|
const merged = mergeAdjacentTextSegments(newSegments);
|
|
651
|
-
let lastChipEndOffset = -1;
|
|
652
|
-
let runningOffset = 0;
|
|
653
|
-
for (const seg of merged) if (seg.type === "text") runningOffset += seg.text.length;
|
|
654
|
-
else {
|
|
655
|
-
runningOffset += chipPlainText(seg).length;
|
|
656
|
-
if (seg.value === chip.value && seg.displayText === chip.displayText && seg.trigger === activeTrigger.config.char) lastChipEndOffset = runningOffset;
|
|
657
|
-
}
|
|
658
667
|
return {
|
|
659
668
|
segments: merged,
|
|
660
|
-
cursorOffset:
|
|
669
|
+
cursorOffset: insertedChip ? triggerStart + chipPlainText(insertedChip).length + trailingText.length : segmentsToPlainText(merged).length
|
|
661
670
|
};
|
|
662
671
|
}
|
|
663
672
|
/**
|
|
@@ -676,7 +685,7 @@ function resolveText(segments, activeTrigger, text) {
|
|
|
676
685
|
const newSegments = [];
|
|
677
686
|
let offset = 0;
|
|
678
687
|
let cursorOffset = triggerStart + text.length;
|
|
679
|
-
for (const seg of segments) {
|
|
688
|
+
for (const seg of mergeAdjacentTextSegments(segments)) {
|
|
680
689
|
if (seg.type === "chip") {
|
|
681
690
|
const chipEnd = offset + chipPlainText(seg).length;
|
|
682
691
|
if (chipEnd <= triggerStart || offset >= triggerEnd) newSegments.push(seg);
|
|
@@ -843,7 +852,23 @@ function replaceTextRange(segments, start, end, replacement) {
|
|
|
843
852
|
});
|
|
844
853
|
inserted = true;
|
|
845
854
|
}
|
|
846
|
-
if (
|
|
855
|
+
if (start === end) {
|
|
856
|
+
newSegments.push(seg);
|
|
857
|
+
if (!inserted && chipStart < start && start < chipEnd) {
|
|
858
|
+
newSegments.push({
|
|
859
|
+
type: "text",
|
|
860
|
+
text: replacement
|
|
861
|
+
});
|
|
862
|
+
inserted = true;
|
|
863
|
+
}
|
|
864
|
+
} else if (chipEnd <= start || chipStart >= end) newSegments.push(seg);
|
|
865
|
+
else if (!inserted) {
|
|
866
|
+
newSegments.push({
|
|
867
|
+
type: "text",
|
|
868
|
+
text: replacement
|
|
869
|
+
});
|
|
870
|
+
inserted = true;
|
|
871
|
+
}
|
|
847
872
|
offset = chipEnd;
|
|
848
873
|
} else {
|
|
849
874
|
const textStart = offset;
|
|
@@ -927,7 +952,7 @@ function segmentsEqual(a, b) {
|
|
|
927
952
|
if (sa.type !== sb.type) return false;
|
|
928
953
|
if (sa.type === "text") {
|
|
929
954
|
if (sb.type !== "text" || sa.text !== sb.text) return false;
|
|
930
|
-
} else if (sb.type !== "chip" || sa.trigger !== sb.trigger || sa.value !== sb.value || sa.displayText !== sb.displayText || sa.autoResolved !== sb.autoResolved) return false;
|
|
955
|
+
} else if (sb.type !== "chip" || sa.trigger !== sb.trigger || sa.value !== sb.value || sa.displayText !== sb.displayText || sa.sigil !== sb.sigil || sa.autoResolved !== sb.autoResolved) return false;
|
|
931
956
|
}
|
|
932
957
|
return true;
|
|
933
958
|
}
|
|
@@ -1144,20 +1169,19 @@ function normalizeListPrefixText(text, markdownEnabled) {
|
|
|
1144
1169
|
* preserved, while an unterminated fence does not suppress later bullets.
|
|
1145
1170
|
*/
|
|
1146
1171
|
function normalizeListPrefixes(segments, markdownEnabled) {
|
|
1147
|
-
const
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
});
|
|
1151
|
-
const protectedLines = fenceProtectedLineIndices(globalLines);
|
|
1152
|
-
let globalIndex = 0;
|
|
1172
|
+
const protectedLines = fenceProtectedLineIndices(segmentsToPlainText(segments).split("\n"));
|
|
1173
|
+
let line = 0;
|
|
1174
|
+
let atLineStart = true;
|
|
1153
1175
|
let changed = false;
|
|
1154
1176
|
const result = segments.map((seg) => {
|
|
1155
|
-
if (seg.type !== "text")
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1177
|
+
if (seg.type !== "text") {
|
|
1178
|
+
atLineStart = false;
|
|
1179
|
+
return seg;
|
|
1180
|
+
}
|
|
1181
|
+
const pieces = seg.text.split("\n");
|
|
1182
|
+
const newText = pieces.map((piece, k) => (k > 0 || atLineStart) && !protectedLines.has(line + k) ? swapListPrefixLine(piece, markdownEnabled) : piece).join("\n");
|
|
1183
|
+
line += pieces.length - 1;
|
|
1184
|
+
if (pieces.length > 1 || seg.text !== "") atLineStart = pieces[pieces.length - 1] === "";
|
|
1161
1185
|
if (newText === seg.text) return seg;
|
|
1162
1186
|
changed = true;
|
|
1163
1187
|
return {
|
|
@@ -4564,6 +4588,68 @@ function composerCommandRows(rows) {
|
|
|
4564
4588
|
insertText: `/${row.name} `
|
|
4565
4589
|
});
|
|
4566
4590
|
}
|
|
4591
|
+
function buildClientCommands({ capabilities, hasModels, setModel, setPermissionMode, clearContext, openPanel }) {
|
|
4592
|
+
const modes = capabilities.permissionModes;
|
|
4593
|
+
const built = [];
|
|
4594
|
+
if (hasModels) built.push({
|
|
4595
|
+
name: "model",
|
|
4596
|
+
description: "Switch the model for this session",
|
|
4597
|
+
argumentHint: "<model>",
|
|
4598
|
+
requiresArgs: true,
|
|
4599
|
+
run: (args) => {
|
|
4600
|
+
const wanted = args.split(/\s+/)[0];
|
|
4601
|
+
if (!wanted) return false;
|
|
4602
|
+
setModel(wanted);
|
|
4603
|
+
return true;
|
|
4604
|
+
}
|
|
4605
|
+
});
|
|
4606
|
+
if (modes.length > 1) built.push({
|
|
4607
|
+
name: "permissions",
|
|
4608
|
+
description: `Set the permission mode (${modes.join(", ")})`,
|
|
4609
|
+
argumentHint: "<mode>",
|
|
4610
|
+
requiresArgs: true,
|
|
4611
|
+
run: (args) => {
|
|
4612
|
+
const wanted = args.split(/\s+/)[0];
|
|
4613
|
+
if (!modes.includes(wanted)) return false;
|
|
4614
|
+
setPermissionMode(wanted);
|
|
4615
|
+
return true;
|
|
4616
|
+
}
|
|
4617
|
+
});
|
|
4618
|
+
if (capabilities.clearContext) built.push({
|
|
4619
|
+
name: "clear",
|
|
4620
|
+
description: "Clear the conversation - the session keeps running and the old one stays resumable",
|
|
4621
|
+
run: () => {
|
|
4622
|
+
clearContext();
|
|
4623
|
+
return true;
|
|
4624
|
+
}
|
|
4625
|
+
});
|
|
4626
|
+
if (capabilities.mcpStatus) built.push({
|
|
4627
|
+
name: "mcp",
|
|
4628
|
+
description: "MCP servers and their status",
|
|
4629
|
+
run: () => (openPanel("mcp"), true)
|
|
4630
|
+
});
|
|
4631
|
+
if (capabilities.contextUsage) built.push({
|
|
4632
|
+
name: "context",
|
|
4633
|
+
description: "Context window usage",
|
|
4634
|
+
run: () => (openPanel("context"), true)
|
|
4635
|
+
});
|
|
4636
|
+
built.push({
|
|
4637
|
+
name: "status",
|
|
4638
|
+
description: "Session details",
|
|
4639
|
+
run: () => (openPanel("info"), true)
|
|
4640
|
+
});
|
|
4641
|
+
if (capabilities.rateLimits) built.push({
|
|
4642
|
+
name: "usage",
|
|
4643
|
+
description: "Rate limits and spend",
|
|
4644
|
+
run: () => (openPanel("usage"), true)
|
|
4645
|
+
});
|
|
4646
|
+
if (capabilities.skillsList) built.push({
|
|
4647
|
+
name: "skills",
|
|
4648
|
+
description: "Browse the skills this session can use",
|
|
4649
|
+
run: () => (openPanel("skills"), true)
|
|
4650
|
+
});
|
|
4651
|
+
return built;
|
|
4652
|
+
}
|
|
4567
4653
|
//#endregion
|
|
4568
4654
|
//#region src/components/agent/transcript-variant.tsx
|
|
4569
4655
|
const VariantContext = createContext("cards");
|
|
@@ -5061,7 +5147,7 @@ function parseFileLink(href, cwd) {
|
|
|
5061
5147
|
line ??= readLine(suffix[2]);
|
|
5062
5148
|
}
|
|
5063
5149
|
if (!target) return;
|
|
5064
|
-
const path =
|
|
5150
|
+
const path = resolvePosix(target, cwd);
|
|
5065
5151
|
return path ? {
|
|
5066
5152
|
path,
|
|
5067
5153
|
...line === void 0 ? {} : { line }
|
|
@@ -5071,18 +5157,6 @@ function readLine(value) {
|
|
|
5071
5157
|
const parsed = value === void 0 ? NaN : Number(value);
|
|
5072
5158
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
5073
5159
|
}
|
|
5074
|
-
function normalize(path) {
|
|
5075
|
-
const out = [];
|
|
5076
|
-
for (const part of path.split("/")) {
|
|
5077
|
-
if (part === "" || part === ".") continue;
|
|
5078
|
-
if (part === "..") {
|
|
5079
|
-
out.pop();
|
|
5080
|
-
continue;
|
|
5081
|
-
}
|
|
5082
|
-
out.push(part);
|
|
5083
|
-
}
|
|
5084
|
-
return `/${out.join("/")}`;
|
|
5085
|
-
}
|
|
5086
5160
|
//#endregion
|
|
5087
5161
|
//#region src/components/terminal/file-link.tsx
|
|
5088
5162
|
const FileLinkContext = createContext(void 0);
|
|
@@ -5559,6 +5633,8 @@ function evict(cache, keep) {
|
|
|
5559
5633
|
//#region src/components/agent/markdown-image.tsx
|
|
5560
5634
|
const LOCAL_PREFIX = "https://local-image.invalid/";
|
|
5561
5635
|
const WEB_SOURCE = /^(?:https?:|data:image\/|blob:)/i;
|
|
5636
|
+
const REMOTE_SOURCE = /^https?:/i;
|
|
5637
|
+
const REMOTE_IMAGE_NOTICE = "remote image, not loaded";
|
|
5562
5638
|
function shieldLocalImages() {
|
|
5563
5639
|
return (tree) => {
|
|
5564
5640
|
walk(tree);
|
|
@@ -5580,9 +5656,50 @@ function localImagePath(src) {
|
|
|
5580
5656
|
return;
|
|
5581
5657
|
}
|
|
5582
5658
|
}
|
|
5659
|
+
function remoteImageHost(src) {
|
|
5660
|
+
if (!src || !REMOTE_SOURCE.test(src.trim()) || localImagePath(src) !== void 0) return;
|
|
5661
|
+
try {
|
|
5662
|
+
return new URL(src.trim()).host;
|
|
5663
|
+
} catch {
|
|
5664
|
+
return;
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5583
5667
|
function MarkdownImage({ src, alt, terminal }) {
|
|
5584
|
-
const links = useFileLinks();
|
|
5585
5668
|
const raw = typeof src === "string" ? src : void 0;
|
|
5669
|
+
const remoteHost = remoteImageHost(raw);
|
|
5670
|
+
if (remoteHost !== void 0) return /* @__PURE__ */ jsx(RemoteImageLink, {
|
|
5671
|
+
href: raw.trim(),
|
|
5672
|
+
host: remoteHost,
|
|
5673
|
+
alt,
|
|
5674
|
+
terminal
|
|
5675
|
+
});
|
|
5676
|
+
return /* @__PURE__ */ jsx(LoadedMarkdownImage, {
|
|
5677
|
+
raw,
|
|
5678
|
+
alt,
|
|
5679
|
+
terminal
|
|
5680
|
+
});
|
|
5681
|
+
}
|
|
5682
|
+
function RemoteImageLink({ href, host, alt, terminal }) {
|
|
5683
|
+
const text = `${typeof alt === "string" && alt ? `${alt} · ` : ""}${host} (${REMOTE_IMAGE_NOTICE})`;
|
|
5684
|
+
if (terminal) return /* @__PURE__ */ jsx("a", {
|
|
5685
|
+
href,
|
|
5686
|
+
target: "_blank",
|
|
5687
|
+
rel: "noopener noreferrer",
|
|
5688
|
+
"data-tone": "faint",
|
|
5689
|
+
title: href,
|
|
5690
|
+
children: text
|
|
5691
|
+
});
|
|
5692
|
+
return /* @__PURE__ */ jsx("a", {
|
|
5693
|
+
href,
|
|
5694
|
+
target: "_blank",
|
|
5695
|
+
rel: "noopener noreferrer",
|
|
5696
|
+
title: href,
|
|
5697
|
+
className: "my-1 inline-block rounded-md border border-border bg-surface-hover px-2 py-1 text-label text-fg-4",
|
|
5698
|
+
children: text
|
|
5699
|
+
});
|
|
5700
|
+
}
|
|
5701
|
+
function LoadedMarkdownImage({ raw, alt, terminal }) {
|
|
5702
|
+
const links = useFileLinks();
|
|
5586
5703
|
const local = localImagePath(raw);
|
|
5587
5704
|
const path = local === void 0 ? void 0 : parseFileLink(local, links?.cwd)?.path;
|
|
5588
5705
|
const host = useHostImageSrc(path);
|
|
@@ -6063,23 +6180,6 @@ function todoLine(todo) {
|
|
|
6063
6180
|
return `${GLYPH[todo.status]} ${todo.text}`;
|
|
6064
6181
|
}
|
|
6065
6182
|
//#endregion
|
|
6066
|
-
//#region src/components/agent/shell-actions.tsx
|
|
6067
|
-
const NOOP = {
|
|
6068
|
-
loadOutput: async () => false,
|
|
6069
|
-
verify: async () => false,
|
|
6070
|
-
kill: async () => false
|
|
6071
|
-
};
|
|
6072
|
-
const ShellActionsContext = createContext(NOOP);
|
|
6073
|
-
function ShellActionsProvider({ value, children }) {
|
|
6074
|
-
return /* @__PURE__ */ jsx(ShellActionsContext.Provider, {
|
|
6075
|
-
value: value ?? NOOP,
|
|
6076
|
-
children
|
|
6077
|
-
});
|
|
6078
|
-
}
|
|
6079
|
-
function useShellActions() {
|
|
6080
|
-
return useContext(ShellActionsContext);
|
|
6081
|
-
}
|
|
6082
|
-
//#endregion
|
|
6083
6183
|
//#region src/components/terminal/shell-row.ts
|
|
6084
6184
|
const SHELL_GLYPH = "$";
|
|
6085
6185
|
const SHELL_KILL_GLYPH = "✕";
|
|
@@ -6146,6 +6246,53 @@ function shellFooterText(item, open, shown) {
|
|
|
6146
6246
|
if (total !== void 0 && total > shown) return `… +${(total - shown).toLocaleString()} lines not shown`;
|
|
6147
6247
|
if (item.expanded === void 0 && item.truncated) return "… fetching the full output";
|
|
6148
6248
|
}
|
|
6249
|
+
//#endregion
|
|
6250
|
+
//#region src/components/agent/shell-actions.tsx
|
|
6251
|
+
const NOOP = {
|
|
6252
|
+
loadOutput: async () => false,
|
|
6253
|
+
verify: async () => false,
|
|
6254
|
+
kill: async () => false
|
|
6255
|
+
};
|
|
6256
|
+
const ShellActionsContext = createContext(NOOP);
|
|
6257
|
+
function ShellActionsProvider({ value, children }) {
|
|
6258
|
+
return /* @__PURE__ */ jsx(ShellActionsContext.Provider, {
|
|
6259
|
+
value: value ?? NOOP,
|
|
6260
|
+
children
|
|
6261
|
+
});
|
|
6262
|
+
}
|
|
6263
|
+
function useShellActions() {
|
|
6264
|
+
return useContext(ShellActionsContext);
|
|
6265
|
+
}
|
|
6266
|
+
function useVerifyRunning(item) {
|
|
6267
|
+
const verify = useShellActions().verify;
|
|
6268
|
+
const running = item.shell.status === "running";
|
|
6269
|
+
const shellId = item.shell.id;
|
|
6270
|
+
useEffect(() => {
|
|
6271
|
+
if (running) verify(shellId);
|
|
6272
|
+
}, [
|
|
6273
|
+
running,
|
|
6274
|
+
shellId,
|
|
6275
|
+
verify
|
|
6276
|
+
]);
|
|
6277
|
+
}
|
|
6278
|
+
function ShellItemActions({ item }) {
|
|
6279
|
+
const actions = useShellActions();
|
|
6280
|
+
const shellId = item.shell.id;
|
|
6281
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6282
|
+
actions.open ? /* @__PURE__ */ jsx(OpenShellAction, { onOpen: () => actions.open?.(shellId) }) : null,
|
|
6283
|
+
actions.agentWrite && shellGrantable(item.shell) ? /* @__PURE__ */ jsx(AgentWriteAction, {
|
|
6284
|
+
granted: item.shell.agentWrite === true,
|
|
6285
|
+
label: shellAgentWriteLabel(item.shell),
|
|
6286
|
+
onToggle: () => void actions.agentWrite?.(shellId, item.shell.agentWrite !== true)
|
|
6287
|
+
}) : null,
|
|
6288
|
+
item.shell.status === "running" ? /* @__PURE__ */ jsx(KillShellAction, { onKill: () => void actions.kill(shellId) }) : null,
|
|
6289
|
+
/* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
|
|
6290
|
+
/* @__PURE__ */ jsx(CopyAction, {
|
|
6291
|
+
text: item.shell.command,
|
|
6292
|
+
label: "Copy command"
|
|
6293
|
+
})
|
|
6294
|
+
] });
|
|
6295
|
+
}
|
|
6149
6296
|
const RESULT_PREVIEW_CHARS$1 = 2e3;
|
|
6150
6297
|
function clipToChars(lines, maxChars) {
|
|
6151
6298
|
const out = [];
|
|
@@ -6555,14 +6702,7 @@ function ShellRow({ item }) {
|
|
|
6555
6702
|
const lines = shellBodyLines(item, open);
|
|
6556
6703
|
const footer = shellFooterText(item, open, lines.length);
|
|
6557
6704
|
const shellId = item.shell.id;
|
|
6558
|
-
|
|
6559
|
-
useEffect(() => {
|
|
6560
|
-
if (running) verify(shellId);
|
|
6561
|
-
}, [
|
|
6562
|
-
running,
|
|
6563
|
-
shellId,
|
|
6564
|
-
verify
|
|
6565
|
-
]);
|
|
6705
|
+
useVerifyRunning(item);
|
|
6566
6706
|
const press = (modifiers) => {
|
|
6567
6707
|
if ((modifiers.meta || modifiers.ctrl) && actions.open) {
|
|
6568
6708
|
actions.open(shellId);
|
|
@@ -6578,20 +6718,7 @@ function ShellRow({ item }) {
|
|
|
6578
6718
|
ref: reveal,
|
|
6579
6719
|
className: open ? "term-open" : void 0,
|
|
6580
6720
|
children: /* @__PURE__ */ jsxs(WithActions, {
|
|
6581
|
-
actions: /* @__PURE__ */
|
|
6582
|
-
actions.open ? /* @__PURE__ */ jsx(OpenShellAction, { onOpen: () => actions.open?.(shellId) }) : null,
|
|
6583
|
-
actions.agentWrite && shellGrantable(item.shell) ? /* @__PURE__ */ jsx(AgentWriteAction, {
|
|
6584
|
-
granted: item.shell.agentWrite === true,
|
|
6585
|
-
label: shellAgentWriteLabel(item.shell),
|
|
6586
|
-
onToggle: () => void actions.agentWrite?.(shellId, item.shell.agentWrite !== true)
|
|
6587
|
-
}) : null,
|
|
6588
|
-
running ? /* @__PURE__ */ jsx(KillShellAction, { onKill: () => void actions.kill(shellId) }) : null,
|
|
6589
|
-
/* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
|
|
6590
|
-
/* @__PURE__ */ jsx(CopyAction, {
|
|
6591
|
-
text: item.shell.command,
|
|
6592
|
-
label: "Copy command"
|
|
6593
|
-
})
|
|
6594
|
-
] }),
|
|
6721
|
+
actions: /* @__PURE__ */ jsx(ShellItemActions, { item }),
|
|
6595
6722
|
children: [
|
|
6596
6723
|
/* @__PURE__ */ jsx(Pressable, {
|
|
6597
6724
|
onPress: press,
|
|
@@ -6991,6 +7118,22 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
6991
7118
|
})
|
|
6992
7119
|
]
|
|
6993
7120
|
}) : null;
|
|
7121
|
+
const stagedStrip = staged.length > 0 && attachments ? /* @__PURE__ */ jsx(AttachmentStrip, { attachments }) : null;
|
|
7122
|
+
const field = (minHeight, maxHeight, fieldClass) => /* @__PURE__ */ jsx(PromptArea, {
|
|
7123
|
+
...bind,
|
|
7124
|
+
triggers,
|
|
7125
|
+
markdown: false,
|
|
7126
|
+
normalizeBullets: false,
|
|
7127
|
+
onSubmit: submit,
|
|
7128
|
+
disabled,
|
|
7129
|
+
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
7130
|
+
minHeight,
|
|
7131
|
+
maxHeight,
|
|
7132
|
+
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
7133
|
+
className: fieldClass,
|
|
7134
|
+
onImagePaste: (file) => attachments?.add([file]),
|
|
7135
|
+
...shellKeys
|
|
7136
|
+
});
|
|
6994
7137
|
if (terminal) {
|
|
6995
7138
|
const line = lineHeight ?? 18;
|
|
6996
7139
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -7007,7 +7150,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
7007
7150
|
children: /* @__PURE__ */ jsxs("div", {
|
|
7008
7151
|
className: "term-composer-body",
|
|
7009
7152
|
children: [
|
|
7010
|
-
|
|
7153
|
+
stagedStrip,
|
|
7011
7154
|
/* @__PURE__ */ jsxs("div", {
|
|
7012
7155
|
className: "term-row",
|
|
7013
7156
|
children: [
|
|
@@ -7015,21 +7158,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
7015
7158
|
gutter,
|
|
7016
7159
|
/* @__PURE__ */ jsxs("div", {
|
|
7017
7160
|
className: "flex min-w-0 items-start",
|
|
7018
|
-
children: [
|
|
7019
|
-
...bind,
|
|
7020
|
-
triggers,
|
|
7021
|
-
markdown: false,
|
|
7022
|
-
normalizeBullets: false,
|
|
7023
|
-
onSubmit: submit,
|
|
7024
|
-
disabled,
|
|
7025
|
-
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
7026
|
-
minHeight: line,
|
|
7027
|
-
maxHeight: line * 10,
|
|
7028
|
-
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
7029
|
-
className: "term-composer-field min-w-0 flex-1",
|
|
7030
|
-
onImagePaste: (file) => attachments?.add([file]),
|
|
7031
|
-
...shellKeys
|
|
7032
|
-
}), submitButton]
|
|
7161
|
+
children: [field(line, line * 10, "term-composer-field min-w-0 flex-1"), submitButton]
|
|
7033
7162
|
})
|
|
7034
7163
|
]
|
|
7035
7164
|
}),
|
|
@@ -7077,42 +7206,14 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
7077
7206
|
/* @__PURE__ */ jsxs("div", {
|
|
7078
7207
|
...dropHandlers,
|
|
7079
7208
|
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"),
|
|
7080
|
-
children: [
|
|
7209
|
+
children: [stagedStrip, inline ? /* @__PURE__ */ jsxs("div", {
|
|
7081
7210
|
className: "flex items-end gap-1 p-1",
|
|
7082
7211
|
children: [
|
|
7083
7212
|
shellMode ? /* @__PURE__ */ jsx(ShellBadge, { onLeave: () => leaveShellMode(false) }) : attach,
|
|
7084
|
-
|
|
7085
|
-
...bind,
|
|
7086
|
-
triggers,
|
|
7087
|
-
markdown: false,
|
|
7088
|
-
normalizeBullets: false,
|
|
7089
|
-
onSubmit: submit,
|
|
7090
|
-
disabled,
|
|
7091
|
-
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
7092
|
-
minHeight: 20,
|
|
7093
|
-
maxHeight: 192,
|
|
7094
|
-
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
7095
|
-
className: "min-w-0 flex-1 py-1 text-body-sm text-text",
|
|
7096
|
-
onImagePaste: (file) => attachments?.add([file]),
|
|
7097
|
-
...shellKeys
|
|
7098
|
-
}),
|
|
7213
|
+
field(20, 192, "min-w-0 flex-1 py-1 text-body-sm text-text"),
|
|
7099
7214
|
submitButton
|
|
7100
7215
|
]
|
|
7101
|
-
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */
|
|
7102
|
-
...bind,
|
|
7103
|
-
triggers,
|
|
7104
|
-
markdown: false,
|
|
7105
|
-
normalizeBullets: false,
|
|
7106
|
-
onSubmit: submit,
|
|
7107
|
-
disabled,
|
|
7108
|
-
placeholder: disabled ? "Session ended" : shellMode ? SHELL_PLACEHOLDER : placeholder,
|
|
7109
|
-
minHeight: 28,
|
|
7110
|
-
maxHeight: 192,
|
|
7111
|
-
"aria-label": shellMode ? "Run a shell command" : "Message the agent",
|
|
7112
|
-
className: "px-3 pt-2.5 pb-0 text-body-sm text-text",
|
|
7113
|
-
onImagePaste: (file) => attachments?.add([file]),
|
|
7114
|
-
...shellKeys
|
|
7115
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
7216
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [field(28, 192, "px-3 pt-2.5 pb-0 text-body-sm text-text"), /* @__PURE__ */ jsxs("div", {
|
|
7116
7217
|
className: "flex items-center justify-between gap-2 px-2 pb-2",
|
|
7117
7218
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
7118
7219
|
className: "flex min-w-0 items-center gap-1",
|
|
@@ -7228,7 +7329,6 @@ function contextNote(engine) {
|
|
|
7228
7329
|
//#endregion
|
|
7229
7330
|
//#region src/components/agent/ContextDialog.tsx
|
|
7230
7331
|
function ContextDialog({ usage, engine, open, onOpenChange, className }) {
|
|
7231
|
-
const note = contextNote(engine);
|
|
7232
7332
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
7233
7333
|
open,
|
|
7234
7334
|
onOpenChange,
|
|
@@ -7237,191 +7337,102 @@ function ContextDialog({ usage, engine, open, onOpenChange, className }) {
|
|
|
7237
7337
|
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
7238
7338
|
title: "Context",
|
|
7239
7339
|
description: usage?.model
|
|
7240
|
-
}), /* @__PURE__ */
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
})
|
|
7244
|
-
/* @__PURE__ */ jsxs("div", {
|
|
7245
|
-
className: "flex items-baseline justify-between gap-4",
|
|
7246
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
7247
|
-
className: "text-label text-fg-3",
|
|
7248
|
-
children: "Used"
|
|
7249
|
-
}), /* @__PURE__ */ jsxs("span", {
|
|
7250
|
-
className: "font-mono text-body-sm text-fg-1",
|
|
7251
|
-
children: [
|
|
7252
|
-
formatTokens(usage.totalTokens),
|
|
7253
|
-
" / ",
|
|
7254
|
-
formatTokens(usage.maxTokens),
|
|
7255
|
-
" · ",
|
|
7256
|
-
usage.percentage.toFixed(0),
|
|
7257
|
-
"%"
|
|
7258
|
-
]
|
|
7259
|
-
})]
|
|
7260
|
-
}),
|
|
7261
|
-
/* @__PURE__ */ jsx("div", {
|
|
7262
|
-
className: "mt-2 h-2 overflow-hidden rounded-full bg-border",
|
|
7263
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
7264
|
-
className: cn("h-full rounded-full", meterTintClass(usage.percentage)),
|
|
7265
|
-
style: { width: `${Math.min(100, Math.max(2, usage.percentage))}%` }
|
|
7266
|
-
})
|
|
7267
|
-
}),
|
|
7268
|
-
usage.categories.length > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
7269
|
-
className: "mt-5",
|
|
7270
|
-
children: [/* @__PURE__ */ jsx("h3", {
|
|
7271
|
-
className: "text-label font-medium text-fg-3",
|
|
7272
|
-
children: "Breakdown"
|
|
7273
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
7274
|
-
className: "mt-2 flex flex-col gap-3",
|
|
7275
|
-
children: usage.categories.map((category) => {
|
|
7276
|
-
const share = category.tokens / Math.max(usage.maxTokens, 1) * 100;
|
|
7277
|
-
const color = cssColor(category.color);
|
|
7278
|
-
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
7279
|
-
className: "flex items-baseline justify-between gap-3",
|
|
7280
|
-
children: [/* @__PURE__ */ jsxs("span", {
|
|
7281
|
-
className: "flex min-w-0 items-center gap-2",
|
|
7282
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
7283
|
-
className: "size-2 shrink-0 rounded-full bg-fg-4",
|
|
7284
|
-
style: color ? { backgroundColor: color } : void 0
|
|
7285
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
7286
|
-
className: "truncate text-body-sm text-fg-1",
|
|
7287
|
-
children: category.name
|
|
7288
|
-
})]
|
|
7289
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
7290
|
-
className: "shrink-0 font-mono text-label text-fg-3",
|
|
7291
|
-
children: formatTokens(category.tokens)
|
|
7292
|
-
})]
|
|
7293
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
7294
|
-
className: "mt-1 h-1 overflow-hidden rounded-full bg-border",
|
|
7295
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
7296
|
-
className: "h-full rounded-full bg-fg-4",
|
|
7297
|
-
style: {
|
|
7298
|
-
width: `${Math.min(100, share)}%`,
|
|
7299
|
-
backgroundColor: color
|
|
7300
|
-
}
|
|
7301
|
-
})
|
|
7302
|
-
})] }, category.name);
|
|
7303
|
-
})
|
|
7304
|
-
})]
|
|
7305
|
-
}) : null
|
|
7306
|
-
] }), note ? /* @__PURE__ */ jsxs("div", {
|
|
7307
|
-
className: "mt-5 border-t border-border pt-4",
|
|
7308
|
-
children: [
|
|
7309
|
-
/* @__PURE__ */ jsx("h3", {
|
|
7310
|
-
className: "text-label font-medium text-fg-3",
|
|
7311
|
-
children: "Why this window is 272K"
|
|
7312
|
-
}),
|
|
7313
|
-
/* @__PURE__ */ jsx("p", {
|
|
7314
|
-
className: "mt-2 text-body-sm text-fg-2",
|
|
7315
|
-
children: note.summary
|
|
7316
|
-
}),
|
|
7317
|
-
note.detail.map((line) => /* @__PURE__ */ jsx("p", {
|
|
7318
|
-
className: "mt-2 text-body-sm text-fg-3",
|
|
7319
|
-
children: line
|
|
7320
|
-
}, line)),
|
|
7321
|
-
/* @__PURE__ */ jsx("p", {
|
|
7322
|
-
className: "mt-2 text-body-sm text-warning",
|
|
7323
|
-
children: note.caveat
|
|
7324
|
-
})
|
|
7325
|
-
]
|
|
7326
|
-
}) : null] })]
|
|
7340
|
+
}), /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(ContextPanel, {
|
|
7341
|
+
usage,
|
|
7342
|
+
engine
|
|
7343
|
+
}) })]
|
|
7327
7344
|
})
|
|
7328
7345
|
});
|
|
7329
7346
|
}
|
|
7330
|
-
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
className: "flex items-baseline justify-between gap-4 pb-1.5",
|
|
7340
|
-
children: [/* @__PURE__ */ jsxs("span", {
|
|
7347
|
+
function ContextPanel({ usage, engine }) {
|
|
7348
|
+
const note = contextNote(engine);
|
|
7349
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!usage ? /* @__PURE__ */ jsx("p", {
|
|
7350
|
+
className: "py-6 text-center text-body-sm text-fg-4",
|
|
7351
|
+
children: "No reading yet - the context window is measured after a turn completes."
|
|
7352
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
7353
|
+
/* @__PURE__ */ jsxs("div", {
|
|
7354
|
+
className: "flex items-baseline justify-between gap-4",
|
|
7355
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
7341
7356
|
className: "text-label text-fg-3",
|
|
7357
|
+
children: "Used"
|
|
7358
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
7359
|
+
className: "font-mono text-body-sm text-fg-1",
|
|
7342
7360
|
children: [
|
|
7343
|
-
|
|
7344
|
-
"
|
|
7345
|
-
|
|
7346
|
-
"
|
|
7347
|
-
|
|
7361
|
+
formatTokens(usage.totalTokens),
|
|
7362
|
+
" / ",
|
|
7363
|
+
formatTokens(usage.maxTokens),
|
|
7364
|
+
" · ",
|
|
7365
|
+
usage.percentage.toFixed(0),
|
|
7366
|
+
"%"
|
|
7348
7367
|
]
|
|
7349
|
-
})
|
|
7350
|
-
type: "button",
|
|
7351
|
-
onClick: () => onShowCompletedChange(!showCompleted),
|
|
7352
|
-
className: "shrink-0 rounded-[4px] px-1 py-0.5 text-label text-fg-4 outline-none hover:bg-row-hover hover:text-fg-2",
|
|
7353
|
-
children: showCompleted ? "Hide completed" : `Show completed (${summary.done})`
|
|
7354
|
-
}) : null]
|
|
7355
|
-
}), shown.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
7356
|
-
className: "py-6 text-center text-body-sm text-fg-4",
|
|
7357
|
-
children: tasks.length === 0 ? "No tasks yet - a checklist appears once the agent plans one." : `${hidden} completed, all hidden.`
|
|
7358
|
-
}) : /* @__PURE__ */ jsx("div", {
|
|
7359
|
-
className: "flex flex-col",
|
|
7360
|
-
children: shown.map((task) => /* @__PURE__ */ jsx(TaskRow$1, {
|
|
7361
|
-
task,
|
|
7362
|
-
onSelect: onSelectTask
|
|
7363
|
-
}, task.key))
|
|
7364
|
-
})]
|
|
7365
|
-
});
|
|
7366
|
-
}
|
|
7367
|
-
function TaskRow$1({ task, onSelect }) {
|
|
7368
|
-
const pressable = onSelect !== void 0 && task.toolUseId !== void 0;
|
|
7369
|
-
const body = task.state === "failed" ? "text-danger" : task.state === "done" ? "text-fg-4" : "text-fg-2";
|
|
7370
|
-
const row = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
7371
|
-
/* @__PURE__ */ jsx(TaskIcon, { state: task.state }),
|
|
7372
|
-
/* @__PURE__ */ jsx("span", {
|
|
7373
|
-
className: cn("min-w-0 flex-1 truncate text-left", task.state === "done" ? "line-through" : void 0),
|
|
7374
|
-
children: task.label
|
|
7368
|
+
})]
|
|
7375
7369
|
}),
|
|
7376
|
-
|
|
7377
|
-
className: "
|
|
7378
|
-
children:
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
|
|
7424
|
-
|
|
7370
|
+
/* @__PURE__ */ jsx("div", {
|
|
7371
|
+
className: "mt-2 h-2 overflow-hidden rounded-full bg-border",
|
|
7372
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
7373
|
+
className: cn("h-full rounded-full", meterTintClass(usage.percentage)),
|
|
7374
|
+
style: { width: `${Math.min(100, Math.max(2, usage.percentage))}%` }
|
|
7375
|
+
})
|
|
7376
|
+
}),
|
|
7377
|
+
usage.categories.length > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
7378
|
+
className: "mt-5",
|
|
7379
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
7380
|
+
className: "text-label font-medium text-fg-3",
|
|
7381
|
+
children: "Breakdown"
|
|
7382
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
7383
|
+
className: "mt-2 flex flex-col gap-3",
|
|
7384
|
+
children: usage.categories.map((category) => {
|
|
7385
|
+
const share = category.tokens / Math.max(usage.maxTokens, 1) * 100;
|
|
7386
|
+
const color = cssColor(category.color);
|
|
7387
|
+
return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
|
|
7388
|
+
className: "flex items-baseline justify-between gap-3",
|
|
7389
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
7390
|
+
className: "flex min-w-0 items-center gap-2",
|
|
7391
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
7392
|
+
className: "size-2 shrink-0 rounded-full bg-fg-4",
|
|
7393
|
+
style: color ? { backgroundColor: color } : void 0
|
|
7394
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
7395
|
+
className: "truncate text-body-sm text-fg-1",
|
|
7396
|
+
children: category.name
|
|
7397
|
+
})]
|
|
7398
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
7399
|
+
className: "shrink-0 font-mono text-label text-fg-3",
|
|
7400
|
+
children: formatTokens(category.tokens)
|
|
7401
|
+
})]
|
|
7402
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
7403
|
+
className: "mt-1 h-1 overflow-hidden rounded-full bg-border",
|
|
7404
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
7405
|
+
className: "h-full rounded-full bg-fg-4",
|
|
7406
|
+
style: {
|
|
7407
|
+
width: `${Math.min(100, share)}%`,
|
|
7408
|
+
backgroundColor: color
|
|
7409
|
+
}
|
|
7410
|
+
})
|
|
7411
|
+
})] }, category.name);
|
|
7412
|
+
})
|
|
7413
|
+
})]
|
|
7414
|
+
}) : null
|
|
7415
|
+
] }), note ? /* @__PURE__ */ jsxs("div", {
|
|
7416
|
+
className: "mt-5 border-t border-border pt-4",
|
|
7417
|
+
children: [
|
|
7418
|
+
/* @__PURE__ */ jsx("h3", {
|
|
7419
|
+
className: "text-label font-medium text-fg-3",
|
|
7420
|
+
children: "Why this window is 272K"
|
|
7421
|
+
}),
|
|
7422
|
+
/* @__PURE__ */ jsx("p", {
|
|
7423
|
+
className: "mt-2 text-body-sm text-fg-2",
|
|
7424
|
+
children: note.summary
|
|
7425
|
+
}),
|
|
7426
|
+
note.detail.map((line) => /* @__PURE__ */ jsx("p", {
|
|
7427
|
+
className: "mt-2 text-body-sm text-fg-3",
|
|
7428
|
+
children: line
|
|
7429
|
+
}, line)),
|
|
7430
|
+
/* @__PURE__ */ jsx("p", {
|
|
7431
|
+
className: "mt-2 text-body-sm text-warning",
|
|
7432
|
+
children: note.caveat
|
|
7433
|
+
})
|
|
7434
|
+
]
|
|
7435
|
+
}) : null] });
|
|
7425
7436
|
}
|
|
7426
7437
|
//#endregion
|
|
7427
7438
|
//#region src/components/agent/EntryIcon.tsx
|
|
@@ -7450,7 +7461,7 @@ function HostFilesDialog({ client, cwd, open, onOpenChange }) {
|
|
|
7450
7461
|
setEntries(response.entries);
|
|
7451
7462
|
setTruncated(response.truncated ?? false);
|
|
7452
7463
|
} catch (e) {
|
|
7453
|
-
setError(e
|
|
7464
|
+
setError(errorMessage(e, "Could not read that directory"));
|
|
7454
7465
|
} finally {
|
|
7455
7466
|
setLoading(false);
|
|
7456
7467
|
}
|
|
@@ -7495,7 +7506,7 @@ function HostFilesDialog({ client, cwd, open, onOpenChange }) {
|
|
|
7495
7506
|
content: response.encoding === "utf8" ? response.content : "(binary file - not shown)"
|
|
7496
7507
|
});
|
|
7497
7508
|
} catch (e) {
|
|
7498
|
-
setError(e
|
|
7509
|
+
setError(errorMessage(e, "Could not read that file"));
|
|
7499
7510
|
} finally {
|
|
7500
7511
|
setLoading(false);
|
|
7501
7512
|
}
|
|
@@ -7595,85 +7606,108 @@ const STATUS_VARIANT = {
|
|
|
7595
7606
|
disabled: "neutral"
|
|
7596
7607
|
};
|
|
7597
7608
|
function McpDialog({ client, sessionId, open, onOpenChange, canManageServers = true, className }) {
|
|
7598
|
-
const
|
|
7599
|
-
const [error, setError] = useState();
|
|
7600
|
-
const [loading, setLoading] = useState(false);
|
|
7601
|
-
const [busyServer, setBusyServer] = useState();
|
|
7602
|
-
const [selectedServer, setSelectedServer] = useState();
|
|
7603
|
-
const [selectedTool, setSelectedTool] = useState();
|
|
7604
|
-
const load = useCallback(async () => {
|
|
7605
|
-
if (!sessionId) return;
|
|
7606
|
-
setLoading(true);
|
|
7607
|
-
setError(void 0);
|
|
7608
|
-
try {
|
|
7609
|
-
setServers(await client.listMcpServers(sessionId));
|
|
7610
|
-
} catch (e) {
|
|
7611
|
-
setError(e instanceof Error ? e.message : "Could not read MCP status");
|
|
7612
|
-
} finally {
|
|
7613
|
-
setLoading(false);
|
|
7614
|
-
}
|
|
7615
|
-
}, [client, sessionId]);
|
|
7616
|
-
useEffect(() => {
|
|
7617
|
-
if (!open) return;
|
|
7618
|
-
setSelectedServer(void 0);
|
|
7619
|
-
setSelectedTool(void 0);
|
|
7620
|
-
load();
|
|
7621
|
-
}, [open, load]);
|
|
7622
|
-
const act = async (name, action) => {
|
|
7623
|
-
if (!sessionId) return;
|
|
7624
|
-
setBusyServer(name);
|
|
7625
|
-
setError(void 0);
|
|
7626
|
-
try {
|
|
7627
|
-
setServers(await client.mcpServerAction(sessionId, name, action));
|
|
7628
|
-
} catch (e) {
|
|
7629
|
-
setError(e instanceof Error ? e.message : `Could not ${action} ${name}`);
|
|
7630
|
-
} finally {
|
|
7631
|
-
setBusyServer(void 0);
|
|
7632
|
-
}
|
|
7633
|
-
};
|
|
7634
|
-
const server = servers?.find((s) => s.name === selectedServer);
|
|
7635
|
-
const tool = server?.tools?.find((t) => t.name === selectedTool);
|
|
7636
|
-
const title = tool?.name ?? server?.name ?? "MCP servers";
|
|
7609
|
+
const mcp = useMcpPanel(client, sessionId, open);
|
|
7637
7610
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
7638
7611
|
open,
|
|
7639
7612
|
onOpenChange,
|
|
7640
7613
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
7641
7614
|
className,
|
|
7642
7615
|
children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
7643
|
-
title,
|
|
7644
|
-
description:
|
|
7645
|
-
actions:
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
}) : /* @__PURE__ */ jsxs(Button, {
|
|
7651
|
-
variant: "ghost",
|
|
7652
|
-
size: "xs",
|
|
7653
|
-
onClick: () => void load(),
|
|
7654
|
-
disabled: loading,
|
|
7655
|
-
children: [loading ? /* @__PURE__ */ jsx(Spinner, { className: "size-3 text-current" }) : /* @__PURE__ */ jsx(RotateCw, { className: "size-3" }), "Refresh"]
|
|
7656
|
-
})
|
|
7657
|
-
}), /* @__PURE__ */ jsxs(DialogBody, { children: [error ? /* @__PURE__ */ jsx("div", {
|
|
7658
|
-
className: "mb-3 rounded-md bg-danger-bg px-3 py-2 text-body-sm text-danger",
|
|
7659
|
-
children: error
|
|
7660
|
-
}) : null, tool ? /* @__PURE__ */ jsx(ToolView, { tool }) : server ? /* @__PURE__ */ jsx(ServerView, {
|
|
7661
|
-
server,
|
|
7662
|
-
busy: busyServer === server.name,
|
|
7663
|
-
canManage: canManageServers,
|
|
7664
|
-
onAct: (action) => void act(server.name, action),
|
|
7665
|
-
onSelectTool: setSelectedTool
|
|
7666
|
-
}) : error && !servers ? null : /* @__PURE__ */ jsx(ServerList, {
|
|
7667
|
-
servers,
|
|
7668
|
-
loading,
|
|
7669
|
-
onSelect: setSelectedServer
|
|
7670
|
-
})] })]
|
|
7616
|
+
title: mcp.title,
|
|
7617
|
+
description: mcp.description,
|
|
7618
|
+
actions: /* @__PURE__ */ jsx(McpPanelActions, { model: mcp })
|
|
7619
|
+
}), /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(McpPanel, {
|
|
7620
|
+
model: mcp,
|
|
7621
|
+
canManageServers
|
|
7622
|
+
}) })]
|
|
7671
7623
|
})
|
|
7672
7624
|
});
|
|
7673
7625
|
}
|
|
7674
|
-
function
|
|
7675
|
-
|
|
7676
|
-
|
|
7626
|
+
function useMcpPanel(client, sessionId, active = true) {
|
|
7627
|
+
const listed = useAsync(() => client.listMcpServers(sessionId), [client, sessionId], { enabled: active && !!client && !!sessionId });
|
|
7628
|
+
const [actError, setActError] = useState();
|
|
7629
|
+
const [busyServer, setBusyServer] = useState();
|
|
7630
|
+
const [selectedServer, setSelectedServer] = useState();
|
|
7631
|
+
const [selectedTool, setSelectedTool] = useState();
|
|
7632
|
+
useEffect(() => {
|
|
7633
|
+
if (active) {
|
|
7634
|
+
setSelectedServer(void 0);
|
|
7635
|
+
setSelectedTool(void 0);
|
|
7636
|
+
setActError(void 0);
|
|
7637
|
+
}
|
|
7638
|
+
}, [
|
|
7639
|
+
active,
|
|
7640
|
+
client,
|
|
7641
|
+
sessionId
|
|
7642
|
+
]);
|
|
7643
|
+
const servers = listed.data;
|
|
7644
|
+
const server = servers?.find((s) => s.name === selectedServer);
|
|
7645
|
+
const tool = server?.tools?.find((t) => t.name === selectedTool);
|
|
7646
|
+
return {
|
|
7647
|
+
servers,
|
|
7648
|
+
server,
|
|
7649
|
+
tool,
|
|
7650
|
+
loading: listed.loading,
|
|
7651
|
+
busyServer,
|
|
7652
|
+
error: actError ?? (listed.error === void 0 ? void 0 : errorMessage(listed.error, "Could not read MCP status")),
|
|
7653
|
+
title: tool?.name ?? server?.name ?? "MCP servers",
|
|
7654
|
+
description: tool ? `${server?.name} tool` : server ? server.serverInfo?.name : void 0,
|
|
7655
|
+
selectServer: setSelectedServer,
|
|
7656
|
+
selectTool: setSelectedTool,
|
|
7657
|
+
back: selectedServer ? () => selectedTool ? setSelectedTool(void 0) : setSelectedServer(void 0) : void 0,
|
|
7658
|
+
reload: () => {
|
|
7659
|
+
setActError(void 0);
|
|
7660
|
+
listed.reload();
|
|
7661
|
+
},
|
|
7662
|
+
act: async (name, action) => {
|
|
7663
|
+
if (!client || !sessionId) return;
|
|
7664
|
+
setBusyServer(name);
|
|
7665
|
+
setActError(void 0);
|
|
7666
|
+
try {
|
|
7667
|
+
listed.setData(await client.mcpServerAction(sessionId, name, action));
|
|
7668
|
+
} catch (e) {
|
|
7669
|
+
setActError(errorMessage(e, `Could not ${action} ${name}`));
|
|
7670
|
+
} finally {
|
|
7671
|
+
setBusyServer(void 0);
|
|
7672
|
+
}
|
|
7673
|
+
}
|
|
7674
|
+
};
|
|
7675
|
+
}
|
|
7676
|
+
function McpPanelActions({ model }) {
|
|
7677
|
+
if (model.back) return /* @__PURE__ */ jsxs(Button, {
|
|
7678
|
+
variant: "ghost",
|
|
7679
|
+
size: "xs",
|
|
7680
|
+
onClick: model.back,
|
|
7681
|
+
children: [/* @__PURE__ */ jsx(ChevronLeft, { className: "size-3.5" }), "Back"]
|
|
7682
|
+
});
|
|
7683
|
+
return /* @__PURE__ */ jsxs(Button, {
|
|
7684
|
+
variant: "ghost",
|
|
7685
|
+
size: "xs",
|
|
7686
|
+
onClick: model.reload,
|
|
7687
|
+
disabled: model.loading,
|
|
7688
|
+
children: [model.loading ? /* @__PURE__ */ jsx(Spinner, { className: "size-3 text-current" }) : /* @__PURE__ */ jsx(RotateCw, { className: "size-3" }), "Refresh"]
|
|
7689
|
+
});
|
|
7690
|
+
}
|
|
7691
|
+
function McpPanel({ model, canManageServers = true }) {
|
|
7692
|
+
const { error, servers, server, tool } = model;
|
|
7693
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [error ? /* @__PURE__ */ jsx("div", {
|
|
7694
|
+
className: "mb-3 rounded-md bg-danger-bg px-3 py-2 text-body-sm text-danger",
|
|
7695
|
+
children: error
|
|
7696
|
+
}) : null, tool ? /* @__PURE__ */ jsx(ToolView, { tool }) : server ? /* @__PURE__ */ jsx(ServerView, {
|
|
7697
|
+
server,
|
|
7698
|
+
busy: model.busyServer === server.name,
|
|
7699
|
+
canManage: canManageServers,
|
|
7700
|
+
onAct: (action) => void model.act(server.name, action),
|
|
7701
|
+
onSelectTool: model.selectTool
|
|
7702
|
+
}) : error && !servers ? null : /* @__PURE__ */ jsx(ServerList, {
|
|
7703
|
+
servers,
|
|
7704
|
+
loading: model.loading,
|
|
7705
|
+
onSelect: model.selectServer
|
|
7706
|
+
})] });
|
|
7707
|
+
}
|
|
7708
|
+
function ServerList({ servers, loading, onSelect }) {
|
|
7709
|
+
if (loading && !servers) return /* @__PURE__ */ jsx("div", {
|
|
7710
|
+
className: "py-6 text-center",
|
|
7677
7711
|
children: /* @__PURE__ */ jsx(Spinner, { className: "size-4 text-fg-4" })
|
|
7678
7712
|
});
|
|
7679
7713
|
if (!servers?.length) return /* @__PURE__ */ jsx("p", {
|
|
@@ -8139,556 +8173,338 @@ function PermissionModeSelect({ mode, onModeChange, modes, canBypass, variant =
|
|
|
8139
8173
|
});
|
|
8140
8174
|
}
|
|
8141
8175
|
//#endregion
|
|
8142
|
-
//#region src/
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8176
|
+
//#region src/components/agent/FrameStrip.tsx
|
|
8177
|
+
const TERMINAL_TONE = {
|
|
8178
|
+
shell: {
|
|
8179
|
+
name: "magenta",
|
|
8180
|
+
live: "magenta"
|
|
8181
|
+
},
|
|
8182
|
+
subagent: {
|
|
8183
|
+
name: "green",
|
|
8184
|
+
live: "mark"
|
|
8185
|
+
}
|
|
8186
|
+
};
|
|
8187
|
+
const CARDS_LIVE_CLASS = {
|
|
8188
|
+
shell: "text-[var(--wd-shell-accent)]",
|
|
8189
|
+
subagent: "text-accent"
|
|
8190
|
+
};
|
|
8191
|
+
function FrameStrip({ kind, name, status, detail, failed, live, onBack, actions, terminal, fontSize, lineHeight }) {
|
|
8192
|
+
if (terminal) {
|
|
8193
|
+
const tones = TERMINAL_TONE[kind];
|
|
8194
|
+
const line = (label) => /* @__PURE__ */ jsxs(Row, {
|
|
8195
|
+
glyph: "←",
|
|
8196
|
+
glyphTone: "dim",
|
|
8197
|
+
indent: 1,
|
|
8198
|
+
tone: failed ? "red" : tones.name,
|
|
8199
|
+
children: [
|
|
8200
|
+
label,
|
|
8201
|
+
status ? /* @__PURE__ */ jsxs(Ink, {
|
|
8202
|
+
tone: failed ? "red" : live ? tones.live : "dim",
|
|
8203
|
+
children: [" · ", status]
|
|
8204
|
+
}) : null,
|
|
8205
|
+
detail ? /* @__PURE__ */ jsxs(Ink, {
|
|
8206
|
+
tone: "faint",
|
|
8207
|
+
children: [" · ", detail]
|
|
8208
|
+
}) : null
|
|
8209
|
+
]
|
|
8210
|
+
});
|
|
8211
|
+
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
8212
|
+
fontSize,
|
|
8213
|
+
lineHeight,
|
|
8214
|
+
className: "shrink-0",
|
|
8215
|
+
children: actions === void 0 ? /* @__PURE__ */ jsx("button", {
|
|
8216
|
+
type: "button",
|
|
8217
|
+
onClick: onBack,
|
|
8218
|
+
"aria-label": "Back to the session",
|
|
8219
|
+
className: "block w-full cursor-pointer text-left",
|
|
8220
|
+
children: line(name)
|
|
8221
|
+
}) : /* @__PURE__ */ jsx(WithActions, {
|
|
8222
|
+
placement: "inline",
|
|
8223
|
+
actions,
|
|
8224
|
+
children: line(/* @__PURE__ */ jsx("button", {
|
|
8225
|
+
type: "button",
|
|
8226
|
+
onClick: onBack,
|
|
8227
|
+
"aria-label": "Back to the session",
|
|
8228
|
+
className: "cursor-pointer text-left",
|
|
8229
|
+
children: name
|
|
8230
|
+
}))
|
|
8231
|
+
})
|
|
8232
|
+
});
|
|
8233
|
+
}
|
|
8234
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8235
|
+
className: "flex shrink-0 items-center gap-2 border-b border-border px-3 py-1.5",
|
|
8236
|
+
children: [
|
|
8237
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
8238
|
+
variant: "ghost",
|
|
8239
|
+
size: "sm",
|
|
8240
|
+
onClick: onBack,
|
|
8241
|
+
className: "h-6 gap-1 px-1.5",
|
|
8242
|
+
children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "size-3.5" }), "Back"]
|
|
8243
|
+
}),
|
|
8244
|
+
/* @__PURE__ */ jsx("span", {
|
|
8245
|
+
className: cn("min-w-0 flex-1 truncate text-body-sm", kind === "shell" && "font-mono", failed ? "text-danger" : "text-fg-2"),
|
|
8246
|
+
children: name
|
|
8247
|
+
}),
|
|
8248
|
+
status ? /* @__PURE__ */ jsx("span", {
|
|
8249
|
+
className: cn("shrink-0 text-label", failed ? "text-danger" : live ? CARDS_LIVE_CLASS[kind] : "text-fg-3"),
|
|
8250
|
+
children: status
|
|
8251
|
+
}) : null,
|
|
8252
|
+
detail ? /* @__PURE__ */ jsx("span", {
|
|
8253
|
+
className: "shrink-0 text-label text-fg-4",
|
|
8254
|
+
children: detail
|
|
8255
|
+
}) : null,
|
|
8256
|
+
actions
|
|
8257
|
+
]
|
|
8258
|
+
});
|
|
8150
8259
|
}
|
|
8151
8260
|
//#endregion
|
|
8152
|
-
//#region src/
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
"
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
const
|
|
8161
|
-
|
|
8162
|
-
"
|
|
8163
|
-
"
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8261
|
+
//#region src/components/agent/SubagentStrip.tsx
|
|
8262
|
+
function SubagentStrip({ task, items, label, onBack, terminal, fontSize, lineHeight }) {
|
|
8263
|
+
const busy = task ? taskBusy(task, items) : false;
|
|
8264
|
+
const failed = task ? taskFailed(task) : false;
|
|
8265
|
+
const pulse = usePulse(busy);
|
|
8266
|
+
const tools = items.reduce((n, item) => n + (item.kind === "tool_call" ? 1 : 0), 0);
|
|
8267
|
+
const startedAt = busy ? task?.ts : void 0;
|
|
8268
|
+
const now = useTicker(startedAt !== void 0);
|
|
8269
|
+
const elapsed = startedAt === void 0 ? void 0 : formatDuration(now - startedAt);
|
|
8270
|
+
const name = task ? taskIdentity(task) : label;
|
|
8271
|
+
const status = !task ? void 0 : failed ? "failed" : busy ? `${pulse} working…` : "done";
|
|
8272
|
+
const detail = [tools > 0 ? `${tools} tool${tools === 1 ? "" : "s"}` : void 0, elapsed].filter(Boolean).join(" · ");
|
|
8273
|
+
return /* @__PURE__ */ jsx(FrameStrip, {
|
|
8274
|
+
kind: "subagent",
|
|
8275
|
+
name,
|
|
8276
|
+
status,
|
|
8277
|
+
detail,
|
|
8278
|
+
failed,
|
|
8279
|
+
live: busy,
|
|
8280
|
+
onBack,
|
|
8281
|
+
terminal,
|
|
8282
|
+
fontSize,
|
|
8283
|
+
lineHeight
|
|
8284
|
+
});
|
|
8170
8285
|
}
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
const shellId = typeof input.shellId === "string" ? input.shellId : "";
|
|
8176
|
-
switch (tool) {
|
|
8177
|
-
case "shell_run": return {
|
|
8178
|
-
kind: "run",
|
|
8179
|
-
command: typeof input.command === "string" ? input.command : ""
|
|
8180
|
-
};
|
|
8181
|
-
case "shell_write": {
|
|
8182
|
-
const keys = Array.isArray(input.keys) ? input.keys.filter((key) => typeof key === "string") : void 0;
|
|
8183
|
-
return {
|
|
8184
|
-
kind: "write",
|
|
8185
|
-
shellId,
|
|
8186
|
-
...typeof input.data === "string" ? { data: input.data } : {},
|
|
8187
|
-
...keys && keys.length > 0 ? { keys } : {}
|
|
8188
|
-
};
|
|
8189
|
-
}
|
|
8190
|
-
case "shell_kill": return {
|
|
8191
|
-
kind: "kill",
|
|
8192
|
-
shellId
|
|
8193
|
-
};
|
|
8194
|
-
case "shell_request_write": return {
|
|
8195
|
-
kind: "grant",
|
|
8196
|
-
shellId,
|
|
8197
|
-
reason: typeof input.reason === "string" ? input.reason : ""
|
|
8198
|
-
};
|
|
8199
|
-
}
|
|
8286
|
+
//#endregion
|
|
8287
|
+
//#region src/components/terminal/blocks.ts
|
|
8288
|
+
function parentOf(item) {
|
|
8289
|
+
return ("parentToolUseId" in item ? item.parentToolUseId : void 0) ?? void 0;
|
|
8200
8290
|
}
|
|
8201
|
-
function
|
|
8202
|
-
|
|
8203
|
-
case "run": return "Agent wants to start a shell";
|
|
8204
|
-
case "write": return `Agent wants to type into shell ${payload.shellId}`;
|
|
8205
|
-
case "kill": return `Agent wants to kill shell ${payload.shellId}`;
|
|
8206
|
-
case "grant": return `Agent asks to type into your shell ${payload.shellId}`;
|
|
8207
|
-
}
|
|
8291
|
+
function subagentItems(items, parentToolUseId) {
|
|
8292
|
+
return items.filter((item) => parentOf(item) === parentToolUseId);
|
|
8208
8293
|
}
|
|
8209
|
-
function
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8294
|
+
function isRunCall(item) {
|
|
8295
|
+
return item.kind === "tool_call";
|
|
8296
|
+
}
|
|
8297
|
+
function taskChildItems(block) {
|
|
8298
|
+
return block.children.flatMap((child) => "run" in child ? child.run : [child.item]);
|
|
8299
|
+
}
|
|
8300
|
+
function pushLeaf(out, item, index) {
|
|
8301
|
+
const previous = out.at(-1);
|
|
8302
|
+
if (isRunCall(item) && !isPeerSend(item)) {
|
|
8303
|
+
if (previous && "run" in previous && foldsTogether(previous.run[0], item)) {
|
|
8304
|
+
previous.run.push(item);
|
|
8305
|
+
previous.indices.push(index);
|
|
8306
|
+
} else out.push({
|
|
8307
|
+
key: `run:${item.id}`,
|
|
8308
|
+
run: [item],
|
|
8309
|
+
indices: [index],
|
|
8310
|
+
index
|
|
8311
|
+
});
|
|
8312
|
+
return;
|
|
8220
8313
|
}
|
|
8314
|
+
out.push({
|
|
8315
|
+
key: `${item.kind}:${item.id}`,
|
|
8316
|
+
item,
|
|
8317
|
+
index
|
|
8318
|
+
});
|
|
8221
8319
|
}
|
|
8222
|
-
function
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8320
|
+
function terminalBlocks(items, offset = 0, fold = true) {
|
|
8321
|
+
if (!fold) return items.map((item, position) => ({
|
|
8322
|
+
key: `${item.kind}:${item.id}`,
|
|
8323
|
+
item,
|
|
8324
|
+
index: offset + position
|
|
8325
|
+
}));
|
|
8326
|
+
const topLevelCalls = /* @__PURE__ */ new Set();
|
|
8327
|
+
for (const item of items) if (item.kind === "tool_call" && parentOf(item) === void 0) topLevelCalls.add(item.id);
|
|
8328
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
8329
|
+
items.forEach((item, position) => {
|
|
8330
|
+
const parent = parentOf(item);
|
|
8331
|
+
if (parent !== void 0 && topLevelCalls.has(parent)) {
|
|
8332
|
+
const list = childrenOf.get(parent);
|
|
8333
|
+
if (list) list.push({
|
|
8334
|
+
item,
|
|
8335
|
+
index: offset + position
|
|
8336
|
+
});
|
|
8337
|
+
else childrenOf.set(parent, [{
|
|
8338
|
+
item,
|
|
8339
|
+
index: offset + position
|
|
8340
|
+
}]);
|
|
8229
8341
|
}
|
|
8230
|
-
|
|
8231
|
-
|
|
8342
|
+
});
|
|
8343
|
+
const out = [];
|
|
8344
|
+
for (const [position, item] of items.entries()) {
|
|
8345
|
+
const index = offset + position;
|
|
8346
|
+
const parent = parentOf(item);
|
|
8347
|
+
if (parent !== void 0 && childrenOf.has(parent)) continue;
|
|
8348
|
+
if (item.kind === "tool_call") {
|
|
8349
|
+
const children = childrenOf.get(item.id);
|
|
8350
|
+
if (children) {
|
|
8351
|
+
const folded = [];
|
|
8352
|
+
for (const child of children) pushLeaf(folded, child.item, child.index);
|
|
8353
|
+
out.push({
|
|
8354
|
+
key: `task:${item.id}`,
|
|
8355
|
+
task: item,
|
|
8356
|
+
children: folded,
|
|
8357
|
+
childIndices: children.map((child) => child.index),
|
|
8358
|
+
index
|
|
8359
|
+
});
|
|
8360
|
+
continue;
|
|
8361
|
+
}
|
|
8362
|
+
}
|
|
8363
|
+
pushLeaf(out, item, index);
|
|
8232
8364
|
}
|
|
8233
8365
|
return out;
|
|
8234
8366
|
}
|
|
8367
|
+
function needsBlank(previous, next) {
|
|
8368
|
+
if (isPeerSend(previous) || isPeerSend(next)) return true;
|
|
8369
|
+
return !(previous.kind === "tool_call" && next.kind === "tool_call");
|
|
8370
|
+
}
|
|
8371
|
+
function blockKind(block) {
|
|
8372
|
+
if (!("item" in block)) return "tool_call";
|
|
8373
|
+
return isPeerSend(block.item) ? "peer_send" : block.item.kind;
|
|
8374
|
+
}
|
|
8375
|
+
function blockNeedsBlank(previous, next) {
|
|
8376
|
+
return !(blockKind(previous) === "tool_call" && blockKind(next) === "tool_call");
|
|
8377
|
+
}
|
|
8235
8378
|
//#endregion
|
|
8236
|
-
//#region src/components/agent/
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8241
|
-
|
|
8242
|
-
|
|
8243
|
-
|
|
8244
|
-
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
}
|
|
8379
|
+
//#region src/components/agent/use-frame.ts
|
|
8380
|
+
function useFrame({ sessionId, request, reveal, onChange, returnTo }) {
|
|
8381
|
+
const [id, setId] = useState(void 0);
|
|
8382
|
+
const [returnReveal, setReturnReveal] = useState(void 0);
|
|
8383
|
+
useEffect(() => {
|
|
8384
|
+
setId(void 0);
|
|
8385
|
+
setReturnReveal(void 0);
|
|
8386
|
+
}, [sessionId]);
|
|
8387
|
+
const returnToRef = useRef(returnTo);
|
|
8388
|
+
returnToRef.current = returnTo;
|
|
8389
|
+
const leave = useCallback(() => {
|
|
8390
|
+
setId((current) => {
|
|
8391
|
+
const toolUseId = current === void 0 ? void 0 : returnToRef.current(current);
|
|
8392
|
+
if (toolUseId !== void 0) setReturnReveal({
|
|
8393
|
+
toolUseId,
|
|
8394
|
+
nonce: Date.now()
|
|
8395
|
+
});
|
|
8396
|
+
});
|
|
8397
|
+
}, []);
|
|
8398
|
+
const requestNonce = request?.nonce;
|
|
8399
|
+
const requestId = request?.id;
|
|
8400
|
+
useEffect(() => {
|
|
8401
|
+
if (requestId === void 0) leave();
|
|
8402
|
+
else setId(requestId);
|
|
8403
|
+
}, [requestNonce]);
|
|
8404
|
+
const revealNonce = reveal?.nonce;
|
|
8405
|
+
useEffect(() => {
|
|
8406
|
+
if (revealNonce !== void 0) setId(void 0);
|
|
8407
|
+
}, [revealNonce]);
|
|
8408
|
+
useEffect(() => {
|
|
8409
|
+
if (id === void 0) return;
|
|
8410
|
+
const onKey = (event) => {
|
|
8411
|
+
if (event.key === "Escape" && !event.defaultPrevented) leave();
|
|
8412
|
+
};
|
|
8413
|
+
window.addEventListener("keydown", onKey);
|
|
8414
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
8415
|
+
}, [id, leave]);
|
|
8416
|
+
const onChangeRef = useRef(onChange);
|
|
8417
|
+
onChangeRef.current = onChange;
|
|
8418
|
+
const reported = useRef(void 0);
|
|
8419
|
+
useEffect(() => {
|
|
8420
|
+
if (reported.current === id) return;
|
|
8421
|
+
reported.current = id;
|
|
8422
|
+
onChangeRef.current?.(id);
|
|
8423
|
+
}, [id]);
|
|
8424
|
+
return {
|
|
8425
|
+
id,
|
|
8426
|
+
enter: setId,
|
|
8427
|
+
leave,
|
|
8428
|
+
returnReveal
|
|
8429
|
+
};
|
|
8430
|
+
}
|
|
8253
8431
|
//#endregion
|
|
8254
|
-
//#region src/components/agent/
|
|
8255
|
-
function
|
|
8256
|
-
const
|
|
8257
|
-
const
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
|
|
8263
|
-
|
|
8432
|
+
//#region src/components/agent/use-subagent-frame.ts
|
|
8433
|
+
function useSubagentFrame(options) {
|
|
8434
|
+
const { sessionId, items, session, reveal, openSubagent, onSubagentChange } = options;
|
|
8435
|
+
const frame = useFrame({
|
|
8436
|
+
sessionId,
|
|
8437
|
+
request: openSubagent && {
|
|
8438
|
+
id: openSubagent.toolUseId,
|
|
8439
|
+
nonce: openSubagent.nonce
|
|
8440
|
+
},
|
|
8441
|
+
reveal,
|
|
8442
|
+
onChange: onSubagentChange,
|
|
8443
|
+
returnTo: (toolUseId) => toolUseId
|
|
8444
|
+
});
|
|
8445
|
+
const subagentId = frame.id;
|
|
8446
|
+
const frameItems = useMemo(() => subagentId === void 0 ? [] : subagentItems(items, subagentId), [items, subagentId]);
|
|
8447
|
+
const task = useMemo(() => subagentId === void 0 ? void 0 : items.find((item) => item.kind === "tool_call" && item.id === subagentId), [items, subagentId]);
|
|
8448
|
+
const fallbackLabel = useMemo(() => {
|
|
8449
|
+
const record = session?.subagents?.find((sub) => sub.toolUseId === subagentId);
|
|
8450
|
+
return record ? subagentLabel(record) : "Sub-agent";
|
|
8451
|
+
}, [session, subagentId]);
|
|
8452
|
+
return {
|
|
8453
|
+
subagentId,
|
|
8454
|
+
enterSubagent: frame.enter,
|
|
8455
|
+
leaveSubagent: frame.leave,
|
|
8456
|
+
returnReveal: frame.returnReveal,
|
|
8457
|
+
frameItems,
|
|
8458
|
+
task,
|
|
8459
|
+
fallbackLabel
|
|
8264
8460
|
};
|
|
8265
|
-
const plan = planFromRequest(request);
|
|
8266
|
-
const shell = plan ? void 0 : shellRequestPayload(request);
|
|
8267
|
-
const summary = toolInputPreview(request.input);
|
|
8268
|
-
const ToolIcon = toolIcon(request.toolName);
|
|
8269
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
8270
|
-
"data-slot": "permission-prompt",
|
|
8271
|
-
className: cn("rounded-lg border border-warning/40 bg-warning-bg p-3", className),
|
|
8272
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
8273
|
-
className: "flex items-start gap-2.5",
|
|
8274
|
-
children: [
|
|
8275
|
-
/* @__PURE__ */ jsx(Hand, { className: "mt-0.5 size-4 shrink-0 text-warning" }),
|
|
8276
|
-
/* @__PURE__ */ jsxs("div", {
|
|
8277
|
-
className: "min-w-0 flex-1",
|
|
8278
|
-
children: [
|
|
8279
|
-
/* @__PURE__ */ jsx("div", {
|
|
8280
|
-
className: "text-body-sm font-medium text-fg-1",
|
|
8281
|
-
children: plan ? "Plan ready for review" : shell ? shellRequestTitle(shell) : request.title ?? request.displayName ?? "Permission needed"
|
|
8282
|
-
}),
|
|
8283
|
-
request.description ? /* @__PURE__ */ jsx("div", {
|
|
8284
|
-
className: "mt-0.5 text-label text-fg-3",
|
|
8285
|
-
children: request.description
|
|
8286
|
-
}) : null,
|
|
8287
|
-
request.decisionReason ? /* @__PURE__ */ jsx("div", {
|
|
8288
|
-
className: "mt-0.5 text-label text-fg-4",
|
|
8289
|
-
children: request.decisionReason
|
|
8290
|
-
}) : null,
|
|
8291
|
-
plan ? /* @__PURE__ */ jsx("div", {
|
|
8292
|
-
className: "mt-1.5 max-h-72 overflow-y-auto rounded-md bg-code-bg px-2.5 py-2 text-body-sm text-fg-2",
|
|
8293
|
-
children: /* @__PURE__ */ jsx(Response, { children: plan })
|
|
8294
|
-
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8295
|
-
shell ? /* @__PURE__ */ jsx("pre", {
|
|
8296
|
-
"data-slot": "shell-request",
|
|
8297
|
-
className: "mt-1.5 max-h-48 overflow-auto rounded-md bg-code-bg px-2.5 py-1.5 font-mono text-body-sm whitespace-pre-wrap text-fg-1",
|
|
8298
|
-
children: shellRequestLines(shell).join("\n")
|
|
8299
|
-
}) : null,
|
|
8300
|
-
/* @__PURE__ */ jsxs("div", {
|
|
8301
|
-
className: "mt-1.5 flex min-w-0 items-center gap-2",
|
|
8302
|
-
children: [
|
|
8303
|
-
/* @__PURE__ */ jsx(ToolIcon, { className: "size-3 shrink-0 text-fg-3" }),
|
|
8304
|
-
/* @__PURE__ */ jsx("span", {
|
|
8305
|
-
className: "shrink-0 font-mono text-label font-medium text-fg-2",
|
|
8306
|
-
children: request.toolName
|
|
8307
|
-
}),
|
|
8308
|
-
summary && !shell ? /* @__PURE__ */ jsx("span", {
|
|
8309
|
-
className: "min-w-0 truncate font-mono text-label text-fg-4",
|
|
8310
|
-
children: summary
|
|
8311
|
-
}) : null
|
|
8312
|
-
]
|
|
8313
|
-
}),
|
|
8314
|
-
/* @__PURE__ */ jsxs("button", {
|
|
8315
|
-
type: "button",
|
|
8316
|
-
className: "mt-1 font-mono text-label text-fg-3 underline-offset-2 hover:underline",
|
|
8317
|
-
onClick: () => setShowInput((v) => !v),
|
|
8318
|
-
children: [
|
|
8319
|
-
showInput ? "Hide" : "Show",
|
|
8320
|
-
" ",
|
|
8321
|
-
request.toolName,
|
|
8322
|
-
" input"
|
|
8323
|
-
]
|
|
8324
|
-
}),
|
|
8325
|
-
showInput ? /* @__PURE__ */ jsx("pre", {
|
|
8326
|
-
className: "mt-1.5 max-h-48 overflow-auto rounded-md bg-code-bg px-2.5 py-1.5 font-mono text-label whitespace-pre-wrap text-fg-2",
|
|
8327
|
-
children: JSON.stringify(request.input, null, 2)
|
|
8328
|
-
}) : null
|
|
8329
|
-
] })
|
|
8330
|
-
]
|
|
8331
|
-
}),
|
|
8332
|
-
/* @__PURE__ */ jsxs("div", {
|
|
8333
|
-
className: "flex shrink-0 flex-wrap justify-end gap-1.5",
|
|
8334
|
-
children: [
|
|
8335
|
-
/* @__PURE__ */ jsx(Button, {
|
|
8336
|
-
size: "sm",
|
|
8337
|
-
onClick: () => onApprove(request.id),
|
|
8338
|
-
children: plan ? "Approve plan" : "Allow"
|
|
8339
|
-
}),
|
|
8340
|
-
/* @__PURE__ */ jsx(Button, {
|
|
8341
|
-
size: "sm",
|
|
8342
|
-
variant: "outline",
|
|
8343
|
-
onClick: () => setDenying((v) => !v),
|
|
8344
|
-
children: plan ? "Keep planning" : "Deny"
|
|
8345
|
-
}),
|
|
8346
|
-
/* @__PURE__ */ jsx(Button, {
|
|
8347
|
-
size: "sm",
|
|
8348
|
-
variant: "outline",
|
|
8349
|
-
onClick: () => deny(true),
|
|
8350
|
-
children: plan ? "Stop the turn" : "Deny & stop"
|
|
8351
|
-
})
|
|
8352
|
-
]
|
|
8353
|
-
})
|
|
8354
|
-
]
|
|
8355
|
-
}), denying ? /* @__PURE__ */ jsxs("div", {
|
|
8356
|
-
className: "mt-2.5 flex items-center gap-2 border-t border-warning/30 pt-2.5",
|
|
8357
|
-
children: [
|
|
8358
|
-
/* @__PURE__ */ jsx(Input, {
|
|
8359
|
-
autoFocus: true,
|
|
8360
|
-
value: reason,
|
|
8361
|
-
onChange: (e) => setReason(e.target.value),
|
|
8362
|
-
onKeyDown: (e) => {
|
|
8363
|
-
if (e.key === "Enter") deny(false);
|
|
8364
|
-
if (e.key === "Escape") setDenying(false);
|
|
8365
|
-
},
|
|
8366
|
-
placeholder: plan ? "What should change? (optional) - the agent keeps planning and reads this" : "Reason (optional) - the agent reads this and can try something else",
|
|
8367
|
-
className: "h-7 flex-1"
|
|
8368
|
-
}),
|
|
8369
|
-
/* @__PURE__ */ jsx(Button, {
|
|
8370
|
-
size: "sm",
|
|
8371
|
-
variant: "outline",
|
|
8372
|
-
onClick: () => setDenying(false),
|
|
8373
|
-
children: "Cancel"
|
|
8374
|
-
}),
|
|
8375
|
-
/* @__PURE__ */ jsx(Button, {
|
|
8376
|
-
size: "sm",
|
|
8377
|
-
variant: "destructive",
|
|
8378
|
-
onClick: () => deny(false),
|
|
8379
|
-
children: plan ? "Keep planning" : "Deny"
|
|
8380
|
-
})
|
|
8381
|
-
]
|
|
8382
|
-
}) : null]
|
|
8383
|
-
});
|
|
8384
8461
|
}
|
|
8385
8462
|
//#endregion
|
|
8386
|
-
//#region src/components/agent/
|
|
8387
|
-
function
|
|
8388
|
-
const
|
|
8389
|
-
const failed =
|
|
8390
|
-
const
|
|
8391
|
-
const
|
|
8392
|
-
const
|
|
8393
|
-
const
|
|
8394
|
-
const
|
|
8395
|
-
const
|
|
8396
|
-
const
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
indent: 1,
|
|
8411
|
-
tone: failed ? "red" : "green",
|
|
8412
|
-
children: [
|
|
8413
|
-
name,
|
|
8414
|
-
status ? /* @__PURE__ */ jsxs(Ink, {
|
|
8415
|
-
tone: failed ? "red" : busy ? "mark" : "dim",
|
|
8416
|
-
children: [" · ", status]
|
|
8417
|
-
}) : null,
|
|
8418
|
-
detail ? /* @__PURE__ */ jsxs(Ink, {
|
|
8419
|
-
tone: "faint",
|
|
8420
|
-
children: [" · ", detail]
|
|
8421
|
-
}) : null
|
|
8422
|
-
]
|
|
8423
|
-
})
|
|
8463
|
+
//#region src/components/agent/ShellStrip.tsx
|
|
8464
|
+
function ShellStrip({ shell, label, cols, onBack, onKill, onAgentWrite, terminal, fontSize, lineHeight }) {
|
|
8465
|
+
const running = shell?.status === "running";
|
|
8466
|
+
const failed = shell ? shellInfoFailed(shell) : false;
|
|
8467
|
+
const name = shell ? shellTitle(shell) : label;
|
|
8468
|
+
const status = shell ? shellInfoStatusText(shell) : void 0;
|
|
8469
|
+
const width = cols ?? shell?.cols;
|
|
8470
|
+
const detail = width === void 0 ? void 0 : `${width} cols`;
|
|
8471
|
+
const granted = shell?.agentWrite === true;
|
|
8472
|
+
const grant = shell && onAgentWrite && shellGrantable(shell) ? () => onAgentWrite(!granted) : void 0;
|
|
8473
|
+
const actions = terminal ? /* @__PURE__ */ jsxs(Fragment$1, { children: [grant && shell ? /* @__PURE__ */ jsx(AgentWriteAction, {
|
|
8474
|
+
granted,
|
|
8475
|
+
label: shellAgentWriteLabel(shell),
|
|
8476
|
+
onToggle: grant
|
|
8477
|
+
}) : null, running && onKill ? /* @__PURE__ */ jsx(KillShellAction, { onKill }) : null] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [grant && shell ? /* @__PURE__ */ jsx("button", {
|
|
8478
|
+
type: "button",
|
|
8479
|
+
"aria-label": shellAgentWriteLabel(shell),
|
|
8480
|
+
"aria-pressed": granted,
|
|
8481
|
+
title: shellAgentWriteLabel(shell),
|
|
8482
|
+
className: cn("shrink-0 text-label", granted ? "text-warning" : "text-fg-3 hover:text-fg-1"),
|
|
8483
|
+
onClick: grant,
|
|
8484
|
+
children: /* @__PURE__ */ jsx(AgentWriteIcon, {
|
|
8485
|
+
granted,
|
|
8486
|
+
className: "size-3.5"
|
|
8424
8487
|
})
|
|
8425
|
-
})
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
className: "shrink-0 text-label text-fg-4",
|
|
8446
|
-
children: detail
|
|
8447
|
-
}) : null
|
|
8448
|
-
]
|
|
8449
|
-
});
|
|
8450
|
-
}
|
|
8451
|
-
//#endregion
|
|
8452
|
-
//#region src/components/terminal/blocks.ts
|
|
8453
|
-
function parentOf(item) {
|
|
8454
|
-
return ("parentToolUseId" in item ? item.parentToolUseId : void 0) ?? void 0;
|
|
8455
|
-
}
|
|
8456
|
-
function subagentItems(items, parentToolUseId) {
|
|
8457
|
-
return items.filter((item) => parentOf(item) === parentToolUseId);
|
|
8458
|
-
}
|
|
8459
|
-
function isRunCall(item) {
|
|
8460
|
-
return item.kind === "tool_call";
|
|
8461
|
-
}
|
|
8462
|
-
function taskChildItems(block) {
|
|
8463
|
-
return block.children.flatMap((child) => "run" in child ? child.run : [child.item]);
|
|
8464
|
-
}
|
|
8465
|
-
function pushLeaf(out, item, index) {
|
|
8466
|
-
const previous = out.at(-1);
|
|
8467
|
-
if (isRunCall(item) && !isPeerSend(item)) {
|
|
8468
|
-
if (previous && "run" in previous && foldsTogether(previous.run[0], item)) {
|
|
8469
|
-
previous.run.push(item);
|
|
8470
|
-
previous.indices.push(index);
|
|
8471
|
-
} else out.push({
|
|
8472
|
-
key: `run:${item.id}`,
|
|
8473
|
-
run: [item],
|
|
8474
|
-
indices: [index],
|
|
8475
|
-
index
|
|
8476
|
-
});
|
|
8477
|
-
return;
|
|
8478
|
-
}
|
|
8479
|
-
out.push({
|
|
8480
|
-
key: `${item.kind}:${item.id}`,
|
|
8481
|
-
item,
|
|
8482
|
-
index
|
|
8483
|
-
});
|
|
8484
|
-
}
|
|
8485
|
-
function terminalBlocks(items, offset = 0, fold = true) {
|
|
8486
|
-
if (!fold) return items.map((item, position) => ({
|
|
8487
|
-
key: `${item.kind}:${item.id}`,
|
|
8488
|
-
item,
|
|
8489
|
-
index: offset + position
|
|
8490
|
-
}));
|
|
8491
|
-
const topLevelCalls = /* @__PURE__ */ new Set();
|
|
8492
|
-
for (const item of items) if (item.kind === "tool_call" && parentOf(item) === void 0) topLevelCalls.add(item.id);
|
|
8493
|
-
const childrenOf = /* @__PURE__ */ new Map();
|
|
8494
|
-
items.forEach((item, position) => {
|
|
8495
|
-
const parent = parentOf(item);
|
|
8496
|
-
if (parent !== void 0 && topLevelCalls.has(parent)) {
|
|
8497
|
-
const list = childrenOf.get(parent);
|
|
8498
|
-
if (list) list.push({
|
|
8499
|
-
item,
|
|
8500
|
-
index: offset + position
|
|
8501
|
-
});
|
|
8502
|
-
else childrenOf.set(parent, [{
|
|
8503
|
-
item,
|
|
8504
|
-
index: offset + position
|
|
8505
|
-
}]);
|
|
8506
|
-
}
|
|
8507
|
-
});
|
|
8508
|
-
const out = [];
|
|
8509
|
-
for (const [position, item] of items.entries()) {
|
|
8510
|
-
const index = offset + position;
|
|
8511
|
-
const parent = parentOf(item);
|
|
8512
|
-
if (parent !== void 0 && childrenOf.has(parent)) continue;
|
|
8513
|
-
if (item.kind === "tool_call") {
|
|
8514
|
-
const children = childrenOf.get(item.id);
|
|
8515
|
-
if (children) {
|
|
8516
|
-
const folded = [];
|
|
8517
|
-
for (const child of children) pushLeaf(folded, child.item, child.index);
|
|
8518
|
-
out.push({
|
|
8519
|
-
key: `task:${item.id}`,
|
|
8520
|
-
task: item,
|
|
8521
|
-
children: folded,
|
|
8522
|
-
childIndices: children.map((child) => child.index),
|
|
8523
|
-
index
|
|
8524
|
-
});
|
|
8525
|
-
continue;
|
|
8526
|
-
}
|
|
8527
|
-
}
|
|
8528
|
-
pushLeaf(out, item, index);
|
|
8529
|
-
}
|
|
8530
|
-
return out;
|
|
8531
|
-
}
|
|
8532
|
-
function needsBlank(previous, next) {
|
|
8533
|
-
if (isPeerSend(previous) || isPeerSend(next)) return true;
|
|
8534
|
-
return !(previous.kind === "tool_call" && next.kind === "tool_call");
|
|
8535
|
-
}
|
|
8536
|
-
function blockKind(block) {
|
|
8537
|
-
if (!("item" in block)) return "tool_call";
|
|
8538
|
-
return isPeerSend(block.item) ? "peer_send" : block.item.kind;
|
|
8539
|
-
}
|
|
8540
|
-
function blockNeedsBlank(previous, next) {
|
|
8541
|
-
return !(blockKind(previous) === "tool_call" && blockKind(next) === "tool_call");
|
|
8542
|
-
}
|
|
8543
|
-
//#endregion
|
|
8544
|
-
//#region src/components/agent/use-subagent-frame.ts
|
|
8545
|
-
function useSubagentFrame(options) {
|
|
8546
|
-
const { sessionId, items, session, reveal, openSubagent, onSubagentChange } = options;
|
|
8547
|
-
const [subagentId, setSubagentId] = useState(void 0);
|
|
8548
|
-
const [returnReveal, setReturnReveal] = useState(void 0);
|
|
8549
|
-
useEffect(() => {
|
|
8550
|
-
setSubagentId(void 0);
|
|
8551
|
-
setReturnReveal(void 0);
|
|
8552
|
-
}, [sessionId]);
|
|
8553
|
-
const leaveSubagent = useCallback(() => {
|
|
8554
|
-
setSubagentId((current) => {
|
|
8555
|
-
if (current !== void 0) setReturnReveal({
|
|
8556
|
-
toolUseId: current,
|
|
8557
|
-
nonce: Date.now()
|
|
8558
|
-
});
|
|
8559
|
-
});
|
|
8560
|
-
}, []);
|
|
8561
|
-
const openSubagentNonce = openSubagent?.nonce;
|
|
8562
|
-
const openSubagentId = openSubagent?.toolUseId;
|
|
8563
|
-
useEffect(() => {
|
|
8564
|
-
if (openSubagentId === void 0) leaveSubagent();
|
|
8565
|
-
else setSubagentId(openSubagentId);
|
|
8566
|
-
}, [openSubagentNonce]);
|
|
8567
|
-
const revealNonce = reveal?.nonce;
|
|
8568
|
-
useEffect(() => {
|
|
8569
|
-
if (revealNonce === void 0) return;
|
|
8570
|
-
setSubagentId(void 0);
|
|
8571
|
-
}, [revealNonce]);
|
|
8572
|
-
useEffect(() => {
|
|
8573
|
-
if (subagentId === void 0) return;
|
|
8574
|
-
const onKey = (event) => {
|
|
8575
|
-
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
8576
|
-
leaveSubagent();
|
|
8577
|
-
};
|
|
8578
|
-
window.addEventListener("keydown", onKey);
|
|
8579
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
8580
|
-
}, [subagentId, leaveSubagent]);
|
|
8581
|
-
const onSubagentChangeRef = useRef(onSubagentChange);
|
|
8582
|
-
onSubagentChangeRef.current = onSubagentChange;
|
|
8583
|
-
const reportedSubagentId = useRef(void 0);
|
|
8584
|
-
useEffect(() => {
|
|
8585
|
-
if (reportedSubagentId.current === subagentId) return;
|
|
8586
|
-
reportedSubagentId.current = subagentId;
|
|
8587
|
-
onSubagentChangeRef.current?.(subagentId);
|
|
8588
|
-
}, [subagentId]);
|
|
8589
|
-
return {
|
|
8590
|
-
subagentId,
|
|
8591
|
-
enterSubagent: setSubagentId,
|
|
8592
|
-
leaveSubagent,
|
|
8593
|
-
returnReveal,
|
|
8594
|
-
frameItems: useMemo(() => subagentId === void 0 ? [] : subagentItems(items, subagentId), [items, subagentId]),
|
|
8595
|
-
task: useMemo(() => subagentId === void 0 ? void 0 : items.find((item) => item.kind === "tool_call" && item.id === subagentId), [items, subagentId]),
|
|
8596
|
-
fallbackLabel: useMemo(() => {
|
|
8597
|
-
const record = session?.subagents?.find((sub) => sub.toolUseId === subagentId);
|
|
8598
|
-
return record ? subagentLabel(record) : "Sub-agent";
|
|
8599
|
-
}, [session, subagentId])
|
|
8600
|
-
};
|
|
8601
|
-
}
|
|
8602
|
-
//#endregion
|
|
8603
|
-
//#region src/components/agent/ShellStrip.tsx
|
|
8604
|
-
function ShellStrip({ shell, label, cols, onBack, onKill, onAgentWrite, terminal, fontSize, lineHeight }) {
|
|
8605
|
-
const running = shell?.status === "running";
|
|
8606
|
-
const failed = shell ? shellInfoFailed(shell) : false;
|
|
8607
|
-
const name = shell ? shellTitle(shell) : label;
|
|
8608
|
-
const status = shell ? shellInfoStatusText(shell) : void 0;
|
|
8609
|
-
const width = cols ?? shell?.cols;
|
|
8610
|
-
const detail = width === void 0 ? void 0 : `${width} cols`;
|
|
8611
|
-
const granted = shell?.agentWrite === true;
|
|
8612
|
-
const grant = shell && onAgentWrite && shellGrantable(shell) ? () => onAgentWrite(!granted) : void 0;
|
|
8613
|
-
if (terminal) return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
8614
|
-
fontSize,
|
|
8615
|
-
lineHeight,
|
|
8616
|
-
className: "shrink-0",
|
|
8617
|
-
children: /* @__PURE__ */ jsx(WithActions, {
|
|
8618
|
-
placement: "inline",
|
|
8619
|
-
actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [grant && shell ? /* @__PURE__ */ jsx(AgentWriteAction, {
|
|
8620
|
-
granted,
|
|
8621
|
-
label: shellAgentWriteLabel(shell),
|
|
8622
|
-
onToggle: grant
|
|
8623
|
-
}) : null, running && onKill ? /* @__PURE__ */ jsx(KillShellAction, { onKill }) : null] }),
|
|
8624
|
-
children: /* @__PURE__ */ jsxs(Row, {
|
|
8625
|
-
glyph: "←",
|
|
8626
|
-
glyphTone: "dim",
|
|
8627
|
-
indent: 1,
|
|
8628
|
-
tone: failed ? "red" : "magenta",
|
|
8629
|
-
children: [
|
|
8630
|
-
/* @__PURE__ */ jsx("button", {
|
|
8631
|
-
type: "button",
|
|
8632
|
-
onClick: onBack,
|
|
8633
|
-
"aria-label": "Back to the session",
|
|
8634
|
-
className: "cursor-pointer text-left",
|
|
8635
|
-
children: name
|
|
8636
|
-
}),
|
|
8637
|
-
status ? /* @__PURE__ */ jsxs(Ink, {
|
|
8638
|
-
tone: failed ? "red" : running ? "magenta" : "dim",
|
|
8639
|
-
children: [" · ", status]
|
|
8640
|
-
}) : null,
|
|
8641
|
-
detail ? /* @__PURE__ */ jsxs(Ink, {
|
|
8642
|
-
tone: "faint",
|
|
8643
|
-
children: [" · ", detail]
|
|
8644
|
-
}) : null
|
|
8645
|
-
]
|
|
8646
|
-
})
|
|
8647
|
-
})
|
|
8648
|
-
});
|
|
8649
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
8650
|
-
className: "flex shrink-0 items-center gap-2 border-b border-border px-3 py-1.5",
|
|
8651
|
-
children: [
|
|
8652
|
-
/* @__PURE__ */ jsxs(Button, {
|
|
8653
|
-
variant: "ghost",
|
|
8654
|
-
size: "sm",
|
|
8655
|
-
onClick: onBack,
|
|
8656
|
-
className: "h-6 gap-1 px-1.5",
|
|
8657
|
-
children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "size-3.5" }), "Back"]
|
|
8658
|
-
}),
|
|
8659
|
-
/* @__PURE__ */ jsx("span", {
|
|
8660
|
-
className: cn("min-w-0 flex-1 truncate font-mono text-body-sm", failed ? "text-danger" : "text-fg-2"),
|
|
8661
|
-
children: name
|
|
8662
|
-
}),
|
|
8663
|
-
status ? /* @__PURE__ */ jsx("span", {
|
|
8664
|
-
className: cn("shrink-0 text-label", failed ? "text-danger" : running ? "text-[var(--wd-shell-accent)]" : "text-fg-3"),
|
|
8665
|
-
children: status
|
|
8666
|
-
}) : null,
|
|
8667
|
-
detail ? /* @__PURE__ */ jsx("span", {
|
|
8668
|
-
className: "shrink-0 text-label text-fg-4",
|
|
8669
|
-
children: detail
|
|
8670
|
-
}) : null,
|
|
8671
|
-
grant && shell ? /* @__PURE__ */ jsx("button", {
|
|
8672
|
-
type: "button",
|
|
8673
|
-
"aria-label": shellAgentWriteLabel(shell),
|
|
8674
|
-
"aria-pressed": granted,
|
|
8675
|
-
title: shellAgentWriteLabel(shell),
|
|
8676
|
-
className: cn("shrink-0 text-label", granted ? "text-warning" : "text-fg-3 hover:text-fg-1"),
|
|
8677
|
-
onClick: grant,
|
|
8678
|
-
children: /* @__PURE__ */ jsx(AgentWriteIcon, {
|
|
8679
|
-
granted,
|
|
8680
|
-
className: "size-3.5"
|
|
8681
|
-
})
|
|
8682
|
-
}) : null,
|
|
8683
|
-
running && onKill ? /* @__PURE__ */ jsx("button", {
|
|
8684
|
-
type: "button",
|
|
8685
|
-
"aria-label": "Kill this shell",
|
|
8686
|
-
title: "Kill this shell",
|
|
8687
|
-
className: "shrink-0 text-label text-fg-3 hover:text-danger",
|
|
8688
|
-
onClick: onKill,
|
|
8689
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
|
|
8690
|
-
}) : null
|
|
8691
|
-
]
|
|
8488
|
+
}) : null, running && onKill ? /* @__PURE__ */ jsx("button", {
|
|
8489
|
+
type: "button",
|
|
8490
|
+
"aria-label": "Kill this shell",
|
|
8491
|
+
title: "Kill this shell",
|
|
8492
|
+
className: "shrink-0 text-label text-fg-3 hover:text-danger",
|
|
8493
|
+
onClick: onKill,
|
|
8494
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
|
|
8495
|
+
}) : null] });
|
|
8496
|
+
return /* @__PURE__ */ jsx(FrameStrip, {
|
|
8497
|
+
kind: "shell",
|
|
8498
|
+
name,
|
|
8499
|
+
status,
|
|
8500
|
+
detail,
|
|
8501
|
+
failed,
|
|
8502
|
+
live: running,
|
|
8503
|
+
onBack,
|
|
8504
|
+
actions,
|
|
8505
|
+
terminal,
|
|
8506
|
+
fontSize,
|
|
8507
|
+
lineHeight
|
|
8692
8508
|
});
|
|
8693
8509
|
}
|
|
8694
8510
|
//#endregion
|
|
@@ -8801,111 +8617,444 @@ function ShellTerminal({ handle, shellId, onEnded, onShell, fontSize, className
|
|
|
8801
8617
|
})]
|
|
8802
8618
|
});
|
|
8803
8619
|
}
|
|
8804
|
-
function useDocumentTheme() {
|
|
8805
|
-
const [theme, setTheme] = useState(() => typeof document === "undefined" ? null : document.documentElement.getAttribute("data-theme"));
|
|
8806
|
-
useEffect(() => {
|
|
8807
|
-
const root = document.documentElement;
|
|
8808
|
-
const sync = () => setTheme(root.getAttribute("data-theme"));
|
|
8809
|
-
sync();
|
|
8810
|
-
const observer = new MutationObserver(sync);
|
|
8811
|
-
observer.observe(root, {
|
|
8812
|
-
attributes: true,
|
|
8813
|
-
attributeFilter: ["data-theme"]
|
|
8814
|
-
});
|
|
8815
|
-
return () => observer.disconnect();
|
|
8816
|
-
}, []);
|
|
8817
|
-
return theme;
|
|
8620
|
+
function useDocumentTheme() {
|
|
8621
|
+
const [theme, setTheme] = useState(() => typeof document === "undefined" ? null : document.documentElement.getAttribute("data-theme"));
|
|
8622
|
+
useEffect(() => {
|
|
8623
|
+
const root = document.documentElement;
|
|
8624
|
+
const sync = () => setTheme(root.getAttribute("data-theme"));
|
|
8625
|
+
sync();
|
|
8626
|
+
const observer = new MutationObserver(sync);
|
|
8627
|
+
observer.observe(root, {
|
|
8628
|
+
attributes: true,
|
|
8629
|
+
attributeFilter: ["data-theme"]
|
|
8630
|
+
});
|
|
8631
|
+
return () => observer.disconnect();
|
|
8632
|
+
}, []);
|
|
8633
|
+
return theme;
|
|
8634
|
+
}
|
|
8635
|
+
function xtermTheme(theme) {
|
|
8636
|
+
return theme === "light" ? {
|
|
8637
|
+
background: "#00000000",
|
|
8638
|
+
foreground: "#1f2328",
|
|
8639
|
+
cursor: "#1f2328",
|
|
8640
|
+
selectionBackground: "#b9c7d980"
|
|
8641
|
+
} : {
|
|
8642
|
+
background: "#00000000",
|
|
8643
|
+
foreground: "#d4d4d4",
|
|
8644
|
+
cursor: "#d4d4d4",
|
|
8645
|
+
selectionBackground: "#3a4a5f80"
|
|
8646
|
+
};
|
|
8647
|
+
}
|
|
8648
|
+
let xtermPromise;
|
|
8649
|
+
function loadXterm() {
|
|
8650
|
+
xtermPromise ??= (async () => {
|
|
8651
|
+
const [core, fitAddon] = await Promise.all([import("@xterm/xterm"), import("@xterm/addon-fit")]);
|
|
8652
|
+
return {
|
|
8653
|
+
Terminal: core.Terminal,
|
|
8654
|
+
FitAddon: fitAddon.FitAddon
|
|
8655
|
+
};
|
|
8656
|
+
})();
|
|
8657
|
+
return xtermPromise;
|
|
8658
|
+
}
|
|
8659
|
+
//#endregion
|
|
8660
|
+
//#region src/components/agent/use-shell-frame.ts
|
|
8661
|
+
function useShellFrame(options) {
|
|
8662
|
+
const { sessionId, items, session, shells, reveal, openShell, onShellChange } = options;
|
|
8663
|
+
const rowIdRef = useRef(void 0);
|
|
8664
|
+
const frame = useFrame({
|
|
8665
|
+
sessionId,
|
|
8666
|
+
request: openShell && {
|
|
8667
|
+
id: openShell.shellId,
|
|
8668
|
+
nonce: openShell.nonce
|
|
8669
|
+
},
|
|
8670
|
+
reveal,
|
|
8671
|
+
onChange: onShellChange,
|
|
8672
|
+
returnTo: () => rowIdRef.current
|
|
8673
|
+
});
|
|
8674
|
+
const shellId = frame.id;
|
|
8675
|
+
const row = useMemo(() => shellId === void 0 ? void 0 : items.find((item) => item.kind === "shell" && item.shell.id === shellId), [items, shellId]);
|
|
8676
|
+
rowIdRef.current = row?.id;
|
|
8677
|
+
const shell = useMemo(() => {
|
|
8678
|
+
if (shellId === void 0) return;
|
|
8679
|
+
return row?.shell ?? shells?.find((record) => record.id === shellId) ?? session?.shells?.find((record) => record.id === shellId);
|
|
8680
|
+
}, [
|
|
8681
|
+
row,
|
|
8682
|
+
shells,
|
|
8683
|
+
session,
|
|
8684
|
+
shellId
|
|
8685
|
+
]);
|
|
8686
|
+
const label = shell ? shell.label || shell.command.split("\n")[0] || "shell" : "shell";
|
|
8687
|
+
return {
|
|
8688
|
+
shellId,
|
|
8689
|
+
enterShell: frame.enter,
|
|
8690
|
+
leaveShell: frame.leave,
|
|
8691
|
+
returnReveal: frame.returnReveal,
|
|
8692
|
+
shell,
|
|
8693
|
+
label
|
|
8694
|
+
};
|
|
8695
|
+
}
|
|
8696
|
+
//#endregion
|
|
8697
|
+
//#region src/lib/plan-request.ts
|
|
8698
|
+
function planFromRequest(request) {
|
|
8699
|
+
if (request?.toolName !== "ExitPlanMode") return;
|
|
8700
|
+
const input = request.input;
|
|
8701
|
+
if (input === null || typeof input !== "object") return;
|
|
8702
|
+
const plan = input.plan;
|
|
8703
|
+
if (typeof plan !== "string" || plan.trim().length === 0) return;
|
|
8704
|
+
return plan;
|
|
8705
|
+
}
|
|
8706
|
+
//#endregion
|
|
8707
|
+
//#region src/lib/shell-request.ts
|
|
8708
|
+
const CONTROL_NAMES = {
|
|
8709
|
+
"\r": "enter",
|
|
8710
|
+
"\n": "newline",
|
|
8711
|
+
" ": "tab",
|
|
8712
|
+
"\x1B": "escape",
|
|
8713
|
+
"": "backspace"
|
|
8714
|
+
};
|
|
8715
|
+
const SHELL_WRITE_TOOLS = [
|
|
8716
|
+
"shell_run",
|
|
8717
|
+
"shell_write",
|
|
8718
|
+
"shell_kill",
|
|
8719
|
+
"shell_request_write"
|
|
8720
|
+
];
|
|
8721
|
+
function shellToolOf(toolName) {
|
|
8722
|
+
if (typeof toolName !== "string") return;
|
|
8723
|
+
const bare = toolName.startsWith("mcp__") ? toolName.slice(toolName.indexOf("__", 5) + 2) : toolName;
|
|
8724
|
+
return SHELL_WRITE_TOOLS.includes(bare) ? bare : void 0;
|
|
8725
|
+
}
|
|
8726
|
+
function shellRequestPayload(request) {
|
|
8727
|
+
const tool = shellToolOf(request?.toolName);
|
|
8728
|
+
if (!tool) return;
|
|
8729
|
+
const input = request?.input !== null && typeof request?.input === "object" ? request.input : {};
|
|
8730
|
+
const shellId = typeof input.shellId === "string" ? input.shellId : "";
|
|
8731
|
+
switch (tool) {
|
|
8732
|
+
case "shell_run": return {
|
|
8733
|
+
kind: "run",
|
|
8734
|
+
command: typeof input.command === "string" ? input.command : ""
|
|
8735
|
+
};
|
|
8736
|
+
case "shell_write": {
|
|
8737
|
+
const keys = Array.isArray(input.keys) ? input.keys.filter((key) => typeof key === "string") : void 0;
|
|
8738
|
+
return {
|
|
8739
|
+
kind: "write",
|
|
8740
|
+
shellId,
|
|
8741
|
+
...typeof input.data === "string" ? { data: input.data } : {},
|
|
8742
|
+
...keys && keys.length > 0 ? { keys } : {}
|
|
8743
|
+
};
|
|
8744
|
+
}
|
|
8745
|
+
case "shell_kill": return {
|
|
8746
|
+
kind: "kill",
|
|
8747
|
+
shellId
|
|
8748
|
+
};
|
|
8749
|
+
case "shell_request_write": return {
|
|
8750
|
+
kind: "grant",
|
|
8751
|
+
shellId,
|
|
8752
|
+
reason: typeof input.reason === "string" ? input.reason : ""
|
|
8753
|
+
};
|
|
8754
|
+
}
|
|
8755
|
+
}
|
|
8756
|
+
function shellRequestTitle(payload) {
|
|
8757
|
+
switch (payload.kind) {
|
|
8758
|
+
case "run": return "Agent wants to start a shell";
|
|
8759
|
+
case "write": return `Agent wants to type into shell ${payload.shellId}`;
|
|
8760
|
+
case "kill": return `Agent wants to kill shell ${payload.shellId}`;
|
|
8761
|
+
case "grant": return `Agent asks to type into your shell ${payload.shellId}`;
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8764
|
+
function shellRequestLines(payload) {
|
|
8765
|
+
switch (payload.kind) {
|
|
8766
|
+
case "run": return payload.command.split("\n").map((line, index) => index === 0 ? `$ ${line}` : ` ${line}`);
|
|
8767
|
+
case "write": {
|
|
8768
|
+
const lines = [];
|
|
8769
|
+
if (payload.data !== void 0) lines.push(`types: ${visibleControls(payload.data)}`);
|
|
8770
|
+
if (payload.keys) lines.push(`presses: ${payload.keys.map((key) => `[${key}]`).join(" ")}`);
|
|
8771
|
+
return lines;
|
|
8772
|
+
}
|
|
8773
|
+
case "kill": return [`kill ${payload.shellId}`];
|
|
8774
|
+
case "grant": return [`why: ${visibleControls(payload.reason)}`, "until the shell ends or you revoke it"];
|
|
8775
|
+
}
|
|
8776
|
+
}
|
|
8777
|
+
function visibleControls(text) {
|
|
8778
|
+
let out = "";
|
|
8779
|
+
for (const char of text) {
|
|
8780
|
+
const code = char.codePointAt(0);
|
|
8781
|
+
if (code >= 32 && code !== 127) {
|
|
8782
|
+
out += char;
|
|
8783
|
+
continue;
|
|
8784
|
+
}
|
|
8785
|
+
const named = CONTROL_NAMES[char];
|
|
8786
|
+
out += named ? `[${named}]` : `[ctrl-${String.fromCharCode(code + 64).toLowerCase()}]`;
|
|
8787
|
+
}
|
|
8788
|
+
return out;
|
|
8789
|
+
}
|
|
8790
|
+
//#endregion
|
|
8791
|
+
//#region src/lib/permission-prompt.ts
|
|
8792
|
+
function permissionPromptModel(request) {
|
|
8793
|
+
const plan = planFromRequest(request);
|
|
8794
|
+
const shell = plan ? void 0 : shellRequestPayload(request);
|
|
8795
|
+
const context = {
|
|
8796
|
+
description: request.description,
|
|
8797
|
+
decisionReason: request.decisionReason
|
|
8798
|
+
};
|
|
8799
|
+
if (plan) return {
|
|
8800
|
+
plan,
|
|
8801
|
+
heading: "Plan ready for review",
|
|
8802
|
+
question: "Ready to implement this plan?",
|
|
8803
|
+
...context,
|
|
8804
|
+
choices: [
|
|
8805
|
+
{
|
|
8806
|
+
key: "allow",
|
|
8807
|
+
button: "Approve plan",
|
|
8808
|
+
option: "Approve plan"
|
|
8809
|
+
},
|
|
8810
|
+
{
|
|
8811
|
+
key: "deny",
|
|
8812
|
+
button: "Keep planning",
|
|
8813
|
+
option: "Keep planning - tell it what to change"
|
|
8814
|
+
},
|
|
8815
|
+
{
|
|
8816
|
+
key: "stop",
|
|
8817
|
+
button: "Stop the turn",
|
|
8818
|
+
option: "No, and stop the turn",
|
|
8819
|
+
danger: true
|
|
8820
|
+
}
|
|
8821
|
+
],
|
|
8822
|
+
denyPlaceholder: "What should change? (optional) - the agent keeps planning and reads this"
|
|
8823
|
+
};
|
|
8824
|
+
return {
|
|
8825
|
+
shell,
|
|
8826
|
+
heading: shell ? shellRequestTitle(shell) : request.title ?? request.displayName ?? "Permission needed",
|
|
8827
|
+
question: shell ? "Do you want to let it?" : "Do you want to proceed?",
|
|
8828
|
+
...context,
|
|
8829
|
+
choices: [
|
|
8830
|
+
{
|
|
8831
|
+
key: "allow",
|
|
8832
|
+
button: "Allow",
|
|
8833
|
+
option: "Yes"
|
|
8834
|
+
},
|
|
8835
|
+
{
|
|
8836
|
+
key: "deny",
|
|
8837
|
+
button: "Deny",
|
|
8838
|
+
option: "No, and tell the agent what to do differently"
|
|
8839
|
+
},
|
|
8840
|
+
{
|
|
8841
|
+
key: "stop",
|
|
8842
|
+
button: "Deny & stop",
|
|
8843
|
+
option: "No, and stop the turn",
|
|
8844
|
+
danger: true
|
|
8845
|
+
}
|
|
8846
|
+
],
|
|
8847
|
+
denyPlaceholder: "Reason (optional) - the agent reads this and can try something else"
|
|
8848
|
+
};
|
|
8849
|
+
}
|
|
8850
|
+
//#endregion
|
|
8851
|
+
//#region src/components/agent/Response.tsx
|
|
8852
|
+
const COMPONENTS = { img: ({ src, alt }) => /* @__PURE__ */ jsx(MarkdownImage, {
|
|
8853
|
+
src,
|
|
8854
|
+
alt
|
|
8855
|
+
}) };
|
|
8856
|
+
const Response = memo(function Response({ children, streaming, className }) {
|
|
8857
|
+
return /* @__PURE__ */ jsx(Streamdown, {
|
|
8858
|
+
mode: streaming ? "streaming" : "static",
|
|
8859
|
+
parseIncompleteMarkdown: streaming,
|
|
8860
|
+
shikiTheme: ["github-light", "github-dark"],
|
|
8861
|
+
linkSafety: { enabled: false },
|
|
8862
|
+
components: COMPONENTS,
|
|
8863
|
+
rehypePlugins: MARKDOWN_REHYPE_PLUGINS,
|
|
8864
|
+
className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
|
|
8865
|
+
children
|
|
8866
|
+
});
|
|
8867
|
+
}, (prev, next) => prev.children === next.children && prev.streaming === next.streaming && prev.className === next.className);
|
|
8868
|
+
//#endregion
|
|
8869
|
+
//#region src/components/agent/PermissionPrompt.tsx
|
|
8870
|
+
function PermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
8871
|
+
const [showInput, setShowInput] = useState(false);
|
|
8872
|
+
const [denying, setDenying] = useState(false);
|
|
8873
|
+
const [reason, setReason] = useState("");
|
|
8874
|
+
const deny = (interrupt) => {
|
|
8875
|
+
const message = reason.trim();
|
|
8876
|
+
onDeny(request.id, message || void 0, interrupt || void 0);
|
|
8877
|
+
setReason("");
|
|
8878
|
+
setDenying(false);
|
|
8879
|
+
};
|
|
8880
|
+
const model = permissionPromptModel(request);
|
|
8881
|
+
const { plan, shell } = model;
|
|
8882
|
+
const [allow, keep, stop] = model.choices;
|
|
8883
|
+
const summary = toolInputPreview(request.input);
|
|
8884
|
+
const ToolIcon = toolIcon(request.toolName);
|
|
8885
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8886
|
+
"data-slot": "permission-prompt",
|
|
8887
|
+
className: cn("rounded-lg border border-warning/40 bg-warning-bg p-3", className),
|
|
8888
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
8889
|
+
className: "flex items-start gap-2.5",
|
|
8890
|
+
children: [
|
|
8891
|
+
/* @__PURE__ */ jsx(Hand, { className: "mt-0.5 size-4 shrink-0 text-warning" }),
|
|
8892
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8893
|
+
className: "min-w-0 flex-1",
|
|
8894
|
+
children: [
|
|
8895
|
+
/* @__PURE__ */ jsx("div", {
|
|
8896
|
+
className: "text-body-sm font-medium text-fg-1",
|
|
8897
|
+
children: model.heading
|
|
8898
|
+
}),
|
|
8899
|
+
model.description ? /* @__PURE__ */ jsx("div", {
|
|
8900
|
+
className: "mt-0.5 text-label text-fg-3",
|
|
8901
|
+
children: model.description
|
|
8902
|
+
}) : null,
|
|
8903
|
+
model.decisionReason ? /* @__PURE__ */ jsx("div", {
|
|
8904
|
+
className: "mt-0.5 text-label text-fg-4",
|
|
8905
|
+
children: model.decisionReason
|
|
8906
|
+
}) : null,
|
|
8907
|
+
plan ? /* @__PURE__ */ jsx("div", {
|
|
8908
|
+
className: "mt-1.5 max-h-72 overflow-y-auto rounded-md bg-code-bg px-2.5 py-2 text-body-sm text-fg-2",
|
|
8909
|
+
children: /* @__PURE__ */ jsx(Response, { children: plan })
|
|
8910
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8911
|
+
shell ? /* @__PURE__ */ jsx("pre", {
|
|
8912
|
+
"data-slot": "shell-request",
|
|
8913
|
+
className: "mt-1.5 max-h-48 overflow-auto rounded-md bg-code-bg px-2.5 py-1.5 font-mono text-body-sm whitespace-pre-wrap text-fg-1",
|
|
8914
|
+
children: shellRequestLines(shell).join("\n")
|
|
8915
|
+
}) : null,
|
|
8916
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8917
|
+
className: "mt-1.5 flex min-w-0 items-center gap-2",
|
|
8918
|
+
children: [
|
|
8919
|
+
/* @__PURE__ */ jsx(ToolIcon, { className: "size-3 shrink-0 text-fg-3" }),
|
|
8920
|
+
/* @__PURE__ */ jsx("span", {
|
|
8921
|
+
className: "shrink-0 font-mono text-label font-medium text-fg-2",
|
|
8922
|
+
children: request.toolName
|
|
8923
|
+
}),
|
|
8924
|
+
summary && !shell ? /* @__PURE__ */ jsx("span", {
|
|
8925
|
+
className: "min-w-0 truncate font-mono text-label text-fg-4",
|
|
8926
|
+
children: summary
|
|
8927
|
+
}) : null
|
|
8928
|
+
]
|
|
8929
|
+
}),
|
|
8930
|
+
/* @__PURE__ */ jsxs("button", {
|
|
8931
|
+
type: "button",
|
|
8932
|
+
className: "mt-1 font-mono text-label text-fg-3 underline-offset-2 hover:underline",
|
|
8933
|
+
onClick: () => setShowInput((v) => !v),
|
|
8934
|
+
children: [
|
|
8935
|
+
showInput ? "Hide" : "Show",
|
|
8936
|
+
" ",
|
|
8937
|
+
request.toolName,
|
|
8938
|
+
" input"
|
|
8939
|
+
]
|
|
8940
|
+
}),
|
|
8941
|
+
showInput ? /* @__PURE__ */ jsx("pre", {
|
|
8942
|
+
className: "mt-1.5 max-h-48 overflow-auto rounded-md bg-code-bg px-2.5 py-1.5 font-mono text-label whitespace-pre-wrap text-fg-2",
|
|
8943
|
+
children: JSON.stringify(request.input, null, 2)
|
|
8944
|
+
}) : null
|
|
8945
|
+
] })
|
|
8946
|
+
]
|
|
8947
|
+
}),
|
|
8948
|
+
/* @__PURE__ */ jsxs("div", {
|
|
8949
|
+
className: "flex shrink-0 flex-wrap justify-end gap-1.5",
|
|
8950
|
+
children: [
|
|
8951
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8952
|
+
size: "sm",
|
|
8953
|
+
onClick: () => onApprove(request.id),
|
|
8954
|
+
children: allow.button
|
|
8955
|
+
}),
|
|
8956
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8957
|
+
size: "sm",
|
|
8958
|
+
variant: "outline",
|
|
8959
|
+
onClick: () => setDenying((v) => !v),
|
|
8960
|
+
children: keep.button
|
|
8961
|
+
}),
|
|
8962
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8963
|
+
size: "sm",
|
|
8964
|
+
variant: "outline",
|
|
8965
|
+
onClick: () => deny(true),
|
|
8966
|
+
children: stop.button
|
|
8967
|
+
})
|
|
8968
|
+
]
|
|
8969
|
+
})
|
|
8970
|
+
]
|
|
8971
|
+
}), denying ? /* @__PURE__ */ jsxs("div", {
|
|
8972
|
+
className: "mt-2.5 flex items-center gap-2 border-t border-warning/30 pt-2.5",
|
|
8973
|
+
children: [
|
|
8974
|
+
/* @__PURE__ */ jsx(Input, {
|
|
8975
|
+
autoFocus: true,
|
|
8976
|
+
value: reason,
|
|
8977
|
+
onChange: (e) => setReason(e.target.value),
|
|
8978
|
+
onKeyDown: (e) => {
|
|
8979
|
+
if (e.key === "Enter") deny(false);
|
|
8980
|
+
if (e.key === "Escape") setDenying(false);
|
|
8981
|
+
},
|
|
8982
|
+
placeholder: model.denyPlaceholder,
|
|
8983
|
+
className: "h-7 flex-1"
|
|
8984
|
+
}),
|
|
8985
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8986
|
+
size: "sm",
|
|
8987
|
+
variant: "outline",
|
|
8988
|
+
onClick: () => setDenying(false),
|
|
8989
|
+
children: "Cancel"
|
|
8990
|
+
}),
|
|
8991
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8992
|
+
size: "sm",
|
|
8993
|
+
variant: "destructive",
|
|
8994
|
+
onClick: () => deny(false),
|
|
8995
|
+
children: keep.button
|
|
8996
|
+
})
|
|
8997
|
+
]
|
|
8998
|
+
}) : null]
|
|
8999
|
+
});
|
|
9000
|
+
}
|
|
9001
|
+
//#endregion
|
|
9002
|
+
//#region src/lib/question-answers.ts
|
|
9003
|
+
const EMPTY_SELECTION = {
|
|
9004
|
+
labels: [],
|
|
9005
|
+
other: "",
|
|
9006
|
+
otherActive: false
|
|
9007
|
+
};
|
|
9008
|
+
function answerFor(selection) {
|
|
9009
|
+
const parts = [...selection.labels];
|
|
9010
|
+
if (selection.otherActive && selection.other.trim()) parts.push(selection.other.trim());
|
|
9011
|
+
return parts.join(", ");
|
|
9012
|
+
}
|
|
9013
|
+
function toggleLabel(selection, label, multiSelect) {
|
|
9014
|
+
if (!multiSelect) return {
|
|
9015
|
+
...selection,
|
|
9016
|
+
labels: [label],
|
|
9017
|
+
otherActive: false
|
|
9018
|
+
};
|
|
9019
|
+
const labels = selection.labels.includes(label) ? selection.labels.filter((l) => l !== label) : [...selection.labels, label];
|
|
9020
|
+
return {
|
|
9021
|
+
...selection,
|
|
9022
|
+
labels
|
|
9023
|
+
};
|
|
8818
9024
|
}
|
|
8819
|
-
function
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
} : {
|
|
8826
|
-
background: "#00000000",
|
|
8827
|
-
foreground: "#d4d4d4",
|
|
8828
|
-
cursor: "#d4d4d4",
|
|
8829
|
-
selectionBackground: "#3a4a5f80"
|
|
9025
|
+
function toggleOther(selection, multiSelect) {
|
|
9026
|
+
const otherActive = !selection.otherActive;
|
|
9027
|
+
return {
|
|
9028
|
+
...selection,
|
|
9029
|
+
otherActive,
|
|
9030
|
+
labels: otherActive && !multiSelect ? [] : selection.labels
|
|
8830
9031
|
};
|
|
8831
9032
|
}
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8838
|
-
FitAddon: fitAddon.FitAddon
|
|
8839
|
-
};
|
|
8840
|
-
})();
|
|
8841
|
-
return xtermPromise;
|
|
9033
|
+
function answersFor(questions, selections) {
|
|
9034
|
+
const answers = {};
|
|
9035
|
+
questions.forEach((question, index) => {
|
|
9036
|
+
answers[question.question] = answerFor(selections[index] ?? EMPTY_SELECTION);
|
|
9037
|
+
});
|
|
9038
|
+
return answers;
|
|
8842
9039
|
}
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
const
|
|
8847
|
-
const
|
|
8848
|
-
const
|
|
8849
|
-
useEffect(() => {
|
|
8850
|
-
setShellId(void 0);
|
|
8851
|
-
setReturnReveal(void 0);
|
|
8852
|
-
}, [sessionId]);
|
|
8853
|
-
const rowIdRef = useRef(void 0);
|
|
8854
|
-
const row = useMemo(() => shellId === void 0 ? void 0 : items.find((item) => item.kind === "shell" && item.shell.id === shellId), [items, shellId]);
|
|
8855
|
-
rowIdRef.current = row?.id;
|
|
8856
|
-
const leaveShell = useCallback(() => {
|
|
8857
|
-
setShellId((current) => {
|
|
8858
|
-
const rowId = rowIdRef.current;
|
|
8859
|
-
if (current !== void 0 && rowId !== void 0) setReturnReveal({
|
|
8860
|
-
toolUseId: rowId,
|
|
8861
|
-
nonce: Date.now()
|
|
8862
|
-
});
|
|
8863
|
-
});
|
|
8864
|
-
}, []);
|
|
8865
|
-
const openShellNonce = openShell?.nonce;
|
|
8866
|
-
const openShellId = openShell?.shellId;
|
|
8867
|
-
useEffect(() => {
|
|
8868
|
-
if (openShellId === void 0) leaveShell();
|
|
8869
|
-
else setShellId(openShellId);
|
|
8870
|
-
}, [openShellNonce]);
|
|
8871
|
-
const revealNonce = reveal?.nonce;
|
|
8872
|
-
useEffect(() => {
|
|
8873
|
-
if (revealNonce === void 0) return;
|
|
8874
|
-
setShellId(void 0);
|
|
8875
|
-
}, [revealNonce]);
|
|
8876
|
-
useEffect(() => {
|
|
8877
|
-
if (shellId === void 0) return;
|
|
8878
|
-
const onKey = (event) => {
|
|
8879
|
-
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
8880
|
-
leaveShell();
|
|
8881
|
-
};
|
|
8882
|
-
window.addEventListener("keydown", onKey);
|
|
8883
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
8884
|
-
}, [shellId, leaveShell]);
|
|
8885
|
-
const onShellChangeRef = useRef(onShellChange);
|
|
8886
|
-
onShellChangeRef.current = onShellChange;
|
|
8887
|
-
const reportedShellId = useRef(void 0);
|
|
8888
|
-
useEffect(() => {
|
|
8889
|
-
if (reportedShellId.current === shellId) return;
|
|
8890
|
-
reportedShellId.current = shellId;
|
|
8891
|
-
onShellChangeRef.current?.(shellId);
|
|
8892
|
-
}, [shellId]);
|
|
8893
|
-
const shell = useMemo(() => {
|
|
8894
|
-
if (shellId === void 0) return;
|
|
8895
|
-
return row?.shell ?? shells?.find((record) => record.id === shellId) ?? session?.shells?.find((record) => record.id === shellId);
|
|
8896
|
-
}, [
|
|
8897
|
-
row,
|
|
8898
|
-
shells,
|
|
8899
|
-
session,
|
|
8900
|
-
shellId
|
|
8901
|
-
]);
|
|
9040
|
+
function useQuestionAnswers(questions) {
|
|
9041
|
+
const [selections, setSelections] = useState(() => questions.map(() => EMPTY_SELECTION));
|
|
9042
|
+
const selectionFor = (index) => selections[index] ?? EMPTY_SELECTION;
|
|
9043
|
+
const answered = (index) => answerFor(selectionFor(index)) !== "";
|
|
9044
|
+
const edit = (index, change) => setSelections((prev) => questions.map((_, i) => i === index ? change(prev[i] ?? EMPTY_SELECTION) : prev[i] ?? EMPTY_SELECTION));
|
|
9045
|
+
const multiSelect = (index) => questions[index]?.multiSelect === true;
|
|
8902
9046
|
return {
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
9047
|
+
selections,
|
|
9048
|
+
selectionFor,
|
|
9049
|
+
answered,
|
|
9050
|
+
complete: questions.every((_, index) => answered(index)),
|
|
9051
|
+
update: (index, patch) => edit(index, (selection) => ({
|
|
9052
|
+
...selection,
|
|
9053
|
+
...patch
|
|
9054
|
+
})),
|
|
9055
|
+
toggle: (index, label) => edit(index, (selection) => toggleLabel(selection, label, multiSelect(index))),
|
|
9056
|
+
toggleOther: (index) => edit(index, (selection) => toggleOther(selection, multiSelect(index))),
|
|
9057
|
+
answers: () => answersFor(questions, selections)
|
|
8909
9058
|
};
|
|
8910
9059
|
}
|
|
8911
9060
|
//#endregion
|
|
@@ -8927,44 +9076,13 @@ const QUESTION_BEHAVIORS = [
|
|
|
8927
9076
|
description: "the agent is told to decide on its own"
|
|
8928
9077
|
}
|
|
8929
9078
|
];
|
|
8930
|
-
const EMPTY_SELECTION = {
|
|
8931
|
-
labels: [],
|
|
8932
|
-
other: "",
|
|
8933
|
-
otherActive: false
|
|
8934
|
-
};
|
|
8935
|
-
function answerFor$1(selection) {
|
|
8936
|
-
const parts = [...selection.labels];
|
|
8937
|
-
if (selection.otherActive && selection.other.trim()) parts.push(selection.other.trim());
|
|
8938
|
-
return parts.join(", ");
|
|
8939
|
-
}
|
|
8940
9079
|
function QuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
8941
9080
|
const questions = parseUserQuestions(request.input);
|
|
8942
|
-
const
|
|
8943
|
-
const
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
} : s));
|
|
8948
|
-
};
|
|
8949
|
-
const toggle = (index, label, multiSelect) => {
|
|
8950
|
-
const current = selections[index] ?? EMPTY_SELECTION;
|
|
8951
|
-
if (multiSelect) update(index, { labels: current.labels.includes(label) ? current.labels.filter((l) => l !== label) : [...current.labels, label] });
|
|
8952
|
-
else update(index, {
|
|
8953
|
-
labels: current.labels[0] === label ? [] : [label],
|
|
8954
|
-
otherActive: false
|
|
8955
|
-
});
|
|
8956
|
-
};
|
|
8957
|
-
const complete = questions.every((_, i) => answerFor$1(selections[i] ?? EMPTY_SELECTION) !== "");
|
|
8958
|
-
const submit = () => {
|
|
8959
|
-
const answers = {};
|
|
8960
|
-
questions.forEach((q, i) => {
|
|
8961
|
-
answers[q.question] = answerFor$1(selections[i] ?? EMPTY_SELECTION);
|
|
8962
|
-
});
|
|
8963
|
-
onAnswer(request.id, {
|
|
8964
|
-
...request.input,
|
|
8965
|
-
answers
|
|
8966
|
-
});
|
|
8967
|
-
};
|
|
9081
|
+
const { selectionFor, update, toggle, toggleOther, complete, answers } = useQuestionAnswers(questions);
|
|
9082
|
+
const submit = () => onAnswer(request.id, {
|
|
9083
|
+
...request.input,
|
|
9084
|
+
answers: answers()
|
|
9085
|
+
});
|
|
8968
9086
|
return /* @__PURE__ */ jsx("div", {
|
|
8969
9087
|
"data-slot": "question-prompt",
|
|
8970
9088
|
className: cn("rounded-lg border border-info/40 bg-info-bg p-3", className),
|
|
@@ -8975,7 +9093,7 @@ function QuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
8975
9093
|
/* @__PURE__ */ jsxs("div", {
|
|
8976
9094
|
className: "flex min-w-0 flex-1 flex-col gap-3",
|
|
8977
9095
|
children: [questions.map((q, index) => {
|
|
8978
|
-
const selection =
|
|
9096
|
+
const selection = selectionFor(index);
|
|
8979
9097
|
return /* @__PURE__ */ jsxs("div", {
|
|
8980
9098
|
className: "flex flex-col gap-1.5",
|
|
8981
9099
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -8993,7 +9111,7 @@ function QuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
8993
9111
|
const selected = selection.labels.includes(option.label);
|
|
8994
9112
|
return /* @__PURE__ */ jsxs("button", {
|
|
8995
9113
|
type: "button",
|
|
8996
|
-
onClick: () => toggle(index, option.label
|
|
9114
|
+
onClick: () => toggle(index, option.label),
|
|
8997
9115
|
className: cn("rounded-md border px-2.5 py-1.5 text-left transition-colors", selected ? "border-info bg-bg" : "border-border bg-bg/50 hover:border-border-strong hover:bg-bg"),
|
|
8998
9116
|
children: [
|
|
8999
9117
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -9014,7 +9132,7 @@ function QuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
9014
9132
|
className: "flex items-center gap-2",
|
|
9015
9133
|
children: [/* @__PURE__ */ jsx("button", {
|
|
9016
9134
|
type: "button",
|
|
9017
|
-
onClick: () =>
|
|
9135
|
+
onClick: () => toggleOther(index),
|
|
9018
9136
|
className: cn("shrink-0 rounded-md border px-2.5 py-1.5 text-body-sm font-medium transition-colors", selection.otherActive ? "border-info bg-bg text-fg-1" : "border-border bg-bg/50 text-fg-3 hover:border-border-strong hover:bg-bg"),
|
|
9019
9137
|
children: "Other…"
|
|
9020
9138
|
}), selection.otherActive ? /* @__PURE__ */ jsx(Textarea, {
|
|
@@ -9223,50 +9341,24 @@ function TerminalPermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
|
9223
9341
|
setReason("");
|
|
9224
9342
|
setDenying(false);
|
|
9225
9343
|
};
|
|
9226
|
-
const
|
|
9227
|
-
const
|
|
9344
|
+
const model = permissionPromptModel(request);
|
|
9345
|
+
const { plan, shell, heading } = model;
|
|
9228
9346
|
const patch = plan || shell ? void 0 : previewPatch(request.input);
|
|
9229
9347
|
const summary = plan || shell ? "" : toolInputPreview(request.input);
|
|
9230
|
-
const heading = plan ? "Plan ready for review" : shell ? shellRequestTitle(shell) : request.displayName ?? request.title ?? "Permission needed";
|
|
9231
9348
|
const subject = patch?.path ?? (summary || void 0);
|
|
9232
9349
|
const reasonInput = denying ? /* @__PURE__ */ jsx(PromptInput, {
|
|
9233
9350
|
value: reason,
|
|
9234
9351
|
onChange: setReason,
|
|
9235
9352
|
onSubmit: () => deny(false),
|
|
9236
9353
|
onCancel: () => setDenying(false),
|
|
9237
|
-
placeholder:
|
|
9354
|
+
placeholder: model.denyPlaceholder
|
|
9238
9355
|
}) : void 0;
|
|
9239
|
-
const options =
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9244
|
-
|
|
9245
|
-
key: "deny",
|
|
9246
|
-
label: "Keep planning - tell it what to change",
|
|
9247
|
-
detail: reasonInput
|
|
9248
|
-
},
|
|
9249
|
-
{
|
|
9250
|
-
key: "stop",
|
|
9251
|
-
label: "No, and stop the turn",
|
|
9252
|
-
danger: true
|
|
9253
|
-
}
|
|
9254
|
-
] : [
|
|
9255
|
-
{
|
|
9256
|
-
key: "allow",
|
|
9257
|
-
label: "Yes"
|
|
9258
|
-
},
|
|
9259
|
-
{
|
|
9260
|
-
key: "deny",
|
|
9261
|
-
label: "No, and tell the agent what to do differently",
|
|
9262
|
-
detail: reasonInput
|
|
9263
|
-
},
|
|
9264
|
-
{
|
|
9265
|
-
key: "stop",
|
|
9266
|
-
label: "No, and stop the turn",
|
|
9267
|
-
danger: true
|
|
9268
|
-
}
|
|
9269
|
-
];
|
|
9356
|
+
const options = model.choices.map((choice) => ({
|
|
9357
|
+
key: choice.key,
|
|
9358
|
+
label: choice.option,
|
|
9359
|
+
danger: choice.danger,
|
|
9360
|
+
detail: choice.key === "deny" ? reasonInput : void 0
|
|
9361
|
+
}));
|
|
9270
9362
|
return /* @__PURE__ */ jsxs("div", {
|
|
9271
9363
|
"data-slot": "permission-prompt",
|
|
9272
9364
|
className,
|
|
@@ -9301,15 +9393,15 @@ function TerminalPermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
|
9301
9393
|
/* @__PURE__ */ jsx(TerminalDiff, { patch }),
|
|
9302
9394
|
/* @__PURE__ */ jsx(Blank, {}),
|
|
9303
9395
|
/* @__PURE__ */ jsx(Rule, { dashed: true })
|
|
9304
|
-
] }) :
|
|
9396
|
+
] }) : model.description ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Row, {
|
|
9305
9397
|
tone: "dim",
|
|
9306
|
-
children:
|
|
9398
|
+
children: model.description
|
|
9307
9399
|
}), /* @__PURE__ */ jsx(Blank, {})] }) : null,
|
|
9308
|
-
|
|
9400
|
+
model.decisionReason ? /* @__PURE__ */ jsx(Row, {
|
|
9309
9401
|
tone: "faint",
|
|
9310
|
-
children:
|
|
9402
|
+
children: model.decisionReason
|
|
9311
9403
|
}) : null,
|
|
9312
|
-
/* @__PURE__ */ jsx(Row, { children:
|
|
9404
|
+
/* @__PURE__ */ jsx(Row, { children: model.question }),
|
|
9313
9405
|
/* @__PURE__ */ jsx(Choices, {
|
|
9314
9406
|
label: heading,
|
|
9315
9407
|
options,
|
|
@@ -9317,9 +9409,10 @@ function TerminalPermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
|
9317
9409
|
onFocus: setFocused,
|
|
9318
9410
|
active: !denying,
|
|
9319
9411
|
onChoose: (index) => {
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
else deny(true);
|
|
9412
|
+
const key = model.choices[index]?.key;
|
|
9413
|
+
if (key === "allow") onApprove(request.id);
|
|
9414
|
+
else if (key === "deny") setDenying(true);
|
|
9415
|
+
else if (key === "stop") deny(true);
|
|
9323
9416
|
}
|
|
9324
9417
|
}),
|
|
9325
9418
|
/* @__PURE__ */ jsx(Blank, {}),
|
|
@@ -9329,54 +9422,18 @@ function TerminalPermissionPrompt({ request, onApprove, onDeny, className }) {
|
|
|
9329
9422
|
}
|
|
9330
9423
|
//#endregion
|
|
9331
9424
|
//#region src/components/terminal/QuestionPrompt.tsx
|
|
9332
|
-
const EMPTY = {
|
|
9333
|
-
labels: [],
|
|
9334
|
-
other: "",
|
|
9335
|
-
otherActive: false
|
|
9336
|
-
};
|
|
9337
|
-
function answerFor(selection) {
|
|
9338
|
-
const parts = [...selection.labels];
|
|
9339
|
-
if (selection.otherActive && selection.other.trim()) parts.push(selection.other.trim());
|
|
9340
|
-
return parts.join(", ");
|
|
9341
|
-
}
|
|
9342
9425
|
function TerminalQuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
9343
9426
|
const questions = parseUserQuestions(request.input);
|
|
9344
|
-
const
|
|
9427
|
+
const { selectionFor, answered, complete, update, toggle, toggleOther, answers } = useQuestionAnswers(questions);
|
|
9345
9428
|
const [cursors, setCursors] = useState(() => questions.map(() => 0));
|
|
9346
9429
|
const [tab, setTab] = useState(0);
|
|
9347
9430
|
const [reviewCursor, setReviewCursor] = useState(0);
|
|
9348
9431
|
const review = tab >= questions.length;
|
|
9349
|
-
const selection =
|
|
9350
|
-
const
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
...patch
|
|
9355
|
-
} : s));
|
|
9356
|
-
const toggle = (index, label, multiSelect) => {
|
|
9357
|
-
setSelections((prev) => prev.map((current, i) => {
|
|
9358
|
-
if (i !== index) return current;
|
|
9359
|
-
if (!multiSelect) return {
|
|
9360
|
-
...current,
|
|
9361
|
-
labels: [label],
|
|
9362
|
-
otherActive: false
|
|
9363
|
-
};
|
|
9364
|
-
return {
|
|
9365
|
-
...current,
|
|
9366
|
-
labels: current.labels.includes(label) ? current.labels.filter((l) => l !== label) : [...current.labels, label]
|
|
9367
|
-
};
|
|
9368
|
-
}));
|
|
9369
|
-
};
|
|
9370
|
-
const submit = () => {
|
|
9371
|
-
const answers = {};
|
|
9372
|
-
questions.forEach((question, index) => {
|
|
9373
|
-
answers[question.question] = answerFor(selections[index] ?? EMPTY);
|
|
9374
|
-
});
|
|
9375
|
-
onAnswer(request.id, {
|
|
9376
|
-
...request.input,
|
|
9377
|
-
answers
|
|
9378
|
-
});
|
|
9379
|
-
};
|
|
9432
|
+
const selection = selectionFor(tab);
|
|
9433
|
+
const submit = () => onAnswer(request.id, {
|
|
9434
|
+
...request.input,
|
|
9435
|
+
answers: answers()
|
|
9436
|
+
});
|
|
9380
9437
|
const dismiss = () => onDismiss(request.id, "Question dismissed by user");
|
|
9381
9438
|
const move = (delta) => setTab((current) => Math.min(questions.length, Math.max(0, current + delta)));
|
|
9382
9439
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -9411,7 +9468,7 @@ function TerminalQuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
9411
9468
|
/* @__PURE__ */ jsx(Blank, {}),
|
|
9412
9469
|
review ? /* @__PURE__ */ jsx(ReviewStep, {
|
|
9413
9470
|
questions,
|
|
9414
|
-
answers: questions.map((_, index) => answerFor(
|
|
9471
|
+
answers: questions.map((_, index) => answerFor(selectionFor(index))),
|
|
9415
9472
|
complete,
|
|
9416
9473
|
cursor: reviewCursor,
|
|
9417
9474
|
onCursor: setReviewCursor,
|
|
@@ -9422,8 +9479,9 @@ function TerminalQuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
9422
9479
|
selection,
|
|
9423
9480
|
cursor: cursors[tab] ?? 0,
|
|
9424
9481
|
onCursor: (next) => setCursors((prev) => prev.map((c, i) => i === tab ? next : c)),
|
|
9425
|
-
onToggle: (label) => toggle(tab, label
|
|
9482
|
+
onToggle: (label) => toggle(tab, label),
|
|
9426
9483
|
onOther: (patch) => update(tab, patch),
|
|
9484
|
+
onToggleOther: () => toggleOther(tab),
|
|
9427
9485
|
onAdvance: () => move(1),
|
|
9428
9486
|
onDismiss: dismiss
|
|
9429
9487
|
}, tab),
|
|
@@ -9432,7 +9490,7 @@ function TerminalQuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
9432
9490
|
]
|
|
9433
9491
|
});
|
|
9434
9492
|
}
|
|
9435
|
-
function QuestionStep({ question, selection, cursor, onCursor, onToggle, onOther, onAdvance, onDismiss }) {
|
|
9493
|
+
function QuestionStep({ question, selection, cursor, onCursor, onToggle, onOther, onToggleOther, onAdvance, onDismiss }) {
|
|
9436
9494
|
const multiSelect = question.multiSelect === true;
|
|
9437
9495
|
const options = [
|
|
9438
9496
|
...question.options.map((option, index) => {
|
|
@@ -9496,7 +9554,7 @@ function QuestionStep({ question, selection, cursor, onCursor, onToggle, onOther
|
|
|
9496
9554
|
return;
|
|
9497
9555
|
}
|
|
9498
9556
|
if (index === question.options.length) {
|
|
9499
|
-
|
|
9557
|
+
onToggleOther();
|
|
9500
9558
|
return;
|
|
9501
9559
|
}
|
|
9502
9560
|
if (multiSelect && index === question.options.length + 1) {
|
|
@@ -9548,89 +9606,259 @@ function ReviewStep({ questions, answers, complete, cursor, onCursor, onSubmit,
|
|
|
9548
9606
|
] });
|
|
9549
9607
|
}
|
|
9550
9608
|
//#endregion
|
|
9609
|
+
//#region src/components/agent/ApprovalPrompts.tsx
|
|
9610
|
+
function ApprovalPrompts({ requests, terminal, fontSize, lineHeight, affordances, hostPrompts, onApprove, onDeny }) {
|
|
9611
|
+
const dismissQuestion = (id) => onDeny(id, "Question dismissed by user");
|
|
9612
|
+
return /* @__PURE__ */ jsx("div", {
|
|
9613
|
+
className: cn(terminal ? "pb-2" : "px-3 pb-2"),
|
|
9614
|
+
children: /* @__PURE__ */ jsx(PromptSurface, {
|
|
9615
|
+
terminal,
|
|
9616
|
+
fontSize,
|
|
9617
|
+
lineHeight,
|
|
9618
|
+
affordances,
|
|
9619
|
+
children: requests.map((request) => {
|
|
9620
|
+
const HostPrompt = hostPrompts?.[request.toolName];
|
|
9621
|
+
if (HostPrompt) return /* @__PURE__ */ jsx(HostPrompt, {
|
|
9622
|
+
request,
|
|
9623
|
+
onApprove,
|
|
9624
|
+
onDeny
|
|
9625
|
+
}, request.id);
|
|
9626
|
+
const isQuestion = request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0;
|
|
9627
|
+
if (terminal) return isQuestion ? /* @__PURE__ */ jsx(TerminalQuestionPrompt, {
|
|
9628
|
+
request,
|
|
9629
|
+
onAnswer: onApprove,
|
|
9630
|
+
onDismiss: dismissQuestion
|
|
9631
|
+
}, request.id) : /* @__PURE__ */ jsx(TerminalPermissionPrompt, {
|
|
9632
|
+
request,
|
|
9633
|
+
onApprove,
|
|
9634
|
+
onDeny
|
|
9635
|
+
}, request.id);
|
|
9636
|
+
return isQuestion ? /* @__PURE__ */ jsx(QuestionPrompt, {
|
|
9637
|
+
request,
|
|
9638
|
+
onAnswer: onApprove,
|
|
9639
|
+
onDismiss: dismissQuestion
|
|
9640
|
+
}, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
9641
|
+
request,
|
|
9642
|
+
onApprove,
|
|
9643
|
+
onDeny
|
|
9644
|
+
}, request.id);
|
|
9645
|
+
})
|
|
9646
|
+
})
|
|
9647
|
+
});
|
|
9648
|
+
}
|
|
9649
|
+
function PromptSurface({ terminal, fontSize, lineHeight, affordances, children }) {
|
|
9650
|
+
if (!terminal) return /* @__PURE__ */ jsx("div", {
|
|
9651
|
+
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] flex-col gap-2",
|
|
9652
|
+
children
|
|
9653
|
+
});
|
|
9654
|
+
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
9655
|
+
fontSize,
|
|
9656
|
+
lineHeight,
|
|
9657
|
+
affordances,
|
|
9658
|
+
bleed: "1ch",
|
|
9659
|
+
className: "term-transcript",
|
|
9660
|
+
children
|
|
9661
|
+
});
|
|
9662
|
+
}
|
|
9663
|
+
//#endregion
|
|
9664
|
+
//#region src/components/agent/session-panel-providers.tsx
|
|
9665
|
+
function SessionPanelProviders({ variant, fileLinks, loadFullResult, shellActions, toolTitles, resultImages, children }) {
|
|
9666
|
+
return /* @__PURE__ */ jsx(TranscriptVariantProvider, {
|
|
9667
|
+
value: variant,
|
|
9668
|
+
children: /* @__PURE__ */ jsx(FileLinkProvider, {
|
|
9669
|
+
value: fileLinks,
|
|
9670
|
+
children: /* @__PURE__ */ jsx(ToolResultFetchProvider, {
|
|
9671
|
+
value: loadFullResult,
|
|
9672
|
+
children: /* @__PURE__ */ jsx(ShellActionsProvider, {
|
|
9673
|
+
value: shellActions,
|
|
9674
|
+
children: /* @__PURE__ */ jsx(ToolTitleProvider, {
|
|
9675
|
+
value: toolTitles,
|
|
9676
|
+
children: /* @__PURE__ */ jsx(ToolResultImageProvider, {
|
|
9677
|
+
value: resultImages,
|
|
9678
|
+
children
|
|
9679
|
+
})
|
|
9680
|
+
})
|
|
9681
|
+
})
|
|
9682
|
+
})
|
|
9683
|
+
})
|
|
9684
|
+
});
|
|
9685
|
+
}
|
|
9686
|
+
//#endregion
|
|
9687
|
+
//#region src/components/agent/use-catch-up.ts
|
|
9688
|
+
function useCatchUp(sessionId, unseen) {
|
|
9689
|
+
const [held, setHeld] = useState({
|
|
9690
|
+
sessionId,
|
|
9691
|
+
mark: unseen,
|
|
9692
|
+
caughtUp: false
|
|
9693
|
+
});
|
|
9694
|
+
let current = held;
|
|
9695
|
+
if (held.sessionId !== sessionId) {
|
|
9696
|
+
current = {
|
|
9697
|
+
sessionId,
|
|
9698
|
+
mark: unseen,
|
|
9699
|
+
caughtUp: false
|
|
9700
|
+
};
|
|
9701
|
+
setHeld(current);
|
|
9702
|
+
}
|
|
9703
|
+
const dismiss = useCallback(() => setHeld((prev) => prev.caughtUp ? prev : {
|
|
9704
|
+
...prev,
|
|
9705
|
+
caughtUp: true
|
|
9706
|
+
}), []);
|
|
9707
|
+
return {
|
|
9708
|
+
mark: current.caughtUp ? void 0 : current.mark,
|
|
9709
|
+
dismiss
|
|
9710
|
+
};
|
|
9711
|
+
}
|
|
9712
|
+
//#endregion
|
|
9713
|
+
//#region src/components/agent/use-host-image.ts
|
|
9714
|
+
const IMAGE_MEDIA_TYPES = {
|
|
9715
|
+
png: "image/png",
|
|
9716
|
+
jpg: "image/jpeg",
|
|
9717
|
+
jpeg: "image/jpeg",
|
|
9718
|
+
gif: "image/gif",
|
|
9719
|
+
webp: "image/webp"
|
|
9720
|
+
};
|
|
9721
|
+
function useHostImage(client, sessionId, producedFiles) {
|
|
9722
|
+
const store = useMemo(() => ({
|
|
9723
|
+
cache: /* @__PURE__ */ new Map(),
|
|
9724
|
+
urls: /* @__PURE__ */ new Set(),
|
|
9725
|
+
live: true
|
|
9726
|
+
}), [client, sessionId]);
|
|
9727
|
+
useEffect(() => {
|
|
9728
|
+
store.live = true;
|
|
9729
|
+
return () => {
|
|
9730
|
+
store.live = false;
|
|
9731
|
+
for (const url of store.urls) URL.revokeObjectURL(url);
|
|
9732
|
+
store.urls.clear();
|
|
9733
|
+
store.cache.clear();
|
|
9734
|
+
};
|
|
9735
|
+
}, [store]);
|
|
9736
|
+
return useCallback((path) => {
|
|
9737
|
+
const produced = producedFiles?.[path];
|
|
9738
|
+
const key = produced ? `produced:${produced.fileId}` : `fs:${path}`;
|
|
9739
|
+
const hit = store.cache.get(key);
|
|
9740
|
+
if (hit) return hit;
|
|
9741
|
+
const pending = (produced && sessionId ? readProduced(client, sessionId, produced.fileId, store) : readHostImage(client, path)).catch(() => {
|
|
9742
|
+
if (store.cache.get(key) === pending) store.cache.delete(key);
|
|
9743
|
+
});
|
|
9744
|
+
store.cache.set(key, pending);
|
|
9745
|
+
return pending;
|
|
9746
|
+
}, [
|
|
9747
|
+
client,
|
|
9748
|
+
sessionId,
|
|
9749
|
+
producedFiles,
|
|
9750
|
+
store
|
|
9751
|
+
]);
|
|
9752
|
+
}
|
|
9753
|
+
async function readProduced(client, sessionId, fileId, store) {
|
|
9754
|
+
const blob = await client.readProducedFile(sessionId, fileId);
|
|
9755
|
+
if (blob.size === 0) return;
|
|
9756
|
+
const url = URL.createObjectURL(blob);
|
|
9757
|
+
if (!store.live) {
|
|
9758
|
+
URL.revokeObjectURL(url);
|
|
9759
|
+
throw new Error("host image store disposed");
|
|
9760
|
+
}
|
|
9761
|
+
store.urls.add(url);
|
|
9762
|
+
return url;
|
|
9763
|
+
}
|
|
9764
|
+
async function readHostImage(client, path) {
|
|
9765
|
+
const file = await client.readHostFile(path);
|
|
9766
|
+
if (file.encoding !== "base64") return;
|
|
9767
|
+
const mediaType = IMAGE_MEDIA_TYPES[path.slice(path.lastIndexOf(".") + 1).toLowerCase()];
|
|
9768
|
+
return mediaType ? `data:${mediaType};base64,${file.content}` : void 0;
|
|
9769
|
+
}
|
|
9770
|
+
//#endregion
|
|
9551
9771
|
//#region src/components/agent/SessionInfoDialog.tsx
|
|
9552
9772
|
function SessionInfoDialog({ state, client, sessionId, open, onOpenChange }) {
|
|
9553
|
-
const session = state.session;
|
|
9554
|
-
const mode = state.permissionMode ? permissionModeMeta(state.permissionMode) : void 0;
|
|
9555
9773
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
9556
9774
|
open,
|
|
9557
9775
|
onOpenChange,
|
|
9558
9776
|
children: /* @__PURE__ */ jsxs(DialogContent, { children: [/* @__PURE__ */ jsx(DialogHeader, {
|
|
9559
9777
|
title: "Session info",
|
|
9560
|
-
description: session?.title
|
|
9561
|
-
}), /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
children: [
|
|
9567
|
-
/* @__PURE__ */ jsx(DialogRow, {
|
|
9568
|
-
label: "Engine",
|
|
9569
|
-
children: state.engine ?? "claude"
|
|
9570
|
-
}),
|
|
9571
|
-
session?.profile ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9572
|
-
label: "Profile",
|
|
9573
|
-
children: session.profile
|
|
9574
|
-
}) : null,
|
|
9575
|
-
state.model ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9576
|
-
label: "Model",
|
|
9577
|
-
mono: true,
|
|
9578
|
-
children: state.model
|
|
9579
|
-
}) : null,
|
|
9580
|
-
mode ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9581
|
-
label: "Permission mode",
|
|
9582
|
-
children: mode.label
|
|
9583
|
-
}) : null,
|
|
9584
|
-
session?.apiKeySource ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9585
|
-
label: "Credentials",
|
|
9586
|
-
children: session.apiKeySource
|
|
9587
|
-
}) : null
|
|
9588
|
-
]
|
|
9589
|
-
}),
|
|
9590
|
-
/* @__PURE__ */ jsxs("div", {
|
|
9591
|
-
className: "py-2",
|
|
9592
|
-
children: [
|
|
9593
|
-
state.cwd ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9594
|
-
label: "Working directory",
|
|
9595
|
-
value: state.cwd
|
|
9596
|
-
}) : null,
|
|
9597
|
-
state.sdkSessionId ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9598
|
-
label: "Engine session id",
|
|
9599
|
-
value: state.sdkSessionId
|
|
9600
|
-
}) : null,
|
|
9601
|
-
session ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9602
|
-
label: "Gateway session id",
|
|
9603
|
-
value: session.id
|
|
9604
|
-
}) : null
|
|
9605
|
-
]
|
|
9606
|
-
}),
|
|
9607
|
-
/* @__PURE__ */ jsxs("div", {
|
|
9608
|
-
className: "py-2",
|
|
9609
|
-
children: [
|
|
9610
|
-
session?.createdAt ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9611
|
-
label: "Started",
|
|
9612
|
-
children: formatRelativeTime(session.createdAt)
|
|
9613
|
-
}) : null,
|
|
9614
|
-
session?.numTurns !== void 0 ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9615
|
-
label: "Turns",
|
|
9616
|
-
children: session.numTurns
|
|
9617
|
-
}) : null,
|
|
9618
|
-
/* @__PURE__ */ jsx(DialogRow, {
|
|
9619
|
-
label: "Cost",
|
|
9620
|
-
mono: true,
|
|
9621
|
-
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
9622
|
-
})
|
|
9623
|
-
]
|
|
9624
|
-
}),
|
|
9625
|
-
state.capabilities.vfs ? /* @__PURE__ */ jsx(SessionFiles, {
|
|
9626
|
-
client,
|
|
9627
|
-
sessionId,
|
|
9628
|
-
open
|
|
9629
|
-
}) : null
|
|
9630
|
-
]
|
|
9778
|
+
description: state.session?.title
|
|
9779
|
+
}), /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(SessionInfoPanel, {
|
|
9780
|
+
state,
|
|
9781
|
+
client,
|
|
9782
|
+
sessionId,
|
|
9783
|
+
active: open
|
|
9631
9784
|
}) })] })
|
|
9632
9785
|
});
|
|
9633
9786
|
}
|
|
9787
|
+
function SessionInfoPanel({ state, client, sessionId, active = true }) {
|
|
9788
|
+
const session = state.session;
|
|
9789
|
+
const mode = state.permissionMode ? permissionModeMeta(state.permissionMode) : void 0;
|
|
9790
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
9791
|
+
className: "flex flex-col divide-y divide-border",
|
|
9792
|
+
children: [
|
|
9793
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9794
|
+
className: "pb-2",
|
|
9795
|
+
children: [
|
|
9796
|
+
/* @__PURE__ */ jsx(DialogRow, {
|
|
9797
|
+
label: "Engine",
|
|
9798
|
+
children: state.engine ?? "claude"
|
|
9799
|
+
}),
|
|
9800
|
+
session?.profile ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9801
|
+
label: "Profile",
|
|
9802
|
+
children: session.profile
|
|
9803
|
+
}) : null,
|
|
9804
|
+
state.model ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9805
|
+
label: "Model",
|
|
9806
|
+
mono: true,
|
|
9807
|
+
children: state.model
|
|
9808
|
+
}) : null,
|
|
9809
|
+
mode ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9810
|
+
label: "Permission mode",
|
|
9811
|
+
children: mode.label
|
|
9812
|
+
}) : null,
|
|
9813
|
+
session?.apiKeySource ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9814
|
+
label: "Credentials",
|
|
9815
|
+
children: session.apiKeySource
|
|
9816
|
+
}) : null
|
|
9817
|
+
]
|
|
9818
|
+
}),
|
|
9819
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9820
|
+
className: "py-2",
|
|
9821
|
+
children: [
|
|
9822
|
+
state.cwd ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9823
|
+
label: "Working directory",
|
|
9824
|
+
value: state.cwd
|
|
9825
|
+
}) : null,
|
|
9826
|
+
state.sdkSessionId ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9827
|
+
label: "Engine session id",
|
|
9828
|
+
value: state.sdkSessionId
|
|
9829
|
+
}) : null,
|
|
9830
|
+
session ? /* @__PURE__ */ jsx(CopyRow, {
|
|
9831
|
+
label: "Gateway session id",
|
|
9832
|
+
value: session.id
|
|
9833
|
+
}) : null
|
|
9834
|
+
]
|
|
9835
|
+
}),
|
|
9836
|
+
/* @__PURE__ */ jsxs("div", {
|
|
9837
|
+
className: "py-2",
|
|
9838
|
+
children: [
|
|
9839
|
+
session?.createdAt ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9840
|
+
label: "Started",
|
|
9841
|
+
children: formatRelativeTime(session.createdAt)
|
|
9842
|
+
}) : null,
|
|
9843
|
+
session?.numTurns !== void 0 ? /* @__PURE__ */ jsx(DialogRow, {
|
|
9844
|
+
label: "Turns",
|
|
9845
|
+
children: session.numTurns
|
|
9846
|
+
}) : null,
|
|
9847
|
+
/* @__PURE__ */ jsx(DialogRow, {
|
|
9848
|
+
label: "Cost",
|
|
9849
|
+
mono: true,
|
|
9850
|
+
children: formatCost(state.costUsd ?? (state.totalCostUsd || void 0))
|
|
9851
|
+
})
|
|
9852
|
+
]
|
|
9853
|
+
}),
|
|
9854
|
+
state.capabilities.vfs ? /* @__PURE__ */ jsx(SessionFiles, {
|
|
9855
|
+
client,
|
|
9856
|
+
sessionId,
|
|
9857
|
+
active
|
|
9858
|
+
}) : null
|
|
9859
|
+
]
|
|
9860
|
+
});
|
|
9861
|
+
}
|
|
9634
9862
|
function CopyRow({ label, value }) {
|
|
9635
9863
|
return /* @__PURE__ */ jsxs("div", {
|
|
9636
9864
|
className: "flex items-start justify-between gap-2 py-1.5",
|
|
@@ -9649,28 +9877,8 @@ function CopyRow({ label, value }) {
|
|
|
9649
9877
|
})]
|
|
9650
9878
|
});
|
|
9651
9879
|
}
|
|
9652
|
-
function SessionFiles({ client, sessionId,
|
|
9653
|
-
const
|
|
9654
|
-
const [loading, setLoading] = useState(false);
|
|
9655
|
-
useEffect(() => {
|
|
9656
|
-
if (!open || !sessionId) return;
|
|
9657
|
-
let cancelled = false;
|
|
9658
|
-
setLoading(true);
|
|
9659
|
-
client.listSessionFiles(sessionId).then((list) => {
|
|
9660
|
-
if (!cancelled) setFiles(list);
|
|
9661
|
-
}).catch(() => {
|
|
9662
|
-
if (!cancelled) setFiles([]);
|
|
9663
|
-
}).finally(() => {
|
|
9664
|
-
if (!cancelled) setLoading(false);
|
|
9665
|
-
});
|
|
9666
|
-
return () => {
|
|
9667
|
-
cancelled = true;
|
|
9668
|
-
};
|
|
9669
|
-
}, [
|
|
9670
|
-
client,
|
|
9671
|
-
sessionId,
|
|
9672
|
-
open
|
|
9673
|
-
]);
|
|
9880
|
+
function SessionFiles({ client, sessionId, active }) {
|
|
9881
|
+
const { data: files, loading } = useAsync(() => client.listSessionFiles(sessionId), [client, sessionId], { enabled: active && !!sessionId });
|
|
9674
9882
|
return /* @__PURE__ */ jsxs("div", {
|
|
9675
9883
|
className: "pt-3",
|
|
9676
9884
|
children: [/* @__PURE__ */ jsx("h3", {
|
|
@@ -10669,13 +10877,13 @@ function blockHeight(block, m) {
|
|
|
10669
10877
|
return itemHeight(block.item, m);
|
|
10670
10878
|
}
|
|
10671
10879
|
//#endregion
|
|
10672
|
-
//#region src/components/
|
|
10673
|
-
function nearestMember
|
|
10880
|
+
//#region src/components/agent/scrubber-marks.ts
|
|
10881
|
+
function nearestMember(cluster, y) {
|
|
10674
10882
|
let best;
|
|
10675
10883
|
for (const member of cluster.marks) if (!best || Math.abs(member.y - y) < Math.abs(best.y - y)) best = member;
|
|
10676
10884
|
return best?.mark;
|
|
10677
10885
|
}
|
|
10678
|
-
const LANE
|
|
10886
|
+
const LANE = {
|
|
10679
10887
|
user: "l",
|
|
10680
10888
|
subagent: "l",
|
|
10681
10889
|
shell: "l",
|
|
@@ -10687,7 +10895,7 @@ const LANE$1 = {
|
|
|
10687
10895
|
recap: "f",
|
|
10688
10896
|
bookmark: "f"
|
|
10689
10897
|
};
|
|
10690
|
-
const LOUDNESS
|
|
10898
|
+
const LOUDNESS = {
|
|
10691
10899
|
approval: 7,
|
|
10692
10900
|
error: 6,
|
|
10693
10901
|
turnFailed: 5,
|
|
@@ -10699,7 +10907,7 @@ const LOUDNESS$1 = {
|
|
|
10699
10907
|
shell: 1,
|
|
10700
10908
|
recap: 0
|
|
10701
10909
|
};
|
|
10702
|
-
const KIND_NAME
|
|
10910
|
+
const KIND_NAME = {
|
|
10703
10911
|
user: "you",
|
|
10704
10912
|
subagent: "sub-agent",
|
|
10705
10913
|
shell: "shell",
|
|
@@ -10711,14 +10919,10 @@ const KIND_NAME$1 = {
|
|
|
10711
10919
|
recap: "catch-up boundary",
|
|
10712
10920
|
bookmark: "bookmark"
|
|
10713
10921
|
};
|
|
10714
|
-
|
|
10715
|
-
function railScale(railH, totalSize, viewportH) {
|
|
10716
|
-
return totalSize > 0 ? railH / Math.max(totalSize, viewportH) : 0;
|
|
10717
|
-
}
|
|
10718
|
-
function doneLine$1(turn) {
|
|
10922
|
+
function doneLine(turn) {
|
|
10719
10923
|
return `${turn.isError ? turn.subtype : "done"} · ${formatDuration(turn.durationMs)} · ${formatCost(turn.totalCostUsd)}`;
|
|
10720
10924
|
}
|
|
10721
|
-
function excerpt
|
|
10925
|
+
function excerpt(item) {
|
|
10722
10926
|
switch (item.kind) {
|
|
10723
10927
|
case "user":
|
|
10724
10928
|
case "assistant_text":
|
|
@@ -10726,31 +10930,35 @@ function excerpt$1(item) {
|
|
|
10726
10930
|
case "notice": return item.text;
|
|
10727
10931
|
case "shell": return item.shell.command;
|
|
10728
10932
|
case "tool_call": return `${item.name}(${toolInputPreview(item.input)})`;
|
|
10729
|
-
case "turn_result": return doneLine
|
|
10933
|
+
case "turn_result": return doneLine(item);
|
|
10730
10934
|
case "file_delivered": return item.path;
|
|
10731
10935
|
default: return "";
|
|
10732
10936
|
}
|
|
10733
10937
|
}
|
|
10734
|
-
function
|
|
10735
|
-
|
|
10938
|
+
function toolCallFailed(item) {
|
|
10939
|
+
return item.kind === "tool_call" && (item.status === "failed" || item.result?.isError === true);
|
|
10940
|
+
}
|
|
10941
|
+
function rowOutcomes(items, frameParentId, rowIndexFor) {
|
|
10942
|
+
const outcome = /* @__PURE__ */ new Map();
|
|
10943
|
+
items.forEach((item, index) => {
|
|
10944
|
+
if (item.kind === "tool_call" && parentOf(item) === frameParentId) outcome.set(rowIndexFor(index), index);
|
|
10945
|
+
});
|
|
10946
|
+
return new Set(outcome.values());
|
|
10947
|
+
}
|
|
10948
|
+
function buildMarks(items, { frameParentId, bookmarks = [], recapItemIndex, rowIndexFor = (index) => index } = {}) {
|
|
10736
10949
|
const marks = [];
|
|
10737
10950
|
const subagentParents = /* @__PURE__ */ new Set();
|
|
10738
10951
|
for (const item of items) {
|
|
10739
10952
|
const parent = parentOf(item);
|
|
10740
10953
|
if (parent !== void 0) subagentParents.add(parent);
|
|
10741
10954
|
}
|
|
10742
|
-
const
|
|
10743
|
-
items.forEach((item, index) => {
|
|
10744
|
-
if (item.kind !== "tool_call" || parentOf(item) !== frameParentId) return;
|
|
10745
|
-
rowOutcome.set(rowIndexFor(index), index);
|
|
10746
|
-
});
|
|
10955
|
+
const outcomes = rowOutcomes(items, frameParentId, rowIndexFor);
|
|
10747
10956
|
let segment = {};
|
|
10748
10957
|
const closeSegment = () => {
|
|
10749
10958
|
const anchor = segment.response ?? segment.turn;
|
|
10750
10959
|
if (anchor !== void 0) marks.push({
|
|
10751
10960
|
kind: segment.failed ? "turnFailed" : "turn",
|
|
10752
10961
|
itemIndex: anchor,
|
|
10753
|
-
rowIndex: rowIndexFor(anchor),
|
|
10754
10962
|
turnIndex: segment.turn
|
|
10755
10963
|
});
|
|
10756
10964
|
segment = {};
|
|
@@ -10758,15 +10966,13 @@ function buildClusters(props, railH) {
|
|
|
10758
10966
|
items.forEach((item, index) => {
|
|
10759
10967
|
if (item.kind === "tool_call" && subagentParents.has(item.id)) marks.push({
|
|
10760
10968
|
kind: "subagent",
|
|
10761
|
-
itemIndex: index
|
|
10762
|
-
rowIndex: rowIndexFor(index)
|
|
10969
|
+
itemIndex: index
|
|
10763
10970
|
});
|
|
10764
10971
|
if (item.kind === "user" && parentOf(item) === frameParentId) {
|
|
10765
10972
|
closeSegment();
|
|
10766
10973
|
marks.push({
|
|
10767
10974
|
kind: "user",
|
|
10768
|
-
itemIndex: index
|
|
10769
|
-
rowIndex: rowIndexFor(index)
|
|
10975
|
+
itemIndex: index
|
|
10770
10976
|
});
|
|
10771
10977
|
} else if (item.kind === "turn_result") {
|
|
10772
10978
|
segment.turn = index;
|
|
@@ -10774,25 +10980,21 @@ function buildClusters(props, railH) {
|
|
|
10774
10980
|
closeSegment();
|
|
10775
10981
|
} else if (item.kind === "notice" && item.level === "error") marks.push({
|
|
10776
10982
|
kind: "error",
|
|
10777
|
-
itemIndex: index
|
|
10778
|
-
rowIndex: rowIndexFor(index)
|
|
10983
|
+
itemIndex: index
|
|
10779
10984
|
});
|
|
10780
10985
|
else if (item.kind === "shell") marks.push({
|
|
10781
10986
|
kind: "shell",
|
|
10782
|
-
itemIndex: index
|
|
10783
|
-
rowIndex: rowIndexFor(index)
|
|
10987
|
+
itemIndex: index
|
|
10784
10988
|
});
|
|
10785
|
-
else if (
|
|
10989
|
+
else if (toolCallFailed(item) && outcomes.has(index)) marks.push({
|
|
10786
10990
|
kind: "toolFailed",
|
|
10787
|
-
itemIndex: index
|
|
10788
|
-
rowIndex: rowIndexFor(index)
|
|
10991
|
+
itemIndex: index
|
|
10789
10992
|
});
|
|
10790
10993
|
else if (item.kind === "assistant_text" && parentOf(item) === frameParentId) {
|
|
10791
10994
|
if (frameParentId !== void 0) {
|
|
10792
10995
|
marks.push({
|
|
10793
10996
|
kind: "turn",
|
|
10794
|
-
itemIndex: index
|
|
10795
|
-
rowIndex: rowIndexFor(index)
|
|
10997
|
+
itemIndex: index
|
|
10796
10998
|
});
|
|
10797
10999
|
return;
|
|
10798
11000
|
}
|
|
@@ -10802,27 +11004,30 @@ function buildClusters(props, railH) {
|
|
|
10802
11004
|
closeSegment();
|
|
10803
11005
|
for (const index of bookmarks) if (index >= 0 && index < items.length) marks.push({
|
|
10804
11006
|
kind: "bookmark",
|
|
10805
|
-
itemIndex: index
|
|
10806
|
-
rowIndex: rowIndexFor(index)
|
|
11007
|
+
itemIndex: index
|
|
10807
11008
|
});
|
|
10808
|
-
if (
|
|
11009
|
+
if (recapItemIndex !== void 0) marks.push({
|
|
10809
11010
|
kind: "recap",
|
|
10810
|
-
itemIndex:
|
|
10811
|
-
rowIndex: recapRow.rowIndex
|
|
11011
|
+
itemIndex: recapItemIndex
|
|
10812
11012
|
});
|
|
10813
|
-
|
|
11013
|
+
return marks;
|
|
11014
|
+
}
|
|
11015
|
+
function proportionalPlacement(railH, itemCount) {
|
|
11016
|
+
const count = Math.max(1, itemCount);
|
|
11017
|
+
const h = Math.max(2, Math.round(railH / count));
|
|
11018
|
+
return (mark) => ({
|
|
11019
|
+
y: Math.min(Math.max(0, railH - h), Math.round(mark.itemIndex / count * railH)),
|
|
11020
|
+
h
|
|
11021
|
+
});
|
|
11022
|
+
}
|
|
11023
|
+
function clusterMarks(marks, place) {
|
|
10814
11024
|
const lanes = /* @__PURE__ */ new Map();
|
|
10815
11025
|
for (const mark of marks) {
|
|
10816
|
-
const
|
|
10817
|
-
const rowH = sizeOfRow(mark.rowIndex);
|
|
10818
|
-
const h = within ? MIN_MARK$1 : Math.max(MIN_MARK$1, Math.round(rowH * scale));
|
|
10819
|
-
const y = Math.min(Math.max(0, railH - h), Math.round((offsetOfRow(mark.rowIndex) + (within ? within.ordinal / within.count * rowH : 0)) * scale));
|
|
10820
|
-
const lane = LANE$1[mark.kind];
|
|
11026
|
+
const lane = LANE[mark.kind];
|
|
10821
11027
|
const list = lanes.get(lane) ?? [];
|
|
10822
11028
|
list.push({
|
|
10823
11029
|
mark,
|
|
10824
|
-
|
|
10825
|
-
h
|
|
11030
|
+
...place(mark)
|
|
10826
11031
|
});
|
|
10827
11032
|
lanes.set(lane, list);
|
|
10828
11033
|
}
|
|
@@ -10832,7 +11037,7 @@ function buildClusters(props, railH) {
|
|
|
10832
11037
|
let current = null;
|
|
10833
11038
|
for (const { mark, y, h } of list) if (current && y <= current.y + current.h + 1) {
|
|
10834
11039
|
current.h = Math.max(current.h, y + h - current.y);
|
|
10835
|
-
if (LOUDNESS
|
|
11040
|
+
if (LOUDNESS[mark.kind] > LOUDNESS[current.kind]) current.kind = mark.kind;
|
|
10836
11041
|
current.marks.push({
|
|
10837
11042
|
mark,
|
|
10838
11043
|
y
|
|
@@ -10851,74 +11056,130 @@ function buildClusters(props, railH) {
|
|
|
10851
11056
|
clusters.push(current);
|
|
10852
11057
|
}
|
|
10853
11058
|
}
|
|
10854
|
-
|
|
10855
|
-
|
|
11059
|
+
return clusters;
|
|
11060
|
+
}
|
|
11061
|
+
function approvalCluster(railH) {
|
|
11062
|
+
return {
|
|
11063
|
+
lane: LANE.approval,
|
|
10856
11064
|
kind: "approval",
|
|
10857
|
-
y: Math.max(0, railH -
|
|
10858
|
-
h:
|
|
11065
|
+
y: Math.max(0, railH - 2),
|
|
11066
|
+
h: 2,
|
|
10859
11067
|
marks: []
|
|
10860
|
-
}
|
|
10861
|
-
return clusters;
|
|
11068
|
+
};
|
|
10862
11069
|
}
|
|
10863
|
-
|
|
11070
|
+
//#endregion
|
|
11071
|
+
//#region src/components/agent/scrubber-peek.tsx
|
|
11072
|
+
const CARD_PEEK = {
|
|
11073
|
+
excerptClass: "wd-scrub-ex",
|
|
11074
|
+
muted: "muted",
|
|
11075
|
+
danger: "danger",
|
|
11076
|
+
glyph: "muted",
|
|
11077
|
+
detail: "muted"
|
|
11078
|
+
};
|
|
11079
|
+
const TERMINAL_PEEK = {
|
|
11080
|
+
excerptClass: "term-scrub-ex",
|
|
11081
|
+
muted: "faint",
|
|
11082
|
+
danger: "red",
|
|
11083
|
+
glyph: "dim",
|
|
11084
|
+
text: "fg",
|
|
11085
|
+
strong: "bright",
|
|
11086
|
+
detail: "fg",
|
|
11087
|
+
answerGlyph: "● "
|
|
11088
|
+
};
|
|
11089
|
+
function peekContent({ cluster, first, items, pendingApprovals, recapLabel }, skin) {
|
|
10864
11090
|
const more = cluster.marks.length > 1 ? ` · ${cluster.marks.length} marks` : "";
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
}
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
children: [first.kind === "user" ? /* @__PURE__ */ jsx("span", {
|
|
10908
|
-
"data-tone": "dim",
|
|
10909
|
-
children: "❯ "
|
|
10910
|
-
}) : null, excerpt$1(item)]
|
|
10911
|
-
}), failure ? /* @__PURE__ */ jsx("div", {
|
|
10912
|
-
className: "term-scrub-ex",
|
|
10913
|
-
"data-tone": "red",
|
|
10914
|
-
children: failure
|
|
10915
|
-
}) : null] });
|
|
10916
|
-
}
|
|
11091
|
+
const kind = first?.kind ?? cluster.kind;
|
|
11092
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
11093
|
+
"data-tone": skin.muted,
|
|
11094
|
+
children: [KIND_NAME[kind], more]
|
|
11095
|
+
}), cluster.kind === "approval" ? approvalBody(pendingApprovals[0], skin) : kind === "recap" ? recapBody(recapLabel, skin) : markBody(first, items, skin)] });
|
|
11096
|
+
}
|
|
11097
|
+
function approvalBody(request, skin) {
|
|
11098
|
+
if (!request) return null;
|
|
11099
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
11100
|
+
"data-tone": skin.strong,
|
|
11101
|
+
children: permissionPromptModel(request).heading
|
|
11102
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
11103
|
+
className: skin.excerptClass,
|
|
11104
|
+
"data-tone": skin.detail,
|
|
11105
|
+
children: `${request.displayName ?? request.toolName}(${toolInputPreview(request.input)})`
|
|
11106
|
+
})] });
|
|
11107
|
+
}
|
|
11108
|
+
function recapBody(label, skin) {
|
|
11109
|
+
return label === void 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
11110
|
+
"data-tone": skin.muted,
|
|
11111
|
+
children: ["※ ", label]
|
|
11112
|
+
});
|
|
11113
|
+
}
|
|
11114
|
+
function markBody(first, items, skin) {
|
|
11115
|
+
if (!first) return null;
|
|
11116
|
+
const item = items[first.itemIndex];
|
|
11117
|
+
if (first.kind === "turn" || first.kind === "turnFailed") {
|
|
11118
|
+
const turn = first.turnIndex === void 0 ? void 0 : items[first.turnIndex];
|
|
11119
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [item?.kind === "assistant_text" ? /* @__PURE__ */ jsxs("div", {
|
|
11120
|
+
className: skin.excerptClass,
|
|
11121
|
+
"data-tone": skin.text,
|
|
11122
|
+
children: [skin.answerGlyph ? /* @__PURE__ */ jsx("span", {
|
|
11123
|
+
"data-tone": skin.glyph,
|
|
11124
|
+
children: skin.answerGlyph
|
|
11125
|
+
}) : null, item.text]
|
|
11126
|
+
}) : null, turn?.kind === "turn_result" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
11127
|
+
"data-tone": turn.isError ? skin.danger : skin.muted,
|
|
11128
|
+
children: doneLine(turn)
|
|
11129
|
+
}), turn.errors?.map((message, index) => /* @__PURE__ */ jsx("div", {
|
|
11130
|
+
"data-tone": skin.danger,
|
|
11131
|
+
children: message
|
|
11132
|
+
}, index))] }) : null] });
|
|
10917
11133
|
}
|
|
11134
|
+
if (!item) return null;
|
|
11135
|
+
const failure = first.kind === "toolFailed" && item.kind === "tool_call" ? item.result?.text.split("\n").find((line) => line.trim() !== "") : void 0;
|
|
10918
11136
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
11137
|
+
className: skin.excerptClass,
|
|
11138
|
+
"data-tone": first.kind === "error" || first.kind === "toolFailed" ? skin.danger : skin.text,
|
|
11139
|
+
children: [first.kind === "user" ? /* @__PURE__ */ jsx("span", {
|
|
11140
|
+
"data-tone": skin.glyph,
|
|
11141
|
+
children: "❯ "
|
|
11142
|
+
}) : null, excerpt(item)]
|
|
11143
|
+
}), failure ? /* @__PURE__ */ jsx("div", {
|
|
11144
|
+
className: skin.excerptClass,
|
|
11145
|
+
"data-tone": skin.danger,
|
|
11146
|
+
children: failure
|
|
11147
|
+
}) : null] });
|
|
11148
|
+
}
|
|
11149
|
+
//#endregion
|
|
11150
|
+
//#region src/components/terminal/scrubber.tsx
|
|
11151
|
+
function railScale(railH, totalSize, viewportH) {
|
|
11152
|
+
return totalSize > 0 ? railH / Math.max(totalSize, viewportH) : 0;
|
|
11153
|
+
}
|
|
11154
|
+
function buildClusters(props, railH) {
|
|
11155
|
+
const { items, bookmarks, frameParentId, recapRow, pendingApprovals, rowIndexFor, offsetOfRow, sizeOfRow, positionInRow, totalSize, viewportH } = props;
|
|
11156
|
+
const marks = buildMarks(items, {
|
|
11157
|
+
frameParentId,
|
|
11158
|
+
bookmarks,
|
|
11159
|
+
rowIndexFor
|
|
11160
|
+
}).map((mark) => ({
|
|
11161
|
+
...mark,
|
|
11162
|
+
rowIndex: rowIndexFor(mark.itemIndex)
|
|
11163
|
+
}));
|
|
11164
|
+
if (recapRow) marks.push({
|
|
11165
|
+
kind: "recap",
|
|
11166
|
+
itemIndex: -1,
|
|
11167
|
+
rowIndex: recapRow.rowIndex
|
|
11168
|
+
});
|
|
11169
|
+
const scale = railScale(railH, totalSize, viewportH);
|
|
11170
|
+
const clusters = clusterMarks(marks, (mark) => {
|
|
11171
|
+
const rowIndex = mark.rowIndex ?? rowIndexFor(mark.itemIndex);
|
|
11172
|
+
const within = mark.itemIndex >= 0 ? positionInRow?.(mark.itemIndex) : void 0;
|
|
11173
|
+
const rowH = sizeOfRow(rowIndex);
|
|
11174
|
+
const h = within ? 2 : Math.max(2, Math.round(rowH * scale));
|
|
11175
|
+
const offset = offsetOfRow(rowIndex) + (within ? within.ordinal / within.count * rowH : 0);
|
|
11176
|
+
return {
|
|
11177
|
+
y: Math.min(Math.max(0, railH - h), Math.round(offset * scale)),
|
|
11178
|
+
h
|
|
11179
|
+
};
|
|
11180
|
+
});
|
|
11181
|
+
if (pendingApprovals.length > 0) clusters.push(approvalCluster(railH));
|
|
11182
|
+
return clusters;
|
|
10922
11183
|
}
|
|
10923
11184
|
function TerminalScrubber(props) {
|
|
10924
11185
|
const { scrollOffset, viewportH, totalSize, onJumpToRow, interactive, fontSize, lineHeight } = props;
|
|
@@ -10993,12 +11254,12 @@ function TerminalScrubber(props) {
|
|
|
10993
11254
|
stick.scrollToBottom();
|
|
10994
11255
|
return;
|
|
10995
11256
|
}
|
|
10996
|
-
const mark = nearestMember
|
|
10997
|
-
if (mark) onJumpToRow(mark.rowIndex);
|
|
11257
|
+
const mark = nearestMember(cluster, railY(clientY));
|
|
11258
|
+
if (mark) onJumpToRow(mark.rowIndex ?? props.rowIndexFor(mark.itemIndex));
|
|
10998
11259
|
};
|
|
10999
11260
|
const showPeek = (cluster, clientY) => {
|
|
11000
11261
|
const y = railY(clientY);
|
|
11001
|
-
const mark = nearestMember
|
|
11262
|
+
const mark = nearestMember(cluster, y);
|
|
11002
11263
|
setPeek((previous) => previous && previous.cluster === cluster && previous.mark === mark ? previous : {
|
|
11003
11264
|
cluster,
|
|
11004
11265
|
mark,
|
|
@@ -11070,243 +11331,29 @@ function TerminalScrubber(props) {
|
|
|
11070
11331
|
...interactive ? {
|
|
11071
11332
|
onPointerEnter: (event) => showPeek(cluster, event.clientY),
|
|
11072
11333
|
onPointerMove: (event) => {
|
|
11073
|
-
if (!drag.current) showPeek(cluster, event.clientY);
|
|
11074
|
-
},
|
|
11075
|
-
onPointerLeave: () => setPeek(null)
|
|
11076
|
-
} : null
|
|
11077
|
-
}, index)),
|
|
11078
|
-
peek ? /* @__PURE__ */ jsx("div", {
|
|
11079
|
-
ref: peekRef,
|
|
11080
|
-
className: "term-scrub-peek",
|
|
11081
|
-
style: { top: peek.y },
|
|
11082
|
-
children: peekContent
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11088
|
-
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
for (const member of cluster.marks) if (!best || Math.abs(member.y - y) < Math.abs(best.y - y)) best = member;
|
|
11093
|
-
return best?.mark;
|
|
11094
|
-
}
|
|
11095
|
-
const LANE = {
|
|
11096
|
-
user: "l",
|
|
11097
|
-
subagent: "l",
|
|
11098
|
-
shell: "l",
|
|
11099
|
-
turn: "r",
|
|
11100
|
-
turnFailed: "r",
|
|
11101
|
-
toolFailed: "r",
|
|
11102
|
-
error: "r",
|
|
11103
|
-
approval: "f",
|
|
11104
|
-
recap: "f",
|
|
11105
|
-
bookmark: "f"
|
|
11106
|
-
};
|
|
11107
|
-
const LOUDNESS = {
|
|
11108
|
-
approval: 7,
|
|
11109
|
-
error: 6,
|
|
11110
|
-
turnFailed: 5,
|
|
11111
|
-
toolFailed: 4,
|
|
11112
|
-
user: 3,
|
|
11113
|
-
turn: 2,
|
|
11114
|
-
bookmark: 1,
|
|
11115
|
-
subagent: 1,
|
|
11116
|
-
shell: 1,
|
|
11117
|
-
recap: 0
|
|
11118
|
-
};
|
|
11119
|
-
const KIND_NAME = {
|
|
11120
|
-
user: "you",
|
|
11121
|
-
subagent: "sub-agent",
|
|
11122
|
-
shell: "shell",
|
|
11123
|
-
turn: "response · turn end",
|
|
11124
|
-
turnFailed: "turn failed",
|
|
11125
|
-
toolFailed: "tool failed",
|
|
11126
|
-
error: "error",
|
|
11127
|
-
approval: "pending approval",
|
|
11128
|
-
recap: "catch-up boundary",
|
|
11129
|
-
bookmark: "bookmark"
|
|
11130
|
-
};
|
|
11131
|
-
function doneLine(turn) {
|
|
11132
|
-
return `${turn.isError ? turn.subtype : "done"} · ${formatDuration(turn.durationMs)} · ${formatCost(turn.totalCostUsd)}`;
|
|
11133
|
-
}
|
|
11134
|
-
function excerpt(item) {
|
|
11135
|
-
switch (item.kind) {
|
|
11136
|
-
case "user":
|
|
11137
|
-
case "assistant_text":
|
|
11138
|
-
case "thinking":
|
|
11139
|
-
case "notice": return item.text;
|
|
11140
|
-
case "shell": return item.shell.command;
|
|
11141
|
-
case "tool_call": return `${item.name}(${toolInputPreview(item.input)})`;
|
|
11142
|
-
case "turn_result": return doneLine(item);
|
|
11143
|
-
case "file_delivered": return item.path;
|
|
11144
|
-
default: return "";
|
|
11145
|
-
}
|
|
11146
|
-
}
|
|
11147
|
-
function buildMarks(items, { frameParentId, bookmarks = [], recapItemIndex } = {}) {
|
|
11148
|
-
const marks = [];
|
|
11149
|
-
const subagentParents = /* @__PURE__ */ new Set();
|
|
11150
|
-
for (const item of items) {
|
|
11151
|
-
const parent = parentOf(item);
|
|
11152
|
-
if (parent !== void 0) subagentParents.add(parent);
|
|
11153
|
-
}
|
|
11154
|
-
let segment = {};
|
|
11155
|
-
const closeSegment = () => {
|
|
11156
|
-
const anchor = segment.response ?? segment.turn;
|
|
11157
|
-
if (anchor !== void 0) marks.push({
|
|
11158
|
-
kind: segment.failed ? "turnFailed" : "turn",
|
|
11159
|
-
itemIndex: anchor,
|
|
11160
|
-
turnIndex: segment.turn
|
|
11161
|
-
});
|
|
11162
|
-
segment = {};
|
|
11163
|
-
};
|
|
11164
|
-
items.forEach((item, index) => {
|
|
11165
|
-
if (item.kind === "tool_call" && subagentParents.has(item.id)) marks.push({
|
|
11166
|
-
kind: "subagent",
|
|
11167
|
-
itemIndex: index
|
|
11168
|
-
});
|
|
11169
|
-
if (item.kind === "user" && parentOf(item) === frameParentId) {
|
|
11170
|
-
closeSegment();
|
|
11171
|
-
marks.push({
|
|
11172
|
-
kind: "user",
|
|
11173
|
-
itemIndex: index
|
|
11174
|
-
});
|
|
11175
|
-
} else if (item.kind === "turn_result") {
|
|
11176
|
-
segment.turn = index;
|
|
11177
|
-
segment.failed = item.isError;
|
|
11178
|
-
closeSegment();
|
|
11179
|
-
} else if (item.kind === "notice" && item.level === "error") marks.push({
|
|
11180
|
-
kind: "error",
|
|
11181
|
-
itemIndex: index
|
|
11182
|
-
});
|
|
11183
|
-
else if (item.kind === "shell") marks.push({
|
|
11184
|
-
kind: "shell",
|
|
11185
|
-
itemIndex: index
|
|
11186
|
-
});
|
|
11187
|
-
else if (item.kind === "tool_call" && parentOf(item) === frameParentId && (item.status === "failed" || item.result?.isError === true)) marks.push({
|
|
11188
|
-
kind: "toolFailed",
|
|
11189
|
-
itemIndex: index
|
|
11190
|
-
});
|
|
11191
|
-
else if (item.kind === "assistant_text" && parentOf(item) === frameParentId) {
|
|
11192
|
-
if (frameParentId !== void 0) {
|
|
11193
|
-
marks.push({
|
|
11194
|
-
kind: "turn",
|
|
11195
|
-
itemIndex: index
|
|
11196
|
-
});
|
|
11197
|
-
return;
|
|
11198
|
-
}
|
|
11199
|
-
segment.response = index;
|
|
11200
|
-
}
|
|
11201
|
-
});
|
|
11202
|
-
closeSegment();
|
|
11203
|
-
for (const index of bookmarks) if (index >= 0 && index < items.length) marks.push({
|
|
11204
|
-
kind: "bookmark",
|
|
11205
|
-
itemIndex: index
|
|
11206
|
-
});
|
|
11207
|
-
if (recapItemIndex !== void 0) marks.push({
|
|
11208
|
-
kind: "recap",
|
|
11209
|
-
itemIndex: recapItemIndex
|
|
11334
|
+
if (!drag.current) showPeek(cluster, event.clientY);
|
|
11335
|
+
},
|
|
11336
|
+
onPointerLeave: () => setPeek(null)
|
|
11337
|
+
} : null
|
|
11338
|
+
}, index)),
|
|
11339
|
+
peek ? /* @__PURE__ */ jsx("div", {
|
|
11340
|
+
ref: peekRef,
|
|
11341
|
+
className: "term-scrub-peek",
|
|
11342
|
+
style: { top: peek.y },
|
|
11343
|
+
children: peekContent({
|
|
11344
|
+
cluster: peek.cluster,
|
|
11345
|
+
first: peek.mark,
|
|
11346
|
+
items: props.items,
|
|
11347
|
+
pendingApprovals: props.pendingApprovals,
|
|
11348
|
+
recapLabel: props.recapRow?.label
|
|
11349
|
+
}, TERMINAL_PEEK)
|
|
11350
|
+
}) : null
|
|
11351
|
+
]
|
|
11352
|
+
})
|
|
11210
11353
|
});
|
|
11211
|
-
return marks;
|
|
11212
|
-
}
|
|
11213
|
-
function clusterMarks(marks, railH, itemCount) {
|
|
11214
|
-
const count = Math.max(1, itemCount);
|
|
11215
|
-
const h = Math.max(2, Math.round(railH / count));
|
|
11216
|
-
const lanes = /* @__PURE__ */ new Map();
|
|
11217
|
-
for (const mark of marks) {
|
|
11218
|
-
const y = Math.min(Math.max(0, railH - h), Math.round(mark.itemIndex / count * railH));
|
|
11219
|
-
const lane = LANE[mark.kind];
|
|
11220
|
-
const list = lanes.get(lane) ?? [];
|
|
11221
|
-
list.push({
|
|
11222
|
-
mark,
|
|
11223
|
-
y
|
|
11224
|
-
});
|
|
11225
|
-
lanes.set(lane, list);
|
|
11226
|
-
}
|
|
11227
|
-
const clusters = [];
|
|
11228
|
-
for (const [lane, list] of lanes) {
|
|
11229
|
-
list.sort((a, b) => a.y - b.y);
|
|
11230
|
-
let current = null;
|
|
11231
|
-
for (const { mark, y } of list) if (current && y <= current.y + current.h + 1) {
|
|
11232
|
-
current.h = Math.max(current.h, y + h - current.y);
|
|
11233
|
-
if (LOUDNESS[mark.kind] > LOUDNESS[current.kind]) current.kind = mark.kind;
|
|
11234
|
-
current.marks.push({
|
|
11235
|
-
mark,
|
|
11236
|
-
y
|
|
11237
|
-
});
|
|
11238
|
-
} else {
|
|
11239
|
-
current = {
|
|
11240
|
-
lane,
|
|
11241
|
-
kind: mark.kind,
|
|
11242
|
-
y,
|
|
11243
|
-
h,
|
|
11244
|
-
marks: [{
|
|
11245
|
-
mark,
|
|
11246
|
-
y
|
|
11247
|
-
}]
|
|
11248
|
-
};
|
|
11249
|
-
clusters.push(current);
|
|
11250
|
-
}
|
|
11251
|
-
}
|
|
11252
|
-
return clusters;
|
|
11253
|
-
}
|
|
11254
|
-
function approvalCluster(railH) {
|
|
11255
|
-
return {
|
|
11256
|
-
lane: LANE.approval,
|
|
11257
|
-
kind: "approval",
|
|
11258
|
-
y: Math.max(0, railH - 2),
|
|
11259
|
-
h: 2,
|
|
11260
|
-
marks: []
|
|
11261
|
-
};
|
|
11262
11354
|
}
|
|
11263
11355
|
//#endregion
|
|
11264
11356
|
//#region src/components/agent/Scrubber.tsx
|
|
11265
|
-
function peekContent(cluster, first, items, pendingApprovals) {
|
|
11266
|
-
const more = cluster.marks.length > 1 ? ` · ${cluster.marks.length} marks` : "";
|
|
11267
|
-
let body = null;
|
|
11268
|
-
if (cluster.kind === "approval") {
|
|
11269
|
-
const request = pendingApprovals[0];
|
|
11270
|
-
body = request ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", { children: request.title ?? "Permission required" }), /* @__PURE__ */ jsx("div", {
|
|
11271
|
-
className: "wd-scrub-ex",
|
|
11272
|
-
"data-tone": "muted",
|
|
11273
|
-
children: `${request.displayName ?? request.toolName}(${toolInputPreview(request.input)})`
|
|
11274
|
-
})] }) : null;
|
|
11275
|
-
} else if (first && first.kind !== "recap") {
|
|
11276
|
-
const item = items[first.itemIndex];
|
|
11277
|
-
if (first.kind === "turn" || first.kind === "turnFailed") {
|
|
11278
|
-
const turn = first.turnIndex === void 0 ? void 0 : items[first.turnIndex];
|
|
11279
|
-
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [item?.kind === "assistant_text" ? /* @__PURE__ */ jsx("div", {
|
|
11280
|
-
className: "wd-scrub-ex",
|
|
11281
|
-
children: item.text
|
|
11282
|
-
}) : null, turn?.kind === "turn_result" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
11283
|
-
"data-tone": turn.isError ? "danger" : "muted",
|
|
11284
|
-
children: doneLine(turn)
|
|
11285
|
-
}), turn.errors?.map((message, index) => /* @__PURE__ */ jsx("div", {
|
|
11286
|
-
"data-tone": "danger",
|
|
11287
|
-
children: message
|
|
11288
|
-
}, index))] }) : null] });
|
|
11289
|
-
} else if (item) {
|
|
11290
|
-
const failure = first.kind === "toolFailed" && item.kind === "tool_call" ? item.result?.text.split("\n").find((line) => line.trim() !== "") : void 0;
|
|
11291
|
-
body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
11292
|
-
className: "wd-scrub-ex",
|
|
11293
|
-
"data-tone": first.kind === "error" || first.kind === "toolFailed" ? "danger" : void 0,
|
|
11294
|
-
children: [first.kind === "user" ? /* @__PURE__ */ jsx("span", {
|
|
11295
|
-
"data-tone": "muted",
|
|
11296
|
-
children: "❯ "
|
|
11297
|
-
}) : null, excerpt(item)]
|
|
11298
|
-
}), failure ? /* @__PURE__ */ jsx("div", {
|
|
11299
|
-
className: "wd-scrub-ex",
|
|
11300
|
-
"data-tone": "danger",
|
|
11301
|
-
children: failure
|
|
11302
|
-
}) : null] });
|
|
11303
|
-
}
|
|
11304
|
-
}
|
|
11305
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
11306
|
-
"data-tone": "muted",
|
|
11307
|
-
children: [KIND_NAME[first?.kind ?? cluster.kind], more]
|
|
11308
|
-
}), body] });
|
|
11309
|
-
}
|
|
11310
11357
|
function Scrubber({ items, pendingApprovals, recapItemIndex, bookmarks, frameParentId, interactive = false, onJumpToItem, className }) {
|
|
11311
11358
|
const railRef = useRef(null);
|
|
11312
11359
|
const peekRef = useRef(null);
|
|
@@ -11336,7 +11383,7 @@ function Scrubber({ items, pendingApprovals, recapItemIndex, bookmarks, framePar
|
|
|
11336
11383
|
frameParentId,
|
|
11337
11384
|
bookmarks,
|
|
11338
11385
|
recapItemIndex
|
|
11339
|
-
}), railH, items.length);
|
|
11386
|
+
}), proportionalPlacement(railH, items.length));
|
|
11340
11387
|
if (pendingApprovals.length > 0) built.push(approvalCluster(railH));
|
|
11341
11388
|
return built;
|
|
11342
11389
|
}, [
|
|
@@ -11388,7 +11435,12 @@ function Scrubber({ items, pendingApprovals, recapItemIndex, bookmarks, framePar
|
|
|
11388
11435
|
ref: peekRef,
|
|
11389
11436
|
className: "wd-scrub-peek",
|
|
11390
11437
|
style: { top: peek.y },
|
|
11391
|
-
children: peekContent(
|
|
11438
|
+
children: peekContent({
|
|
11439
|
+
cluster: peek.cluster,
|
|
11440
|
+
first: peek.mark,
|
|
11441
|
+
items,
|
|
11442
|
+
pendingApprovals
|
|
11443
|
+
}, CARD_PEEK)
|
|
11392
11444
|
}) : null]
|
|
11393
11445
|
});
|
|
11394
11446
|
}
|
|
@@ -11694,53 +11746,6 @@ function TaskRow({ block, fileUrl, onOpenSubagent }) {
|
|
|
11694
11746
|
children: row
|
|
11695
11747
|
});
|
|
11696
11748
|
}
|
|
11697
|
-
function useRunStart$1(status) {
|
|
11698
|
-
const running = status === "running" || status === "starting";
|
|
11699
|
-
const [startedAt, setStartedAt] = useState(void 0);
|
|
11700
|
-
useEffect(() => {
|
|
11701
|
-
setStartedAt((previous) => running ? previous ?? Date.now() : void 0);
|
|
11702
|
-
}, [running]);
|
|
11703
|
-
return running ? startedAt : void 0;
|
|
11704
|
-
}
|
|
11705
|
-
function working(state) {
|
|
11706
|
-
if (state.status !== "running" && state.status !== "starting") return false;
|
|
11707
|
-
const last = state.items.at(-1);
|
|
11708
|
-
if (!last) return true;
|
|
11709
|
-
if (last.kind === "assistant_text" && last.streaming) return false;
|
|
11710
|
-
if (last.kind === "thinking" && last.id === "streaming-thinking") return false;
|
|
11711
|
-
return true;
|
|
11712
|
-
}
|
|
11713
|
-
function TerminalTranscript({ state, fileUrl, fontSize, lineHeight, affordances, className }) {
|
|
11714
|
-
const runStartedAt = useRunStart$1(state.status);
|
|
11715
|
-
const blocks = useMemo(() => terminalBlocks(state.items), [state.items]);
|
|
11716
|
-
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
11717
|
-
fontSize,
|
|
11718
|
-
lineHeight,
|
|
11719
|
-
affordances,
|
|
11720
|
-
bleed: "1ch",
|
|
11721
|
-
className: cn("term-transcript", className),
|
|
11722
|
-
children: /* @__PURE__ */ jsxs(PeerNamesProvider, {
|
|
11723
|
-
items: state.items,
|
|
11724
|
-
children: [blocks.map((block, index) => {
|
|
11725
|
-
const next = blocks[index + 1];
|
|
11726
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && blockNeedsBlank(blocks[index - 1], block) ? /* @__PURE__ */ jsx(Blank, {}) : null, /* @__PURE__ */ jsx(ActionPlacementProvider, {
|
|
11727
|
-
value: next && !blockNeedsBlank(block, next) ? "inline" : "below",
|
|
11728
|
-
children: "run" in block ? /* @__PURE__ */ jsx(RunRow, { items: block.run }) : "item" in block ? /* @__PURE__ */ jsx(TerminalItemView, {
|
|
11729
|
-
item: block.item,
|
|
11730
|
-
fileUrl
|
|
11731
|
-
}) : /* @__PURE__ */ jsx(TaskRow, {
|
|
11732
|
-
block,
|
|
11733
|
-
fileUrl
|
|
11734
|
-
})
|
|
11735
|
-
})] }, block.key);
|
|
11736
|
-
}), working(state) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [state.items.length > 0 ? /* @__PURE__ */ jsx(Blank, {}) : null, /* @__PURE__ */ jsx(WorkingRow, {
|
|
11737
|
-
label: state.status === "starting" ? "Starting…" : "Working…",
|
|
11738
|
-
startedAt: runStartedAt,
|
|
11739
|
-
tokens: state.contextUsage?.totalTokens
|
|
11740
|
-
})] }) : null]
|
|
11741
|
-
})
|
|
11742
|
-
});
|
|
11743
|
-
}
|
|
11744
11749
|
//#endregion
|
|
11745
11750
|
//#region src/components/agent/FileCard.tsx
|
|
11746
11751
|
function FileCard({ item, href, className }) {
|
|
@@ -12188,34 +12193,13 @@ function ToolCard({ item, hostImage }) {
|
|
|
12188
12193
|
function ShellCard({ item }) {
|
|
12189
12194
|
const [open, setOpen] = useState(false);
|
|
12190
12195
|
const actions = useShellActions();
|
|
12191
|
-
const running = item.shell.status === "running";
|
|
12192
12196
|
const failed = shellFailed(item);
|
|
12193
12197
|
const lines = shellBodyLines(item, open);
|
|
12194
12198
|
const footer = shellFooterText(item, open, lines.length);
|
|
12195
12199
|
const shellId = item.shell.id;
|
|
12196
|
-
|
|
12197
|
-
useEffect(() => {
|
|
12198
|
-
if (running) verify(shellId);
|
|
12199
|
-
}, [
|
|
12200
|
-
running,
|
|
12201
|
-
shellId,
|
|
12202
|
-
verify
|
|
12203
|
-
]);
|
|
12200
|
+
useVerifyRunning(item);
|
|
12204
12201
|
return /* @__PURE__ */ jsx(WithActions, {
|
|
12205
|
-
actions: /* @__PURE__ */
|
|
12206
|
-
actions.open ? /* @__PURE__ */ jsx(OpenShellAction, { onOpen: () => actions.open?.(shellId) }) : null,
|
|
12207
|
-
actions.agentWrite && shellGrantable(item.shell) ? /* @__PURE__ */ jsx(AgentWriteAction, {
|
|
12208
|
-
granted: item.shell.agentWrite === true,
|
|
12209
|
-
label: shellAgentWriteLabel(item.shell),
|
|
12210
|
-
onToggle: () => void actions.agentWrite?.(shellId, item.shell.agentWrite !== true)
|
|
12211
|
-
}) : null,
|
|
12212
|
-
running ? /* @__PURE__ */ jsx(KillShellAction, { onKill: () => void actions.kill(shellId) }) : null,
|
|
12213
|
-
/* @__PURE__ */ jsx(BookmarkAction, { id: item.id }),
|
|
12214
|
-
/* @__PURE__ */ jsx(CopyAction, {
|
|
12215
|
-
text: item.shell.command,
|
|
12216
|
-
label: "Copy command"
|
|
12217
|
-
})
|
|
12218
|
-
] }),
|
|
12202
|
+
actions: /* @__PURE__ */ jsx(ShellItemActions, { item }),
|
|
12219
12203
|
children: /* @__PURE__ */ jsxs("div", {
|
|
12220
12204
|
"data-slot": "shell",
|
|
12221
12205
|
className: "overflow-hidden rounded-md border border-border bg-surface",
|
|
@@ -12781,6 +12765,12 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
12781
12765
|
})
|
|
12782
12766
|
});
|
|
12783
12767
|
}
|
|
12768
|
+
function TerminalTranscript(props) {
|
|
12769
|
+
return /* @__PURE__ */ jsx(Transcript, {
|
|
12770
|
+
...props,
|
|
12771
|
+
variant: "terminal"
|
|
12772
|
+
});
|
|
12773
|
+
}
|
|
12784
12774
|
//#endregion
|
|
12785
12775
|
//#region src/lib/session-cost.ts
|
|
12786
12776
|
const GAP_SHARE = .02;
|
|
@@ -13080,20 +13070,6 @@ function UsageDialog({ rateLimits, subscriptionType, engine, totalCostUsd, costU
|
|
|
13080
13070
|
}
|
|
13081
13071
|
//#endregion
|
|
13082
13072
|
//#region src/components/agent/SessionPanel.tsx
|
|
13083
|
-
function PromptSurface({ terminal, metrics, affordances, children }) {
|
|
13084
|
-
if (!terminal) return /* @__PURE__ */ jsx("div", {
|
|
13085
|
-
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] flex-col gap-2",
|
|
13086
|
-
children
|
|
13087
|
-
});
|
|
13088
|
-
return /* @__PURE__ */ jsx(TerminalSurface, {
|
|
13089
|
-
fontSize: metrics?.fontSize,
|
|
13090
|
-
lineHeight: metrics?.lineHeight,
|
|
13091
|
-
affordances,
|
|
13092
|
-
bleed: "1ch",
|
|
13093
|
-
className: "term-transcript",
|
|
13094
|
-
children
|
|
13095
|
-
});
|
|
13096
|
-
}
|
|
13097
13073
|
const INTERACTIVE = [
|
|
13098
13074
|
"button",
|
|
13099
13075
|
"a",
|
|
@@ -13109,17 +13085,49 @@ const INTERACTIVE = [
|
|
|
13109
13085
|
"[role=\"radio\"]",
|
|
13110
13086
|
"[role=\"tab\"]"
|
|
13111
13087
|
].join(",");
|
|
13088
|
+
const PANEL_ITEMS = [
|
|
13089
|
+
{
|
|
13090
|
+
panel: "context",
|
|
13091
|
+
label: "Context",
|
|
13092
|
+
Icon: ChartPie
|
|
13093
|
+
},
|
|
13094
|
+
{
|
|
13095
|
+
panel: "usage",
|
|
13096
|
+
label: "Usage",
|
|
13097
|
+
Icon: Gauge
|
|
13098
|
+
},
|
|
13099
|
+
{
|
|
13100
|
+
panel: "info",
|
|
13101
|
+
label: "Session info",
|
|
13102
|
+
Icon: Info
|
|
13103
|
+
},
|
|
13104
|
+
{
|
|
13105
|
+
panel: "mcp",
|
|
13106
|
+
label: "MCP servers",
|
|
13107
|
+
Icon: Plug
|
|
13108
|
+
},
|
|
13109
|
+
{
|
|
13110
|
+
panel: "skills",
|
|
13111
|
+
label: "Skills",
|
|
13112
|
+
Icon: Sparkles
|
|
13113
|
+
},
|
|
13114
|
+
{
|
|
13115
|
+
panel: "files",
|
|
13116
|
+
label: "Project files",
|
|
13117
|
+
Icon: FolderTree
|
|
13118
|
+
}
|
|
13119
|
+
];
|
|
13112
13120
|
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptFont = "sans", affordances, terminalMetrics, scrubber = false, bookmarks, peerMentions = true, onToggleBookmark, reveal, subagents, shells, openSubagent, onSubagentChange, openShell, onShellChange, stickyPrompt = false, controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, approvalPrompts, toolHost, clientTools, cacheTranscript, emptyState, onLinkClick, onOpenFile, fontSize, className }) {
|
|
13113
|
-
const
|
|
13114
|
-
|
|
13121
|
+
const cell = {
|
|
13122
|
+
fontSize: terminalMetrics?.fontSize ?? fontSize,
|
|
13123
|
+
lineHeight: terminalMetrics?.lineHeight ?? (fontSize !== void 0 ? Math.round(fontSize * (18 / 13)) : void 0)
|
|
13124
|
+
};
|
|
13115
13125
|
const external = panelSurface === "external";
|
|
13116
13126
|
const statusExternal = statusSurface === "external";
|
|
13117
13127
|
const controlsInStatus = controlsSurface === "status" && !statusExternal;
|
|
13118
13128
|
const controlsExternal = controlsSurface === "external" || controlsInStatus;
|
|
13119
13129
|
const [protocolError, setProtocolError] = useState(void 0);
|
|
13120
13130
|
const [panel, setPanel] = useState();
|
|
13121
|
-
const [showCompletedTasks, setShowCompletedTasks] = useState(false);
|
|
13122
|
-
const [taskReveal, setTaskReveal] = useState();
|
|
13123
13131
|
const { state, connection, replaying, protocolMismatch, shell, pricing, models, effectiveModel, handle, send, runShell, approve, deny, interrupt, clearContext, setModel, setPermissionMode, reconnectNow, loadFullResult, loadShellOutput, verifyShell, killShell, setShellAgentWrite } = useClaudeSession(client, sessionId, {
|
|
13124
13132
|
onProtocolError: setProtocolError,
|
|
13125
13133
|
cacheTranscript
|
|
@@ -13160,12 +13168,7 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13160
13168
|
if (returnReveal && shellReturnReveal) return returnReveal.nonce >= shellReturnReveal.nonce ? returnReveal : shellReturnReveal;
|
|
13161
13169
|
return returnReveal ?? shellReturnReveal;
|
|
13162
13170
|
}, [returnReveal, shellReturnReveal]);
|
|
13163
|
-
const
|
|
13164
|
-
useEffect(() => {
|
|
13165
|
-
setCaughtUp(false);
|
|
13166
|
-
}, [sessionId]);
|
|
13167
|
-
const [catchUpMark] = useState(unseen);
|
|
13168
|
-
const catchUp = caughtUp ? void 0 : catchUpMark;
|
|
13171
|
+
const { mark: catchUp, dismiss: dismissCatchUp } = useCatchUp(sessionId, unseen);
|
|
13169
13172
|
const newCount = catchUp ? Math.max(0, state.items.length - catchUp.itemCount) : 0;
|
|
13170
13173
|
const openPanel = useCallback((target) => {
|
|
13171
13174
|
if (external) onOpenPanel?.(target);
|
|
@@ -13209,70 +13212,17 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13209
13212
|
subagents,
|
|
13210
13213
|
state.session?.subagents
|
|
13211
13214
|
]);
|
|
13212
|
-
const
|
|
13213
|
-
|
|
13214
|
-
|
|
13215
|
-
|
|
13216
|
-
|
|
13217
|
-
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
const wanted = args.split(/\s+/)[0];
|
|
13222
|
-
if (!wanted) return false;
|
|
13223
|
-
setModel(wanted);
|
|
13224
|
-
return true;
|
|
13225
|
-
}
|
|
13226
|
-
});
|
|
13227
|
-
if (modes.length > 1) built.push({
|
|
13228
|
-
name: "permissions",
|
|
13229
|
-
description: `Set the permission mode (${modes.join(", ")})`,
|
|
13230
|
-
argumentHint: "<mode>",
|
|
13231
|
-
requiresArgs: true,
|
|
13232
|
-
run: (args) => {
|
|
13233
|
-
const wanted = args.split(/\s+/)[0];
|
|
13234
|
-
if (!modes.includes(wanted)) return false;
|
|
13235
|
-
setPermissionMode(wanted);
|
|
13236
|
-
return true;
|
|
13237
|
-
}
|
|
13238
|
-
});
|
|
13239
|
-
if (capabilities.clearContext) built.push({
|
|
13240
|
-
name: "clear",
|
|
13241
|
-
description: "Clear the conversation - the session keeps running and the old one stays resumable",
|
|
13242
|
-
run: () => {
|
|
13243
|
-
clearContext();
|
|
13244
|
-
return true;
|
|
13245
|
-
}
|
|
13246
|
-
});
|
|
13247
|
-
if (capabilities.mcpStatus) built.push({
|
|
13248
|
-
name: "mcp",
|
|
13249
|
-
description: "MCP servers and their status",
|
|
13250
|
-
run: () => (openPanel("mcp"), true)
|
|
13251
|
-
});
|
|
13252
|
-
if (capabilities.contextUsage) built.push({
|
|
13253
|
-
name: "context",
|
|
13254
|
-
description: "Context window usage",
|
|
13255
|
-
run: () => (openPanel("context"), true)
|
|
13256
|
-
});
|
|
13257
|
-
built.push({
|
|
13258
|
-
name: "status",
|
|
13259
|
-
description: "Session details",
|
|
13260
|
-
run: () => (openPanel("info"), true)
|
|
13261
|
-
});
|
|
13262
|
-
if (capabilities.rateLimits) built.push({
|
|
13263
|
-
name: "usage",
|
|
13264
|
-
description: "Rate limits and spend",
|
|
13265
|
-
run: () => (openPanel("usage"), true)
|
|
13266
|
-
});
|
|
13267
|
-
if (capabilities.skillsList) built.push({
|
|
13268
|
-
name: "skills",
|
|
13269
|
-
description: "Browse the skills this session can use",
|
|
13270
|
-
run: () => (openPanel("skills"), true)
|
|
13271
|
-
});
|
|
13272
|
-
return built;
|
|
13273
|
-
}, [
|
|
13215
|
+
const hasModels = models.length > 0;
|
|
13216
|
+
const clientCommands = useMemo(() => buildClientCommands({
|
|
13217
|
+
capabilities,
|
|
13218
|
+
hasModels,
|
|
13219
|
+
setModel,
|
|
13220
|
+
setPermissionMode,
|
|
13221
|
+
clearContext,
|
|
13222
|
+
openPanel
|
|
13223
|
+
}), [
|
|
13274
13224
|
capabilities,
|
|
13275
|
-
|
|
13225
|
+
hasModels,
|
|
13276
13226
|
openPanel,
|
|
13277
13227
|
clearContext,
|
|
13278
13228
|
setModel,
|
|
@@ -13293,45 +13243,31 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13293
13243
|
onVitalsRef.current = onVitals;
|
|
13294
13244
|
const vitalsModel = effectiveModel ?? state.model;
|
|
13295
13245
|
const permissionModes = useMemo(() => permissionModeChoices(capabilities.permissionModes, state.session?.canBypassPermissions), [capabilities.permissionModes, state.session?.canBypassPermissions]);
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
status: state.status,
|
|
13299
|
-
connection,
|
|
13300
|
-
engine: state.engine,
|
|
13301
|
-
capabilities: state.capabilities,
|
|
13302
|
-
model: vitalsModel,
|
|
13303
|
-
models,
|
|
13304
|
-
permissionMode: state.permissionMode,
|
|
13305
|
-
permissionModes,
|
|
13306
|
-
skills: state.skills,
|
|
13307
|
-
composerCommands,
|
|
13308
|
-
cwd: state.cwd,
|
|
13309
|
-
contextUsage: state.contextUsage,
|
|
13310
|
-
tasks,
|
|
13311
|
-
rateLimits,
|
|
13312
|
-
rateLimitsUpdatedAt: usageUpdatedAt,
|
|
13313
|
-
itemCount: state.items.length,
|
|
13314
|
-
totalCostUsd: state.totalCostUsd
|
|
13315
|
-
});
|
|
13316
|
-
}, [
|
|
13317
|
-
state.status,
|
|
13246
|
+
const vitals = {
|
|
13247
|
+
status: state.status,
|
|
13318
13248
|
connection,
|
|
13319
|
-
state.engine,
|
|
13320
|
-
state.capabilities,
|
|
13321
|
-
vitalsModel,
|
|
13249
|
+
engine: state.engine,
|
|
13250
|
+
capabilities: state.capabilities,
|
|
13251
|
+
model: vitalsModel,
|
|
13322
13252
|
models,
|
|
13323
|
-
state.permissionMode,
|
|
13253
|
+
permissionMode: state.permissionMode,
|
|
13324
13254
|
permissionModes,
|
|
13325
|
-
state.skills,
|
|
13255
|
+
skills: state.skills,
|
|
13326
13256
|
composerCommands,
|
|
13327
|
-
state.cwd,
|
|
13328
|
-
state.contextUsage,
|
|
13257
|
+
cwd: state.cwd,
|
|
13258
|
+
contextUsage: state.contextUsage,
|
|
13329
13259
|
tasks,
|
|
13330
13260
|
rateLimits,
|
|
13331
|
-
usageUpdatedAt,
|
|
13332
|
-
state.items.length,
|
|
13333
|
-
state.totalCostUsd
|
|
13334
|
-
|
|
13261
|
+
rateLimitsUpdatedAt: usageUpdatedAt,
|
|
13262
|
+
itemCount: state.items.length,
|
|
13263
|
+
totalCostUsd: state.totalCostUsd
|
|
13264
|
+
};
|
|
13265
|
+
const lastVitals = useRef(void 0);
|
|
13266
|
+
useEffect(() => {
|
|
13267
|
+
if (lastVitals.current && sameVitals(lastVitals.current, vitals)) return;
|
|
13268
|
+
lastVitals.current = vitals;
|
|
13269
|
+
onVitalsRef.current?.(vitals);
|
|
13270
|
+
});
|
|
13335
13271
|
const onControlsRef = useRef(onControls);
|
|
13336
13272
|
onControlsRef.current = onControls;
|
|
13337
13273
|
const setters = useRef({
|
|
@@ -13385,42 +13321,36 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13385
13321
|
const local = matchClientCommand(text, clientCommands);
|
|
13386
13322
|
if (local && local.command.run(local.args)) return;
|
|
13387
13323
|
}
|
|
13388
|
-
|
|
13324
|
+
dismissCatchUp();
|
|
13389
13325
|
repinTranscript.current?.();
|
|
13390
13326
|
send(text, attachmentIds);
|
|
13391
13327
|
};
|
|
13328
|
+
const menuShows = {
|
|
13329
|
+
context: capabilities.contextUsage,
|
|
13330
|
+
usage: capabilities.rateLimits,
|
|
13331
|
+
info: true,
|
|
13332
|
+
mcp: capabilities.mcpStatus,
|
|
13333
|
+
skills: capabilities.skillsList,
|
|
13334
|
+
files: hostFiles.available
|
|
13335
|
+
};
|
|
13392
13336
|
const actionsMenu = /* @__PURE__ */ jsxs(Menu$1, { children: [/* @__PURE__ */ jsx(MenuTrigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
13393
13337
|
variant: "ghost",
|
|
13394
13338
|
size: "icon-sm",
|
|
13395
13339
|
"aria-label": "Session actions",
|
|
13396
13340
|
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
|
|
13397
|
-
}) }), /* @__PURE__ */
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13405
|
-
}) : null,
|
|
13406
|
-
/* @__PURE__ */ jsxs(MenuItem, {
|
|
13407
|
-
onClick: () => openPanel("info"),
|
|
13408
|
-
children: [/* @__PURE__ */ jsx(Info, { className: "size-3.5 text-fg-3" }), " Session info"]
|
|
13409
|
-
}),
|
|
13410
|
-
capabilities.mcpStatus ? /* @__PURE__ */ jsxs(MenuItem, {
|
|
13411
|
-
onClick: () => openPanel("mcp"),
|
|
13412
|
-
children: [/* @__PURE__ */ jsx(Plug, { className: "size-3.5 text-fg-3" }), " MCP servers"]
|
|
13413
|
-
}) : null,
|
|
13414
|
-
capabilities.skillsList ? /* @__PURE__ */ jsxs(MenuItem, {
|
|
13415
|
-
onClick: () => openPanel("skills"),
|
|
13416
|
-
children: [/* @__PURE__ */ jsx(Sparkles, { className: "size-3.5 text-fg-3" }), " Skills"]
|
|
13417
|
-
}) : null,
|
|
13418
|
-
hostFiles.available ? /* @__PURE__ */ jsxs(MenuItem, {
|
|
13419
|
-
onClick: () => openPanel("files"),
|
|
13420
|
-
children: [/* @__PURE__ */ jsx(FolderTree, { className: "size-3.5 text-fg-3" }), " Project files"]
|
|
13421
|
-
}) : null
|
|
13422
|
-
] })] });
|
|
13341
|
+
}) }), /* @__PURE__ */ jsx(MenuContent, { children: PANEL_ITEMS.filter((item) => menuShows[item.panel]).map(({ panel: target, label, Icon }) => /* @__PURE__ */ jsxs(MenuItem, {
|
|
13342
|
+
onClick: () => openPanel(target),
|
|
13343
|
+
children: [
|
|
13344
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-3.5 text-fg-3" }),
|
|
13345
|
+
" ",
|
|
13346
|
+
label
|
|
13347
|
+
]
|
|
13348
|
+
}, target)) })] });
|
|
13423
13349
|
const menu = external ? null : actionsMenu;
|
|
13350
|
+
const dialog = (target) => ({
|
|
13351
|
+
open: panel === target,
|
|
13352
|
+
onOpenChange: (next) => setPanel(next ? target : void 0)
|
|
13353
|
+
});
|
|
13424
13354
|
const headerTakesActions = typeof header === "function";
|
|
13425
13355
|
const sessionControls = /* @__PURE__ */ jsxs(Fragment$1, { children: [models.length ? /* @__PURE__ */ jsx(ModelSelect, {
|
|
13426
13356
|
models,
|
|
@@ -13445,8 +13375,6 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13445
13375
|
onOpenStatus: external && !onOpenPanel ? void 0 : () => openPanel("info"),
|
|
13446
13376
|
onOpenContext: external && !onOpenPanel ? void 0 : () => openPanel("context"),
|
|
13447
13377
|
onOpenUsage: external && !onOpenPanel ? void 0 : () => openPanel("usage"),
|
|
13448
|
-
tasks,
|
|
13449
|
-
onOpenTasks: external && !onOpenPanel ? void 0 : () => openPanel("tasks"),
|
|
13450
13378
|
actions: headerTakesActions ? void 0 : menu
|
|
13451
13379
|
});
|
|
13452
13380
|
const fileLinks = useMemo(() => onOpenFile ? {
|
|
@@ -13477,296 +13405,208 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
13477
13405
|
if (window.getSelection()?.isCollapsed === false) return;
|
|
13478
13406
|
composerRef.current?.focus();
|
|
13479
13407
|
};
|
|
13480
|
-
return /* @__PURE__ */ jsx(
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
13489
|
-
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13510
|
-
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
|
|
13533
|
-
|
|
13534
|
-
|
|
13535
|
-
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13562
|
-
|
|
13563
|
-
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
onApprove: approve,
|
|
13637
|
-
onDeny: deny
|
|
13638
|
-
}, request.id);
|
|
13639
|
-
})
|
|
13640
|
-
})
|
|
13641
|
-
}) : null,
|
|
13642
|
-
readOnly || subagentId !== void 0 || framedShellId !== void 0 ? null : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Composer, {
|
|
13643
|
-
ref: composerRef,
|
|
13644
|
-
onSend: handleSend,
|
|
13645
|
-
onInterrupt: interrupt,
|
|
13646
|
-
busy,
|
|
13647
|
-
disabled: ended || !sessionId,
|
|
13648
|
-
commands: capabilities.slashCommands ? state.commands : void 0,
|
|
13649
|
-
skills: capabilities.skillsList ? state.skills : void 0,
|
|
13650
|
-
clientCommands,
|
|
13651
|
-
attachments,
|
|
13652
|
-
draft,
|
|
13653
|
-
onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
|
|
13654
|
-
peers: peers.peers,
|
|
13655
|
-
onShellCommand: shell ? runShell : void 0,
|
|
13656
|
-
layout: controlsExternal ? "inline" : "stacked",
|
|
13657
|
-
toolbar: controlsExternal ? void 0 : sessionControls,
|
|
13658
|
-
fontSize: effectiveTermFontSize,
|
|
13659
|
-
lineHeight: effectiveTermLineHeight,
|
|
13660
|
-
affordances
|
|
13661
|
-
}) }),
|
|
13662
|
-
statusPlacement === "bottom" ? statusBar : null,
|
|
13663
|
-
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
13664
|
-
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
13665
|
-
state,
|
|
13666
|
-
client,
|
|
13667
|
-
sessionId,
|
|
13668
|
-
open: panel === "info",
|
|
13669
|
-
onOpenChange: (next) => setPanel(next ? "info" : void 0)
|
|
13670
|
-
}),
|
|
13671
|
-
/* @__PURE__ */ jsx(ContextDialog, {
|
|
13672
|
-
usage: state.contextUsage,
|
|
13673
|
-
engine: state.engine ?? "claude",
|
|
13674
|
-
open: panel === "context",
|
|
13675
|
-
onOpenChange: (next) => setPanel(next ? "context" : void 0)
|
|
13676
|
-
}),
|
|
13677
|
-
/* @__PURE__ */ jsx(UsageDialog, {
|
|
13678
|
-
rateLimits: windows,
|
|
13679
|
-
subscriptionType: state.subscriptionType,
|
|
13680
|
-
engine: state.engine ?? "claude",
|
|
13681
|
-
totalCostUsd: state.totalCostUsd,
|
|
13682
|
-
costUsd: state.costUsd,
|
|
13683
|
-
usageByModel: state.usageByModel,
|
|
13684
|
-
pricing,
|
|
13685
|
-
spend: profileSpend,
|
|
13686
|
-
updatedAt: usageUpdatedAt,
|
|
13687
|
-
open: panel === "usage",
|
|
13688
|
-
onOpenChange: (next) => setPanel(next ? "usage" : void 0)
|
|
13689
|
-
}),
|
|
13690
|
-
/* @__PURE__ */ jsx(McpDialog, {
|
|
13691
|
-
client,
|
|
13692
|
-
sessionId,
|
|
13693
|
-
canManageServers: capabilities.mcpServerActions,
|
|
13694
|
-
open: panel === "mcp",
|
|
13695
|
-
onOpenChange: (next) => setPanel(next ? "mcp" : void 0)
|
|
13696
|
-
}),
|
|
13697
|
-
/* @__PURE__ */ jsx(TasksDialog, {
|
|
13698
|
-
tasks,
|
|
13699
|
-
showCompleted: showCompletedTasks,
|
|
13700
|
-
onShowCompletedChange: setShowCompletedTasks,
|
|
13701
|
-
onSelectTask: (task) => {
|
|
13702
|
-
if (task.toolUseId) setTaskReveal({
|
|
13703
|
-
toolUseId: task.toolUseId,
|
|
13704
|
-
nonce: Date.now()
|
|
13705
|
-
});
|
|
13706
|
-
},
|
|
13707
|
-
open: panel === "tasks",
|
|
13708
|
-
onOpenChange: (next) => setPanel(next ? "tasks" : void 0)
|
|
13709
|
-
}),
|
|
13710
|
-
/* @__PURE__ */ jsx(SkillsDialog, {
|
|
13711
|
-
skills: state.skills,
|
|
13712
|
-
open: panel === "skills",
|
|
13713
|
-
onOpenChange: (next) => setPanel(next ? "skills" : void 0),
|
|
13714
|
-
onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
|
|
13715
|
-
}),
|
|
13716
|
-
/* @__PURE__ */ jsx(HostFilesDialog, {
|
|
13717
|
-
client,
|
|
13718
|
-
cwd: state.cwd,
|
|
13719
|
-
open: panel === "files",
|
|
13720
|
-
onOpenChange: (next) => setPanel(next ? "files" : void 0)
|
|
13721
|
-
})
|
|
13722
|
-
] }) : null
|
|
13723
|
-
] })
|
|
13724
|
-
})
|
|
13725
|
-
})
|
|
13408
|
+
return /* @__PURE__ */ jsx(SessionPanelProviders, {
|
|
13409
|
+
variant: transcriptVariant,
|
|
13410
|
+
fileLinks,
|
|
13411
|
+
loadFullResult,
|
|
13412
|
+
shellActions,
|
|
13413
|
+
toolTitles: state.toolTitles,
|
|
13414
|
+
resultImages,
|
|
13415
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
13416
|
+
ref: panelRef,
|
|
13417
|
+
"data-slot": "session-panel",
|
|
13418
|
+
"data-agent-font": transcriptFont,
|
|
13419
|
+
onClick: handleClick,
|
|
13420
|
+
className: cn("relative flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
|
|
13421
|
+
style: fontSize !== void 0 ? { "--wd-font-size": `${Math.round(fontSize)}px` } : void 0,
|
|
13422
|
+
children: /* @__PURE__ */ jsxs(ImageViewerProvider, { children: [
|
|
13423
|
+
headerTakesActions ? header({ actions: menu }) : header,
|
|
13424
|
+
statusPlacement === "top" ? statusBar : null,
|
|
13425
|
+
protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
|
|
13426
|
+
level: "warning",
|
|
13427
|
+
children: [
|
|
13428
|
+
"Server speaks protocol v",
|
|
13429
|
+
protocolMismatch,
|
|
13430
|
+
", this build renders v",
|
|
13431
|
+
PROTOCOL_VERSION,
|
|
13432
|
+
". Some events may not render."
|
|
13433
|
+
]
|
|
13434
|
+
}) : null,
|
|
13435
|
+
protocolError ? /* @__PURE__ */ jsx(Notice, {
|
|
13436
|
+
level: "error",
|
|
13437
|
+
onDismiss: () => setProtocolError(void 0),
|
|
13438
|
+
children: protocolError
|
|
13439
|
+
}) : null,
|
|
13440
|
+
framedShellId !== void 0 ? /* @__PURE__ */ jsx(ShellStrip, {
|
|
13441
|
+
shell: framedShell,
|
|
13442
|
+
label: framedShellLabel,
|
|
13443
|
+
onBack: leaveShell,
|
|
13444
|
+
onKill: () => void killShell(framedShellId),
|
|
13445
|
+
onAgentWrite: agentWrite ? (enabled) => void agentWrite(framedShellId, enabled) : void 0,
|
|
13446
|
+
terminal,
|
|
13447
|
+
...cell
|
|
13448
|
+
}) : null,
|
|
13449
|
+
framedShellId === void 0 && subagentId !== void 0 ? /* @__PURE__ */ jsx(SubagentStrip, {
|
|
13450
|
+
task: subagentTask,
|
|
13451
|
+
items: subagentFrameItems,
|
|
13452
|
+
label: subagentFallbackLabel,
|
|
13453
|
+
onBack: leaveSubagent,
|
|
13454
|
+
terminal,
|
|
13455
|
+
...cell
|
|
13456
|
+
}) : null,
|
|
13457
|
+
framedShellId !== void 0 ? /* @__PURE__ */ jsx(ShellTerminal, {
|
|
13458
|
+
handle,
|
|
13459
|
+
shellId: framedShellId,
|
|
13460
|
+
fontSize: cell.fontSize
|
|
13461
|
+
}, framedShellId) : /* @__PURE__ */ jsx(BookmarkProvider, {
|
|
13462
|
+
value: bookmarkHandle,
|
|
13463
|
+
children: /* @__PURE__ */ jsx(Transcript, {
|
|
13464
|
+
state,
|
|
13465
|
+
fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
|
|
13466
|
+
attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
|
|
13467
|
+
canBrowseFiles: hostFiles.available,
|
|
13468
|
+
sessionNames: peers.names,
|
|
13469
|
+
hostImage,
|
|
13470
|
+
variant: transcriptVariant,
|
|
13471
|
+
...cell,
|
|
13472
|
+
affordances,
|
|
13473
|
+
stickyPrompt,
|
|
13474
|
+
scrubber,
|
|
13475
|
+
bookmarks,
|
|
13476
|
+
replaying,
|
|
13477
|
+
catchUp: catchUp && newCount > 0 ? {
|
|
13478
|
+
from: catchUp.itemCount,
|
|
13479
|
+
since: catchUp.since
|
|
13480
|
+
} : void 0,
|
|
13481
|
+
reveal: frameReturnReveal ?? reveal,
|
|
13482
|
+
frame: subagentId === void 0 ? void 0 : { parentToolUseId: subagentId },
|
|
13483
|
+
onOpenSubagent: enterSubagent,
|
|
13484
|
+
emptyState,
|
|
13485
|
+
jumpToRecapRef: jumpToRecap,
|
|
13486
|
+
repinRef: repinTranscript
|
|
13487
|
+
}, subagentId ?? "session")
|
|
13488
|
+
}),
|
|
13489
|
+
catchUp && newCount > 0 && !replaying && subagentId === void 0 && framedShellId === void 0 ? /* @__PURE__ */ jsx(CatchUpBanner, {
|
|
13490
|
+
count: newCount,
|
|
13491
|
+
since: catchUp.since,
|
|
13492
|
+
terminal,
|
|
13493
|
+
onJump: () => jumpToRecap.current?.(),
|
|
13494
|
+
onDismiss: dismissCatchUp
|
|
13495
|
+
}) : null,
|
|
13496
|
+
!readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx(ApprovalPrompts, {
|
|
13497
|
+
requests: state.pendingApprovals,
|
|
13498
|
+
terminal,
|
|
13499
|
+
...cell,
|
|
13500
|
+
affordances,
|
|
13501
|
+
hostPrompts: approvalPrompts,
|
|
13502
|
+
onApprove: approve,
|
|
13503
|
+
onDeny: deny
|
|
13504
|
+
}) : null,
|
|
13505
|
+
readOnly || subagentId !== void 0 || framedShellId !== void 0 ? null : /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Composer, {
|
|
13506
|
+
ref: composerRef,
|
|
13507
|
+
onSend: handleSend,
|
|
13508
|
+
onInterrupt: interrupt,
|
|
13509
|
+
busy,
|
|
13510
|
+
disabled: ended || !sessionId,
|
|
13511
|
+
commands: capabilities.slashCommands ? state.commands : void 0,
|
|
13512
|
+
skills: capabilities.skillsList ? state.skills : void 0,
|
|
13513
|
+
clientCommands,
|
|
13514
|
+
attachments,
|
|
13515
|
+
draft,
|
|
13516
|
+
onSearchFiles: hostFiles.available ? searchComposerFiles : void 0,
|
|
13517
|
+
peers: peers.peers,
|
|
13518
|
+
onShellCommand: shell ? runShell : void 0,
|
|
13519
|
+
layout: controlsExternal ? "inline" : "stacked",
|
|
13520
|
+
toolbar: controlsExternal ? void 0 : sessionControls,
|
|
13521
|
+
...cell,
|
|
13522
|
+
affordances
|
|
13523
|
+
}) }),
|
|
13524
|
+
statusPlacement === "bottom" ? statusBar : null,
|
|
13525
|
+
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
13526
|
+
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
13527
|
+
state,
|
|
13528
|
+
client,
|
|
13529
|
+
sessionId,
|
|
13530
|
+
...dialog("info")
|
|
13531
|
+
}),
|
|
13532
|
+
/* @__PURE__ */ jsx(ContextDialog, {
|
|
13533
|
+
usage: state.contextUsage,
|
|
13534
|
+
engine: state.engine ?? "claude",
|
|
13535
|
+
...dialog("context")
|
|
13536
|
+
}),
|
|
13537
|
+
/* @__PURE__ */ jsx(UsageDialog, {
|
|
13538
|
+
rateLimits: windows,
|
|
13539
|
+
subscriptionType: state.subscriptionType,
|
|
13540
|
+
engine: state.engine ?? "claude",
|
|
13541
|
+
totalCostUsd: state.totalCostUsd,
|
|
13542
|
+
costUsd: state.costUsd,
|
|
13543
|
+
usageByModel: state.usageByModel,
|
|
13544
|
+
pricing,
|
|
13545
|
+
spend: profileSpend,
|
|
13546
|
+
updatedAt: usageUpdatedAt,
|
|
13547
|
+
...dialog("usage")
|
|
13548
|
+
}),
|
|
13549
|
+
/* @__PURE__ */ jsx(McpDialog, {
|
|
13550
|
+
client,
|
|
13551
|
+
sessionId,
|
|
13552
|
+
canManageServers: capabilities.mcpServerActions,
|
|
13553
|
+
...dialog("mcp")
|
|
13554
|
+
}),
|
|
13555
|
+
/* @__PURE__ */ jsx(SkillsDialog, {
|
|
13556
|
+
skills: state.skills,
|
|
13557
|
+
...dialog("skills"),
|
|
13558
|
+
onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
|
|
13559
|
+
}),
|
|
13560
|
+
/* @__PURE__ */ jsx(HostFilesDialog, {
|
|
13561
|
+
client,
|
|
13562
|
+
cwd: state.cwd,
|
|
13563
|
+
...dialog("files")
|
|
13726
13564
|
})
|
|
13565
|
+
] }) : null
|
|
13566
|
+
] })
|
|
13567
|
+
})
|
|
13568
|
+
});
|
|
13569
|
+
}
|
|
13570
|
+
function CatchUpBanner({ count, since, terminal, onJump, onDismiss }) {
|
|
13571
|
+
return /* @__PURE__ */ jsx("div", {
|
|
13572
|
+
className: "px-3 pb-1",
|
|
13573
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
13574
|
+
"data-slot": "catch-up",
|
|
13575
|
+
className: "mx-auto flex w-full max-w-[var(--wd-transcript-max-width)] items-center gap-2 text-label text-fg-3",
|
|
13576
|
+
children: [
|
|
13577
|
+
/* @__PURE__ */ jsx("span", {
|
|
13578
|
+
"aria-hidden": true,
|
|
13579
|
+
className: cn("select-none", terminal ? "text-fg-3" : "text-accent"),
|
|
13580
|
+
children: "※"
|
|
13581
|
+
}),
|
|
13582
|
+
/* @__PURE__ */ jsxs("span", {
|
|
13583
|
+
className: "min-w-0 flex-1 truncate",
|
|
13584
|
+
children: [
|
|
13585
|
+
count,
|
|
13586
|
+
" new ",
|
|
13587
|
+
count === 1 ? "row" : "rows",
|
|
13588
|
+
since !== void 0 ? ` since you were last here` : ""
|
|
13589
|
+
]
|
|
13590
|
+
}),
|
|
13591
|
+
/* @__PURE__ */ jsx("button", {
|
|
13592
|
+
type: "button",
|
|
13593
|
+
onClick: onJump,
|
|
13594
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
13595
|
+
children: "jump"
|
|
13596
|
+
}),
|
|
13597
|
+
/* @__PURE__ */ jsx("button", {
|
|
13598
|
+
type: "button",
|
|
13599
|
+
onClick: onDismiss,
|
|
13600
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
13601
|
+
children: "dismiss"
|
|
13727
13602
|
})
|
|
13728
|
-
|
|
13603
|
+
]
|
|
13729
13604
|
})
|
|
13730
13605
|
});
|
|
13731
13606
|
}
|
|
13732
|
-
function
|
|
13733
|
-
|
|
13734
|
-
const objectUrls = useRef([]);
|
|
13735
|
-
useEffect(() => () => {
|
|
13736
|
-
for (const url of objectUrls.current) URL.revokeObjectURL(url);
|
|
13737
|
-
objectUrls.current = [];
|
|
13738
|
-
}, []);
|
|
13739
|
-
return useCallback((path) => {
|
|
13740
|
-
const produced = producedFiles?.[path];
|
|
13741
|
-
const key = produced ? `produced:${produced.fileId}` : `fs:${path}`;
|
|
13742
|
-
const hit = cache.current.get(key);
|
|
13743
|
-
if (hit) return hit;
|
|
13744
|
-
const pending = produced && sessionId ? client.readProducedFile(sessionId, produced.fileId).then((blob) => {
|
|
13745
|
-
if (blob.size === 0) return;
|
|
13746
|
-
const url = URL.createObjectURL(blob);
|
|
13747
|
-
objectUrls.current.push(url);
|
|
13748
|
-
return url;
|
|
13749
|
-
}).catch(() => void 0) : client.readHostFile(path).then((file) => {
|
|
13750
|
-
if (file.encoding !== "base64") return;
|
|
13751
|
-
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
13752
|
-
const mediaType = IMAGE_MEDIA_TYPES[extension];
|
|
13753
|
-
return mediaType ? `data:${mediaType};base64,${file.content}` : void 0;
|
|
13754
|
-
}).catch(() => void 0);
|
|
13755
|
-
cache.current.set(key, pending);
|
|
13756
|
-
return pending;
|
|
13757
|
-
}, [
|
|
13758
|
-
client,
|
|
13759
|
-
sessionId,
|
|
13760
|
-
producedFiles
|
|
13761
|
-
]);
|
|
13607
|
+
function sameVitals(a, b) {
|
|
13608
|
+
return Object.keys(b).every((key) => Object.is(a[key], b[key]));
|
|
13762
13609
|
}
|
|
13763
|
-
const IMAGE_MEDIA_TYPES = {
|
|
13764
|
-
png: "image/png",
|
|
13765
|
-
jpg: "image/jpeg",
|
|
13766
|
-
jpeg: "image/jpeg",
|
|
13767
|
-
gif: "image/gif",
|
|
13768
|
-
webp: "image/webp"
|
|
13769
|
-
};
|
|
13770
13610
|
function Notice({ level, onDismiss, children }) {
|
|
13771
13611
|
return /* @__PURE__ */ jsx("div", {
|
|
13772
13612
|
className: "px-3 pt-2",
|
|
@@ -13893,6 +13733,6 @@ function resolveAgainstCwd(path, cwd) {
|
|
|
13893
13733
|
return parseFileLink(path, cwd)?.path ?? path;
|
|
13894
13734
|
}
|
|
13895
13735
|
//#endregion
|
|
13896
|
-
export {
|
|
13736
|
+
export { ShellActionsProvider as $, Spinner as $t, PermissionPrompt as A, buttonVariants as An, PromptTokenText as At, ModelSelect as B, rankPeerSessions as Bt, SessionInfoDialog as C, SelectValue as Cn, Blank as Ct, QUESTION_BEHAVIORS as D, Badge as Dn, CopyAction as Dt, TerminalPermissionPrompt as E, Input as En, AgentWriteIcon as Et, SubagentStrip as F, TranscriptVariantProvider as Ft, useMcpPanel as G, mentionTrigger as Gt, McpDialog as H, commandTrigger as Ht, PERMISSION_MODES as I, useTranscriptVariant as It, ContextDialog as J, plainTextToSegments as Jt, HostFilesDialog as K, usePromptAreaState as Kt, PermissionModeSelect as L, matchClientCommand as Lt, useShellFrame as M, SkillNamesProvider as Mt, ShellTerminal as N, isMutatingTool as Nt, QuestionPrompt as O, badgeVariants as On, WithActions as Ot, ShellStrip as P, toolIcon as Pt, TerminalSurface as Q, CodeBlock as Qt, permissionModeChoices as R, mergeComposerRows as Rt, STATUS_META as S, SelectTrigger as Sn, Band as St, TerminalQuestionPrompt as T, Textarea as Tn, Row as Tt, McpPanel as U, hashtagTrigger as Ut, SkillsDialog as V, skillPrompt as Vt, McpPanelActions as W, launchTrigger as Wt, contextNote as X, ProgressRing as Xt, ContextPanel as Y, segmentsToPlainText as Yt, Composer as Z, Splitter as Zt, Loader as _, OptionSelect as _n, FileLinkProvider as _t, UsageDialog as a, Dialog$1 as an, shellGrantable as at, ConversationScrollButton as b, SelectItem as bn, TerminalDiff as bt, TerminalTranscript as c, DialogContent as cn, shellInfoStatusText as ct, Reasoning as d, DialogTrigger as dn, useToolTitle as dt, CopyButton as en, useShellActions as et, Message as f, Menu$1 as fn, TerminalMarkdown as ft, SessionEmptyState as g, MenuTrigger as gn, useOpenImage as gt, TerminalItemView as h, MenuSeparator as hn, ViewableImage as ht, SessionPanel as i, TooltipProvider as in, shellAgentWriteLabel as it, Response as j, cn as jn, SessionNamesProvider as jt, parseUserQuestions as k, Button as kn, useAffordances as kt, Transcript as l, DialogHeader as ln, shellTitle as lt, FileCard as m, MenuItem as mn, ImageViewerProvider as mt, usePathLinks as n, Tip as nn, SHELL_GLYPH as nt, UsageMeters as o, DialogBody as on, shellInfoFailed as ot, MessageContent as p, MenuContent as pn, ImageViewer as pt, EntryIcon as q, PromptArea as qt, matchPath as r, TooltipContent as rn, SHELL_KILL_GLYPH as rt, useMinuteClock as s, DialogClose as sn, shellInfoLabel as st, resolveAgainstCwd as t, copyText as tn, SHELL_AGENT_WRITE_NOTE as tt, ToolCallCard as u, DialogRow as un, ToolTitleProvider as ut, Conversation as v, Select$1 as vn, useFileLinks as vt, SessionInfoPanel as w, PortalScope as wn, Ink as wt, StatusBar as x, SelectItemText as xn, previewPatch as xt, ConversationContent as y, SelectContent as yn, parseFileLink as yt, permissionModeMeta as z, rankComposerRows as zt };
|
|
13897
13737
|
|
|
13898
|
-
//# sourceMappingURL=use-path-links-
|
|
13738
|
+
//# sourceMappingURL=use-path-links-C6Fh5zdx.mjs.map
|