From b45f41876745c6e098f4ad62b8e948764a825c29 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 10 Mar 2026 14:58:12 +0100 Subject: [PATCH 1/5] refactor: move permission requests to dock, replacing chatbox instead of stacking Replace inline permission rendering with a dedicated PermissionDock component using kilo-ui's DockPrompt, matching the pattern from packages/app/. The prompt input is now hidden when a permission or question is pending, instead of being stacked below it. --- .../src/components/chat/AssistantMessage.tsx | 101 ++---------- .../src/components/chat/ChatView.tsx | 123 +++++--------- .../src/components/chat/PermissionDock.tsx | 90 +++++++++++ .../src/components/chat/TaskToolExpanded.tsx | 151 ++++-------------- .../webview-ui/src/styles/chat.css | 94 ++++++----- 5 files changed, 218 insertions(+), 341 deletions(-) create mode 100644 packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx index c4a9fcc9766..a948caf68dd 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/AssistantMessage.tsx @@ -4,14 +4,13 @@ * Unlike the upstream AssistantParts, this renders each read/glob/grep/list tool * individually for maximum verbosity in the VS Code sidebar context. * - * Permissions and questions with a tool context are rendered inline with their - * tool call rather than in the bottom dock. + * Questions with a tool context are rendered inline with their tool call. + * Permissions are rendered in the bottom dock (PermissionDock). */ import { Component, For, Show, createMemo } from "solid-js" import { Dynamic } from "solid-js/web" import { Part, PART_MAPPING, ToolRegistry } from "@kilocode/kilo-ui/message-part" -import { Button } from "@kilocode/kilo-ui/button" import type { AssistantMessage as SDKAssistantMessage, Part as SDKPart, @@ -20,24 +19,20 @@ import type { } from "@kilocode/sdk/v2" import { useData } from "@kilocode/kilo-ui/context/data" import { useSession } from "../../context/session" -import { useLanguage } from "../../context/language" import { QuestionDock } from "./QuestionDock" // Tools that the upstream message-part renderer suppresses (returns null for). -// We render these ourselves via ToolRegistry when they have a pending permission -// or when they complete, so the user can see what the AI set up. -// We also use this set in ChatView to know NOT to block the prompt input for -// these tool permissions (since they're shown inline in the message stream). +// We render these ourselves via ToolRegistry when they complete, +// so the user can see what the AI set up. export const UPSTREAM_SUPPRESSED_TOOLS = new Set(["todowrite", "todoread"]) -function isRenderable(part: SDKPart, pendingPermissionCallIDs: Set): boolean { +function isRenderable(part: SDKPart): boolean { if (part.type === "tool") { const tool = (part as SDKPart & { tool: string }).tool const state = (part as SDKPart & { state: { status: string } }).state if (UPSTREAM_SUPPRESSED_TOOLS.has(tool)) { - const callID = (part as SDKPart & { callID: string }).callID - // Show todo parts when waiting for permission (inline) or when completed (to show what happened) - return pendingPermissionCallIDs.has(callID) || state.status === "completed" + // Show todo parts only when completed (permissions are now in the dock) + return state.status === "completed" } if (tool === "question" && (state.status === "pending" || state.status === "running")) return false return true @@ -76,52 +71,29 @@ function TodoToolCard(props: { part: ToolPart }) { export const AssistantMessage: Component = (props) => { const data = useData() const session = useSession() - const language = useLanguage() - const id = () => session.currentSessionID() - const permissions = () => session.permissions().filter((p) => p.sessionID === id() && p.tool) - const questions = () => session.questions().filter((q) => q.sessionID === id() && q.tool) - - const pendingPermissionCallIDs = createMemo(() => { - const ids = new Set() - for (const p of permissions()) { - if (p.tool?.messageID === props.message.id) ids.add(p.tool.callID) - } - return ids - }) + const questions = () => session.questions().filter((q) => q.sessionID === session.currentSessionID() && q.tool) const parts = createMemo(() => { const stored = data.store.part?.[props.message.id] if (!stored) return [] - return (stored as SDKPart[]).filter((part) => isRenderable(part, pendingPermissionCallIDs())) + return (stored as SDKPart[]).filter((part) => isRenderable(part)) }) - const permissionForPart = (part: SDKPart) => { - if (part.type !== "tool") return undefined - const callID = (part as SDKPart & { callID: string }).callID - return permissions().find((p) => p.tool!.callID === callID && p.tool!.messageID === props.message.id) - } - // Questions linked to this message (rendered after the last part) const questionForMessage = () => questions().find((q) => q.tool!.messageID === props.message.id) - const decide = (permissionId: string, response: "once" | "always" | "reject") => { - if (session.respondingPermissions().has(permissionId)) return - session.respondToPermission(permissionId, response) - } - return ( <> {(part) => { - const perm = () => permissionForPart(part) // Upstream PART_MAPPING["tool"] returns null for todowrite/todoread, // so we detect them here and render via ToolRegistry directly. const isUpstreamSuppressed = part.type === "tool" && UPSTREAM_SUPPRESSED_TOOLS.has((part as SDKPart & { tool: string }).tool) return ( -
+
= (props) => { > - - {(p) => { - const isTodoPerm = UPSTREAM_SUPPRESSED_TOOLS.has(p.toolName) - // For todo tools: show the friendly operation description instead of raw patterns like '*' - // For other tools: show patterns only if they're meaningful (not just '*') - const meaningfulPatterns = p.patterns.filter((pat) => pat !== "*") - return ( -
e.stopPropagation()}> - 0}> -
- - {(pattern) => {pattern}} - -
-
- -

- {p.toolName === "todowrite" - ? language.t("settings.permissions.tool.todowrite.description") - : language.t("settings.permissions.tool.todoread.description")} -

-
-
- - - -
-

{language.t("ui.permission.sessionHint")}

-
- ) - }} -
) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx index 75db890f034..23317774b38 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx @@ -3,20 +3,18 @@ * Main chat container that combines all chat components */ -import { Component, For, Show, createEffect, on, onCleanup, onMount } from "solid-js" +import { Component, Show, createEffect, on, onCleanup, onMount } from "solid-js" import { Button } from "@kilocode/kilo-ui/button" import { Icon } from "@kilocode/kilo-ui/icon" -import { BasicTool } from "@kilocode/kilo-ui/basic-tool" import { TaskHeader } from "./TaskHeader" import { MessageList } from "./MessageList" import { PromptInput } from "./PromptInput" import { QuestionDock } from "./QuestionDock" -import { UPSTREAM_SUPPRESSED_TOOLS } from "./AssistantMessage" +import { PermissionDock } from "./PermissionDock" import { useSession } from "../../context/session" import { useVSCode } from "../../context/vscode" import { useLanguage } from "../../context/language" import { useWorktreeMode } from "../../context/worktree-mode" -import type { PermissionRequest } from "../../types/messages" interface ChatViewProps { onSelectSession?: (id: string) => void @@ -41,16 +39,14 @@ export const ChatView: Component = (props) => { const allPermissions = () => session.permissions() const allQuestions = () => session.questions() - // Bottom-dock permission: prefer current-session non-tool permissions, + // Bottom-dock permission: prefer current-session permissions, // then fall back to any pending permission (including child sessions). const questionRequest = () => - allQuestions().find((q) => q.sessionID === id() && !q.tool) ?? allQuestions().find((q) => !q.tool) ?? allQuestions()[0] - const permissionRequest = () => - allPermissions().find((p) => p.sessionID === id() && !p.tool) ?? allPermissions().find((p) => !p.tool) ?? allPermissions()[0] - // Only block the prompt when there's a non-inline permission or any question pending - // (todo permissions are shown inline, not in the bottom dock) - const isInlinePermission = (p: PermissionRequest) => p.tool && UPSTREAM_SUPPRESSED_TOOLS.has(p.toolName) - const blocked = () => allPermissions().some((p) => !isInlinePermission(p)) || allQuestions().length > 0 + allQuestions().find((q) => q.sessionID === id() && !q.tool) ?? + allQuestions().find((q) => !q.tool) ?? + allQuestions()[0] + const permissionRequest = () => allPermissions().find((p) => p.sessionID === id()) ?? allPermissions()[0] + const blocked = () => allPermissions().length > 0 || allQuestions().length > 0 // When a bottom-dock permission/question disappears while the session is busy, // the scroll container grows taller. Dispatch a custom event so MessageList can @@ -95,87 +91,42 @@ export const ChatView: Component = (props) => { {(req) => } - {(perm) => { - const fromChild = () => perm.sessionID !== id() - const subtitle = () => fromChild() ? `${perm.toolName} (subagent)` : perm.toolName - return ( -
- - 0}> -
- - {(pattern) => {pattern}} - -
-
-
-
-
- - - -
-

{language.t("ui.permission.sessionHint")}

-
-
- ) - }} + {(perm) => ( + + )}
- -
- - + + +
- -
+ + + +
+
+ -
diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx new file mode 100644 index 00000000000..39b42e1c9c2 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx @@ -0,0 +1,90 @@ +/** + * PermissionDock component + * Displays permission requests from the AI assistant in the dock above the prompt input. + * Uses kilo-ui's DockPrompt component for proper surface styling. + * Modeled after the app's SessionPermissionDock. + */ + +import { Component, For, Show } from "solid-js" +import { Button } from "@kilocode/kilo-ui/button" +import { DockPrompt } from "@kilocode/kilo-ui/dock-prompt" +import { Icon } from "@kilocode/kilo-ui/icon" +import { useSession } from "../../context/session" +import { useLanguage } from "../../context/language" +import type { PermissionRequest } from "../../types/messages" + +export const PermissionDock: Component<{ + request: PermissionRequest + responding: boolean + onDecide: (response: "once" | "always" | "reject") => void +}> = (props) => { + const session = useSession() + const language = useLanguage() + + const fromChild = () => props.request.sessionID !== session.currentSessionID() + + const toolDescription = () => { + const key = `settings.permissions.tool.${props.request.toolName}.description` + const value = language.t(key as Parameters[0]) + if (value === key) return "" + return value + } + + const subtitle = () => (fromChild() ? `${props.request.toolName} (subagent)` : props.request.toolName) + + return ( + + + + +
+ {language.t("notification.permission.title")} + {subtitle()} +
+ + } + footer={ + <> +
+
+ + + +
+ + } + > + +
+
+
+ + 0}> +
+
+
+ + ) +} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx index 11109816071..f5d60efcbd1 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx @@ -7,10 +7,9 @@ * Call registerExpandedTaskTool() once at app startup to activate. */ -import { Component, createEffect, createMemo, For, Match, Show, Switch } from "solid-js" +import { Component, createEffect, createMemo, For, Show } from "solid-js" import { ToolRegistry, ToolProps, getToolInfo } from "@kilocode/kilo-ui/message-part" import { BasicTool } from "@kilocode/kilo-ui/basic-tool" -import { Button } from "@kilocode/kilo-ui/button" import { Icon } from "@kilocode/kilo-ui/icon" import { useData } from "@kilocode/kilo-ui/context/data" import { useI18n } from "@kilocode/kilo-ui/context/i18n" @@ -64,36 +63,6 @@ const TaskToolRenderer: Component = (props) => { return getSessionToolParts(data.store, id) }) - // Permission from child session - const childPermission = createMemo(() => { - const id = childSessionId() - if (!id) return undefined - const perms = data.store.permission?.[id] as unknown[] - return (perms as PermissionRequest[] | undefined)?.[0] - }) - - const childToolPart = createMemo(() => { - const perm = childPermission() - if (!perm || !perm.tool) return undefined - const id = childSessionId() - if (!id) return undefined - const messages = (data.store.message?.[id] as SDKMessage[] | undefined) ?? [] - const msg = [...messages].reverse().find((m: SDKMessage) => m.id === perm.tool!.messageID) - if (!msg) return undefined - const parts = (data.store.part?.[msg.id] as ToolPart[] | undefined) ?? [] - return parts.find((p) => p.type === "tool" && p.callID === perm.tool!.callID) as ToolPart | undefined - }) - - const respond = (response: "once" | "always" | "reject") => { - const perm = childPermission() - if (!perm || !data.respondToPermission) return - data.respondToPermission({ - sessionID: perm.sessionID, - permissionID: perm.id, - response, - }) - } - const autoScroll = createAutoScroll({ working: running, overflowAnchor: "auto", @@ -112,100 +81,40 @@ const TaskToolRenderer: Component = (props) => {
) - // Render the child tool card that triggered a permission (shown when permission is pending) - const renderChildToolCard = () => { - const part = childToolPart() - if (!part) return null - const render = ToolRegistry.render(part.tool) - if (!render) return null - const metadata = (part.state as { metadata?: Record })?.metadata ?? {} - const input = part.state?.input ?? {} - const output = (part.state as { output?: string })?.output - return render({ - input: input as Record, - tool: part.tool, - metadata: metadata as Record, - output, - status: part.state.status, - defaultOpen: true, - }) - } - return ( -
- - {/* Branch 1: pending permission from child session */} - - <> - }> - {renderChildToolCard()} - -
-
- - - -
-

