From 481f8361cfc5ea4be929d9afd63d996ed51131af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Uruchurtu?= Date: Thu, 11 Jun 2026 19:37:26 -0600 Subject: [PATCH] fix(vscode): polish chat tool call previews --- .changeset/polish-vscode-tool-previews.md | 5 + .../kilo-ui/src/components/basic-tool.css | 210 ++++++++++++++++-- .../kilo-ui/src/components/collapsible.css | 6 +- .../kilo-ui/src/components/message-part.css | 70 ++++-- .../kilo-ui/src/components/message-part.tsx | 94 +++----- .../src/components/shell-rolling-results.tsx | 28 +-- packages/kilo-ui/src/stories/icon.stories.tsx | 57 ++++- .../src/stories/message-part.stories.tsx | 53 ++++- .../components/chat/VscodeToolOverrides.tsx | 2 +- .../webview-ui/src/stories/StoryProviders.tsx | 6 + .../src/stories/tool-call-lab.stories.tsx | 132 +++++++++++ .../webview-ui/src/styles/chat-layout.css | 9 +- .../webview-ui/src/styles/tool-overrides.css | 4 +- 13 files changed, 560 insertions(+), 116 deletions(-) create mode 100644 .changeset/polish-vscode-tool-previews.md create mode 100644 packages/kilo-vscode/webview-ui/src/stories/tool-call-lab.stories.tsx diff --git a/.changeset/polish-vscode-tool-previews.md b/.changeset/polish-vscode-tool-previews.md new file mode 100644 index 00000000000..62f96ed3ed3 --- /dev/null +++ b/.changeset/polish-vscode-tool-previews.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Polish chat tool-call previews for shell, search, and background-process output. diff --git a/packages/kilo-ui/src/components/basic-tool.css b/packages/kilo-ui/src/components/basic-tool.css index 7ea63c439e2..8998c2c4ebb 100644 --- a/packages/kilo-ui/src/components/basic-tool.css +++ b/packages/kilo-ui/src/components/basic-tool.css @@ -35,14 +35,23 @@ [data-slot="basic-tool-tool-subtitle"] { font-size: var(--kilo-font-size-12); + color: var(--text-weak); } [data-slot="basic-tool-tool-title"] { - font-size: var(--kilo-font-size-14); + font-size: var(--kilo-font-size-12); + font-weight: var(--font-weight-regular); + color: var(--text-weak); } [data-slot="message-part-title-text"] { - font-size: var(--kilo-font-size-14); + font-size: var(--kilo-font-size-12); + font-weight: var(--font-weight-regular); + } + + [data-slot="basic-tool-tool-arg"] { + font-size: var(--kilo-font-size-12); + color: var(--text-weak); } [data-slot="message-part-title-filename"] { @@ -108,7 +117,7 @@ html[data-theme="kilo-vscode"] [data-component="tool-trigger"] { align-items: center; justify-content: center; flex-shrink: 0; - color: var(--icon-base); + color: var(--text-weak); [data-component="icon"] { display: flex; @@ -118,27 +127,71 @@ html[data-theme="kilo-vscode"] [data-component="tool-trigger"] { /* Card styling for tool calls in the VS Code sidebar theme */ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-type="tool"] { - border-radius: var(--radius-md); - border: 1px solid var(--border-weak-base, var(--vscode-panel-border)); - overflow: hidden; + border-radius: 0; + border: 0; + overflow: visible; /* Header trigger — add bottom border when the collapsible is open */ [data-component="collapsible"].tool-collapsible { - gap: 0px; + gap: 8px; border-radius: 0; [data-slot="collapsible-trigger"] { - padding: 0 8px; - height: 36px; - background-color: var(--surface-inset-base, var(--vscode-sideBar-background)); + margin-inline: -6px; + width: calc(100% + 12px); + padding: 2px 6px; + min-height: 24px; + height: auto; + background-color: transparent; &:hover { - background-color: var(--surface-inset-base-hover, var(--vscode-list-hoverBackground)); + background-color: transparent; } } + [data-slot="basic-tool-tool-trigger-content"] { + align-self: center; + gap: 6px; + } + + [data-slot="basic-tool-tool-info-structured"], + [data-slot="basic-tool-tool-info-main"] { + gap: 6px; + } + + [data-slot="basic-tool-tool-title"] + + :is( + [data-slot="basic-tool-tool-subtitle"], + [data-slot="basic-tool-tool-arg"], + [data-slot="message-part-meta-line"], + [data-slot="webfetch-meta"], + [data-component="shell-submessage"] + )::before { + content: "·"; + margin-right: 6px; + color: var(--text-weak); + } + + [data-slot="basic-tool-tool-title"], + [data-slot="basic-tool-tool-subtitle"], + [data-slot="basic-tool-tool-arg"], + [data-slot="message-part-title-text"], + [data-slot="message-part-title-filename"], + [data-slot="message-part-directory-inline"], + [data-slot="message-part-meta-line"] { + line-height: 16px; + } + [data-slot="collapsible-trigger"][aria-expanded="true"] { - border-bottom: 1px solid var(--border-weak-base, var(--vscode-panel-border)); + border-bottom: 0; + } + + [data-slot="collapsible-trigger"]:has([data-slot="collapsible-arrow"]) { + border-radius: 4px; + cursor: pointer; + transition: + background-color 0.15s ease, + color 0.15s ease; } /* Arrow always visible (no fade-on-hover) */ @@ -146,13 +199,32 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty opacity: 1; } - /* Arrow: DOWN when collapsed, UP when expanded (matches question-dock toggle) */ + /* Arrow: RIGHT when collapsed, DOWN when expanded. */ [data-slot="collapsible-arrow-icon"] { - transform: translateZ(0) rotate(0deg); + transform: translateZ(0) rotate(-90deg); } [data-slot="collapsible-trigger"][aria-expanded="true"] [data-slot="collapsible-arrow-icon"] { - transform: translateZ(0) rotate(180deg); + transform: translateZ(0) rotate(0deg); + } + + [data-slot="collapsible-trigger"]:has([data-slot="collapsible-arrow"]):hover { + background-color: var(--vscode-list-hoverBackground, var(--surface-raised-base-hover)); + + [data-slot="basic-tool-tool-title"], + [data-slot="basic-tool-tool-subtitle"], + [data-slot="basic-tool-tool-arg"], + [data-slot="message-part-title-text"], + [data-slot="message-part-title-filename"], + [data-slot="message-part-directory-inline"], + [data-slot="message-part-meta-line"] { + color: var(--vscode-list-hoverForeground, var(--vscode-foreground, var(--text-strong))); + } + + [data-slot="basic-tool-icon"], + [data-slot="collapsible-arrow-icon"] { + color: var(--vscode-list-hoverForeground, var(--vscode-foreground, var(--icon-base))); + } } } @@ -174,6 +246,76 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty margin-top: 4px; } + [data-component="context-tool-group-trigger"] { + min-height: 20px; + + [data-slot="context-tool-group-title"] { + gap: 6px; + font-size: var(--kilo-font-size-12); + font-weight: var(--font-weight-regular); + line-height: 16px; + color: var(--text-weak); + } + + [data-slot="context-tool-group-summary"] { + color: var(--text-weak); + } + + [data-slot="context-tool-group-summary"]::before { + content: "·"; + margin-right: 6px; + color: var(--text-weak); + } + } + + [data-component="context-tool-expanded-list"] { + max-height: 180px; + overflow-y: auto; + padding: 4px 0; + border: 1px solid var(--border-weak-base); + background: color-mix( + in srgb, + var(--vscode-terminal-background, var(--vscode-panel-background)) 92%, + black 8% + ); + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + [data-component="context-tool-expanded-row"], + [data-component="context-tool-rolling-row"] { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + align-items: baseline; + column-gap: 8px; + min-height: 20px; + font-size: var(--kilo-font-size-12); + line-height: 16px; + } + + [data-component="context-tool-expanded-row"] { + padding: 2px 12px; + } + + [data-slot="context-tool-expanded-action"], + [data-slot="context-tool-rolling-action"] { + color: var(--text-weak); + } + + [data-slot="context-tool-expanded-detail"], + [data-slot="context-tool-rolling-detail"] { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--vscode-terminal-foreground, var(--vscode-editor-foreground)); + font-family: var(--font-family-mono); + font-feature-settings: var(--font-family-mono--font-feature-settings); + } + /* Expandable tool output content */ [data-component="tool-output"] { padding: 8px 12px; @@ -186,4 +328,42 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty overflow-y: auto; } } + + [data-component="tool-output"][data-variant="preview"] { + max-height: 240px; + padding: 8px 12px 10px; + border: 1px solid var(--border-weak-base); + background: color-mix( + in srgb, + var(--vscode-terminal-background, var(--vscode-panel-background)) 92%, + black 8% + ); + color: var(--vscode-terminal-foreground, var(--vscode-editor-foreground)); + font-family: var(--font-family-mono); + font-feature-settings: var(--font-family-mono--font-feature-settings); + font-size: var(--kilo-font-size-12); + line-height: var(--line-height-large); + white-space: pre-wrap; + overflow-wrap: anywhere; + word-break: normal; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + + [data-component="markdown"] { + color: inherit; + font: inherit; + line-height: inherit; + white-space: inherit; + overflow-wrap: inherit; + } + + [data-component="markdown"] > *, + [data-component="markdown"] p, + [data-component="markdown"] pre { + margin: 0; + } + } } diff --git a/packages/kilo-ui/src/components/collapsible.css b/packages/kilo-ui/src/components/collapsible.css index b6ddd4a009d..ced943ce5f0 100644 --- a/packages/kilo-ui/src/components/collapsible.css +++ b/packages/kilo-ui/src/components/collapsible.css @@ -6,13 +6,13 @@ } } -/* VS Code theme: tool-collapsible arrows point DOWN (collapsed) and UP (expanded), never right */ +/* VS Code theme: tool-collapsible arrows point RIGHT when collapsed and DOWN when expanded. */ html[data-theme="kilo-vscode"] [data-component="collapsible"].tool-collapsible { [data-slot="collapsible-arrow-icon"] { - transform: translateZ(0) rotate(0deg); + transform: translateZ(0) rotate(-90deg); } [data-slot="collapsible-trigger"][aria-expanded="true"] [data-slot="collapsible-arrow-icon"] { - transform: translateZ(0) rotate(180deg); + transform: translateZ(0) rotate(0deg); } } diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css index 0998bf6044c..e57dc450de4 100644 --- a/packages/kilo-ui/src/components/message-part.css +++ b/packages/kilo-ui/src/components/message-part.css @@ -210,23 +210,68 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { border-radius: 0; - background: var(--vscode-terminal-background, var(--vscode-panel-background)); + border: 0; + background: transparent; + overflow: visible; + + [data-slot="bash-terminal"] { + background: color-mix( + in srgb, + var(--vscode-terminal-background, var(--vscode-panel-background)) 92%, + black 8% + ); + } [data-slot="bash-pre"] code { color: var(--vscode-terminal-foreground, var(--vscode-editor-foreground)); } - - [data-slot="bash-divider"] { - background: var(--vscode-panel-border, var(--border-weak-base)); - } } -/* Bash tool: section layout (command + output) */ +/* Bash tool: static terminal preview with separate command/output surfaces. */ +[data-component="bash-output"] { + display: flex; + flex-direction: column; + gap: 4px; + border: 0; + border-radius: 0; + background: transparent; + overflow: visible; +} + +[data-component="bash-output"] [data-slot="bash-terminal"] { + border-radius: 0; + border: 1px solid var(--border-weak-base); + background: var(--surface-raised-base); + overflow: hidden; +} + [data-component="bash-output"] [data-slot="bash-section"] { position: relative; } +[data-component="bash-output"] [data-slot="bash-section"][data-kind="command"] { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + align-items: start; + column-gap: 8px; + padding: 8px 12px 7px; +} + +[data-component="bash-output"] [data-slot="bash-section"][data-kind="output"] { + padding: 8px 12px 10px; +} + +[data-component="bash-output"] [data-slot="bash-prompt"] { + color: var(--text-weak, var(--vscode-descriptionForeground)); + font-family: var(--font-family-mono); + font-feature-settings: var(--font-family-mono--font-feature-settings); + font-size: var(--kilo-font-size-12); + line-height: var(--line-height-large); + user-select: none; +} + [data-component="bash-output"] [data-slot="bash-section-code"] { + min-width: 0; overflow-y: auto; overflow-x: hidden; max-height: 240px; @@ -254,25 +299,22 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { pointer-events: auto; } -/* Edge-to-edge divider (matches MCP tool divider) */ -[data-component="bash-output"] [data-slot="bash-divider"] { - height: 1px; - background: var(--border-weak-base); +[data-component="bash-output"] [data-slot="bash-pre"] { + margin: 0; + padding: 0; } -/* Shiki syntax-highlighted shell output */ -[data-component="bash-output"] .shiki, [data-component="shell-expanded-output"] .shiki { margin: 0; padding: 12px; background: transparent !important; } -[data-component="bash-output"] .shiki code, +[data-component="bash-output"] [data-slot="bash-pre"] code, [data-component="shell-expanded-output"] .shiki code { font-family: var(--font-family-mono); font-feature-settings: var(--font-family-mono--font-feature-settings); - font-size: var(--font-size-small); + font-size: var(--kilo-font-size-12); line-height: var(--line-height-large); white-space: pre-wrap; overflow-wrap: anywhere; diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx index ba9527f8deb..704a5b69ba0 100644 --- a/packages/kilo-ui/src/components/message-part.tsx +++ b/packages/kilo-ui/src/components/message-part.tsx @@ -56,8 +56,6 @@ import { ShellRollingResults } from "./shell-rolling-results" import { reasoningHeading } from "./reasoning-heading" import { extractFilePathFromHref } from "../file-path" import { normalize } from "./session-diff" -import { deferredHighlight } from "../context/marked" -import { escapeHtml } from "../util/escape-html" // Windows CLI tools (e.g. winget) use \r to overwrite progress bars in-place. // Without this, every progress frame renders as a separate visual line. @@ -1846,7 +1844,7 @@ ToolRegistry.register({ > {(output) => ( -
+
)} @@ -1877,7 +1875,7 @@ ToolRegistry.register({ > {(output) => ( -
+
)} @@ -1911,7 +1909,7 @@ ToolRegistry.register({ > {(output) => ( -
+
)} @@ -2111,37 +2109,6 @@ function BashCopyButton(props: { value: () => string; label: string }) { function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?: string; active?: boolean }) { const data = useData() const i18n = useI18n() - const cmdState = { signal: { aborted: false } } - const outState = { signal: { aborted: false } } - let cmdRef: HTMLDivElement | undefined - let outRef: HTMLDivElement | undefined - - createEffect(() => { - cmdState.signal.aborted = true - if (!props.active) return - const cmd = props.cmd - if (!cmdRef || !cmd) return - const signal = { aborted: false } - cmdState.signal = signal - cmdRef.innerHTML = `
${escapeHtml(cmd)}
` - void deferredHighlight(cmdRef, undefined, signal) - }) - - createEffect(() => { - outState.signal.aborted = true - if (!props.active) return - const out = props.output - if (!outRef || !out) return - const signal = { aborted: false } - outState.signal = signal - outRef.innerHTML = `
${escapeHtml(out)}
` - void deferredHighlight(outRef, undefined, signal) - }) - - onCleanup(() => { - cmdState.signal.aborted = true - outState.signal.aborted = true - }) const openInEditor = () => { // When output was truncated, open the full output file on disk @@ -2156,34 +2123,40 @@ function BashHighlightedOutput(props: { cmd: string; output: string; outputPath? return (
-
{i18n.t("ui.messagePart.shell.command")}
-
-
-
- props.cmd} label={i18n.t("ui.message.copy")} /> +
+
+ +
+
{props.cmd}
+
+
+ props.cmd} label={i18n.t("ui.message.copy")} /> +
- -
- -
{i18n.t("ui.messagePart.shell.output")}
-
-
-
- - - - - - props.output} label={i18n.t("ui.message.copy")} /> +
+
+
+
{props.output}
+
+
+ + + + + + props.output} label={i18n.t("ui.message.copy")} /> +
@@ -2223,7 +2196,6 @@ ToolRegistry.register({ { - resize() - return Math.ceil(bodyRef?.getBoundingClientRect().height ?? 0) - } - onMount(() => { resize() if (!topRef) return @@ -120,20 +113,13 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) { createEffect(() => { props.cmd props.out + if (!props.open) return queueMicrotask(() => { resize() updateMask() }) }) - useCollapsible({ - content: () => contentRef, - body: () => bodyRef, - open: () => props.open, - measure, - onOpen: updateMask, - }) - const handleCopy = async (e: MouseEvent) => { e.stopPropagation() const cmd = props.cmd ? `$ ${props.cmd}` : "" @@ -145,8 +131,14 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) { } return ( -
-
+
+
diff --git a/packages/kilo-ui/src/stories/icon.stories.tsx b/packages/kilo-ui/src/stories/icon.stories.tsx index ff3a703dadf..f67abb5db69 100644 --- a/packages/kilo-ui/src/stories/icon.stories.tsx +++ b/packages/kilo-ui/src/stories/icon.stories.tsx @@ -1,6 +1,6 @@ /** @jsxImportSource solid-js */ import type { Meta, StoryObj } from "storybook-solidjs-vite" -import { Icon } from "@opencode-ai/ui/icon" +import { Icon } from "../components/icon" const meta: Meta = { title: "Components/Icon", @@ -89,6 +89,26 @@ const iconNames = [ "layout-bottom", ] as const +const toolIcons = [ + { tool: "Read", icon: "glasses", note: "File reads" }, + { tool: "List", icon: "bullet-list", note: "Directory lists" }, + { tool: "Glob", icon: "magnifying-glass-menu", note: "File pattern search" }, + { tool: "Grep", icon: "magnifying-glass-menu", note: "Content search" }, + { tool: "WebFetch", icon: "window-cursor", note: "Fetch URL" }, + { tool: "WebSearch", icon: "window-cursor", note: "Search web" }, + { tool: "CodeSearch", icon: "code", note: "Code search" }, + { tool: "Task", icon: "task", note: "Subagent" }, + { tool: "Bash", icon: "console", note: "Shell command" }, + { tool: "Edit", icon: "code-lines", note: "Modify file" }, + { tool: "Write", icon: "code-lines", note: "Write file" }, + { tool: "Apply Patch", icon: "code-lines", note: "Patch files" }, + { tool: "TodoWrite", icon: "checklist", note: "Update todos" }, + { tool: "TodoRead", icon: "checklist", note: "Read todos" }, + { tool: "Question", icon: "bubble-5", note: "Ask user" }, + { tool: "Skill", icon: "brain", note: "Load skill" }, + { tool: "MCP/default", icon: "mcp", note: "Fallback tool" }, +] as const + export const AllIcons: Story = { render: () => (
( +
+ {toolIcons.map((item) => ( +
+ +
+ {item.tool} + {item.icon} + {item.note} +
+
+ ))} +
+ ), + parameters: { layout: "fullscreen" }, +} diff --git a/packages/kilo-ui/src/stories/message-part.stories.tsx b/packages/kilo-ui/src/stories/message-part.stories.tsx index 2a48c6060b9..fbb70763dc5 100644 --- a/packages/kilo-ui/src/stories/message-part.stories.tsx +++ b/packages/kilo-ui/src/stories/message-part.stories.tsx @@ -1,6 +1,6 @@ /** @jsxImportSource solid-js */ import type { Meta, StoryObj } from "storybook-solidjs-vite" -import { UserMessageDisplay, AssistantParts } from "../components/message-part" +import { UserMessageDisplay, AssistantParts, Part } from "../components/message-part" import { DataProvider } from "@opencode-ai/ui/context/data" import { DiffComponentProvider } from "@kilocode/kilo-ui/context/diff" import { CodeComponentProvider } from "@kilocode/kilo-ui/context/code" @@ -274,6 +274,38 @@ const mockDataContextGroup = createMockData([completedToolPart, grepCompleted, g const mockDataEdit = createMockData([editCompletedPart]) const mockDataWrite = createMockData([writeCompletedPart]) +const vscodeReadPart: ToolPart = { + ...completedToolPart, + id: "part-vscode-read-001", + callID: "call-vscode-read-001", + state: { + ...completedToolPart.state, + input: { + filePath: "/Users/helios/.superconductor/worktrees/kilo-code/sc-zero-helium-f589/packages/kilo-vscode/AGENTS.md", + offset: 1, + limit: 200, + }, + metadata: { + loaded: ["/project/packages/kilo-vscode/AGENTS.md"], + }, + }, +} + +const vscodeGlobPart: ToolPart = { + ...globCompleted, + id: "part-vscode-glob-001", + callID: "call-vscode-glob-001", + state: { + ...globCompleted.state, + input: { + path: "/Users/helios/.superconductor/worktrees/kilo-code/sc-zero-helium-f589", + pattern: "packages/kilo-vscode/webview-ui/src/**/*.tsx", + }, + }, +} + +const vscodeToolParts = [vscodeGlobPart, vscodeGlobPart, vscodeGlobPart, vscodeReadPart] + function AllProviders(props: { children: any; data?: MockData; onOpenDiff?: () => void }) { return ( @@ -326,6 +358,25 @@ export const AssistantMessageStory: Story = { ), } +export const VscodeToolBlocks: Story = { + globals: { theme: "kilo-vscode", vscodeTheme: "dark-modern" }, + render: () => ( + +
+

+ I’ll inspect the UI test setup and existing patterns first, then identify the smallest relevant test change + to make. +

+
+ {vscodeToolParts.map((part) => ( + + ))} +
+
+
+ ), +} + // --- Edit tool in running/pending state (Part → ToolPartDisplay path) --- export const WithRunningTool: Story = { diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx index c04c6cf870e..5d21ea7a9b6 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx @@ -138,7 +138,7 @@ function BackgroundProcessTool(props: ToolProps) { {(value) => ( -
+
{value()}
)} diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index 9fca0126250..10e71f10b3a 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx @@ -187,6 +187,9 @@ export function mockSessionValue(overrides?: { loading: () => false, loadingOlderMessages: () => false, hasOlderMessages: () => false, + submitting: () => false, + draftSessionID: () => undefined, + setDraftSessionID: noop, messageMutation: () => undefined, messages: () => [], visibleMessages: () => [], @@ -195,6 +198,8 @@ export function mockSessionValue(overrides?: { allParts: () => ({}), allStatusMap: () => ({}), getParts: () => [], + getSessionToolParts: () => [], + getSessionToolCount: () => 0, isErrorHidden: () => false, hydrateParts: noop, todos: () => [], @@ -255,6 +260,7 @@ export function mockSessionValue(overrides?: { deleteSession: noop, renameSession: noop, syncSession: noop, + exportSessionTranscript: noop, cloudPreviewId: () => null, selectCloudSession: noop, } diff --git a/packages/kilo-vscode/webview-ui/src/stories/tool-call-lab.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/tool-call-lab.stories.tsx new file mode 100644 index 00000000000..5488086cff3 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/stories/tool-call-lab.stories.tsx @@ -0,0 +1,132 @@ +/** @jsxImportSource solid-js */ +import { For } from "solid-js" +import type { Meta, StoryObj } from "storybook-solidjs-vite" +import { Part } from "@kilocode/kilo-ui/message-part" +import type { AssistantMessage as SDKAssistantMessage, Part as SDKPart, ToolPart } from "@kilocode/sdk/v2" +import { StoryProviders } from "./StoryProviders" +import { registerVscodeToolOverrides } from "../components/chat/VscodeToolOverrides" + +registerVscodeToolOverrides() + +const SID = "tool-call-lab-session" +const MID = "tool-call-lab-message" +const stamp = Date.now() + +const base: SDKAssistantMessage = { + id: MID, + sessionID: SID, + role: "assistant", + parentID: "tool-call-lab-user-message", + time: { created: stamp - 9000, completed: stamp - 1000 }, + modelID: "anthropic/claude-sonnet-4-6", + providerID: "kilo", + mode: "default", + agent: "default", + path: { cwd: "/project", root: "/project" }, + cost: 0.0021, + tokens: { total: 742, input: 386, output: 356, reasoning: 0, cache: { read: 0, write: 0 } }, +} + +const long = [ + "packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx", + "packages/kilo-vscode/webview-ui/src/stories/tool-call-lab.stories.tsx", + "packages/kilo-ui/src/components/message-part.tsx", +].join("\n") + +const hits = [ + "packages/kilo-ui/src/components/message-part.tsx:1847:
", + "packages/kilo-ui/src/components/basic-tool.css:250: [data-component=\"tool-output\"]", + "packages/kilo-vscode/webview-ui/src/components/chat/VscodeToolOverrides.tsx:141: background process output", +].join("\n") + +const tree = [ + "packages/kilo-ui/src/components/", + " basic-tool.css", + " context-tool-results.tsx", + " message-part.css", + " message-part.tsx", + "packages/kilo-vscode/webview-ui/src/stories/", + " tool-call-lab.stories.tsx", +].join("\n") + +const proc = [ + "pid: 48122", + "status: running", + "cwd: /project", + "command: bun run --cwd packages/kilo-vscode storybook", + "last_output:", + "Storybook 9.0.18 for solid-vite started", + "Local: http://localhost:6007/", +].join("\n") + +function completed(input: Record, title: string, value: string): ToolPart["state"] { + return { + status: "completed", + input, + output: value, + title, + metadata: {}, + time: { start: stamp - 5000, end: stamp - 4400 }, + } +} + +function tool(id: string, call: string, name: string, state: ToolPart["state"]): ToolPart { + return { + id, + sessionID: SID, + messageID: MID, + type: "tool", + callID: call, + tool: name, + state, + } +} + +const previews: SDKPart[] = [ + tool( + "lab-preview-glob", + "lab-call-preview-glob", + "glob", + completed({ pattern: "packages/**/tool*.tsx", path: "." }, "Find tool files", long), + ), + tool( + "lab-preview-grep", + "lab-call-preview-grep", + "grep", + completed({ pattern: "data-component=\"tool-output\"", include: "*.tsx", path: "." }, "Search tool output", hits), + ), + tool( + "lab-preview-list", + "lab-call-preview-list", + "list", + completed({ path: "packages/kilo-ui/src/components" }, "List component files", tree), + ), + tool( + "lab-preview-background", + "lab-call-preview-background", + "background_process", + completed({ action: "status", id: "bgp_storybook", description: "Check Storybook server" }, "Check Storybook server", proc), + ), +] + +const meta: Meta = { + title: "Labs/Tool Call Lab", + parameters: { layout: "padded" }, +} + +export default meta + +type Story = StoryObj + +export const SearchPreviews: Story = { + name: "Search Previews", + render: () => ( + +
+
+ {(part) => } +
+
+
+ ), +} diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css b/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css index 0e625dda4e3..6444e8ab250 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat-layout.css @@ -211,10 +211,17 @@ .vscode-session-turn-assistant { display: flex; flex-direction: column; - gap: 12px; + gap: 2px; width: 100%; } +.vscode-session-turn-assistant [data-component="tool-part-wrapper"][data-part-type="text"] + + [data-component="tool-part-wrapper"][data-part-type="tool"], +.vscode-session-turn-assistant [data-component="tool-part-wrapper"][data-part-type="tool"] + + [data-component="tool-part-wrapper"][data-part-type="text"] { + margin-top: 6px; +} + .vscode-session-turn-diffs { width: 100%; } diff --git a/packages/kilo-vscode/webview-ui/src/styles/tool-overrides.css b/packages/kilo-vscode/webview-ui/src/styles/tool-overrides.css index 2eefff2c787..a8144337f61 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/tool-overrides.css +++ b/packages/kilo-vscode/webview-ui/src/styles/tool-overrides.css @@ -47,7 +47,9 @@ [data-slot="background-process-output"] { margin: 0; font: inherit; - font-family: var(--font-mono); + font-family: var(--font-family-mono); + font-size: var(--kilo-font-size-12); + line-height: var(--line-height-large); white-space: pre-wrap; overflow-wrap: anywhere; }