mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
fix(vscode): restore tool preview behavior
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user