{i18n.t("ui.permission.sessionHint")}

-
- -
- - {/* Branch 2: normal — compact list of child tool calls */} - - -
-
- - {(item) => { - const info = createMemo(() => getToolInfo(item.tool, item.state?.input)) - const subtitle = createMemo(() => { - if (info().subtitle) return info().subtitle - const state = item.state as { status: string; title?: string } - if (state.status === "completed" || state.status === "running") { - return state.title - } - return undefined - }) - return ( -
- - {info().title} - - {subtitle()} - -
- ) - }} -
-
-
-
-
-
+
+ +
+
+ + {(item) => { + const info = createMemo(() => getToolInfo(item.tool, item.state?.input)) + const subtitle = createMemo(() => { + if (info().subtitle) return info().subtitle + const state = item.state as { status: string; title?: string } + if (state.status === "completed" || state.status === "running") { + return state.title + } + return undefined + }) + return ( +
+ + {info().title} + + {subtitle()} + +
+ ) + }} +
+
+
+
) } -// Minimal PermissionRequest shape we need -interface PermissionRequest { - id: string - sessionID: string - tool?: { messageID: string; callID: string } - metadata?: Record -} - /** * Override the upstream "task" tool registration with the v1.0.25-style renderer. * Must be called once at app startup. diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat.css b/packages/kilo-vscode/webview-ui/src/styles/chat.css index dc9c2cde563..bd82cea41e5 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat.css @@ -1094,56 +1094,64 @@ } /* ============================================ - Permission Dock (patterns inside BasicTool) + Permission Dock (VS Code overrides) ============================================ */ -.permission-dock-patterns { - display: flex; - flex-direction: column; - gap: 4px; - max-height: 120px; - overflow-y: auto; - padding: 8px 12px; -} - -.permission-dock-pattern { - font-size: 12px; - font-family: var(--vscode-editor-font-family, monospace); - color: var(--vscode-foreground); - word-break: break-all; -} - -/* Permission Prompt (inline with tool cards) */ -[data-component="tool-part-wrapper"][data-permission="true"] { - /* When wrapping a Part + permission, the outer wrapper provides the card border. - Remove the inner Part's tool-part-wrapper border so we don't get double borders. */ - > [data-component="tool-part-wrapper"] { - border: none; - border-radius: 0; +[data-component="dock-prompt"][data-kind="permission"] { + [data-slot="permission-body"] { + padding: 10px 12px 0; + gap: 8px; } -} -[data-component="permission-prompt"] { - border-top: 1px solid var(--border-weak-base, var(--vscode-panel-border)); - padding: 8px 12px; -} + [data-slot="permission-header-title"] { + font-size: 13px; + display: flex; + align-items: baseline; + gap: 8px; + } -[data-component="permission-prompt"] [data-slot="permission-description"] { - font-size: 12px; - color: var(--text-weak, var(--vscode-descriptionForeground)); - margin: 0 0 8px; -} + [data-slot="permission-header-subtitle"] { + font-size: 11px; + font-weight: var(--font-weight-regular, 400); + color: var(--text-weak, var(--vscode-descriptionForeground)); + } -[data-component="permission-prompt"] [data-slot="permission-actions"] { - display: flex; - align-items: center; - gap: 6px; -} + [data-slot="permission-hint"] { + font-size: 12px; + } -[data-component="permission-prompt"] [data-slot="permission-hint"] { - font-size: 11px; - color: var(--text-weak, var(--vscode-descriptionForeground)); - margin: 4px 0 0; + [data-slot="permission-patterns"] { + margin-top: 0; + margin-bottom: 0; + max-height: 120px; + + code { + font-size: 12px; + font-family: var(--vscode-editor-font-family, monospace); + color: var(--vscode-foreground); + word-break: break-all; + } + } + + [data-slot="permission-footer"] { + padding: 8px; + margin-top: 0; + } + + [data-slot="permission-footer-actions"] > [data-component="button"][data-variant="primary"] { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); + border: 1px solid var(--vscode-button-border, transparent); + + &:hover:not(:disabled) { + background-color: var(--vscode-button-hoverBackground); + } + } + + [data-slot="permission-footer-actions"] > [data-component="button"][data-variant="ghost"] { + border: none; + box-shadow: none; + } } /* Dialog Confirmation */ From c3f72d3463398c82138ca53719c72dc0536c83e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 10 Mar 2026 14:00:29 +0000 Subject: [PATCH 2/5] chore: update kilo-vscode visual regression baselines --- .../composite-webview/bash-with-permission-chromium-linux.png | 4 ++-- .../composite-webview/glob-with-permission-chromium-linux.png | 4 ++-- .../composite-webview/permission-dock-chromium-linux.png | 4 ++-- .../todo-write-with-permission-chromium-linux.png | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png index cb4ea8c6ef7..88843db73a1 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6cbba3354994879f21489539615bbeeb71cb944980c642d502fdab3c4500e73 -size 11000 +oid sha256:5c6951a91692a94a01b94b9b75bfc5c7f4d82f930f301d8b33a965e14e0cf9ea +size 2619 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png index eb3edfc7392..504d004ac61 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bcb19f99cbd4cbaf403e2224139ff47318c2618457975d4f957b481962031836 -size 9735 +oid sha256:4e3a05c2f4c3352b58dee74bddd51bbc11943cd707dc70305e4b9b381b60d3ba +size 1393 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-chromium-linux.png index 2cc64b57e70..6555c17a5a4 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a225a66c7981745089a46f20841d5f214d23d905b8b31194cfba9f278a3763d -size 10965 +oid sha256:cae28aa54297014cb01b26120197b3bcab0b0a250c21d90c1050de3e09ee622b +size 10743 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png index 16210893824..dfdbaf69c7a 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9777ee1cb00c3632e71c64d2518f86aab1e4199d52e95b36c0d6344ac042994a -size 14844 +oid sha256:eea43670fc751460f12f527fe9ba4cd15039502603caa200ddbd661ba63b3a9c +size 177 From 0ef7805b5430cd098dce49577efec37fd6d01b44 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 10 Mar 2026 15:29:06 +0100 Subject: [PATCH 3/5] fix: keep chatbox visible when permission dock is shown Show the PermissionDock above the chatbox instead of replacing it. --- .../src/components/chat/ChatView.tsx | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx index 23317774b38..740d5683b65 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx @@ -99,34 +99,32 @@ export const ChatView: Component = (props) => { /> )} - - -
+ +
+ + - - - -
-
- + +
+
From 0abf4df829edfaab7d88128922ff8eda174db83b Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 10 Mar 2026 15:42:20 +0100 Subject: [PATCH 4/5] test: update visual regression stories for permission/question dock above chatbox Update permission stories to render ChatView with PermissionDock above the chatbox instead of old inline permission buttons. Add new stories for todowrite permission dock, write permission with file patterns, and question dock above chatbox. --- .../src/stories/composite.stories.tsx | 158 +++++++++++------- 1 file changed, 99 insertions(+), 59 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx index ab71bd221d8..e2b6d265090 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx @@ -8,18 +8,10 @@ */ import type { Meta, StoryObj } from "storybook-solidjs-vite" -import { For, Show } from "solid-js" -import { Part } from "@kilocode/kilo-ui/message-part" -import { BasicTool } from "@kilocode/kilo-ui/basic-tool" -import { Button } from "@kilocode/kilo-ui/button" -import type { - AssistantMessage as SDKAssistantMessage, - TextPart, - ToolPart, - Message as SDKMessage, -} from "@kilocode/sdk/v2" +import type { AssistantMessage as SDKAssistantMessage, TextPart, ToolPart } from "@kilocode/sdk/v2" import { StoryProviders, defaultMockData, mockSessionValue } from "./StoryProviders" import { AssistantMessage } from "../components/chat/AssistantMessage" +import { ChatView } from "../components/chat/ChatView" import { registerVscodeToolOverrides } from "../components/chat/VscodeToolOverrides" import { SessionContext } from "../context/session" import type { PermissionRequest, QuestionRequest } from "../types/messages" @@ -336,80 +328,120 @@ export default meta type Story = StoryObj // --------------------------------------------------------------------------- -// 1. Tool with inline permission (glob) +// 1. Permission dock — glob (above chatbox) // --------------------------------------------------------------------------- export const GlobWithPermission: Story = { - name: "Glob + Inline Permission", + name: "Permission Dock — glob above chatbox", render: () => { const perms = [globPermission] - const data = dataWith([globPending], perms) + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", permissions: perms }), + messages: () => [{ id: "msg-001" }] as any[], + } return ( - - + + +
+ +
+
) }, } // --------------------------------------------------------------------------- -// 2. Tool with inline permission (bash) +// 2. Permission dock — bash (above chatbox) // --------------------------------------------------------------------------- export const BashWithPermission: Story = { - name: "Bash + Inline Permission", + name: "Permission Dock — bash above chatbox", render: () => { const perms = [bashPermission] - const data = dataWith([bashPending], perms) + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", permissions: perms }), + messages: () => [{ id: "msg-001" }] as any[], + } return ( - - + + +
+ +
+
) }, } // --------------------------------------------------------------------------- -// 3. Permission dock (non-tool bottom prompt) +// 3. Permission dock — write with file patterns (above chatbox) // --------------------------------------------------------------------------- -export const PermissionDock: Story = { - name: "Permission Dock", +export const PermissionDockWrite: Story = { + name: "Permission Dock — write with patterns", render: () => { - const perm = dockPermission + const perms = [dockPermission] + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", permissions: perms }), + messages: () => [{ id: "msg-001" }] as any[], + } return ( - -
- - 0}> -
- {(pattern) => {pattern}} -
-
-
-
-
- - - -
-

