fix(vscode): restore tool preview behavior

This commit is contained in:
Iván Uruchurtu
2026-06-16 19:47:30 -06:00
parent 3623676d78
commit 33def8874a
7 changed files with 63 additions and 38 deletions
@@ -194,7 +194,7 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
[data-slot="message-part-title-filename"],
[data-slot="message-part-directory-inline"],
[data-slot="message-part-meta-line"] {
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
[data-slot="collapsible-trigger"][aria-expanded="true"] {
@@ -271,7 +271,7 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
background: var(--surface-tool-output-base);
color: var(--text-weak);
font-size: var(--kilo-font-size-12);
line-height: 16px;
line-height: var(--kilo-font-size-16);
scrollbar-width: none;
&::-webkit-scrollbar {
@@ -296,7 +296,7 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
gap: 6px;
font-size: var(--kilo-font-size-12);
font-weight: var(--font-weight-regular);
line-height: 16px;
line-height: var(--kilo-font-size-16);
color: var(--text-weak);
}
@@ -332,7 +332,7 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
column-gap: 8px;
min-height: 20px;
font-size: var(--kilo-font-size-12);
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
[data-component="context-tool-expanded-row"] {
@@ -438,13 +438,13 @@ html[data-theme="kilo-vscode"] [data-component="todos"] {
[data-slot="checkbox-checkbox-label"] {
color: var(--text-weak);
font-size: var(--kilo-font-size-12);
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
[data-slot="message-part-todo-hidden"] {
color: var(--text-weaker);
font-size: var(--kilo-font-size-12);
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
[data-slot="message-part-todo-content"][data-changed="changed"] {
@@ -630,7 +630,7 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
color: var(--text-weak);
font-size: var(--kilo-font-size-12);
font-weight: var(--font-weight-regular);
line-height: 16px;
line-height: var(--kilo-font-size-16);
[data-component="icon"] {
color: var(--text-weak);
@@ -641,7 +641,7 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
[data-slot="reasoning-title"] {
color: var(--text-weak);
font-weight: var(--font-weight-regular);
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
[data-slot="reasoning-label"] + [data-slot="reasoning-title"]::before {
@@ -675,7 +675,7 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
[data-component="markdown"] {
font-size: var(--kilo-font-size-12);
line-height: 16px;
line-height: var(--kilo-font-size-16);
}
}
}
@@ -2114,24 +2114,39 @@ function BashCopyButton(props: { value: () => string; label: string }) {
)
}
function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?: string }) {
function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?: string; active?: boolean }) {
const data = useData()
const i18n = useI18n()
const state = { signal: { aborted: false } }
let ref: HTMLDivElement | undefined
const cmdState = { signal: { aborted: false } }
const outState = { signal: { aborted: false } }
let cmdRef: HTMLDivElement | undefined
let outRef: HTMLDivElement | undefined
createEffect(() => {
state.signal.aborted = true
cmdState.signal.aborted = true
if (!props.active) return
const cmd = props.cmd
if (!ref || !cmd) return
if (!cmdRef || !cmd) return
const signal = { aborted: false }
state.signal = signal
ref.innerHTML = `<pre data-slot="bash-pre"><code data-lang="shellscript">${escapeHtml(cmd)}</code></pre>`
void deferredHighlight(ref, undefined, signal)
cmdState.signal = signal
cmdRef.innerHTML = `<pre data-slot="bash-pre"><code data-lang="shellscript">${escapeHtml(cmd)}</code></pre>`
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 = `<pre data-slot="bash-pre"><code data-lang="log">${escapeHtml(out)}</code></pre>`
void deferredHighlight(outRef, undefined, signal)
})
onCleanup(() => {
state.signal.aborted = true
cmdState.signal.aborted = true
outState.signal.aborted = true
})
const openInEditor = () => {
@@ -2152,7 +2167,7 @@ function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?
<span data-slot="bash-prompt" aria-hidden="true">
$
</span>
<div data-slot="bash-section-code" data-scrollable ref={ref} />
<div data-slot="bash-section-code" data-scrollable ref={cmdRef} />
<div data-slot="bash-section-actions">
<BashCopyButton value={() => props.cmd} label={i18n.t("ui.message.copy")} />
</div>
@@ -2162,11 +2177,7 @@ function BashHighlightedOutput(props: { cmd: string; output: string; outputPath?
<Show when={props.output}>
<div data-slot="bash-terminal" data-kind="output">
<div data-slot="bash-section" data-kind="output">
<div data-slot="bash-section-code" data-scrollable>
<pre data-slot="bash-pre">
<code>{props.output}</code>
</pre>
</div>
<div data-slot="bash-section-code" data-scrollable ref={outRef} />
<div data-slot="bash-section-actions">
<Show when={data.openContent || (props.outputPath && data.openFile)}>
<Tooltip value={i18n.t("ui.messagePart.openInEditor")} placement="bottom" gutter={4}>
@@ -2236,7 +2247,7 @@ ToolRegistry.register({
}
>
<Show when={mounted()}>
<BashHighlightedOutput cmd={cmd()} output={out()} outputPath={props.metadata.outputPath} />
<BashHighlightedOutput cmd={cmd()} output={out()} outputPath={props.metadata.outputPath} active={open()} />
</Show>
</BasicTool>
)
@@ -102,6 +102,22 @@ describe("webview font-size architecture", () => {
).toEqual([])
})
it("uses scalable line heights in polished tool previews", () => {
const files = [
path.join(REPO, "packages/kilo-ui/src/components/basic-tool.css"),
path.join(REPO, "packages/kilo-ui/src/components/message-part.css"),
]
const violations = files.flatMap((file) => {
const src = stripComments(fs.readFileSync(file, "utf-8"))
return Array.from(
src.matchAll(/line-height\s*:\s*\d+(?:\.\d+)?px\b/g),
(match) => `${rel(file)}:${line(src, match.index ?? 0)}`,
)
})
expect(violations).toEqual([])
})
it("injects and live-broadcasts the webview font-size setting to all webview providers", () => {
const util = fs.readFileSync(path.join(ROOT, "src/utils.ts"), "utf-8")
expect(util, "buildWebviewHtml must seed webview font tokens before app code runs").toContain("getWebviewFontSize")
@@ -202,15 +202,21 @@ describe("Bash tool static terminal preview (source)", () => {
it("BashHighlightedOutput syntax highlights the command next to the prompt", () => {
expect(src).toContain('data-slot="bash-terminal" data-kind="command"')
expect(src).toContain('data-slot="bash-prompt"')
expect(src).toContain('data-slot="bash-section-code" data-scrollable ref={ref}')
expect(src).toContain('data-slot="bash-section-code" data-scrollable ref={cmdRef}')
expect(src).toContain('data-lang="shellscript"')
expect(src).toContain("escapeHtml(cmd)")
})
it("BashHighlightedOutput renders output as plain code", () => {
it("BashHighlightedOutput syntax highlights log output", () => {
expect(src).toContain('data-slot="bash-terminal" data-kind="output"')
expect(src).toMatch(/<pre data-slot="bash-pre">\s*<code>\{props\.output\}<\/code>\s*<\/pre>/)
expect(src).not.toMatch(/data-lang="log"/)
expect(src).toContain('data-slot="bash-section-code" data-scrollable ref={outRef}')
expect(src).toContain('data-lang="log"')
expect(src).toContain("escapeHtml(out)")
})
it("BashHighlightedOutput highlights only while expanded", () => {
expect(src).toContain("if (!props.active) return")
expect(block).toContain("active={open()}")
})
it("BashHighlightedOutput keeps command and output in separate terminal containers", () => {
@@ -122,7 +122,7 @@ const TaskToolRenderer: Component<ToolProps> = (props) => {
)
return (
<div data-component="tool-part-wrapper" data-part-type="tool" data-tool={props.tool}>
<div data-component="tool-part-wrapper">
<BasicTool
icon="task"
status={props.status}
@@ -1,11 +1,3 @@
/* ============================================
Todo tool — align checkboxes with icon in header
============================================ */
[data-component="todos"] {
padding: 8px 12px 10px;
}
/* ============================================
Task Tool (sub-agent, v1.0.25 style)
tool-output scrollable container size override