diff --git a/packages/kilo-docs/AGENTS.md b/packages/kilo-docs/AGENTS.md index 0eed736250a..bdc036e7fd3 100644 --- a/packages/kilo-docs/AGENTS.md +++ b/packages/kilo-docs/AGENTS.md @@ -30,6 +30,12 @@ Use the Markdoc image tag format: Note that this site is served under kilo.ai/docs so the `/docs` prefix **must** be present in every image path. +#### Generated screenshots + +When updating screenshots for active docs pages, prefer generated screenshot-test assets from `packages/kilo-docs/public/img/screenshot-tests/` and reference them as `/docs/img/screenshot-tests/...`. Only replace a hand-captured image when the generated screenshot matches the docs content closely. Do not replace screenshots in VSCode Legacy docs tabs or sections. + +If a docs page references a generated VS Code visual-regression screenshot, record that usage in `packages/kilo-vscode/tests/visual-regression.spec.ts` by adding the story ID to the `DOCS` map. Keep `packages/kilo-vscode/tests/visual-regression.spec.mts` in sync while that file exists. If no matching generated screenshot exists, add or update a Storybook story in `packages/kilo-vscode/webview-ui/src/stories/` and let visual-regression CI generate the baseline. + Image attributes: | Attribute | Type | Required | Description | diff --git a/packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md b/packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md index 249692c8d50..19ff14dc2da 100644 --- a/packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md +++ b/packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md @@ -9,7 +9,7 @@ description: "Track and manage tasks with AI-generated todo lists" **Why it matters**: Complex workflows have lots of moving parts. Without structure, it's easy to miss steps, duplicate work, or forget what comes next. -{% image src="/docs/img/task-todo-list/task-todo-list-1.png" alt="Task Todo List overview showing interactive checklist in Kilo Code" width="500" /%} +{% image src="/docs/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png" alt="Task Todo List overview showing interactive checklist in Kilo Code" width="420" /%} ## How to trigger todo lists @@ -53,7 +53,7 @@ Kilo updates the list when: **1. Task Header Summary** Quick progress overview with your next important item -{% image src="/docs/img/task-todo-list/task-header.png" alt="Task header summary showing todo list progress" width="500" /%} +{% image src="/docs/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png" alt="Task header summary showing todo list progress" width="420" /%} Click the task header summary to expand the full list inline and jump to the current item. diff --git a/packages/kilo-docs/pages/customize/workflows.md b/packages/kilo-docs/pages/customize/workflows.md index 50ea192b3b6..d57d1d1b315 100644 --- a/packages/kilo-docs/pages/customize/workflows.md +++ b/packages/kilo-docs/pages/customize/workflows.md @@ -8,7 +8,7 @@ platform: new Workflows (also called **slash commands** in the new extension) automate repetitive tasks by defining step-by-step instructions for Kilo Code to execute. -{% image src="/docs/img/slash-commands/workflows.png" alt="Workflows tab in Kilo Code" width="600" caption="Workflows tab in Kilo Code" /%} +{% image src="/docs/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-chromium-linux.png" alt="Workflows tab in Kilo Code" width="420" caption="Workflows tab in Kilo Code" /%} ## Creating Workflows diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png index 963e13adb0a..f1e6bc8a35b 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ab73f8c0585e9f889c51073428aa0e7082d7aecdc3d5b0c459720c1b860c436 -size 4890 +oid sha256:d34153690f8aa4ef7e06e12385a184c151843f3ae75a9955619a6d7e88dc8c8b +size 7981 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png new file mode 100644 index 00000000000..c8ecdbcbb55 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4d7ac9d6322d2cf673a6353cb07cf9979ad55351769ba9d90eed386170f6c42 +size 40854 diff --git a/packages/kilo-vscode/AGENTS.md b/packages/kilo-vscode/AGENTS.md index ff630a3ac06..04604160a61 100644 --- a/packages/kilo-vscode/AGENTS.md +++ b/packages/kilo-vscode/AGENTS.md @@ -186,6 +186,12 @@ New webview features must use **`@kilocode/kilo-ui`** components instead of raw - **Prefer kilo-ui styles**: Always reuse existing kilo-ui CSS variables, tokens, and component styles instead of writing custom CSS. If a style doesn't exist in kilo-ui yet, add it there and reuse it rather than inlining or duplicating styles in the webview. - **Icons**: kilo-ui has 75+ custom SVG icons in [`packages/ui/src/components/icon.tsx`](../../packages/ui/src/components/icon.tsx). To list all available icon names: `node -e "const c=require('fs').readFileSync('../../packages/ui/src/components/icon.tsx','utf8');[...c.matchAll(/^\\s{2}[\"']?([\\w-]+)[\"']?:\\s*\x60/gm)].map(m=>m[1]).sort().forEach(n=>console.log(n))"`. Icon names use both hyphenated (`arrow-left`) and bare-word (`brain`, `console`, `providers`) keys. +## Docs Screenshot Stories + +When adding or updating Storybook stories for screenshots used by docs, make the story content match the docs page closely before replacing the docs image. Do not replace screenshots from VSCode Legacy docs tabs or sections. + +Generated screenshot baselines live under `packages/kilo-docs/public/img/screenshot-tests/` and are referenced from docs as `/docs/img/screenshot-tests/...`. If a generated VS Code visual-regression screenshot is used in docs, add the docs usage to the `DOCS` map in `tests/visual-regression.spec.ts` and keep `tests/visual-regression.spec.mts` in sync while that file exists. + ## Debugging - Extension logs: "Extension Host" output channel (not Debug Console) diff --git a/packages/kilo-vscode/tests/visual-regression.spec.mts b/packages/kilo-vscode/tests/visual-regression.spec.mts index d3d816ca19f..6877dfe7b6c 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.mts +++ b/packages/kilo-vscode/tests/visual-regression.spec.mts @@ -53,6 +53,27 @@ const SKIP = new Set([ "composite-webview--permission-dock-config-preloaded", ]) +const DOCS = new Map([ + [ + "chat--task-header-with-todos", + [ + "packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png", + ], + ], + [ + "composite-webview--todo-write-docs-overview", + [ + "packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png", + ], + ], + [ + "settings--agent-behaviour-workflows", + [ + "packages/kilo-docs/pages/customize/workflows.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-chromium-linux.png", + ], + ], +]) + // Generate one test() per story so Playwright's scheduler can distribute // them freely across workers — no manual sharding needed. // Skip fetching stories on macOS since test.skip() above already marks the file skipped. @@ -60,6 +81,10 @@ const stories = IS_DARWIN ? [] : (await fetchStories()).filter((s) => !SKIP.has( for (const story of stories) { test(`${story.title} / ${story.name}`, async ({ page }) => { + for (const ref of DOCS.get(story.id) ?? []) { + test.info().annotations.push({ type: "docs", description: ref }) + } + // Narrow stories (IDs ending in "-200") use a 200px viewport // The "-200" suffix comes from the export name convention (e.g. Default200, WithThinking200) const narrow = story.id.endsWith("-200") @@ -74,6 +99,6 @@ for (const story of stories) { const [component, variant] = story.id.split("--") const root = page.locator("#storybook-root") - await expect(root).toHaveScreenshot(["visual-regression", component!, `${variant}.png`]) + await expect(root).toHaveScreenshot(["visual-regression", component!, `${variant}-chromium-linux.png`]) }) } diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts b/packages/kilo-vscode/tests/visual-regression.spec.ts index f5354e4cd69..75940ae1de5 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts @@ -54,6 +54,27 @@ const SKIP = new Set([ "composite-webview--permission-dock-config-preloaded", ]) +const DOCS = new Map([ + [ + "chat--task-header-with-todos", + [ + "packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png", + ], + ], + [ + "composite-webview--todo-write-docs-overview", + [ + "packages/kilo-docs/pages/code-with-ai/features/task-todo-list.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-docs-overview-chromium-linux.png", + ], + ], + [ + "settings--agent-behaviour-workflows", + [ + "packages/kilo-docs/pages/customize/workflows.md:/docs/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-chromium-linux.png", + ], + ], +]) + // Generate one test() per story so Playwright's scheduler can distribute // them freely across workers — no manual sharding needed. // Skip fetching stories on macOS since test.skip() above already marks the file skipped. @@ -61,6 +82,10 @@ const stories = IS_DARWIN ? [] : (await fetchStories()).filter((s) => !SKIP.has( for (const story of stories) { test(`${story.title} / ${story.name}`, async ({ page }) => { + for (const ref of DOCS.get(story.id) ?? []) { + test.info().annotations.push({ type: "docs", description: ref }) + } + // Narrow stories (IDs ending in "-200") use a 200px viewport const narrow = story.id.endsWith("-200") await page.setViewportSize({ width: narrow ? 200 : 420, height: 720 }) @@ -74,6 +99,6 @@ for (const story of stories) { const [component, variant] = story.id.split("--") const root = page.locator("#storybook-root") - await expect(root).toHaveScreenshot(["visual-regression", component!, `${variant!}.png`]) + await expect(root).toHaveScreenshot(["visual-regression", component!, `${variant!}-chromium-linux.png`]) }) } diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index aec050b64d4..c08c9bfba1a 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx @@ -67,6 +67,7 @@ const MOCK_PROVIDERS = { name: "Anthropic: Claude Sonnet 4.6", inputPrice: 0.003, outputPrice: 0.015, + limit: { context: 200000, output: 8192 }, }, }, }, diff --git a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx index 67229d5d457..a6c5f8522f4 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/chat.stories.tsx @@ -16,7 +16,7 @@ import { SuggestBar } from "../components/chat/SuggestBar" import { MessageList } from "../components/chat/MessageList" import { SessionContext } from "../context/session" import { ServerContext } from "../context/server" -import type { QuestionRequest, SuggestionRequest, TodoItem } from "../types/messages" +import type { Message, Part, QuestionRequest, SuggestionRequest, TodoItem } from "../types/messages" const SESSION_ID = "story-session-chat-001" @@ -449,10 +449,141 @@ export const MessageListSubagentToQueuedUserSpacing: Story = { // TaskHeader with todos // --------------------------------------------------------------------------- +const headerNow = 1_700_000_000_000 +const headerUserID = "user-task-header-001" +const headerAssistantID = "asst-task-header-001" +const headerMessages: Message[] = [ + { + id: headerUserID, + sessionID: SESSION_ID, + role: "user", + content: "Can you use the update_todo_list tool to create a CLI interface implementation plan?", + createdAt: new Date(headerNow - 12000).toISOString(), + time: { created: headerNow - 12000 }, + }, + { + id: headerAssistantID, + sessionID: SESSION_ID, + role: "assistant", + parentID: headerUserID, + content: "I'll track the CLI interface implementation with a todo list.", + createdAt: new Date(headerNow - 10000).toISOString(), + time: { created: headerNow - 10000 }, + modelID: "anthropic/claude-sonnet-4-6", + providerID: "kilo", + mode: "default", + agent: "code", + path: { cwd: "/project", root: "/project" }, + }, +] +const headerParts: Record = { + [headerAssistantID]: [ + { + id: "part-header-read-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "read", + state: { + status: "completed", + input: { filePath: "packages/opencode/src/cli/index.ts" }, + output: "export async function main() { /* existing CLI bootstrap */ }", + title: "Read CLI entrypoint", + }, + }, + { + id: "part-header-text-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "text", + text: "I found the existing command registration and argument parsing flow.", + }, + { + id: "part-header-glob-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "glob", + state: { + status: "completed", + input: { pattern: "packages/opencode/src/**/*.ts" }, + output: + "packages/opencode/src/cli/index.ts\npackages/opencode/src/command/run.ts\npackages/opencode/src/config/config.ts", + title: "Find CLI files", + }, + }, + { + id: "part-header-edit-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "edit", + state: { + status: "completed", + input: { filePath: "packages/opencode/src/cli/index.ts" }, + output: "Updated the command registry to expose the new interface hook.", + title: "Update CLI registry", + }, + }, + { + id: "part-header-bash-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "bash", + state: { + status: "completed", + input: { command: "bun run check-types:webview", description: "Typecheck webview" }, + output: "Checked 1 project. No type errors found.", + title: "Run typecheck", + }, + }, + { + id: "part-header-write-001", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "write", + state: { + status: "completed", + input: { filePath: "packages/opencode/src/cli/interface.ts" }, + output: "Created the CLI interface implementation scaffold.", + title: "Create interface scaffold", + }, + }, + { + id: "part-header-text-002", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "text", + text: "Next I am wiring the implementation into the existing command path.", + }, + { + id: "part-header-bash-002", + sessionID: SESSION_ID, + messageID: headerAssistantID, + type: "tool", + tool: "bash", + state: { + status: "running", + input: { command: "bun test packages/opencode/test/cli.test.ts", description: "Run CLI tests" }, + title: "Run CLI tests", + }, + }, + ], +} + const mockTodosInProgress: TodoItem[] = [ - { id: "1", content: "Create a haiku about Jan", status: "completed" }, - { id: "2", content: "Create a poem about Henk", status: "in_progress" }, - { id: "3", content: "Write a limerick about the team", status: "pending" }, + { id: "1", content: "Project setup and architecture backlog", status: "completed" }, + { id: "2", content: "Configuration schema for target jobs", status: "completed" }, + { id: "3", content: "Core scanning logic", status: "completed" }, + { id: "4", content: "Build invocation and error handling", status: "completed" }, + { id: "5", content: "CLI interface implementation", status: "in_progress" }, + { id: "6", content: "Storage layer implementation", status: "pending" }, + { id: "7", content: "Character profiles and prompt types", status: "pending" }, + { id: "8", content: "Local tests and integration tests", status: "pending" }, + { id: "9", content: "Migration guide", status: "pending" }, + { id: "10", content: "Release validation", status: "pending" }, ] const mockTodosAllDone: TodoItem[] = [ @@ -465,19 +596,22 @@ export const TaskHeaderWithTodos: Story = { render: () => { const session = { ...mockSessionValue({ id: SESSION_ID, status: "busy" }), - messages: () => [{ id: "msg-001" }] as any[], + messages: () => headerMessages, currentSession: () => ({ id: SESSION_ID, - title: "Writing poems about the team", - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + title: "Task: Can you use the update_todo_list tool to create a CLI interface implementation?", + createdAt: new Date(headerNow - 12000).toISOString(), + updatedAt: new Date(headerNow).toISOString(), }), todos: () => mockTodosInProgress, + getParts: (id: string) => headerParts[id] ?? [], + contextUsage: () => ({ tokens: 34300, percentage: 17 }), + costBreakdown: () => [{ label: "Session", cost: 0.64 }], } return ( -
+
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 69a755de639..58e2e88b87c 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/composite.stories.tsx @@ -292,6 +292,52 @@ const todoWriteCompleted: ToolPart = { }, } +const docsTodos = [ + { + id: "1", + content: "Project setup and core architecture (package.json, tsconfig, documentation, type definitions)", + status: "completed", + }, + { + id: "2", + content: "Configuration system (scraper config, targets.json, validation utilities)", + status: "completed", + }, + { + id: "3", + content: "Core scraping engine (browser manager, orchestrator, selector engine, content extractor)", + status: "completed", + }, + { + id: "4", + content: "Utility modules (DOM utils, retry logic, URL handling, validation)", + status: "completed", + }, + { id: "5", content: "CLI interface implementation", status: "in_progress" }, + { id: "6", content: "Storage layer implementation (database and file storage)", status: "pending" }, + { id: "7", content: "Chart extractors for specific chart types", status: "pending" }, + { id: "8", content: "Logging and error handling systems", status: "pending" }, + { id: "9", content: "Test suites (unit and integration tests)", status: "pending" }, + { id: "10", content: "Main entry point and final integration", status: "pending" }, +] + +const todoWriteDocsOverview: ToolPart = { + id: "part-todo-docs-001", + sessionID: SESSION_ID, + messageID: ASST_MSG_ID, + type: "tool", + callID: "call-todo-docs-001", + tool: "todowrite", + state: { + status: "completed", + input: { todos: docsTodos }, + output: "Updated 10 todos", + title: "Todo List Updated", + metadata: { todos: docsTodos }, + time: { start: now - 3000, end: now - 2800 }, + }, +} + const todoWritePermission: PermissionRequest = { id: "perm-todo-001", sessionID: SESSION_ID, @@ -609,6 +655,18 @@ export const TodoWriteCompleted: Story = { }, } +export const TodoWriteDocsOverview: Story = { + name: "TodoWrite — docs overview", + render: () => { + const data = dataWith([todoWriteDocsOverview]) + return ( + + + + ) + }, +} + // --------------------------------------------------------------------------- // 12. Permission dock — edit tool with file patterns // ---------------------------------------------------------------------------