Approval applies only to the current session

+ + +
+
-
+ + + ) + }, +} + +// --------------------------------------------------------------------------- +// 3b. Permission dock — todowrite (above chatbox) +// --------------------------------------------------------------------------- + +export const PermissionDockTodo: Story = { + name: "Permission Dock — todowrite above chatbox", + render: () => { + const perms = [todoWritePermission] + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", permissions: perms }), + messages: () => [{ id: "msg-001" }] as any[], + } + return ( + + +
+ +
+
+
+ ) + }, +} + +// --------------------------------------------------------------------------- +// 3c. Question dock above chatbox +// --------------------------------------------------------------------------- + +export const QuestionAboveChatbox: Story = { + name: "Question Dock — above chatbox", + render: () => { + const qs = [questionRequest] + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", questions: qs }), + messages: () => [{ id: "msg-001" }] as any[], + } + return ( + + +
+ +
+
) }, @@ -550,17 +582,25 @@ export const QuestionDismissed: Story = { } // --------------------------------------------------------------------------- -// 10. TodoWrite with inline permission (pending — shows todo list + permission prompt) +// 10. TodoWrite with permission in dock (pending — permission shown above chatbox) // --------------------------------------------------------------------------- export const TodoWriteWithPermission: Story = { - name: "TodoWrite + Inline Permission", + name: "TodoWrite + Permission in Dock", render: () => { const perms = [todoWritePermission] const data = dataWith([todoWritePending], perms) + const session = { + ...mockSessionValue({ id: SESSION_ID, status: "busy", permissions: perms }), + messages: () => [{ id: "msg-001" }] as any[], + } return ( - - + + +
+ +
+
) }, From 20fae0b854dca9656138572ec03bb2a445aec22c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 10 Mar 2026 14:44:28 +0000 Subject: [PATCH 5/5] chore: update kilo-vscode visual regression baselines --- .../composite-webview/bash-with-permission-chromium-linux.png | 4 ++-- .../composite-webview/glob-with-permission-chromium-linux.png | 4 ++-- .../composite-webview/permission-dock-todo-chromium-linux.png | 3 +++ .../permission-dock-write-chromium-linux.png | 3 +++ .../question-above-chatbox-chromium-linux.png | 3 +++ .../todo-write-with-permission-chromium-linux.png | 4 ++-- 6 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png create mode 100644 packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png create mode 100644 packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png index 88843db73a1..ba3d7a96c7d 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5c6951a91692a94a01b94b9b75bfc5c7f4d82f930f301d8b33a965e14e0cf9ea -size 2619 +oid sha256:59b9045133b989b85e3748e4fe509b317e21761280f26b3ee46f837bccf3a1ad +size 14489 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png index 504d004ac61..d59de67ff10 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e3a05c2f4c3352b58dee74bddd51bbc11943cd707dc70305e4b9b381b60d3ba -size 1393 +oid sha256:ce43eb9d6415fdb082ff03ab15080219c6275f7ae1bd09689f7d020a5511347c +size 15274 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png new file mode 100644 index 00000000000..bce78534484 --- /dev/null +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6fcd2e69976f2c9a02b24e721e96638ec20a6711d3853d0795e2913315ca0b5 +size 14341 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png new file mode 100644 index 00000000000..83a8e0c1fe7 --- /dev/null +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ed8885168e17a44fee3cd34e32143a6514fce09c3cd143dcf3be3088164d696 +size 16827 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png new file mode 100644 index 00000000000..f83f906ecac --- /dev/null +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:83076ce468f046d5a884d8abf38189718641803cc966cae255e75e238894ae72 +size 30673 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png index dfdbaf69c7a..9c5e298920f 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eea43670fc751460f12f527fe9ba4cd15039502603caa200ddbd661ba63b3a9c -size 177 +oid sha256:26b18e59c4eccd851e4cb11f62f4b7b09e0fce56e9922b1ec51a94a4d9aeae67 +size 17664