diff --git a/.changeset/add-alibaba-provider.md b/.changeset/add-alibaba-provider.md deleted file mode 100644 index 256b5d883c..0000000000 --- a/.changeset/add-alibaba-provider.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-gateway": minor ---- - -Add Alibaba as a supported AI SDK provider for routing Qwen model requests via the native `@ai-sdk/alibaba` adapter. diff --git a/.changeset/agent-manager-message-fork.md b/.changeset/agent-manager-message-fork.md deleted file mode 100644 index 23fc7bdf7f..0000000000 --- a/.changeset/agent-manager-message-fork.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Support forking Agent Manager sessions from a specific user message. diff --git a/.changeset/custom-provider-delete-sticks.md b/.changeset/custom-provider-delete-sticks.md deleted file mode 100644 index ae10a1ec3f..0000000000 --- a/.changeset/custom-provider-delete-sticks.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"kilo-code": patch -"@kilocode/cli": patch ---- - -Fix custom provider model and variant deletions being silently reverted on save. Removing a model or reasoning variant from a custom provider now actually removes it from your config. diff --git a/.changeset/fix-worktree-session-routing.md b/.changeset/fix-worktree-session-routing.md deleted file mode 100644 index d0d5fae918..0000000000 --- a/.changeset/fix-worktree-session-routing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fixed Agent Manager incorrectly duplicating worktree sessions into the Local tab when forking a session or using "Continue in Worktree". diff --git a/.changeset/infinite-compaction-loop-cap.md b/.changeset/infinite-compaction-loop-cap.md new file mode 100644 index 0000000000..23c9e0e6cd --- /dev/null +++ b/.changeset/infinite-compaction-loop-cap.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Fix an infinite "busy" loop that could occur when a model kept reporting context overflow after every compaction. Each turn now caps compactions at three attempts and closes the turn with a visible context-overflow error instead of silently looping forever. diff --git a/.changeset/kiloclaw-chat-panel.md b/.changeset/kiloclaw-chat-panel.md deleted file mode 100644 index 59a3569346..0000000000 --- a/.changeset/kiloclaw-chat-panel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Add KiloClaw chat panel to the VS Code extension diff --git a/.changeset/plan-followup-continue-click.md b/.changeset/plan-followup-continue-click.md deleted file mode 100644 index b3a6be4d39..0000000000 --- a/.changeset/plan-followup-continue-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix the "Continue here" button not submitting after a plan is finished. Picking an option on a single-question prompt now sends the reply immediately — matching the CLI behaviour — and the redundant "Type your own answer" row no longer appears on the plan follow-up question. diff --git a/.changeset/question-custom-answer-duplicate.md b/.changeset/question-custom-answer-duplicate.md deleted file mode 100644 index d5f1021732..0000000000 --- a/.changeset/question-custom-answer-duplicate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix duplicate text shown when typing a custom answer in the question tool. The preview text above the input field is now hidden while editing, so only the input value is visible. diff --git a/.changeset/question-dock-explicit-submit.md b/.changeset/question-dock-explicit-submit.md new file mode 100644 index 0000000000..96e5645120 --- /dev/null +++ b/.changeset/question-dock-explicit-submit.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Restore explicit Submit behavior for single-choice question prompts in the VS Code extension so option clicks stay visible for review instead of immediately sending the answer. diff --git a/.changeset/queued-messages-stay-at-bottom.md b/.changeset/queued-messages-stay-at-bottom.md deleted file mode 100644 index fc28d66d16..0000000000 --- a/.changeset/queued-messages-stay-at-bottom.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix queued follow-up messages so they stay stacked at the bottom of the chat while the previous turn is still being processed, instead of getting interleaved with tool output. diff --git a/.changeset/quiet-review-summary.md b/.changeset/quiet-review-summary.md deleted file mode 100644 index eb3ab9f2aa..0000000000 --- a/.changeset/quiet-review-summary.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/cli": patch ---- - -Clarify suggest tool guidance so the assistant writes its final summary before offering a local review. diff --git a/.changeset/restore-virtual-history.md b/.changeset/restore-virtual-history.md deleted file mode 100644 index 433d931ca9..0000000000 --- a/.changeset/restore-virtual-history.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Restore earlier chat history when scrolling through virtualized message lists. diff --git a/.changeset/scroll-up-while-busy.md b/.changeset/scroll-up-while-busy.md deleted file mode 100644 index 67073cf95d..0000000000 --- a/.changeset/scroll-up-while-busy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix chat scroll jumping back to the bottom while the session is busy — you can now scroll up to read earlier context while a response is streaming or while a question is waiting for your answer. diff --git a/.changeset/sidebar-message-forks.md b/.changeset/sidebar-message-forks.md deleted file mode 100644 index 3c07a889db..0000000000 --- a/.changeset/sidebar-message-forks.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Support forking sidebar conversations from any user message. diff --git a/.changeset/snapshot-diff-freeze.md b/.changeset/snapshot-diff-freeze.md new file mode 100644 index 0000000000..4f2ffb136a --- /dev/null +++ b/.changeset/snapshot-diff-freeze.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Fix TUI freeze on huge-file diffs. Session-summary and file-view patches now use git directly instead of a JavaScript Myers implementation, so files of any size render a full diff without blocking the session. diff --git a/.changeset/suggest-tool-stuck-session.md b/.changeset/suggest-tool-stuck-session.md deleted file mode 100644 index 305bc24b2b..0000000000 --- a/.changeset/suggest-tool-stuck-session.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix a stuck session state when the suggest tool was left open. If the suggestion was never accepted or dismissed (for example, because VS Code was closed while it was showing), the session stayed marked as busy and any follow-up messages appeared queued forever. The session is now marked idle while waiting for a response to a suggestion. diff --git a/.changeset/update-anthropic-sdk-3071.md b/.changeset/update-anthropic-sdk-3071.md deleted file mode 100644 index 8b418e0910..0000000000 --- a/.changeset/update-anthropic-sdk-3071.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@kilocode/cli": patch -"@kilocode/kilo-gateway": patch ---- - -Update `@ai-sdk/anthropic` to 3.0.71, adding `xhigh` effort for Opus 4.7 adaptive thinking (3.0.70) and fixing fine-grained tool streaming beta header for Opus 4.7 (3.0.71) diff --git a/.changeset/update-bedrock-vertex-providers.md b/.changeset/update-bedrock-vertex-providers.md deleted file mode 100644 index e64fc61bf4..0000000000 --- a/.changeset/update-bedrock-vertex-providers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/cli": patch ---- - -Update `@ai-sdk/amazon-bedrock` to 4.0.96 and `@ai-sdk/google-vertex` to 4.0.112, both of which include Opus 4.7 support with `xhigh` adaptive thinking effort diff --git a/.changeset/vscode-subagent-spacing.md b/.changeset/vscode-subagent-spacing.md deleted file mode 100644 index 7fe964ed86..0000000000 --- a/.changeset/vscode-subagent-spacing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Restore spacing between sub-agent output and the following user message in the VS Code chat. diff --git a/.gitattributes b/.gitattributes index 3044164203..a53ef3c352 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ # Visual regression baseline snapshots packages/kilo-ui/tests/**/*.png filter=lfs diff=lfs merge=lfs -text packages/kilo-vscode/tests/**/*.png filter=lfs diff=lfs merge=lfs -text +packages/kilo-docs/public/img/screenshot-tests/**/*.png filter=lfs diff=lfs merge=lfs -text # Hide non-English localization files by default in GitHub PR diffs. **/i18n/*.ts linguist-generated=true diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index 734d589d77..a041bc7256 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -40,19 +40,12 @@ permissions: jobs: smoke-test: name: Smoke Test - runs-on: ubuntu-24.04 + runs-on: blacksmith-2vcpu-ubuntu-2404 timeout-minutes: 30 env: KILO_API_KEY: ${{ secrets.KILO_API_KEY }} KILO_ORG_ID: ${{ secrets.KILO_ORG_ID }} steps: - - name: Free disk space - continue-on-error: true - run: | - sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \ - /usr/local/share/boost /opt/hostedtoolcache - sudo docker image prune --all --force - - name: Checkout kilo-bench uses: actions/checkout@v4 with: diff --git a/.github/workflows/visual-regression.yml b/.github/workflows/visual-regression.yml index 369da65856..4f49c4aa46 100644 --- a/.github/workflows/visual-regression.yml +++ b/.github/workflows/visual-regression.yml @@ -26,7 +26,7 @@ jobs: - "packages/kilo-vscode/.storybook/**" - "packages/kilo-vscode/tests/visual-regression*" - "packages/kilo-vscode/tests/permission-dock-dropdown*" - - "packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/**" + - "packages/kilo-docs/public/img/screenshot-tests/**" - ".github/workflows/visual-regression.yml" - name: Check if PR is from a fork id: fork-check @@ -127,7 +127,7 @@ jobs: const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8')); const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs')); const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; })); - const dir = 'tests/visual-regression.spec.ts-snapshots'; + const dir = '../kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression'; if (!fs.existsSync(dir)) process.exit(0); for (const component of fs.readdirSync(dir)) { const cdir = path.join(dir, component); @@ -143,7 +143,7 @@ jobs: - name: Check for baseline changes (fork PRs) if: needs.check-paths.outputs.is_fork == 'true' run: | - git add packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/ if git diff --cached --quiet; then echo "No visual regression detected." else @@ -157,7 +157,7 @@ jobs: - name: Fail if baselines still changing after auto-update if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit.outputs.is_baseline_update == 'true' run: | - git add packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/ if git diff --cached --quiet; then echo "Baselines are stable after auto-update." else @@ -176,7 +176,7 @@ jobs: run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-ui/ if git diff --cached --quiet; then echo "No new baselines — nothing to commit." echo "changed=false" >> "$GITHUB_OUTPUT" @@ -291,7 +291,7 @@ jobs: const idx = JSON.parse(fs.readFileSync('storybook-static/index.json', 'utf8')); const stories = Object.values(idx.entries || idx.stories || {}).filter(s => s.id && !s.id.endsWith('--docs')); const expected = new Set(stories.map(s => { const [c,v] = s.id.split('--'); return c + '/' + v + '-chromium-linux.png'; })); - const dir = 'tests/visual-regression.spec.ts-snapshots'; + const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression'; if (!fs.existsSync(dir)) process.exit(0); for (const component of fs.readdirSync(dir)) { const cdir = path.join(dir, component); @@ -307,7 +307,7 @@ jobs: - name: Remove stale baselines for permission-dock-dropdown tests run: | node -e " - const fs = require('fs'), path = require('path'); + const fs = require('fs'); const specPath = 'tests/permission-dock-dropdown.spec.ts'; const expected = new Set(); if (fs.existsSync(specPath)) { @@ -316,20 +316,16 @@ jobs: let m; while ((m = re.exec(spec)) !== null) { const parts = m[1].split(',').map(s => s.trim().replace(/[\"']/g, '')); - expected.add(parts.join('/').replace(/\.png$/, '-chromium-linux.png')); + const file = parts[parts.length - 1]; + if (file) expected.add(file.replace(/\.png$/, '-chromium-linux.png')); } } - const dir = 'tests/permission-dock-dropdown.spec.ts-snapshots'; + const dir = '../kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown'; if (!fs.existsSync(dir)) process.exit(0); - for (const sub of fs.readdirSync(dir)) { - const sdir = path.join(dir, sub); - if (!fs.statSync(sdir).isDirectory()) continue; - for (const file of fs.readdirSync(sdir)) { - const rel = sub + '/' + file; - if (file.endsWith('.png') && !expected.has(rel)) { - console.log('Removing stale baseline:', rel); - fs.unlinkSync(path.join(sdir, file)); - } + for (const file of fs.readdirSync(dir)) { + if (file.endsWith('.png') && !expected.has(file)) { + console.log('Removing stale baseline:', file); + fs.unlinkSync(dir + '/' + file); } } " @@ -338,8 +334,7 @@ jobs: - name: Check for baseline changes (fork PRs) if: needs.check-paths.outputs.is_fork == 'true' run: | - git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ - [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/ if git diff --cached --quiet; then echo "No visual regression detected." else @@ -353,8 +348,7 @@ jobs: - name: Fail if baselines still changing after auto-update if: needs.check-paths.outputs.is_fork != 'true' && steps.check-baseline-commit-vscode.outputs.is_baseline_update == 'true' run: | - git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ - [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/ if git diff --cached --quiet; then echo "Baselines are stable after auto-update." else @@ -373,8 +367,7 @@ jobs: run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/ - [ -d packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots ] && git add packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/ + git add packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/ if git diff --cached --quiet; then echo "No new baselines — nothing to commit." echo "changed=false" >> "$GITHUB_OUTPUT" diff --git a/bun.lock b/bun.lock index 47e7ad3b26..c6e4b08ed4 100644 --- a/bun.lock +++ b/bun.lock @@ -30,7 +30,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -86,7 +86,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -119,7 +119,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -170,7 +170,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -199,7 +199,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@ai-sdk/alibaba": "1.0.17", "@ai-sdk/anthropic": "3.0.71", @@ -235,7 +235,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.2.14", + "version": "7.2.20", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -248,7 +248,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -268,7 +268,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", @@ -303,7 +303,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -358,7 +358,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.2.14", + "version": "7.2.20", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -510,7 +510,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@kilocode/sdk": "workspace:*", "effect": "catalog:", @@ -535,7 +535,7 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "semver": "^7.6.3", }, @@ -546,7 +546,7 @@ }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "cross-spawn": "catalog:", }, @@ -561,7 +561,7 @@ }, "packages/server": { "name": "@opencode-ai/server", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "effect": "catalog:", }, @@ -571,7 +571,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.2.14", + "version": "7.2.20", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -594,7 +594,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -644,7 +644,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.2.14", + "version": "7.2.20", "dependencies": { "zod": "catalog:", }, @@ -664,6 +664,7 @@ ], "patchedDependencies": { "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", + "stream-chat@9.38.0": "patches/stream-chat@9.38.0.patch", }, "overrides": { "@effect/platform-node-shared": "4.0.0-beta.46", diff --git a/nix/hashes.json b/nix/hashes.json index 14da256fb5..9c16b21c2b 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-XbN+85hGFq53RxAaksXBwD4n2PYrcVimDyJGsyi4IW0=", - "aarch64-linux": "sha256-F6lWJh3J2vdRv+gfYFa8kNPNHgBRhjlwtQdFKHNjaZo=", - "aarch64-darwin": "sha256-3oURfnhyuvj86o4TCH9vCnIoNVcwwRFE6wcc4xG2qLY=", - "x86_64-darwin": "sha256-pQUBadkJdkqPKpi5sgJsEGw40ZeASDK1xG/XpcfnECo=" + "x86_64-linux": "sha256-ReAVmBtIE8Et9mDuzCWuB/ExtqaEQRXYPYoMEJ604Qw=", + "aarch64-linux": "sha256-4Ce94KfjrppSRLrF6ogA1nZCBIqo3RvRjPd4Y+Xrcrg=", + "aarch64-darwin": "sha256-RBqhQJclQc71cR9Aby8HQncYMadIpL//pE+QnF8og5w=", + "x86_64-darwin": "sha256-WrYlAn5cjrlBVcPzGg+ysrzWXjsM6bDQhu9lUIPe8cs=" } } diff --git a/package.json b/package.json index 27766c649b..201b42b35b 100644 --- a/package.json +++ b/package.json @@ -135,8 +135,9 @@ }, "patchedDependencies": { "@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch", - "solid-js@1.9.10": "patches/solid-js@1.9.10.patch" + "solid-js@1.9.10": "patches/solid-js@1.9.10.patch", + "stream-chat@9.38.0": "patches/stream-chat@9.38.0.patch" }, - "version": "7.2.14", + "version": "7.2.20", "peerDependencies": {} } diff --git a/packages/app/package.json b/packages/app/package.json index f127033c22..9ba7916da7 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.2.14", + "version": "7.2.20", "description": "", "type": "module", "exports": { diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 101b5ae6a5..b8ba98e055 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 21d53b38e9..7c314c348d 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 0de0e0eee0..474ba2f1da 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "1.4.6" +version = "7.2.20" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.4.6/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.20/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.4.6/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.20/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.4.6/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.20/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.4.6/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.20/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.4.6/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.20/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/AGENTS.md b/packages/kilo-docs/AGENTS.md index 0eed736250..bdc036e7fd 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/components/TopNav.tsx b/packages/kilo-docs/components/TopNav.tsx index 1f1dafae5a..d0a7734a1d 100644 --- a/packages/kilo-docs/components/TopNav.tsx +++ b/packages/kilo-docs/components/TopNav.tsx @@ -215,6 +215,15 @@ interface TopNavProps { showMobileMenuButton?: boolean } +function preview(url: string) { + if (typeof window === "undefined" || !URL.canParse(url)) return url + + const value = new URL(url) + if (value.hostname !== "kilo.ai" || !value.pathname.startsWith("/docs")) return url + + return `${window.location.origin}${value.pathname}${value.search}${value.hash}` +} + export function TopNav({ onMobileMenuToggle, isMobileMenuOpen = false, showMobileMenuButton = true }: TopNavProps) { const router = useRouter() const [openDropdown, setOpenDropdown] = useState(null) @@ -250,6 +259,12 @@ export function TopNav({ onMobileMenuToggle, isMobileMenuOpen = false, showMobil indexName: process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME || "docsearch", apiKey: process.env.NEXT_PUBLIC_ALGOLIA_API_KEY || "24b09689d5b4223813d9b8e48563c8f6", askAi: process.env.NEXT_PUBLIC_ALGOLIA_ASSISTANT_ID || "askAIDemo", + transformItems(items) { + return items.map((item) => ({ + ...item, + url: preview(item.url), + })) + }, }) }, []) diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index 9d3bdb2e47..c69de58f63 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.2.14", + "version": "7.2.20", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", 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 249692c8d5..19ff14dc2d 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 50ea192b3b..d57d1d1b31 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-ui/tests/visual-regression.spec.ts-snapshots/components-accordion/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-accordion/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-accordion/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-accordion/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-accordion/multiple-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-accordion/multiple-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-accordion/multiple-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-accordion/multiple-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/all-icons-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/all-icons-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/all-icons-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/all-icons-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/cursor-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/cursor-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/cursor-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/cursor-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/vs-code-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/vs-code-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/vs-code-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/vs-code-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/zed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/zed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-appicon/zed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-appicon/zed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/all-sizes-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/all-sizes-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/all-sizes-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/all-sizes-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/with-custom-colors-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/with-custom-colors-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/with-custom-colors-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/with-custom-colors-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/with-image-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/with-image-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-avatar/with-image-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-avatar/with-image-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/default-open-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/default-open-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/default-open-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/generic-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/generic-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/generic-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/locked-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/locked-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/locked-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/no-children-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/no-children-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/no-children-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/no-children-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/with-args-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-basictool/with-args-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-basictool/with-args-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/ghost-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/ghost-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/ghost-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/ghost-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/primary-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/primary-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/primary-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/primary-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/secondary-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/secondary-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/secondary-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/secondary-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/with-icon-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/with-icon-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-button/with-icon-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-button/with-icon-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/error-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/error-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/error-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/error-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/info-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/info-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/info-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/info-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/success-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/success-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/success-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/success-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/warning-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/warning-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-card/warning-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-card/warning-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/checked-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/checked-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/checked-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/checked-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/disabled-checked-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/disabled-checked-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/disabled-checked-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/disabled-checked-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/indeterminate-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/indeterminate-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/indeterminate-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/indeterminate-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/unchecked-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/unchecked-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/unchecked-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/unchecked-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/with-description-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/with-description-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-checkbox/with-description-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-checkbox/with-description-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/no-line-numbers-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/no-line-numbers-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/no-line-numbers-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/no-line-numbers-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/python-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/python-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/python-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/python-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/short-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/short-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/short-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/short-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/split-overflow-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/split-overflow-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/split-overflow-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/split-overflow-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/type-script-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/type-script-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-code/type-script-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-code/type-script-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/collapsed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/collapsed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/collapsed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/collapsed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/ghost-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/ghost-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/ghost-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/ghost-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-collapsible/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-collapsible/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-contextmenu/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-contextmenu/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-contextmenu/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-contextmenu/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-contextmenu/with-groups-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-contextmenu/with-groups-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-contextmenu/with-groups-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-contextmenu/with-groups-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/no-title-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/no-title-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/no-title-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/no-title-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/x-large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/x-large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dialog/x-large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dialog/x-large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/added-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/added-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/added-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/added-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/config-change-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/config-change-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/config-change-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/config-change-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/deleted-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/deleted-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/deleted-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/deleted-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/split-view-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/split-view-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diff/split-view-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diff/split-view-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/bars-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/bars-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/bars-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/bars-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffchanges/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffchanges/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffssr/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffssr/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffssr/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffssr/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffssr/with-split-style-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffssr/with-split-style-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-diffssr/with-split-style-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-diffssr/with-split-style-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-checkbox-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-checkbox-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-checkbox-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-checkbox-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-groups-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-groups-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-groups-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-groups-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-sub-menu-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-sub-menu-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-dropdownmenu/with-sub-menu-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-dropdownmenu/with-sub-menu-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-errordetails/collapsed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/collapsed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-errordetails/collapsed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-errordetails/expanded-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-errordetails/expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-errordetails/expanded-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/folder-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/folder-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/folder-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/folder-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/folder-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/folder-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/folder-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/folder-expanded-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/java-script-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/java-script-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/java-script-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/java-script-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/markdown-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/markdown-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/markdown-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/markdown-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/type-script-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/type-script-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-fileicon/type-script-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-fileicon/type-script-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-hovercard/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-hovercard/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-hovercard/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-hovercard/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-hovercard/with-user-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-hovercard/with-user-card-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-hovercard/with-user-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-hovercard/with-user-card-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/all-icons-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/all-icons-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/all-icons-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/all-icons-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/medium-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/medium-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/medium-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/medium-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-icon/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-icon/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/ghost-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/ghost-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/ghost-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/ghost-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/primary-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/primary-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/primary-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/primary-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/secondary-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/secondary-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/secondary-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/secondary-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-iconbutton/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-iconbutton/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/with-landscape-image-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/with-landscape-image-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/with-landscape-image-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/with-landscape-image-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/with-portrait-image-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/with-portrait-image-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-imagepreview/with-portrait-image-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-imagepreview/with-portrait-image-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/controlled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/controlled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/controlled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/controlled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/with-width-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/with-width-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-inlineinput/with-width-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-inlineinput/with-width-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-keybind/combination-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-keybind/combination-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-keybind/combination-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-keybind/combination-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-keybind/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-keybind/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-keybind/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-keybind/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/anchor-closed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/anchor-closed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/anchor-closed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/anchor-closed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/anchor-open-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/anchor-open-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/anchor-open-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/anchor-open-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/comment-closed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/comment-closed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/comment-closed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/comment-closed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/comment-default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/comment-default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/comment-default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/comment-default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/editor-default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/editor-default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/editor-default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/editor-default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/editor-with-value-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/editor-with-value-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/editor-with-value-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/editor-with-value-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/interactive-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/interactive-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-linecomment/interactive-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-linecomment/interactive-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/empty-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/empty-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/with-current-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/with-current-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/with-current-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/with-current-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/with-search-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/with-search-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-list/with-search-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-list/with-search-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/full-logo-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/full-logo-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/full-logo-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/full-logo-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/mark-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/mark-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/mark-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/mark-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/splash-mark-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/splash-mark-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-logo/splash-mark-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-logo/splash-mark-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/code-block-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/code-block-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/code-block-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/code-block-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/lists-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/lists-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/lists-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/lists-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/short-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/short-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-markdown/short-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-markdown/short-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/compact-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/compact-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/compact-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/compact-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagenav/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagenav/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/assistant-message-story-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/assistant-message-story-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/assistant-message-story-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/full-conversation-turn-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/full-conversation-turn-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/full-conversation-turn-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/tool-hint-errors-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/tool-hint-errors-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/tool-hint-errors-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/tool-hint-errors-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/user-message-story-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/user-message-story-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/user-message-story-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-bash-tool-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-bash-tool-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-bash-tool-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-bash-tool-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-bash-tool-expanded-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-context-group-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-context-group-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-context-group-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-context-group-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-error-tool-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-error-tool-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-error-tool-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-reasoning-collapsed-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-collapsed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-reasoning-collapsed-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-reasoning-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-reasoning-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-reasoning-expanded-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-running-tool-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-messagepart/with-running-tool-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-messagepart/with-running-tool-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/no-title-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/no-title-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/no-title-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/no-title-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/with-description-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/with-description-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-popover/with-description-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-popover/with-description-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/custom-range-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/custom-range-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/custom-range-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/custom-range-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/empty-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/empty-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/full-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/full-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/full-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/full-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/hidden-label-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/hidden-label-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/hidden-label-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/hidden-label-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/with-label-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/with-label-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/with-label-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/with-label-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/with-value-label-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/with-value-label-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progress/with-value-label-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progress/with-value-label-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/complete-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/complete-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/complete-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/complete-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/empty-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/empty-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/half-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/half-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/half-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/half-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/quarter-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/quarter-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/quarter-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/quarter-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/three-quarters-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/three-quarters-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-progresscircle/three-quarters-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-progresscircle/three-quarters-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/all-icons-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/all-icons-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/all-icons-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/all-icons-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/anthropic-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/anthropic-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/anthropic-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/anthropic-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/gallery-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/gallery-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/gallery-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/gallery-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/google-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/google-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/google-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/google-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-providericon/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-providericon/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/medium-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/medium-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/medium-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/medium-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/with-custom-labels-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/with-custom-labels-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-radiogroup/with-custom-labels-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-radiogroup/with-custom-labels-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-resizehandle/horizontal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-resizehandle/horizontal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-resizehandle/horizontal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-resizehandle/horizontal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-resizehandle/vertical-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-resizehandle/vertical-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-resizehandle/vertical-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-resizehandle/vertical-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/settings-variant-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/settings-variant-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/settings-variant-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/settings-variant-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/with-current-value-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/with-current-value-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/with-current-value-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/with-current-value-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/with-group-by-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/with-group-by-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-select/with-group-by-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-select/with-group-by-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/empty-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/empty-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/single-file-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/single-file-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/single-file-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/single-file-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/split-view-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/split-view-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionreview/split-view-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionreview/split-view-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/with-steps-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/with-steps-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/with-steps-expanded-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/working-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-sessionturn/working-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-sessionturn/working-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/colored-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/colored-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/colored-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/small-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-spinner/small-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-spinner/small-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-stickyaccordionheader/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-stickyaccordionheader/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-stickyaccordionheader/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-stickyaccordionheader/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-stickyaccordionheader/in-scroll-container-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-stickyaccordionheader/in-scroll-container-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-stickyaccordionheader/in-scroll-container-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-stickyaccordionheader/in-scroll-container-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/disabled-on-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/disabled-on-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/disabled-on-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/disabled-on-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/off-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/off-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/off-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/off-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/on-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/on-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/on-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/on-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/with-description-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/with-description-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-switch/with-description-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-switch/with-description-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/alt-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/alt-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/alt-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/alt-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/pill-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/pill-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/pill-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/pill-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/settings-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/settings-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/settings-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/settings-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/vertical-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/vertical-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tabs/vertical-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tabs/vertical-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/large-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/large-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/large-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/large-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tag/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tag/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/copyable-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/copyable-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/copyable-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/copyable-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/copyable-link-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/copyable-link-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/copyable-link-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/copyable-link-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/disabled-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/disabled-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/disabled-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/disabled-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/ghost-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/ghost-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/ghost-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/ghost-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/multiline-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/multiline-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/multiline-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/multiline-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/normal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/normal-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/normal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/normal-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-description-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-description-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-description-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-description-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-error-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-error-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-error-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-error-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-label-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-label-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-textfield/with-label-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-textfield/with-label-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/all-variants-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/all-variants-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/all-variants-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/all-variants-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/error-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/error-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/error-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/error-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/loading-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/loading-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/loading-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/loading-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/success-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/success-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/success-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/success-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/with-actions-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/with-actions-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/with-actions-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/with-actions-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/with-icon-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/with-icon-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-toast/with-icon-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-toast/with-icon-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/default-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/default-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/force-open-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/force-open-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/force-open-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/placement-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/placement-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/placement-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/placement-chromium-linux.png diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/with-keybind-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/with-keybind-chromium-linux.png similarity index 100% rename from packages/kilo-ui/tests/visual-regression.spec.ts-snapshots/components-tooltip/with-keybind-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-ui/visual-regression/components-tooltip/with-keybind-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rule-approved-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rule-approved-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rule-denied-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rule-denied-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/config-preloaded-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/config-preloaded-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/config-preloaded-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/config-preloaded-expanded-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/glob-rule-approved-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/glob-rule-approved-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/many-rules-mixed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/many-rules-mixed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/subagent-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/subagent-expanded-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/write-expanded-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/permission-dock-dropdown/write-expanded-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/all-colors-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/all-colors-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/all-colors-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/all-colors-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/collapsed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/collapsed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/collapsed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/collapsed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/default-color-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/default-color-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/default-color-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/default-color-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/dense-sidebar-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/dense-sidebar-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/dense-sidebar-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/dense-sidebar-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/expanded-with-items-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/expanded-with-items-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/expanded-with-items-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/expanded-with-items-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/first-and-last-section-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/first-and-last-section-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/first-and-last-section-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/first-and-last-section-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/long-section-name-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/long-section-name-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/long-section-name-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/long-section-name-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/multiple-sections-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/multiple-sections-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/multiple-sections-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/multiple-sections-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-active-worktree-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-active-worktree-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-active-worktree-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-active-worktree-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-busy-worktree-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-busy-worktree-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-busy-worktree-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-busy-worktree-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-pr-badges-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-pr-badges-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-pr-badges-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-pr-badges-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-stale-worktree-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-stale-worktree-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-stale-worktree-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-stale-worktree-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-versions-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-versions-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager-sections/with-versions-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager-sections/with-versions-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/diff-panel-with-diffs-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/diff-panel-with-diffs-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/diff-panel-with-diffs-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/diff-panel-with-diffs-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/file-tree-empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/file-tree-empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/file-tree-empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/file-tree-empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/file-tree-with-changes-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/file-tree-with-changes-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/file-tree-with-changes-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/file-tree-with-changes-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/full-screen-diff-with-changes-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/full-screen-diff-with-changes-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/full-screen-diff-with-changes-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/full-screen-diff-with-changes-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-approved-checks-failing-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-approved-checks-failing-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-approved-checks-failing-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-approved-checks-failing-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-approved-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-approved-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-approved-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-approved-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-changes-requested-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-changes-requested-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-changes-requested-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-changes-requested-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-checks-failing-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-checks-failing-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-checks-failing-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-checks-failing-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-closed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-closed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-closed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-closed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-draft-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-draft-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-draft-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-draft-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-merged-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-merged-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-merged-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-merged-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-no-review-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-no-review-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-no-review-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-no-review-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-pending-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-pending-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/pr-badge-pending-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/pr-badge-pending-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-multiple-tabs-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-multiple-tabs-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-multiple-tabs-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-multiple-tabs-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-single-tab-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-single-tab-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-single-tab-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-single-tab-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-with-review-tab-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-with-review-tab-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/tab-bar-with-review-tab-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/tab-bar-with-review-tab-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-active-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-active-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-active-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-active-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-busy-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-busy-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-busy-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-busy-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-default-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-default-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-default-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-default-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-grouped-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-grouped-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-grouped-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-grouped-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-pending-delete-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-pending-delete-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-pending-delete-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-pending-delete-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-stale-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-stale-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-stale-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-stale-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-with-stats-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-with-stats-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/agentmanager/worktree-item-with-stats-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/agentmanager/worktree-item-with-stats-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-idle-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-idle-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-idle-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-idle-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-with-messages-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-with-messages-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-with-messages-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-with-messages-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-with-pending-question-empty-input-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-with-pending-question-empty-input-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/chat-view-with-pending-question-empty-input-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/chat-view-with-pending-question-empty-input-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/message-list-subagent-to-queued-user-spacing-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-subagent-to-queued-user-spacing-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/message-list-subagent-to-queued-user-spacing-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-subagent-to-queued-user-spacing-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-many-options-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-many-options-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-many-options-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-many-options-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-multi-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-multi-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-multi-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-multi-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-single-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-single-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/question-dock-single-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/question-dock-single-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/suggest-bar-review-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/suggest-bar-review-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/suggest-bar-review-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/suggest-bar-review-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/task-header-with-todos-all-done-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-all-done-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/task-header-with-todos-all-done-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-all-done-chromium-linux.png 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 new file mode 100644 index 0000000000..f1e6bc8a35 --- /dev/null +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/task-header-with-todos-chromium-linux.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d34153690f8aa4ef7e06e12385a184c151843f3ae75a9955619a6d7e88dc8c8b +size 7981 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/welcome-with-switcher-and-notification-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/welcome-with-switcher-and-notification-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/chat/welcome-with-switcher-and-notification-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/welcome-with-switcher-and-notification-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/components-shell/shell-execution-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/components-shell/shell-execution-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-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-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/bash-with-permission-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/bash-with-permission-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/chat-busy-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/chat-busy-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/chat-busy-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/chat-busy-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/chat-idle-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/chat-idle-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/chat-idle-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/chat-idle-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/diff-summary-collapsed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/diff-summary-collapsed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/diff-summary-collapsed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/diff-summary-collapsed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/glob-with-permission-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/glob-with-permission-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/mcp-tool-cards-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/mcp-tool-cards-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/mcp-tool-cards-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/mcp-tool-cards-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/mcp-tool-expanded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/mcp-tool-expanded-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/mcp-tool-expanded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/mcp-tool-expanded-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/multiple-tool-calls-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/multiple-tool-calls-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/multiple-tool-calls-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/multiple-tool-calls-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-bash-many-rules-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-bash-many-rules-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-config-preloaded-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-config-preloaded-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-config-preloaded-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-config-preloaded-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-edit-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-external-dir-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-external-dir-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-heredoc-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-heredoc-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-heredoc-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-heredoc-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-subagent-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-subagent-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-todo-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-todo-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-websearch-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-websearch-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-write-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-write-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/question-above-chatbox-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-above-chatbox-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/question-above-chatbox-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-dismissed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/question-dismissed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/question-dismissed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/question-dismissed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-completed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-completed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-completed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-completed-chromium-linux.png 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 0000000000..c8ecdbcbb5 --- /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/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-with-permission-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/todo-write-with-permission-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/tool-cards-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/tool-cards-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/tool-cards-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/tool-cards-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/history-sessionlist/with-items-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/history-sessionlist/with-items-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/history-sessionlist/with-items-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/history-sessionlist/with-items-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-mcp-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-mcp-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-mcp-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-mcp-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-mode-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-mode-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-mode-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-mode-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-skill-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-skill-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/installed-skill-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/installed-skill-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-with-installed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-with-installed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-with-installed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-with-installed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-with-items-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-with-items-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/mcp-tab-with-items-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/mcp-tab-with-items-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-with-installed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-with-installed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-with-installed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-with-installed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-with-items-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-with-items-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/modes-tab-with-items-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/modes-tab-with-items-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-mcp-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-mcp-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-mcp-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-mcp-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-mode-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-mode-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-mode-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-mode-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-skill-card-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-skill-card-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/single-skill-card-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/single-skill-card-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-with-installed-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-with-installed-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-with-installed-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-with-installed-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-with-items-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-with-items-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/marketplace/skills-tab-with-items-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/marketplace/skills-tab-with-items-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/logged-in-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/logged-in-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/logged-in-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/logged-in-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/logged-in-personal-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/logged-in-personal-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/logged-in-personal-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/logged-in-personal-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/not-logged-in-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/not-logged-in-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/profile/not-logged-in-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/profile/not-logged-in-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/default-200-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/default-200-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/default-200-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/default-200-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/default-420-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/default-420-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/default-420-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/default-420-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-model-override-200-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-model-override-200-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-model-override-200-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-model-override-200-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-model-override-420-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-model-override-420-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-model-override-420-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-model-override-420-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-thinking-200-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-thinking-200-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-thinking-200-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-thinking-200-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-thinking-420-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-thinking-420-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/prompt-input/with-thinking-420-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/prompt-input/with-thinking-420-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-agents-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-agents-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-agents-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-agents-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-edit-custom-mode-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-edit-custom-mode-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-edit-custom-mode-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-edit-custom-mode-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-workflows-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-workflows-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-workflows-empty-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-empty-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/agent-behaviour-workflows-empty-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/agent-behaviour-workflows-empty-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-local-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-local-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-local-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-local-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-local-with-env-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-local-with-env-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-local-with-env-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-local-with-env-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-remote-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-remote-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mcp-edit-view-remote-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mcp-edit-view-remote-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mode-edit-export-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mode-edit-export-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/mode-edit-export-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/mode-edit-export-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/providers-configure-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/providers-configure-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/providers-configure-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/providers-configure-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/settings-panel-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/settings/settings-panel-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/settings/settings-panel-chromium-linux.png diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/shared/model-selector-no-providers-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/shared/model-selector-no-providers-chromium-linux.png similarity index 100% rename from packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/shared/model-selector-no-providers-chromium-linux.png rename to packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/shared/model-selector-no-providers-chromium-linux.png diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index f13f58bad6..53fabe773b 100644 --- a/packages/kilo-gateway/package.json +++ b/packages/kilo-gateway/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-gateway", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration", diff --git a/packages/kilo-gateway/src/api/constants.ts b/packages/kilo-gateway/src/api/constants.ts index 5c020ab6b0..d7a1eb9b17 100644 --- a/packages/kilo-gateway/src/api/constants.ts +++ b/packages/kilo-gateway/src/api/constants.ts @@ -70,6 +70,6 @@ export const HEADER_FEATURE = "X-KILOCODE-FEATURE" /** Environment variable name for feature override */ export const ENV_FEATURE = "KILOCODE_FEATURE" -export const PROMPTS = ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo"] as const +export const PROMPTS = ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo", "ling"] as const export const AI_SDK_PROVIDERS = ["alibaba", "anthropic", "openai", "openai-compatible", "openrouter"] as const diff --git a/packages/kilo-gateway/src/server/routes.ts b/packages/kilo-gateway/src/server/routes.ts index 6a79aa01ec..f09b945a28 100644 --- a/packages/kilo-gateway/src/server/routes.ts +++ b/packages/kilo-gateway/src/server/routes.ts @@ -35,6 +35,8 @@ interface KiloRoutesDeps extends ImportDeps { Instance: ImportDeps["Instance"] & { disposeAll(): Promise } } +const FIM_TIMEOUT_MS = 30_000 + /** * Create Kilo Gateway routes with OpenCode dependencies injected * @@ -342,25 +344,35 @@ export function createKiloRoutes(deps: KiloRoutesDeps) { [HEADER_FEATURE]: "autocomplete", } - const response = await fetch(endpoint, { - method: "POST", - headers, - body: JSON.stringify({ - model: fimModel, - prompt: prefix, - suffix, - max_tokens: fimMaxTokens, - temperature: fimTemperature, - stream: true, - }), - }) + const signal = AbortSignal.any([c.req.raw.signal, AbortSignal.timeout(FIM_TIMEOUT_MS)]) - if (!response.ok) { - const errorText = await response.text() - return c.json({ error: `FIM request failed: ${response.status} ${errorText}` }, response.status as any) + let response: Response + try { + response = await fetch(endpoint, { + method: "POST", + headers, + signal, + body: JSON.stringify({ + model: fimModel, + prompt: prefix, + suffix, + max_tokens: fimMaxTokens, + temperature: fimTemperature, + stream: true, + }), + }) + } catch (err) { + if (err instanceof DOMException && err.name === "TimeoutError") + return c.json({ error: "FIM request timed out" }, 504 as any) + if (signal.aborted) return c.json({ error: "FIM request canceled" }, 499 as any) + throw err + } + + if (!response.ok) { + const text = await response.text() + return c.json({ error: `FIM request failed: ${response.status} ${text}` }, response.status as any) } - // Stream the response through return new Response(response.body, { headers: { "Content-Type": "text/event-stream", diff --git a/packages/kilo-i18n/package.json b/packages/kilo-i18n/package.json index 46c1fff9b8..c795106e09 100644 --- a/packages/kilo-i18n/package.json +++ b/packages/kilo-i18n/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-i18n", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-i18n/src/ar.ts b/packages/kilo-i18n/src/ar.ts index ee2a0ffdaf..3a6374008b 100644 --- a/packages/kilo-i18n/src/ar.ts +++ b/packages/kilo-i18n/src/ar.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "إلغاء", "marketplace.contribute.prompt": "هل تفتقد مهارة أو وضعًا أو خادم MCP؟", "marketplace.contribute.cta": "ساهم على GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "نفّذ", + "plan.followup.question": "جاهز للتنفيذ؟", + "plan.followup.answer.newSession": "بدء جلسة جديدة", + "plan.followup.answer.newSession.description": "نفّذ في جلسة جديدة بسياق نظيف", + "plan.followup.answer.continue": "المتابعة هنا", + "plan.followup.answer.continue.description": "نفّذ الخطة في هذه الجلسة", } diff --git a/packages/kilo-i18n/src/br.ts b/packages/kilo-i18n/src/br.ts index 38bfb6ae82..5a9db6c39d 100644 --- a/packages/kilo-i18n/src/br.ts +++ b/packages/kilo-i18n/src/br.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Cancelar", "marketplace.contribute.prompt": "Está faltando uma skill, modo ou servidor MCP?", "marketplace.contribute.cta": "Contribuir no GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementar", + "plan.followup.question": "Pronto para implementar?", + "plan.followup.answer.newSession": "Iniciar nova sessão", + "plan.followup.answer.newSession.description": "Implementar em uma nova sessão com contexto limpo", + "plan.followup.answer.continue": "Continuar aqui", + "plan.followup.answer.continue.description": "Implementar o plano nesta sessão", } diff --git a/packages/kilo-i18n/src/bs.ts b/packages/kilo-i18n/src/bs.ts index 63aad6b807..1b88c607db 100644 --- a/packages/kilo-i18n/src/bs.ts +++ b/packages/kilo-i18n/src/bs.ts @@ -76,4 +76,12 @@ export const dict = { "marketplace.warning.cancel": "Otkaži", "marketplace.contribute.prompt": "Nedostaje vještina, način rada ili MCP server?", "marketplace.contribute.cta": "Doprinesi na GitHub-u", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementiraj", + "plan.followup.question": "Spreman za implementaciju?", + "plan.followup.answer.newSession": "Pokreni novu sesiju", + "plan.followup.answer.newSession.description": "Implementiraj u novoj sesiji s čistim kontekstom", + "plan.followup.answer.continue": "Nastavi ovdje", + "plan.followup.answer.continue.description": "Implementiraj plan u ovoj sesiji", } diff --git a/packages/kilo-i18n/src/da.ts b/packages/kilo-i18n/src/da.ts index 53442d3736..912ecaaad7 100644 --- a/packages/kilo-i18n/src/da.ts +++ b/packages/kilo-i18n/src/da.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Annuller", "marketplace.contribute.prompt": "Mangler du en skill, tilstand eller MCP-server?", "marketplace.contribute.cta": "Bidrag på GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementér", + "plan.followup.question": "Klar til at implementere?", + "plan.followup.answer.newSession": "Start ny session", + "plan.followup.answer.newSession.description": "Implementér i en ny session med ren kontekst", + "plan.followup.answer.continue": "Fortsæt her", + "plan.followup.answer.continue.description": "Implementér planen i denne session", } diff --git a/packages/kilo-i18n/src/de.ts b/packages/kilo-i18n/src/de.ts index 190ceff2d6..2e08b98b27 100644 --- a/packages/kilo-i18n/src/de.ts +++ b/packages/kilo-i18n/src/de.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Abbrechen", "marketplace.contribute.prompt": "Fehlt ein Skill, Modus oder MCP-Server?", "marketplace.contribute.cta": "Auf GitHub beitragen", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Umsetzen", + "plan.followup.question": "Bereit zur Umsetzung?", + "plan.followup.answer.newSession": "Neue Sitzung starten", + "plan.followup.answer.newSession.description": "In einer neuen Sitzung mit leerem Kontext umsetzen", + "plan.followup.answer.continue": "Hier fortfahren", + "plan.followup.answer.continue.description": "Den Plan in dieser Sitzung umsetzen", } diff --git a/packages/kilo-i18n/src/en.ts b/packages/kilo-i18n/src/en.ts index 2e1f38828c..cacebb54f9 100644 --- a/packages/kilo-i18n/src/en.ts +++ b/packages/kilo-i18n/src/en.ts @@ -73,4 +73,14 @@ export const dict = { "marketplace.warning.cancel": "Cancel", "marketplace.contribute.prompt": "Missing a skill, mode, or MCP server?", "marketplace.contribute.cta": "Contribute on GitHub", + + // Plan follow-up question shown after plan_exit. The English strings here must match + // the canonical `label`/`header`/`question` sent by the backend — those canonical labels + // are still what the backend matches on (see packages/opencode/src/kilocode/plan-followup.ts). + "plan.followup.header": "Implement", + "plan.followup.question": "Ready to implement?", + "plan.followup.answer.newSession": "Start new session", + "plan.followup.answer.newSession.description": "Implement in a fresh session with a clean context", + "plan.followup.answer.continue": "Continue here", + "plan.followup.answer.continue.description": "Implement the plan in this session", } diff --git a/packages/kilo-i18n/src/es.ts b/packages/kilo-i18n/src/es.ts index 62fa5ec0ac..9325ae29a4 100644 --- a/packages/kilo-i18n/src/es.ts +++ b/packages/kilo-i18n/src/es.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Cancelar", "marketplace.contribute.prompt": "¿Falta una skill, modo o servidor MCP?", "marketplace.contribute.cta": "Contribuir en GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementar", + "plan.followup.question": "¿Listo para implementar?", + "plan.followup.answer.newSession": "Iniciar nueva sesión", + "plan.followup.answer.newSession.description": "Implementar en una sesión nueva con contexto limpio", + "plan.followup.answer.continue": "Continuar aquí", + "plan.followup.answer.continue.description": "Implementar el plan en esta sesión", } diff --git a/packages/kilo-i18n/src/fr.ts b/packages/kilo-i18n/src/fr.ts index 43e34edc4d..51b5735b3e 100644 --- a/packages/kilo-i18n/src/fr.ts +++ b/packages/kilo-i18n/src/fr.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Annuler", "marketplace.contribute.prompt": "Il manque une skill, un mode ou un serveur MCP ?", "marketplace.contribute.cta": "Contribuer sur GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implémenter", + "plan.followup.question": "Prêt à implémenter ?", + "plan.followup.answer.newSession": "Démarrer une nouvelle session", + "plan.followup.answer.newSession.description": "Implémenter dans une nouvelle session avec un contexte vierge", + "plan.followup.answer.continue": "Continuer ici", + "plan.followup.answer.continue.description": "Implémenter le plan dans cette session", } diff --git a/packages/kilo-i18n/src/ja.ts b/packages/kilo-i18n/src/ja.ts index f75cccfb4a..bf1ae85ff5 100644 --- a/packages/kilo-i18n/src/ja.ts +++ b/packages/kilo-i18n/src/ja.ts @@ -69,4 +69,12 @@ export const dict = { "marketplace.warning.cancel": "キャンセル", "marketplace.contribute.prompt": "スキル、モード、MCP サーバーが見つかりませんか?", "marketplace.contribute.cta": "GitHub で貢献する", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "実装", + "plan.followup.question": "実装する準備はできましたか?", + "plan.followup.answer.newSession": "新しいセッションを開始", + "plan.followup.answer.newSession.description": "クリーンなコンテキストの新しいセッションで実装する", + "plan.followup.answer.continue": "ここで続行", + "plan.followup.answer.continue.description": "このセッションで計画を実装する", } diff --git a/packages/kilo-i18n/src/ko.ts b/packages/kilo-i18n/src/ko.ts index 23c9fe1740..f126065497 100644 --- a/packages/kilo-i18n/src/ko.ts +++ b/packages/kilo-i18n/src/ko.ts @@ -69,4 +69,12 @@ export const dict = { "marketplace.warning.cancel": "취소", "marketplace.contribute.prompt": "스킬, 모드 또는 MCP 서버가 없나요?", "marketplace.contribute.cta": "GitHub에서 기여하기", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "구현", + "plan.followup.question": "구현할 준비가 되셨나요?", + "plan.followup.answer.newSession": "새 세션 시작", + "plan.followup.answer.newSession.description": "깨끗한 컨텍스트의 새 세션에서 구현", + "plan.followup.answer.continue": "여기서 계속하기", + "plan.followup.answer.continue.description": "이 세션에서 계획 구현", } diff --git a/packages/kilo-i18n/src/nl.ts b/packages/kilo-i18n/src/nl.ts index 00072f1984..20e2dd6d1c 100644 --- a/packages/kilo-i18n/src/nl.ts +++ b/packages/kilo-i18n/src/nl.ts @@ -73,4 +73,12 @@ export const dict = { "marketplace.warning.cancel": "Annuleren", "marketplace.contribute.prompt": "Mist er een skill, modus of MCP-server?", "marketplace.contribute.cta": "Bijdragen op GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementeren", + "plan.followup.question": "Klaar om te implementeren?", + "plan.followup.answer.newSession": "Nieuwe sessie starten", + "plan.followup.answer.newSession.description": "Implementeren in een nieuwe sessie met een lege context", + "plan.followup.answer.continue": "Hier doorgaan", + "plan.followup.answer.continue.description": "Het plan in deze sessie implementeren", } diff --git a/packages/kilo-i18n/src/no.ts b/packages/kilo-i18n/src/no.ts index 85cfce2679..e1c1ac61bc 100644 --- a/packages/kilo-i18n/src/no.ts +++ b/packages/kilo-i18n/src/no.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Avbryt", "marketplace.contribute.prompt": "Mangler du en skill, modus eller MCP-server?", "marketplace.contribute.cta": "Bidra på GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Implementer", + "plan.followup.question": "Klar til å implementere?", + "plan.followup.answer.newSession": "Start ny økt", + "plan.followup.answer.newSession.description": "Implementer i en ny økt med ren kontekst", + "plan.followup.answer.continue": "Fortsett her", + "plan.followup.answer.continue.description": "Implementer planen i denne økten", } diff --git a/packages/kilo-i18n/src/pl.ts b/packages/kilo-i18n/src/pl.ts index 48d436413c..0593170d9b 100644 --- a/packages/kilo-i18n/src/pl.ts +++ b/packages/kilo-i18n/src/pl.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Anuluj", "marketplace.contribute.prompt": "Brakuje skilla, trybu lub serwera MCP?", "marketplace.contribute.cta": "Wnieś wkład na GitHubie", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Wdróż", + "plan.followup.question": "Gotowy do wdrożenia?", + "plan.followup.answer.newSession": "Rozpocznij nową sesję", + "plan.followup.answer.newSession.description": "Wdróż w nowej sesji z czystym kontekstem", + "plan.followup.answer.continue": "Kontynuuj tutaj", + "plan.followup.answer.continue.description": "Wdróż plan w tej sesji", } diff --git a/packages/kilo-i18n/src/ru.ts b/packages/kilo-i18n/src/ru.ts index 0ac0e661fd..74acae5927 100644 --- a/packages/kilo-i18n/src/ru.ts +++ b/packages/kilo-i18n/src/ru.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Отмена", "marketplace.contribute.prompt": "Не хватает навыка, режима или MCP-сервера?", "marketplace.contribute.cta": "Внести вклад на GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Реализовать", + "plan.followup.question": "Готовы реализовать?", + "plan.followup.answer.newSession": "Начать новую сессию", + "plan.followup.answer.newSession.description": "Реализовать в новой сессии с чистым контекстом", + "plan.followup.answer.continue": "Продолжить здесь", + "plan.followup.answer.continue.description": "Реализовать план в этой сессии", } diff --git a/packages/kilo-i18n/src/th.ts b/packages/kilo-i18n/src/th.ts index d8a03606c7..48b02146af 100644 --- a/packages/kilo-i18n/src/th.ts +++ b/packages/kilo-i18n/src/th.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "ยกเลิก", "marketplace.contribute.prompt": "ไม่พบทักษะ โหมด หรือเซิร์ฟเวอร์ MCP ที่ต้องการ?", "marketplace.contribute.cta": "ร่วมสมทบบน GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "ดำเนินการ", + "plan.followup.question": "พร้อมดำเนินการหรือยัง?", + "plan.followup.answer.newSession": "เริ่มเซสชันใหม่", + "plan.followup.answer.newSession.description": "ดำเนินการในเซสชันใหม่ที่มีบริบทว่างเปล่า", + "plan.followup.answer.continue": "ดำเนินการต่อที่นี่", + "plan.followup.answer.continue.description": "ดำเนินการตามแผนในเซสชันนี้", } diff --git a/packages/kilo-i18n/src/tr.ts b/packages/kilo-i18n/src/tr.ts index 0a3a39d3db..e307f79077 100644 --- a/packages/kilo-i18n/src/tr.ts +++ b/packages/kilo-i18n/src/tr.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "İptal", "marketplace.contribute.prompt": "Bir yetenek, mod veya MCP sunucusu mu eksik?", "marketplace.contribute.cta": "GitHub'da katkıda bulun", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Uygula", + "plan.followup.question": "Uygulamaya hazır mısın?", + "plan.followup.answer.newSession": "Yeni oturum başlat", + "plan.followup.answer.newSession.description": "Temiz bir bağlamla yeni bir oturumda uygula", + "plan.followup.answer.continue": "Burada devam et", + "plan.followup.answer.continue.description": "Planı bu oturumda uygula", } diff --git a/packages/kilo-i18n/src/uk.ts b/packages/kilo-i18n/src/uk.ts index cb3b1090ce..7d1707a3e5 100644 --- a/packages/kilo-i18n/src/uk.ts +++ b/packages/kilo-i18n/src/uk.ts @@ -71,4 +71,12 @@ export const dict = { "marketplace.warning.cancel": "Скасувати", "marketplace.contribute.prompt": "Бракує навички, режиму або MCP-сервера?", "marketplace.contribute.cta": "Зробити внесок на GitHub", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "Реалізувати", + "plan.followup.question": "Готові реалізувати?", + "plan.followup.answer.newSession": "Почати нову сесію", + "plan.followup.answer.newSession.description": "Реалізувати в новій сесії з чистим контекстом", + "plan.followup.answer.continue": "Продовжити тут", + "plan.followup.answer.continue.description": "Реалізувати план у цій сесії", } diff --git a/packages/kilo-i18n/src/zh.ts b/packages/kilo-i18n/src/zh.ts index d444f4e8ee..d5cd78e877 100644 --- a/packages/kilo-i18n/src/zh.ts +++ b/packages/kilo-i18n/src/zh.ts @@ -68,4 +68,12 @@ export const dict = { "marketplace.warning.cancel": "取消", "marketplace.contribute.prompt": "缺少技能、模式或 MCP 服务器?", "marketplace.contribute.cta": "在 GitHub 上贡献", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "实现", + "plan.followup.question": "准备好实现了吗?", + "plan.followup.answer.newSession": "开启新会话", + "plan.followup.answer.newSession.description": "在具有干净上下文的新会话中实现", + "plan.followup.answer.continue": "在此继续", + "plan.followup.answer.continue.description": "在本会话中实现计划", } diff --git a/packages/kilo-i18n/src/zht.ts b/packages/kilo-i18n/src/zht.ts index 275727428b..5cdb8dff67 100644 --- a/packages/kilo-i18n/src/zht.ts +++ b/packages/kilo-i18n/src/zht.ts @@ -68,4 +68,12 @@ export const dict = { "marketplace.warning.cancel": "取消", "marketplace.contribute.prompt": "缺少技能、模式或 MCP 伺服器?", "marketplace.contribute.cta": "在 GitHub 上貢獻", + + // Plan follow-up question shown after plan_exit + "plan.followup.header": "實作", + "plan.followup.question": "準備好實作了嗎?", + "plan.followup.answer.newSession": "開啟新工作階段", + "plan.followup.answer.newSession.description": "在具有乾淨上下文的新工作階段中實作", + "plan.followup.answer.continue": "在此繼續", + "plan.followup.answer.continue.description": "在本工作階段中實作計畫", } diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index af676db0ce..27ba2baf44 100644 --- a/packages/kilo-telemetry/package.json +++ b/packages/kilo-telemetry/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-telemetry", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "description": "Telemetry for Kilo CLI - PostHog analytics integration", diff --git a/packages/kilo-ui/package.json b/packages/kilo-ui/package.json index 652953d00e..54daac7360 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-ui/playwright.config.ts b/packages/kilo-ui/playwright.config.ts index a40fa59151..ae9f765438 100644 --- a/packages/kilo-ui/playwright.config.ts +++ b/packages/kilo-ui/playwright.config.ts @@ -3,6 +3,7 @@ import { defineConfig, devices } from "@playwright/test" export default defineConfig({ testDir: "./tests", testMatch: "**/*.spec.ts", + snapshotPathTemplate: "../kilo-docs/public/img/screenshot-tests/kilo-ui/{arg}{ext}", fullyParallel: true, forbidOnly: !!process.env["CI"], retries: process.env["CI"] ? 1 : 0, diff --git a/packages/kilo-ui/tests/visual-regression.spec.ts b/packages/kilo-ui/tests/visual-regression.spec.ts index 385f1b6180..90146045d1 100644 --- a/packages/kilo-ui/tests/visual-regression.spec.ts +++ b/packages/kilo-ui/tests/visual-regression.spec.ts @@ -163,6 +163,6 @@ for (const story of stories) { // Use [component, variant] path so snapshots are grouped per component dir. const [component, variant] = story.id.split("--") const root = page.locator("#storybook-root") - await expect(root).toHaveScreenshot([component, `${variant}.png`]) + await expect(root).toHaveScreenshot(["visual-regression", component, `${variant}.png`]) }) } diff --git a/packages/kilo-vscode/AGENTS.md b/packages/kilo-vscode/AGENTS.md index ff630a3ac0..04604160a6 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/CHANGELOG.md b/packages/kilo-vscode/CHANGELOG.md index 265535291a..b0b3bfb122 100644 --- a/packages/kilo-vscode/CHANGELOG.md +++ b/packages/kilo-vscode/CHANGELOG.md @@ -1,5 +1,49 @@ # kilo-code +## 7.2.19 + +## 7.2.18 + +## 7.2.17 + +### Minor Changes + +- [#9207](https://github.com/Kilo-Org/kilocode/pull/9207) [`4d85c23`](https://github.com/Kilo-Org/kilocode/commit/4d85c232681fb6844521bda5209dd021d742edd6) - Support forking Agent Manager sessions from a specific user message. + +- [#9244](https://github.com/Kilo-Org/kilocode/pull/9244) [`18442f6`](https://github.com/Kilo-Org/kilocode/commit/18442f695dee16ce98e1fe06c74cea74e6e18be0) - Support forking sidebar conversations from any user message. + +### Patch Changes + +- [#9305](https://github.com/Kilo-Org/kilocode/pull/9305) [`b4cb8c3`](https://github.com/Kilo-Org/kilocode/commit/b4cb8c3c04b6f7918032840785d3f6a6a8d077ac) - Prewarm the autocomplete backend on activation so inline completions are ready on first keystroke without opening the Kilo sidebar, and refresh autocomplete state when workspace folders change. + +- [#9318](https://github.com/Kilo-Org/kilocode/pull/9318) [`bfe4482`](https://github.com/Kilo-Org/kilocode/commit/bfe44822ed51292606daeb34325a0847d381ba40) - Prevent canceled autocomplete debounce requests from staying pending indefinitely. + +- [#9316](https://github.com/Kilo-Org/kilocode/pull/9316) [`bf98bbe`](https://github.com/Kilo-Org/kilocode/commit/bf98bbe34d2b143d0f7e5f50aa3732715ded75a0) - Cap autocomplete ignore path caching so long sessions do not retain unlimited paths. + +- [#9239](https://github.com/Kilo-Org/kilocode/pull/9239) [`2b17a7b`](https://github.com/Kilo-Org/kilocode/commit/2b17a7b4e80bb2bd30bd95d047c31ad17dd339b6) - Fix custom provider model and variant deletions being silently reverted on save. Removing a model or reasoning variant from a custom provider now actually removes it from your config. + +- [#9241](https://github.com/Kilo-Org/kilocode/pull/9241) [`6c0439b`](https://github.com/Kilo-Org/kilocode/commit/6c0439b0003d2bd011a9aa5bf0b634c18a0e9771) - Fix custom provider variant name validation showing inline errors correctly when a variant name is left empty + +- [#9208](https://github.com/Kilo-Org/kilocode/pull/9208) [`acd5798`](https://github.com/Kilo-Org/kilocode/commit/acd5798d99027e4281c8b7fb6c741ff8d63d8c2c) - Fixed Agent Manager incorrectly duplicating worktree sessions into the Local tab when forking a session or using "Continue in Worktree". + +- [#7960](https://github.com/Kilo-Org/kilocode/pull/7960) [`d1aed36`](https://github.com/Kilo-Org/kilocode/commit/d1aed364fb5d8aa6d45800c3647a7e1a1287c427) - Add KiloClaw chat panel to the VS Code extension + +- [#9245](https://github.com/Kilo-Org/kilocode/pull/9245) [`ec5ac2e`](https://github.com/Kilo-Org/kilocode/commit/ec5ac2e19f69052dae375c9ddc2f7edb67c62358) - Fix the "Continue here" button not submitting after a plan is finished. Picking an option on a single-question prompt now sends the reply immediately — matching the CLI behaviour — and the redundant "Type your own answer" row no longer appears on the plan follow-up question. + +- [#9246](https://github.com/Kilo-Org/kilocode/pull/9246) [`c529142`](https://github.com/Kilo-Org/kilocode/commit/c529142d7273092f657f02c66f39f06e9ed55ecc) - Translate the follow-up prompt shown after finishing a plan. The "Ready to implement?" question, "Start new session" and "Continue here" buttons, and their descriptions now respect the language configured in the VS Code sidebar. + +- [#9129](https://github.com/Kilo-Org/kilocode/pull/9129) [`60709fd`](https://github.com/Kilo-Org/kilocode/commit/60709fd015aa206c7466a6197642f144280ea2be) - Fix duplicate text shown when typing a custom answer in the question tool. The preview text above the input field is now hidden while editing, so only the input value is visible. + +- [#9195](https://github.com/Kilo-Org/kilocode/pull/9195) [`7038ce0`](https://github.com/Kilo-Org/kilocode/commit/7038ce0612179c72d4d369cdd7e337995c3a56fd) - Fix queued follow-up messages so they stay stacked at the bottom of the chat while the previous turn is still being processed, instead of getting interleaved with tool output. + +- [#9194](https://github.com/Kilo-Org/kilocode/pull/9194) [`0ace2f9`](https://github.com/Kilo-Org/kilocode/commit/0ace2f960f634c27199468c214cebd0154c998db) - Restore earlier chat history when scrolling through virtualized message lists. + +- [#9236](https://github.com/Kilo-Org/kilocode/pull/9236) [`6f17bb7`](https://github.com/Kilo-Org/kilocode/commit/6f17bb753bc83ba8fbe999fefe109275370637d1) - Fix chat scroll jumping back to the bottom while the session is busy — you can now scroll up to read earlier context while a response is streaming or while a question is waiting for your answer. + +- [#9199](https://github.com/Kilo-Org/kilocode/pull/9199) [`7a1388d`](https://github.com/Kilo-Org/kilocode/commit/7a1388d8d5849aac017a02a33527603c48d0b0a4) - Fix a stuck session state when the suggest tool was left open. If the suggestion was never accepted or dismissed (for example, because VS Code was closed while it was showing), the session stayed marked as busy and any follow-up messages appeared queued forever. The session is now marked idle while waiting for a response to a suggestion. + +- [#9141](https://github.com/Kilo-Org/kilocode/pull/9141) [`61ec925`](https://github.com/Kilo-Org/kilocode/commit/61ec925c509d6437942c23a604aaaeefa16d3c3f) - Restore spacing between sub-agent output and the following user message in the VS Code chat. + ## 7.2.14 ### Minor Changes diff --git a/packages/kilo-vscode/eslint.config.mjs b/packages/kilo-vscode/eslint.config.mjs index a95ef16cd3..f07e7b327e 100644 --- a/packages/kilo-vscode/eslint.config.mjs +++ b/packages/kilo-vscode/eslint.config.mjs @@ -79,10 +79,6 @@ export default [ ], rules: { complexity: ["error", 27] }, }, - { - files: ["webview-ui/src/components/settings/CustomProviderDialog.tsx"], - rules: { complexity: ["error", 26] }, - }, { files: ["src/agent-manager/WorktreeStateManager.ts"], rules: { complexity: ["error", 24] }, diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 4728e81e4a..1aebe0e82b 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -2,7 +2,7 @@ "name": "kilo-code", "displayName": "Kilo Code: AI Coding Agent, Copilot, and Autocomplete", "description": "Open Source AI coding agent that generates code from natural language, automates tasks, and runs terminal commands. Features inline autocomplete, browser automation, automated refactoring, and custom modes for planning, coding, and debugging. Supports 500+ AI models including Claude (Anthropic), Gemini, Grok, GPT, Codex and GLM.", - "version": "7.2.14", + "version": "7.2.20", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/packages/kilo-vscode/playwright.config.ts b/packages/kilo-vscode/playwright.config.ts index 8d2c81b834..5a42beb7ff 100644 --- a/packages/kilo-vscode/playwright.config.ts +++ b/packages/kilo-vscode/playwright.config.ts @@ -3,6 +3,7 @@ import { defineConfig, devices } from "@playwright/test" export default defineConfig({ testDir: "./tests", testMatch: "**/*.spec.ts", + snapshotPathTemplate: "../kilo-docs/public/img/screenshot-tests/kilo-vscode/{arg}{ext}", fullyParallel: true, forbidOnly: !!process.env["CI"], retries: process.env["CI"] ? 1 : 0, diff --git a/packages/kilo-vscode/script/publish.ts b/packages/kilo-vscode/script/publish.ts index 8741734e5a..9f324249a8 100755 --- a/packages/kilo-vscode/script/publish.ts +++ b/packages/kilo-vscode/script/publish.ts @@ -47,7 +47,11 @@ for (const target of targets) { console.log(` ✅ Published ${target} to VS Code Marketplace`) console.log(`\n📤 Publishing ${target} to Open VSX${prerelease ? " (pre-release)" : ""}...`) - await $`npx ovsx publish ${flag} --pat ${process.env.OPENVSX_TOKEN} --packagePath ${vsixPath}` + await retry(() => $`npx ovsx publish ${flag} --pat ${process.env.OPENVSX_TOKEN} --packagePath ${vsixPath}`, { + attempts: 3, + delay: 10_000, + label: `ovsx publish ${target}`, + }) console.log(` ✅ Published ${target} to Open VSX`) } @@ -58,3 +62,16 @@ if (Script.release) { } console.log("\n✨ All targets published successfully!") + +async function retry(fn: () => Promise, opts: { attempts: number; delay: number; label: string }): Promise { + for (let i = 1; i <= opts.attempts; i++) { + try { + return await fn() + } catch (err) { + if (i === opts.attempts) throw err + console.warn(` ⚠️ ${opts.label} failed (attempt ${i}/${opts.attempts}), retrying in ${opts.delay / 1000}s...`) + await new Promise((r) => setTimeout(r, opts.delay)) + } + } + throw new Error("unreachable") +} diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index 42e5dfa869..92a0f10ddb 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -64,6 +64,9 @@ export function activate(context: vscode.ExtensionContext) { } }) + // Prewarm the CLI backend early so autocomplete is ready before first editor use. + ensureBackendForAutocomplete(connectionService) + // Track all open tab panel providers so toolbar button commands can target them. // NOTE: The editor/title toolbar for tab panels intentionally omits Agent Manager // and Marketplace buttons (unlike the sidebar). Too many icons causes VS Code to @@ -355,9 +358,6 @@ export function activate(context: vscode.ExtensionContext) { // Register autocomplete provider registerAutocompleteProvider(context, connectionService) - // Start the CLI backend server eagerly so autocomplete works without opening a Kilo tab. - ensureBackendForAutocomplete(connectionService) - // Register commit message generation registerCommitMessageService(context, connectionService) diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts index 8fd77bd4a4..6a0e925fba 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts @@ -4,18 +4,6 @@ import type { KiloConnectionService } from "../cli-backend" const DEFAULT_MODEL = "mistralai/codestral-2508" const PROVIDER_DISPLAY_NAME = "Kilo Gateway" -/** Chunk from an LLM streaming response */ -export type ApiStreamChunk = - | { type: "text"; text: string } - | { - type: "usage" - totalCost?: number - inputTokens?: number - outputTokens?: number - cacheReadTokens?: number - cacheWriteTokens?: number - } - export class AutocompleteModel { private connectionService: KiloConnectionService | null = null public profileName: string | null = null @@ -34,10 +22,6 @@ export class AutocompleteModel { this.connectionService = service } - public supportsFim(): boolean { - return true - } - /** * Generate a FIM (Fill-in-the-Middle) completion via the CLI backend. * Uses the SDK's kilo.fim() SSE endpoint which handles auth and streaming. @@ -102,20 +86,6 @@ export class AutocompleteModel { } } - /** - * Generate response via chat completions (holefiller fallback). - * Not used when FIM is supported, but kept for compatibility. - */ - public async generateResponse( - systemPrompt: string, - userPrompt: string, - onChunk: (chunk: ApiStreamChunk) => void, - ): Promise { - // FIM is the primary strategy; this method is a fallback. - // For now, throw — callers should use generateFimResponse via supportsFim(). - throw new Error("Chat-based completions are not supported via CLI backend. Use FIM (supportsFim() returns true).") - } - public getModelName(): string { return DEFAULT_MODEL } diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts index e98fc60cc6..6ab38e7ff4 100644 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts @@ -75,13 +75,6 @@ describe("AutocompleteModel", () => { }) }) - describe("supportsFim", () => { - it("always returns true", () => { - const model = new AutocompleteModel() - expect(model.supportsFim()).toBe(true) - }) - }) - describe("getModelName", () => { it("returns the default model", () => { const model = new AutocompleteModel() @@ -165,13 +158,4 @@ describe("AutocompleteModel", () => { ) }) }) - - describe("generateResponse", () => { - it("throws because FIM is the primary strategy", async () => { - const model = new AutocompleteModel() - await expect(model.generateResponse("system", "user", vi.fn())).rejects.toThrow( - "Chat-based completions are not supported via CLI backend", - ) - }) - }) }) diff --git a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts index bb4e52f000..35117fca85 100644 --- a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts +++ b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts @@ -98,22 +98,9 @@ export class ChatTextAreaAutocomplete { let response = "" try { - // Use FIM if supported, otherwise fall back to chat-based completion - if (this.model.supportsFim()) { - await this.model.generateFimResponse(prefix, suffix, (chunk) => { - response += chunk - }) - } else { - // Fall back to chat-based completion for models without FIM support - const systemPrompt = this.getChatSystemPrompt() - const userPrompt = this.getChatUserPrompt(prefix) - - await this.model.generateResponse(systemPrompt, userPrompt, (chunk) => { - if (chunk.type === "text") { - response += chunk.text - } - }) - } + await this.model.generateFimResponse(prefix, suffix, (chunk) => { + response += chunk + }) const latencyMs = Date.now() - startTime @@ -153,35 +140,6 @@ export class ChatTextAreaAutocomplete { } } - /** - * Get system prompt for chat-based completion - */ - private getChatSystemPrompt(): string { - return `You are an intelligent chat completion assistant. Your task is to complete the user's message naturally based on the provided context. - -## RULES -- Provide a natural, conversational completion -- Be concise - typically 1-15 words -- Match the user's tone and style -- Use context from visible code if relevant -- NEVER repeat what the user already typed -- NEVER start with comments (//, /*, #) -- If the user is in the middle of typing a word (e.g., "hel"), include the COMPLETE word in your response (e.g., "hello world" not just "lo world") -- This allows proper prefix matching to remove the overlap correctly -- Return ONLY the completion text, no explanations or formatting` - } - - /** - * Get user prompt for chat-based completion - */ - private getChatUserPrompt(prefix: string): string { - return `${prefix} - -TASK: Complete the user's message naturally. -- If the user is mid-word (e.g., typed "hel"), return the COMPLETE word (e.g., "hello world") so prefix matching can work correctly -- Return ONLY the completion text (what comes next), no explanations.` - } - private async buildPrefix(userText: string, visibleCodeContext?: VisibleCodeContext): Promise { return buildChatPrefix(userText, visibleCodeContext?.editors) } diff --git a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts deleted file mode 100644 index 6fb284743d..0000000000 --- a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { ChatTextAreaAutocomplete } from "../ChatTextAreaAutocomplete" -import { ProviderSettingsManager } from "../../../../core/config/ProviderSettingsManager" -import { AutocompleteModel } from "../../AutocompleteModel" -import { ApiStreamChunk } from "../../../../api/transform/stream" - -describe("ChatTextAreaAutocomplete", () => { - let autocomplete: ChatTextAreaAutocomplete - let mockProviderSettingsManager: ProviderSettingsManager - - beforeEach(() => { - mockProviderSettingsManager = {} as ProviderSettingsManager - autocomplete = new ChatTextAreaAutocomplete(mockProviderSettingsManager) - }) - - describe("getCompletion", () => { - it("should work with non-FIM models using chat-based completion", async () => { - // Setup: Model without FIM support (like Mistral) - const mockModel = new AutocompleteModel() - - vi.spyOn(mockModel, "hasValidCredentials").mockReturnValue(true) - vi.spyOn(mockModel, "supportsFim").mockReturnValue(false) - vi.spyOn(mockModel, "generateResponse").mockImplementation(async (systemPrompt, userPrompt, onChunk) => { - // Simulate streaming chat response - const chunks: ApiStreamChunk[] = [{ type: "text", text: "write a function" }] - for (const chunk of chunks) { - onChunk(chunk) - } - return { - cost: 0, - inputTokens: 15, - outputTokens: 8, - cacheWriteTokens: 0, - cacheReadTokens: 0, - } - }) - - // @ts-expect-error - accessing private property for test - autocomplete.model = mockModel - - const result = await autocomplete.getCompletion("How to ") - - expect(mockModel.generateResponse).toHaveBeenCalled() - expect(result.suggestion).toBe("write a function") - }) - }) - - describe("cleanSuggestion", () => { - it("should filter code patterns (comments, preprocessor)", () => { - // Comments - filtered by the regex check in cleanSuggestion - expect(autocomplete.cleanSuggestion("// comment", "")).toBe("") - expect(autocomplete.cleanSuggestion("/* comment", "")).toBe("") - expect(autocomplete.cleanSuggestion("* something", "")).toBe("") - - // Code patterns - expect(autocomplete.cleanSuggestion("#include", "")).toBe("") - expect(autocomplete.cleanSuggestion("# Header", "")).toBe("") - }) - - it("should filter empty content", () => { - // Empty content is filtered by postprocessAutocompleteSuggestion - expect(autocomplete.cleanSuggestion("", "")).toBe("") - }) - - it("should accept natural language suggestions", () => { - expect(autocomplete.cleanSuggestion("Hello world", "")).toBe("Hello world") - expect(autocomplete.cleanSuggestion("Can you help me", "")).toBe("Can you help me") - expect(autocomplete.cleanSuggestion("test123", "")).toBe("test123") - expect(autocomplete.cleanSuggestion("What's up?", "")).toBe("What's up?") - }) - - it("should accept symbols in middle of text", () => { - expect(autocomplete.cleanSuggestion("Text with # in middle", "")).toBe("Text with # in middle") - expect(autocomplete.cleanSuggestion("Hello // but not a comment", "")).toBe("Hello // but not a comment") - }) - - it("should truncate at first newline", () => { - expect(autocomplete.cleanSuggestion("First line\nSecond line", "")).toBe("First line") - }) - - it("should remove prefix overlap", () => { - expect(autocomplete.cleanSuggestion("Hello world", "Hello ")).toBe("world") - }) - }) -}) diff --git a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/AutocompleteInlineCompletionProvider.ts b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/AutocompleteInlineCompletionProvider.ts index 93ef16b749..2e2c865dff 100644 --- a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/AutocompleteInlineCompletionProvider.ts +++ b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/AutocompleteInlineCompletionProvider.ts @@ -299,7 +299,7 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple clearTimeout(this.debounceTimer) this.debounceTimer = null } - this.debouncedPendingRequest = null + this.settleDebouncedPendingRequest() this.pendingRequests.length = 0 this.fimAbortController?.abort() this.fimAbortController = null @@ -484,6 +484,15 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple } } + private settleDebouncedPendingRequest(): void { + const pending = this.debouncedPendingRequest + if (!pending) return + + this.removePendingRequest(pending) + pending.resolve?.() + this.debouncedPendingRequest = null + } + /** * Debounced fetch with leading edge execution and pending request reuse. * - First call executes immediately (leading edge) @@ -519,10 +528,8 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple // otherwise linger with a never-resolving promise. if (this.debounceTimer !== null) { clearTimeout(this.debounceTimer) - if (this.debouncedPendingRequest) { - this.removePendingRequest(this.debouncedPendingRequest) - this.debouncedPendingRequest = null - } + this.debounceTimer = null + this.settleDebouncedPendingRequest() } // Create the pending request object first so we can reference it in the cleanup @@ -533,14 +540,17 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple } const requestPromise = new Promise((resolve) => { + pendingRequest.resolve = resolve this.debounceTimer = setTimeout(async () => { this.debounceTimer = null this.debouncedPendingRequest = null this.isFirstCall = true // Reset for next sequence - await this.fetchAndCacheSuggestion(prompt, prefix, suffix, languageId) - // Remove this request from pending when done - this.removePendingRequest(pendingRequest) - resolve() + try { + await this.fetchAndCacheSuggestion(prompt, prefix, suffix, languageId) + } finally { + this.removePendingRequest(pendingRequest) + resolve() + } }, this.debounceDelayMs) }) diff --git a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/AutocompleteInlineCompletionProvider.test.ts b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/AutocompleteInlineCompletionProvider.test.ts index 65d709f723..fa64a47745 100644 --- a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/AutocompleteInlineCompletionProvider.test.ts +++ b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/AutocompleteInlineCompletionProvider.test.ts @@ -851,7 +851,6 @@ describe("AutocompleteInlineCompletionProvider", () => { }), getModelName: vi.fn().mockReturnValue("test-model"), getProviderDisplayName: vi.fn().mockReturnValue("test-provider"), - supportsFim: vi.fn().mockReturnValue(true), hasValidCredentials: vi.fn().mockReturnValue(true), // Default to true for tests } as unknown as AutocompleteModel mockCostTrackingCallback = vi.fn() as CostTrackingCallback @@ -1370,7 +1369,7 @@ describe("AutocompleteInlineCompletionProvider", () => { await provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken) // Second call should set a debounce timer - provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken) + const promise = provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken) // Verify timer is set for trailing edge const timerCountBeforeDispose = vi.getTimerCount() @@ -1379,9 +1378,10 @@ describe("AutocompleteInlineCompletionProvider", () => { // Dispose the provider before timer fires provider.dispose() - // Verify timer is cleared + // Verify timer is cleared and the pending request settles const timerCountAfterDispose = vi.getTimerCount() expect(timerCountAfterDispose).toBeLessThan(timerCountBeforeDispose) + await expect(promise).resolves.toEqual([]) }) }) }) @@ -2072,6 +2072,23 @@ describe("AutocompleteInlineCompletionProvider", () => { expect(callCount).toBe(2) }) + it("should settle canceled debounced requests when the timer is reset", async () => { + await provider.provideInlineCompletionItems(mockDocument, mockPosition, mockContext, mockToken) + + const doc2 = new MockTextDocument(vscode.Uri.file("/test.ts"), "const x = 1\nconst z = 3") + const promise2 = provider.provideInlineCompletionItems(doc2, mockPosition, mockContext, mockToken) + + await vi.advanceTimersByTimeAsync(100) + + const doc3 = new MockTextDocument(vscode.Uri.file("/test.ts"), "const x = 1\nconst q = 4") + const promise3 = provider.provideInlineCompletionItems(doc3, mockPosition, mockContext, mockToken) + + await expect(promise2).resolves.toEqual([]) + + await vi.advanceTimersByTimeAsync(500) + await promise3 + }) + it("should NOT reuse pending request when user backspaces (prefix shrinks)", async () => { // Mock the model to track call count let callCount = 0 diff --git a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/uselessSuggestionFilter.test.ts b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/uselessSuggestionFilter.test.ts index 2a23682396..b2cd98dbfc 100644 --- a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/uselessSuggestionFilter.test.ts +++ b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/__tests__/uselessSuggestionFilter.test.ts @@ -42,25 +42,15 @@ describe("postprocessAutocompleteSuggestion", () => { expect(result).toBe("test") }) - it("handles Mercury/Granite prefix duplication", () => { + it("handles Mercury prefix duplication", () => { const result = postprocessAutocompleteSuggestion({ suggestion: "const x = 42", prefix: "const x = ", suffix: "", - model: "granite-20b", + model: "inception/mercury-edit", }) expect(result).toBe("42") }) - - it("handles Gemini/Gemma file separator", () => { - const result = postprocessAutocompleteSuggestion({ - suggestion: "const x = 1<|file_separator|>", - prefix: "", - suffix: "", - model: "gemini-pro", - }) - expect(result).toBe("const x = 1") - }) }) describe("extreme repetition filtering", () => { diff --git a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/uselessSuggestionFilter.ts b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/uselessSuggestionFilter.ts index ea47bd2379..db1d975b4e 100644 --- a/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/uselessSuggestionFilter.ts +++ b/packages/kilo-vscode/src/services/autocomplete/classic-auto-complete/uselessSuggestionFilter.ts @@ -133,7 +133,7 @@ function normalizeToCompleteLine(params: AutocompleteSuggestion): AutocompleteSu * @param params.suggestion - The suggested text to insert * @param params.prefix - The text before the cursor position * @param params.suffix - The text after the cursor position - * @param params.model - The model string (e.g., "codestral", "qwen3", etc.) + * @param params.model - The model string (e.g., "codestral", "mercury", etc.) * @param params.languageId - Optional language ID for language-specific filtering * @returns The processed suggestion text, or undefined if it should be filtered out */ diff --git a/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/postprocessing/index.ts b/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/postprocessing/index.ts index 0e67bdf798..7f384b09a4 100644 --- a/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/postprocessing/index.ts +++ b/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/postprocessing/index.ts @@ -133,34 +133,18 @@ export function postprocessCompletion({ } } - if (llm.model.includes("qwen3")) { - // Qwen3 always starts from special thinking markers, and we don't want them to output these contents - // Remove all content from " - completion = completion.replace(/.*?<\/think>/s, "") - completion = completion.replace(/<\/think>/, "") - - // Remove any number of newline characters at the beginning and end - completion = completion.replace(/^\n+|\n+$/g, "") - } - - if (llm.model.includes("mercury") || llm.model.includes("granite")) { + if (llm.model.includes("mercury")) { completion = removePrefixOverlap(completion, prefix) - } - // // If completion starts with multiple whitespaces, but the cursor is at the end of the line - // // then it should probably be on a new line - if ( - llm.model.includes("mercury") && - (completion.startsWith(" ") || completion.startsWith("\t")) && - !prefix.endsWith("\n") && - (suffix.startsWith("\n") || suffix.trim().length === 0) - ) { - completion = "\n" + completion - } - - if ((llm.model.includes("gemini") || llm.model.includes("gemma")) && completion.endsWith("<|file_separator|>")) { - // "<|file_separator|>" is 18 characters long - completion = completion.slice(0, -18) + // If completion starts with multiple whitespaces, but the cursor is at the + // end of the line then it should probably be on a new line + if ( + (completion.startsWith(" ") || completion.startsWith("\t")) && + !prefix.endsWith("\n") && + (suffix.startsWith("\n") || suffix.trim().length === 0) + ) { + completion = "\n" + completion + } } // If prefix ends with space and so does completion, then remove the space from completion diff --git a/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/templating/AutocompleteTemplate.ts b/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/templating/AutocompleteTemplate.ts index 6cff0486d2..93c4de15e6 100644 --- a/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/templating/AutocompleteTemplate.ts +++ b/packages/kilo-vscode/src/services/autocomplete/continuedev/core/autocomplete/templating/AutocompleteTemplate.ts @@ -1,8 +1,11 @@ // Fill in the middle prompts +// +// We only expose Codestral and Mercury Edit as autocomplete models — every +// other FIM template in the upstream continuedev list is unreachable. import { CompletionOptions } from "../../index.js" import { getLastNUriRelativePathParts, getShortestUniqueRelativeUriPaths } from "../../util/uri.js" -import { AutocompleteCodeSnippet, AutocompleteSnippet, AutocompleteSnippetType } from "../types.js" +import { AutocompleteSnippet, AutocompleteSnippetType } from "../types.js" type TemplateRenderer = ( prefix: string, @@ -27,55 +30,6 @@ export interface AutocompleteTemplate { completionOptions?: Partial } -// https://huggingface.co/stabilityai/stable-code-3b -const stableCodeFimTemplate: AutocompleteTemplate = { - template: (prefix: string, suffix: string): string => { - return `${prefix}${suffix}` - }, - completionOptions: { - stop: ["", "", "", "", "<|endoftext|>", "", ""], - }, -} - -// https://github.com/QwenLM/Qwen2.5-Coder?tab=readme-ov-file#3-file-level-code-completion-fill-in-the-middle -// This issue asks about the use of <|repo_name|> and <|file_sep|> together with <|fim_prefix|>, <|fim_suffix|> and <|fim_middle|> -// https://github.com/QwenLM/Qwen2.5-Coder/issues/343 -const qwenCoderFimTemplate: AutocompleteTemplate = { - template: (prefix: string, suffix: string): string => { - return `<|fim_prefix|>${prefix}<|fim_suffix|>${suffix}<|fim_middle|>` - }, - completionOptions: { - stop: [ - "<|endoftext|>", - "<|fim_prefix|>", - "<|fim_middle|>", - "<|fim_suffix|>", - "<|fim_pad|>", - "<|repo_name|>", - "<|file_sep|>", - "<|im_start|>", - "<|im_end|>", - ], - }, -} - -const seedCoderFimTemplate: AutocompleteTemplate = { - template: (prefix: string, suffix: string): string => { - return `<[fim-prefix]>${prefix}<[fim-suffix]>${suffix}<[fim-middle]>` - }, - completionOptions: { - stop: [ - "<[end▁of▁sentence]>", - "<[fim-prefix]>", - "<[fim-middle]>", - "<[fim-suffix]>", - "<[PAD▁TOKEN]>", - "<[SEP▁TOKEN]>", - "<[begin▁of▁sentence]>", - ], - }, -} - const codestralMultifileFimTemplate: AutocompleteTemplate = { compilePrefixSuffix: (prefix, suffix, filepath, _reponame, snippets, workspaceUris): [string, string] => { function getFileName(snippet: { uri: string; uniquePath: string }) { @@ -158,217 +112,9 @@ const mercuryMultifileFimTemplate: AutocompleteTemplate = { }, } -const codegemmaFimTemplate: AutocompleteTemplate = { - template: (prefix: string, suffix: string): string => { - return `<|fim_prefix|>${prefix}<|fim_suffix|>${suffix}<|fim_middle|>` - }, - completionOptions: { - stop: ["<|fim_prefix|>", "<|fim_suffix|>", "<|fim_middle|>", "<|file_separator|>", "", ""], - }, -} - -const codeLlamaFimTemplate: AutocompleteTemplate = { - template: (prefix: string, suffix: string): string => { - return `
 ${prefix} ${suffix} `
-  },
-  completionOptions: { stop: ["
", "", "", ""] },
-}
-
-// https://huggingface.co/deepseek-ai/deepseek-coder-1.3b-base
-const deepseekFimTemplate: AutocompleteTemplate = {
-  template: (prefix: string, suffix: string): string => {
-    return `<|fim▁begin|>${prefix}<|fim▁hole|>${suffix}<|fim▁end|>`
-  },
-  completionOptions: {
-    stop: ["<|fim▁begin|>", "<|fim▁hole|>", "<|fim▁end|>", "//", "<|end▁of▁sentence|>"],
-  },
-}
-
-// https://github.com/THUDM/CodeGeeX4/blob/main/guides/Infilling_guideline.md
-const codegeexFimTemplate: AutocompleteTemplate = {
-  template: (prefix, suffix, filepath, _reponame, language, allSnippets, workspaceUris): string => {
-    const snippets = allSnippets.filter(
-      (snippet) => snippet.type === AutocompleteSnippetType.Code,
-    ) as AutocompleteCodeSnippet[]
-
-    const relativePaths = getShortestUniqueRelativeUriPaths(
-      [...snippets.map((snippet) => snippet.filepath), filepath],
-      workspaceUris,
-    )
-    const baseTemplate = `###PATH:${
-      relativePaths[relativePaths.length - 1]
-    }\n###LANGUAGE:${language}\n###MODE:BLOCK\n<|code_suffix|>${suffix}<|code_prefix|>${prefix}<|code_middle|>`
-    if (snippets.length === 0) {
-      return `<|user|>\n${baseTemplate}<|assistant|>\n`
-    }
-    const references = `###REFERENCE:\n${snippets
-      .map((snippet, i) => `###PATH:${relativePaths[i]}\n${snippet.content}\n`)
-      .join("###REFERENCE:\n")}`
-    const prompt = `<|user|>\n${references}\n${baseTemplate}<|assistant|>\n`
-    return prompt
-  },
-  completionOptions: {
-    stop: ["<|user|>", "<|code_suffix|>", "<|code_prefix|>", "<|code_middle|>", "<|assistant|>", "<|endoftext|>"],
-  },
-}
-
-const holeFillerTemplate: AutocompleteTemplate = {
-  template: (prefix: string, suffix: string) => {
-    // From https://github.com/VictorTaelin/AI-scripts
-    const SYSTEM_MSG = `You are a HOLE FILLER. You are provided with a file containing holes, formatted as '{{HOLE_NAME}}'. Your TASK is to complete with a string to replace this hole with, inside a  XML tag, including context-aware indentation, if needed.  All completions MUST be truthful, accurate, well-written and correct.
-
-## EXAMPLE QUERY:
-
-
-function sum_evens(lim) {
-  var sum = 0;
-  for (var i = 0; i < lim; ++i) {
-    {{FILL_HERE}}
-  }
-  return sum;
-}
-
-
-TASK: Fill the {{FILL_HERE}} hole.
-
-## CORRECT COMPLETION
-
-if (i % 2 === 0) {
-      sum += i;
-    }
-
-## EXAMPLE QUERY:
-
-
-def sum_list(lst):
-  total = 0
-  for x in lst:
-  {{FILL_HERE}}
-  return total
-
-print sum_list([1, 2, 3])
-
-
-## CORRECT COMPLETION:
-
-  total += x
-
-## EXAMPLE QUERY:
-
-
-// data Tree a = Node (Tree a) (Tree a) | Leaf a
-
-// sum :: Tree Int -> Int
-// sum (Node lft rgt) = sum lft + sum rgt
-// sum (Leaf val)     = val
-
-// convert to TypeScript:
-{{FILL_HERE}}
-
-
-## CORRECT COMPLETION:
-
-type Tree
-  = {$:"Node", lft: Tree, rgt: Tree}
-  | {$:"Leaf", val: T};
-
-function sum(tree: Tree): number {
-  switch (tree.$) {
-    case "Node":
-      return sum(tree.lft) + sum(tree.rgt);
-    case "Leaf":
-      return tree.val;
-  }
-}
-
-## EXAMPLE QUERY:
-
-The 5th {{FILL_HERE}} is Jupiter.
-
-## CORRECT COMPLETION:
-
-planet from the Sun
-
-## EXAMPLE QUERY:
-
-function hypothenuse(a, b) {
-  return Math.sqrt({{FILL_HERE}}b ** 2);
-}
-
-## CORRECT COMPLETION:
-
-a ** 2 + `
-
-    const fullPrompt =
-      SYSTEM_MSG +
-      `\n\n\n${prefix}{{FILL_HERE}}${suffix}\n\nTASK: Fill the {{FILL_HERE}} hole. Answer only with the CORRECT completion, and NOTHING ELSE. Do it now.\n`
-    return fullPrompt
-  },
-  completionOptions: {
-    stop: [""],
-  },
-}
-
 export function getTemplateForModel(model: string): AutocompleteTemplate {
-  const lowerCaseModel = model.toLowerCase()
-
-  // if (lowerCaseModel.includes("starcoder2")) {
-  //   return starcoder2FimTemplate;
-  // }
-  if (lowerCaseModel.includes("mercury")) {
+  if (model.toLowerCase().includes("mercury")) {
     return mercuryMultifileFimTemplate
   }
-
-  if (lowerCaseModel.includes("qwen") && lowerCaseModel.includes("coder")) {
-    return qwenCoderFimTemplate
-  }
-
-  if (lowerCaseModel.includes("seed") && lowerCaseModel.includes("coder")) {
-    return seedCoderFimTemplate
-  }
-
-  if (
-    lowerCaseModel.includes("starcoder") ||
-    lowerCaseModel.includes("star-coder") ||
-    lowerCaseModel.includes("starchat") ||
-    lowerCaseModel.includes("octocoder") ||
-    lowerCaseModel.includes("stable") ||
-    lowerCaseModel.includes("codeqwen") ||
-    lowerCaseModel.includes("qwen")
-  ) {
-    return stableCodeFimTemplate
-  }
-
-  if (lowerCaseModel.includes("codestral")) {
-    return codestralMultifileFimTemplate
-  }
-
-  if (lowerCaseModel.includes("codegemma")) {
-    return codegemmaFimTemplate
-  }
-
-  if (lowerCaseModel.includes("codellama")) {
-    return codeLlamaFimTemplate
-  }
-
-  if (lowerCaseModel.includes("deepseek")) {
-    return deepseekFimTemplate
-  }
-
-  if (lowerCaseModel.includes("codegeex")) {
-    return codegeexFimTemplate
-  }
-
-  // if (
-  // 	lowerCaseModel.includes("gpt") ||
-  // 	lowerCaseModel.includes("davinci-002") ||
-  // 	lowerCaseModel.includes("claude") ||
-  // 	lowerCaseModel.includes("granite3") ||
-  // 	lowerCaseModel.includes("granite-3")
-  // ) {
-  // Default Fallback Mode
-  return holeFillerTemplate
-  //}
-
-  //return stableCodeFimTemplate
+  return codestralMultifileFimTemplate
 }
diff --git a/packages/kilo-vscode/src/services/autocomplete/shims/FileIgnoreController.ts b/packages/kilo-vscode/src/services/autocomplete/shims/FileIgnoreController.ts
index 1b8c639cb4..9b0e3d9957 100644
--- a/packages/kilo-vscode/src/services/autocomplete/shims/FileIgnoreController.ts
+++ b/packages/kilo-vscode/src/services/autocomplete/shims/FileIgnoreController.ts
@@ -14,6 +14,7 @@ const SENSITIVE_PATTERNS = [".env", ".env.*"]
 // path.isAbsolute() on POSIX does not recognise these, so we check explicitly
 // to avoid passing them to the `ignore` package which throws a RangeError.
 const WINDOWS_DRIVE = /^[a-zA-Z]:[/\\]/
+const REALPATH_CACHE_MAX = 1_000
 
 function toPosix(filePath: string): string {
   return filePath.replace(/\\/g, "/")
@@ -32,6 +33,7 @@ export class FileIgnoreController {
   async initialize(): Promise {
     this.ignoreInstance = ignore()
     this.loadedContents = []
+    this.realpathCache.clear()
 
     if (!this.workspacePath) {
       return
@@ -65,6 +67,14 @@ export class FileIgnoreController {
     this.ignoreInstance.add(SENSITIVE_PATTERNS)
   }
 
+  private cacheRealpath(input: string, resolved: string): void {
+    if (this.realpathCache.size >= REALPATH_CACHE_MAX) {
+      const key = this.realpathCache.keys().next().value
+      if (key !== undefined) this.realpathCache.delete(key)
+    }
+    this.realpathCache.set(input, resolved)
+  }
+
   private toRelativePath(filePath: string): string | null {
     if (!filePath) {
       return null
@@ -85,7 +95,7 @@ export class FileIgnoreController {
     } else {
       try {
         resolved = fs.realpathSync(absoluteInput)
-        this.realpathCache.set(absoluteInput, resolved)
+        this.cacheRealpath(absoluteInput, resolved)
       } catch {
         // Keep unresolved path when file does not exist yet.
       }
@@ -142,6 +152,7 @@ export class FileIgnoreController {
 
   dispose(): void {
     this.loadedContents = []
+    this.realpathCache.clear()
     this.ignoreInstance = ignore()
   }
 }
diff --git a/packages/kilo-vscode/src/services/autocomplete/types.ts b/packages/kilo-vscode/src/services/autocomplete/types.ts
index ecbae591dc..1fddf8b01e 100644
--- a/packages/kilo-vscode/src/services/autocomplete/types.ts
+++ b/packages/kilo-vscode/src/services/autocomplete/types.ts
@@ -110,6 +110,7 @@ export interface PendingRequest {
   prefix: string
   suffix: string
   promise: Promise
+  resolve?: () => void
 }
 
 // ============================================================================
diff --git a/packages/kilo-vscode/tests/unit/custom-provider-dialog-validate.test.ts b/packages/kilo-vscode/tests/unit/custom-provider-dialog-validate.test.ts
new file mode 100644
index 0000000000..337dd77a14
--- /dev/null
+++ b/packages/kilo-vscode/tests/unit/custom-provider-dialog-validate.test.ts
@@ -0,0 +1,146 @@
+import { describe, expect, it } from "bun:test"
+import { validateCustomProvider } from "../../webview-ui/src/components/settings/CustomProviderValidation"
+import type { FormState } from "../../webview-ui/src/components/settings/CustomProviderValidation"
+
+// Simple translator that returns the key so tests can assert on key names
+const t = (key: string) => key
+
+function base(): FormState {
+  return {
+    providerID: "my-provider",
+    name: "My Provider",
+    baseURL: "https://example.com/v1",
+    apiKey: "",
+    models: [{ id: "model-1", name: "Model One", reasoning: false, variants: [] }],
+    headers: [],
+    saving: false,
+  }
+}
+
+function args(form: FormState) {
+  return {
+    form,
+    t,
+    editing: false,
+    disabledProviders: [],
+    existingProviderIDs: new Set(),
+  }
+}
+
+describe("validateCustomProvider – variant name validation", () => {
+  it("allows submit when reasoning is enabled with no variants", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeDefined()
+    expect(out.errors.models[0].variants).toEqual([])
+  })
+
+  it("allows submit when reasoning is enabled with a named variant", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    form.models[0].variants = [
+      {
+        name: "fast",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+    ]
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeDefined()
+    expect(out.errors.models[0].variants?.[0]?.name).toBeUndefined()
+  })
+
+  it("blocks submit and reports error when reasoning is enabled with an empty variant name", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    form.models[0].variants = [
+      {
+        name: "",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+    ]
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeUndefined()
+    expect(out.errors.models[0].variants?.[0]?.name).toBe("provider.custom.error.required")
+  })
+
+  it("blocks submit and reports error when reasoning is enabled with a whitespace-only variant name", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    form.models[0].variants = [
+      {
+        name: "   ",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+    ]
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeUndefined()
+    expect(out.errors.models[0].variants?.[0]?.name).toBe("provider.custom.error.required")
+  })
+
+  it("blocks submit and reports duplicate error for two variants with the same name", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    form.models[0].variants = [
+      {
+        name: "fast",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+      {
+        name: "fast",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+    ]
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeUndefined()
+    expect(out.errors.models[0].variants?.[1]?.name).toBe("provider.custom.error.duplicate")
+  })
+
+  it("ignores variants entirely when reasoning is disabled, even if they have empty names", () => {
+    const form = base()
+    form.models[0].reasoning = false
+    form.models[0].variants = [
+      {
+        name: "",
+        enableThinking: undefined,
+        thinking: undefined,
+        reasoningEffort: undefined,
+        chatTemplateArgs: undefined,
+      },
+    ]
+    const out = validateCustomProvider(args(form))
+    // No variant errors produced; form is allowed to submit
+    expect(out.errors.models[0].variants).toEqual([])
+    // Variant is not included in the saved config
+    expect(out.result).toBeDefined()
+    const saved = out.result!.config.models["model-1"] as Record
+    expect(saved.variants).toBeUndefined()
+  })
+
+  it("persists named variants in the saved config when reasoning is enabled", () => {
+    const form = base()
+    form.models[0].reasoning = true
+    form.models[0].variants = [
+      { name: "eco", enableThinking: true, thinking: undefined, reasoningEffort: "low", chatTemplateArgs: undefined },
+    ]
+    const out = validateCustomProvider(args(form))
+    expect(out.result).toBeDefined()
+    const saved = out.result!.config.models["model-1"] as Record
+    expect(saved.variants).toEqual({ eco: { enable_thinking: true, reasoningEffort: "low" } })
+  })
+})
diff --git a/packages/kilo-vscode/tests/unit/plan-followup-locale-keys.test.ts b/packages/kilo-vscode/tests/unit/plan-followup-locale-keys.test.ts
new file mode 100644
index 0000000000..638ce3ae2c
--- /dev/null
+++ b/packages/kilo-vscode/tests/unit/plan-followup-locale-keys.test.ts
@@ -0,0 +1,64 @@
+import { describe, expect, test } from "bun:test"
+import { dict as ar } from "@kilocode/kilo-i18n/ar"
+import { dict as br } from "@kilocode/kilo-i18n/br"
+import { dict as bs } from "@kilocode/kilo-i18n/bs"
+import { dict as da } from "@kilocode/kilo-i18n/da"
+import { dict as de } from "@kilocode/kilo-i18n/de"
+import { dict as en } from "@kilocode/kilo-i18n/en"
+import { dict as es } from "@kilocode/kilo-i18n/es"
+import { dict as fr } from "@kilocode/kilo-i18n/fr"
+import { dict as ja } from "@kilocode/kilo-i18n/ja"
+import { dict as ko } from "@kilocode/kilo-i18n/ko"
+import { dict as nl } from "@kilocode/kilo-i18n/nl"
+import { dict as no } from "@kilocode/kilo-i18n/no"
+import { dict as pl } from "@kilocode/kilo-i18n/pl"
+import { dict as ru } from "@kilocode/kilo-i18n/ru"
+import { dict as th } from "@kilocode/kilo-i18n/th"
+import { dict as tr } from "@kilocode/kilo-i18n/tr"
+import { dict as uk } from "@kilocode/kilo-i18n/uk"
+import { dict as zh } from "@kilocode/kilo-i18n/zh"
+import { dict as zht } from "@kilocode/kilo-i18n/zht"
+
+const dicts: Record> = {
+  ar,
+  br,
+  bs,
+  da,
+  de,
+  en,
+  es,
+  fr,
+  ja,
+  ko,
+  nl,
+  no,
+  pl,
+  ru,
+  th,
+  tr,
+  uk,
+  zh,
+  zht,
+}
+
+const keys = [
+  "plan.followup.header",
+  "plan.followup.question",
+  "plan.followup.answer.newSession",
+  "plan.followup.answer.newSession.description",
+  "plan.followup.answer.continue",
+  "plan.followup.answer.continue.description",
+]
+
+describe("plan follow-up i18n keys", () => {
+  for (const locale of Object.keys(dicts)) {
+    test(`${locale} defines every plan.followup.* key`, () => {
+      const d = dicts[locale]!
+      for (const key of keys) {
+        const value = d[key]
+        expect(value, `${locale} is missing ${key}`).toBeDefined()
+        expect(value, `${locale} has empty value for ${key}`).toBeTruthy()
+      }
+    })
+  }
+})
diff --git a/packages/kilo-vscode/tests/unit/question-dock-contract.test.ts b/packages/kilo-vscode/tests/unit/question-dock-contract.test.ts
new file mode 100644
index 0000000000..fb9b4ca761
--- /dev/null
+++ b/packages/kilo-vscode/tests/unit/question-dock-contract.test.ts
@@ -0,0 +1,61 @@
+/**
+ * QuestionDock submission contract tests.
+ *
+ * Static analysis — reads QuestionDock source and locks the explicit-submit
+ * behavior for single-question option picks.
+ */
+
+import { describe, expect, it } from "bun:test"
+import fs from "node:fs"
+import path from "node:path"
+
+const ROOT = path.resolve(import.meta.dir, "../..")
+const FILE = path.join(ROOT, "webview-ui/src/components/chat/QuestionDock.tsx")
+
+function readFile(filePath: string): string {
+  return fs.readFileSync(filePath, "utf-8")
+}
+
+function extractBody(source: string, name: string): string {
+  const marker = `const ${name} = `
+  const start = source.indexOf(marker)
+  if (start === -1) return ""
+  const rest = source.slice(start + marker.length)
+  const next = rest.search(/\n  const /)
+  return next === -1 ? rest : rest.slice(0, next)
+}
+
+describe("QuestionDock explicit submit contract", () => {
+  const source = readFile(FILE)
+  const pick = extractBody(source, "pick")
+
+  it("keeps option clicks local instead of replying immediately", () => {
+    expect(pick.length).toBeGreaterThan(0)
+    expect(pick).not.toContain("reply([[answer]])")
+  })
+
+  it("still advances multi-question single-select flows", () => {
+    expect(pick).toContain('if (outcome.kind === "advance")')
+    expect(pick).toContain('setStore("tab", store.tab + 1)')
+  })
+
+  it("still syncs the optimistic agent selection on pick", () => {
+    expect(pick).toContain("syncAgent(answers, kinds)")
+  })
+
+  it("restores the optimistic agent before dismissing a question", () => {
+    const reject = extractBody(source, "reject")
+    expect(reject).toContain("if (prevAgent !== undefined)")
+    expect(reject).toContain("session.selectAgent(prevAgent)")
+    expect(reject).toContain("prevAgent = undefined")
+    const reset = reject.indexOf("prevAgent = undefined")
+    const sending = reject.indexOf('setStore("sending", true)')
+    expect(reset).toBeGreaterThan(-1)
+    expect(sending).toBeGreaterThan(-1)
+    expect(reset, "reject should restore the agent before sending the dismissal").toBeLessThan(sending)
+  })
+
+  it("keeps the footer Submit button wired to submit()", () => {
+    expect(source).toContain('
@@ -439,7 +458,7 @@ export const QuestionDock: Component<{ request: QuestionRequest }> = (props) =>
                   const answered = () => Boolean(value())
                   return (
                     
- {q.question} + {tr(language.t, q.questionKey, q.question)} {answered() ? value() : language.t("ui.question.review.notAnswered")} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/question-dock-utils.ts b/packages/kilo-vscode/webview-ui/src/components/chat/question-dock-utils.ts index 62395ef009..615aa02fb3 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/question-dock-utils.ts +++ b/packages/kilo-vscode/webview-ui/src/components/chat/question-dock-utils.ts @@ -1,19 +1,38 @@ import type { QuestionOption } from "../../types/messages" +/** + * Translate a backend-provided i18n key, falling back to the canonical label when no key is + * set or the key is missing from the dictionary. + * + * Implementation detail: our `language.t` (see webview-ui/src/context/language.tsx) returns + * the key string back when a translation is missing. We detect that "echo" and substitute + * the fallback. If `language.t` ever changes to return `undefined` / empty / throw on miss, + * this helper's fallback branch must be updated to match. + * + * Edge case: if a translator ever writes a value identical to the dotted key string, this + * helper would falsely fall back to the English label. Namespaced keys (`plan.followup.*`) + * make this practically impossible, but keep it in mind before picking ambiguous key names. + */ +export function tr(translate: (key: string) => string, key: string | undefined, fallback: string): string { + if (!key) return fallback + const result = translate(key) + if (result === key) return fallback + return result +} + export type PickOutcome = { kind: "submit" } | { kind: "advance" } | { kind: "stay" } /** * Decide what should happen after a user picks an option in the question dock. * * - Multi-select prompts: the pick only toggles local state; no tab change, no submit. - * - Single-question single-select, option pick: submit immediately (matches the TUI). + * - Single-question single-select prompts: keep the pick local and wait for explicit Submit. * - Multi-question single-select, option pick: advance to the next tab. * - Custom-input path for a single-select is handled separately in handleCustomSubmit. */ export function pickOutcome(input: { single: boolean; multi: boolean; custom: boolean }): PickOutcome { if (input.multi) return { kind: "stay" } - if (input.single && input.custom) return { kind: "stay" } - if (input.single) return { kind: "submit" } + if (input.single) return { kind: "stay" } return { kind: "advance" } } diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx index 1267d9a014..390225adc4 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx @@ -7,7 +7,7 @@ import { Spinner } from "@kilocode/kilo-ui/spinner" import { TextField } from "@kilocode/kilo-ui/text-field" import { showToast } from "@kilocode/kilo-ui/toast" import { For, Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js" -import { createStore } from "solid-js/store" +import { createStore, reconcile } from "solid-js/store" import { useConfig } from "../../context/config" import { useLanguage } from "../../context/language" import { useProvider } from "../../context/provider" @@ -22,12 +22,10 @@ import type { ModelEntry, ReasoningEffortValue, ThinkingTypeValue, - Translator, VariantEntry, } from "./CustomProviderModelCard" - -const PROVIDER_ID = /^[a-z0-9][a-z0-9-_]*$/ -const OPENAI_COMPATIBLE = "@ai-sdk/openai-compatible" +import { validateCustomProvider } from "./CustomProviderValidation" +import type { FormErrors, FormState, HeaderRow } from "./CustomProviderValidation" const DEBOUNCE_MS = 500 const SEARCH_DEBOUNCE_MS = 150 @@ -42,183 +40,8 @@ function fuzzy(query: string, target: string) { return qi === q.length } -type HeaderRow = { - key: string - value: string -} - -type FormState = { - providerID: string - name: string - baseURL: string - apiKey: string - models: ModelEntry[] - headers: HeaderRow[] - saving: boolean -} - -type FormErrors = { - providerID: string | undefined - name: string | undefined - baseURL: string | undefined - models: Array<{ id?: string; name?: string; variants?: Array<{ name?: string }> }> - headers: Array<{ key?: string; value?: string }> -} - type FetchedModel = { id: string; name: string } -type ValidateArgs = { - form: FormState - t: Translator - editing: boolean - disabledProviders: string[] - existingProviderIDs: Set - /** Preserved env vars from the existing provider config (edit mode only) */ - existingEnv?: string[] -} - -function validateCustomProvider(input: ValidateArgs) { - const providerID = input.form.providerID.trim() - const name = input.form.name.trim() - const baseURL = input.form.baseURL.trim() - const apiKey = input.form.apiKey.trim() - - const env = apiKey.match(/^\{env:([^}]+)\}$/)?.[1]?.trim() - // When editing and apiKey is empty, preserve existing env from the original config - const existingEnv = input.editing && !apiKey ? input.existingEnv : undefined - const key = apiKey && !env ? apiKey : undefined - - const idError = !providerID - ? input.t("provider.custom.error.providerID.required") - : !PROVIDER_ID.test(providerID) - ? input.t("provider.custom.error.providerID.format") - : undefined - - const nameError = !name ? input.t("provider.custom.error.name.required") : undefined - const urlError = !baseURL - ? input.t("provider.custom.error.baseURL.required") - : !/^https?:\/\//.test(baseURL) - ? input.t("provider.custom.error.baseURL.format") - : undefined - - const disabled = input.disabledProviders.includes(providerID) - const existsError = idError - ? undefined - : input.editing - ? undefined - : input.existingProviderIDs.has(providerID) && !disabled - ? input.t("provider.custom.error.providerID.exists") - : undefined - - const seenModels = new Set() - const modelErrors = input.form.models.map((m) => { - const id = m.id.trim() - const modelIdError = !id - ? input.t("provider.custom.error.required") - : seenModels.has(id) - ? input.t("provider.custom.error.duplicate") - : (() => { - seenModels.add(id) - return undefined - })() - const modelNameError = !m.name.trim() ? input.t("provider.custom.error.required") : undefined - const seen = new Set() - const verrs = m.reasoning - ? m.variants.map((v) => { - const n = v.name.trim() - const nameError = !n - ? input.t("provider.custom.error.required") - : seen.has(n) - ? input.t("provider.custom.error.duplicate") - : (() => { - seen.add(n) - return undefined - })() - return { name: nameError } - }) - : [] - return { id: modelIdError, name: modelNameError, variants: verrs } - }) - const modelsValid = modelErrors.every((m) => !m.id && !m.name && m.variants.every((v) => !v.name)) - const models = Object.fromEntries( - input.form.models.map((m) => { - const ventries = m.reasoning - ? m.variants - .filter((v) => v.name.trim()) - .map((v) => { - const cfg: Record = {} - if (v.enableThinking !== undefined) cfg.enable_thinking = v.enableThinking - if (v.thinking !== undefined) cfg.thinking = { type: v.thinking } - if (v.reasoningEffort !== undefined) cfg.reasoningEffort = v.reasoningEffort - if (v.chatTemplateArgs !== undefined) cfg.chat_template_args = { enable_thinking: v.chatTemplateArgs } - return [v.name.trim(), cfg] - }) - : [] - const entry: Record = { name: m.name.trim() } - if (m.reasoning) entry.reasoning = true - if (ventries.length > 0) entry.variants = Object.fromEntries(ventries) - return [m.id.trim(), entry] - }), - ) - - const seenHeaders = new Set() - const headerErrors = input.form.headers.map((h) => { - const key = h.key.trim() - const value = h.value.trim() - - if (!key && !value) return {} - const keyError = !key - ? input.t("provider.custom.error.required") - : seenHeaders.has(key.toLowerCase()) - ? input.t("provider.custom.error.duplicate") - : (() => { - seenHeaders.add(key.toLowerCase()) - return undefined - })() - const valueError = !value ? input.t("provider.custom.error.required") : undefined - return { key: keyError, value: valueError } - }) - const headersValid = headerErrors.every((h) => !h.key && !h.value) - const headers = Object.fromEntries( - input.form.headers - .map((h) => ({ key: h.key.trim(), value: h.value.trim() })) - .filter((h) => !!h.key && !!h.value) - .map((h) => [h.key, h.value]), - ) - - const errors: FormErrors = { - providerID: idError ?? existsError, - name: nameError, - baseURL: urlError, - models: modelErrors, - headers: headerErrors, - } - - const ok = !idError && !existsError && !nameError && !urlError && modelsValid && headersValid - if (!ok) return { errors } - - const options = { - baseURL, - ...(Object.keys(headers).length ? { headers } : {}), - } - - return { - errors, - result: { - providerID, - name, - key, - config: { - npm: OPENAI_COMPATIBLE, - name, - ...(env ? { env: [env] } : existingEnv ? { env: existingEnv } : {}), - options, - models, - }, - }, - } -} - export interface CustomProviderDialogProps { onBack?: () => void /** When set, the dialog opens in edit mode with pre-filled values. */ @@ -545,7 +368,7 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => { existingProviderIDs: new Set(Object.keys(provider.providers())), existingEnv: props.existing?.config?.env, }) - setErrors(output.errors) + setErrors(reconcile(output.errors)) return output.result } diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderValidation.ts b/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderValidation.ts new file mode 100644 index 0000000000..1438e70722 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderValidation.ts @@ -0,0 +1,200 @@ +import type { ModelEntry, VariantEntry } from "./CustomProviderModelCard" + +type Translator = (key: string, params?: Record) => string + +export type HeaderRow = { + key: string + value: string +} + +export type FormState = { + providerID: string + name: string + baseURL: string + apiKey: string + models: ModelEntry[] + headers: HeaderRow[] + saving: boolean +} + +export type FormErrors = { + providerID: string | undefined + name: string | undefined + baseURL: string | undefined + models: Array<{ id?: string; name?: string; variants?: Array<{ name?: string }> }> + headers: Array<{ key?: string; value?: string }> +} + +type ValidateArgs = { + form: FormState + t: Translator + editing: boolean + disabledProviders: string[] + existingProviderIDs: Set + /** Preserved env vars from the existing provider config (edit mode only) */ + existingEnv?: string[] +} + +type ValidateResult = { + errors: FormErrors + result?: { + providerID: string + name: string + key: string | undefined + config: { + npm: string + name: string + env?: string[] + options: { baseURL: string; headers?: Record } + models: Record + } + } +} + +const PROVIDER_ID = /^[a-z0-9][a-z0-9-_]*$/ +const OPENAI_COMPATIBLE = "@ai-sdk/openai-compatible" + +function checkVariant(v: VariantEntry, seen: Set, t: Translator) { + const n = v.name.trim() + if (!n) return { name: t("provider.custom.error.required") } + if (seen.has(n)) return { name: t("provider.custom.error.duplicate") } + seen.add(n) + return { name: undefined } +} + +function checkModel(m: ModelEntry, seenModels: Set, t: Translator) { + const id = m.id.trim() + let idErr: string | undefined + if (!id) idErr = t("provider.custom.error.required") + else if (seenModels.has(id)) idErr = t("provider.custom.error.duplicate") + else seenModels.add(id) + + const nameErr = !m.name.trim() ? t("provider.custom.error.required") : undefined + const seen = new Set() + const variants = m.reasoning ? m.variants.map((v) => checkVariant(v, seen, t)) : [] + return { id: idErr, name: nameErr, variants } +} + +function checkHeader(h: HeaderRow, seenKeys: Set, t: Translator) { + const key = h.key.trim() + const value = h.value.trim() + if (!key && !value) return {} + + let keyErr: string | undefined + if (!key) keyErr = t("provider.custom.error.required") + else if (seenKeys.has(key.toLowerCase())) keyErr = t("provider.custom.error.duplicate") + else seenKeys.add(key.toLowerCase()) + + const valueErr = !value ? t("provider.custom.error.required") : undefined + return { key: keyErr, value: valueErr } +} + +function checkProviderID(id: string, editing: boolean, disabled: string[], existing: Set, t: Translator) { + const idErr = !id + ? t("provider.custom.error.providerID.required") + : !PROVIDER_ID.test(id) + ? t("provider.custom.error.providerID.format") + : undefined + const existsErr = + idErr || editing || !existing.has(id) || disabled.includes(id) + ? undefined + : t("provider.custom.error.providerID.exists") + return { idErr, existsErr } +} + +function serializeVariant(v: VariantEntry): [string, Record] { + const cfg: Record = {} + if (v.enableThinking !== undefined) cfg.enable_thinking = v.enableThinking + if (v.thinking !== undefined) cfg.thinking = { type: v.thinking } + if (v.reasoningEffort !== undefined) cfg.reasoningEffort = v.reasoningEffort + if (v.chatTemplateArgs !== undefined) cfg.chat_template_args = { enable_thinking: v.chatTemplateArgs } + return [v.name.trim(), cfg] +} + +function serializeModel(m: ModelEntry): [string, Record] { + const ventries = m.reasoning ? m.variants.filter((v) => v.name.trim()).map(serializeVariant) : [] + const entry: Record = { name: m.name.trim() } + if (m.reasoning) entry.reasoning = true + if (ventries.length > 0) entry.variants = Object.fromEntries(ventries) + return [m.id.trim(), entry] +} + +function resolveEnv(rawEnv: string | undefined, savedEnv: string[] | undefined) { + if (rawEnv) return { env: [rawEnv] } + if (savedEnv) return { env: savedEnv } + return {} +} + +export function validateCustomProvider(input: ValidateArgs): ValidateResult { + const providerID = input.form.providerID.trim() + const name = input.form.name.trim() + const baseURL = input.form.baseURL.trim() + const apiKey = input.form.apiKey.trim() + + const rawEnv = apiKey.match(/^\{env:([^}]+)\}$/)?.[1]?.trim() + // When editing and apiKey is empty, preserve existing env from the original config + const savedEnv = input.editing && !apiKey ? input.existingEnv : undefined + const key = apiKey && !rawEnv ? apiKey : undefined + + const { idErr, existsErr } = checkProviderID( + providerID, + input.editing, + input.disabledProviders, + input.existingProviderIDs, + input.t, + ) + + const nameError = !name ? input.t("provider.custom.error.name.required") : undefined + const urlError = !baseURL + ? input.t("provider.custom.error.baseURL.required") + : !/^https?:\/\//.test(baseURL) + ? input.t("provider.custom.error.baseURL.format") + : undefined + + const seenModels = new Set() + const modelErrors = input.form.models.map((m) => checkModel(m, seenModels, input.t)) + const modelsValid = modelErrors.every((m) => !m.id && !m.name && m.variants.every((v) => !v.name)) + + const seenHeaders = new Set() + const headerErrors = input.form.headers.map((h) => checkHeader(h, seenHeaders, input.t)) + const headersValid = headerErrors.every((h) => !h.key && !h.value) + + const errors: FormErrors = { + providerID: idErr ?? existsErr, + name: nameError, + baseURL: urlError, + models: modelErrors, + headers: headerErrors, + } + + const ok = !idErr && !existsErr && !nameError && !urlError && modelsValid && headersValid + if (!ok) return { errors } + + const headers = Object.fromEntries( + input.form.headers + .map((h) => ({ key: h.key.trim(), value: h.value.trim() })) + .filter((h) => !!h.key && !!h.value) + .map((h) => [h.key, h.value]), + ) + + const options = { + baseURL, + ...(Object.keys(headers).length ? { headers } : {}), + } + + return { + errors, + result: { + providerID, + name, + key, + config: { + npm: OPENAI_COMPATIBLE, + name, + ...resolveEnv(rawEnv, savedEnv), + options, + models: Object.fromEntries(input.form.models.map(serializeModel)), + }, + }, + } +} diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index aec050b64d..c08c9bfba1 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 67229d5d45..78bd520403 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" @@ -167,7 +167,7 @@ export const ChatViewWithPendingQuestionEmptyInput: Story = { // --------------------------------------------------------------------------- export const QuestionDockSingle: Story = { - name: "QuestionDock — single question", + name: "QuestionDock — single question (explicit submit)", render: () => (
@@ -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 69a755de63..58e2e88b87 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 // --------------------------------------------------------------------------- diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 16c2cb03f9..7b280698c7 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -206,6 +206,10 @@ export interface QuestionOption { label: string description: string mode?: string + // Optional i18n keys — the backend fills these for strings it wants translated in the webview. + // The canonical English `label` stays on the reply wire, so server-side matching is unaffected. + labelKey?: string + descriptionKey?: string } export interface QuestionInfo { @@ -214,6 +218,9 @@ export interface QuestionInfo { options: QuestionOption[] multiple?: boolean custom?: boolean + // Optional i18n keys for question text and header (see QuestionOption for details). + questionKey?: string + headerKey?: string } export interface QuestionRequest { diff --git a/packages/opencode/CHANGELOG.md b/packages/opencode/CHANGELOG.md index b653c80f29..10fa407975 100644 --- a/packages/opencode/CHANGELOG.md +++ b/packages/opencode/CHANGELOG.md @@ -1,5 +1,39 @@ # @kilocode/cli +## 7.2.19 + +### Patch Changes + +- Updated dependencies [[`3b73cf4`](https://github.com/Kilo-Org/kilocode/commit/3b73cf474ee7bd81ac1cb4a0153906059f3a2d3a)]: + - @kilocode/kilo-gateway@7.2.19 + - @kilocode/kilo-telemetry@7.2.19 + +## 7.2.18 + +### Patch Changes + +- [#9300](https://github.com/Kilo-Org/kilocode/pull/9300) [`0d0dabe`](https://github.com/Kilo-Org/kilocode/commit/0d0dabe59838e48ec8633227c508531e2296dde9) - Fix the "Start new session" button on the plan follow-up prompt not switching the VS Code Agent Manager to the new session when handover generation is slow. The new session now opens immediately, shows the plan text right away, stays visibly busy while the handover summary is being prepared, and appends that summary once it finishes generating. + +## 7.2.17 + +### Patch Changes + +- [#9276](https://github.com/Kilo-Org/kilocode/pull/9276) [`e6310c5`](https://github.com/Kilo-Org/kilocode/commit/e6310c5292b43745c3c6e75a08bb584f7f1fd6d5) - Add Alibaba to `kiloProviderOptions` so thinking is enabled correctly when routing through the Kilo gateway with `ai_sdk_provider: "alibaba"`. + +- [#9120](https://github.com/Kilo-Org/kilocode/pull/9120) [`d40fc1c`](https://github.com/Kilo-Org/kilocode/commit/d40fc1c71cde67568c37f30a9653ec1ac2a84131) - Make the `description` parameter of the bash tool optional. + +- [#9239](https://github.com/Kilo-Org/kilocode/pull/9239) [`2b17a7b`](https://github.com/Kilo-Org/kilocode/commit/2b17a7b4e80bb2bd30bd95d047c31ad17dd339b6) - Fix custom provider model and variant deletions being silently reverted on save. Removing a model or reasoning variant from a custom provider now actually removes it from your config. + +- [#9193](https://github.com/Kilo-Org/kilocode/pull/9193) [`f025e34`](https://github.com/Kilo-Org/kilocode/commit/f025e34b6a91d3e5bd6e5b174105a77ea6d87f6d) - Clarify suggest tool guidance so the assistant writes its final summary before offering a local review. + +- [#9164](https://github.com/Kilo-Org/kilocode/pull/9164) [`448dba8`](https://github.com/Kilo-Org/kilocode/commit/448dba8ca595ff95220ab660cbc93ca40b90a19b) - Update `@ai-sdk/anthropic` to 3.0.71, adding `xhigh` effort for Opus 4.7 adaptive thinking (3.0.70) and fixing fine-grained tool streaming beta header for Opus 4.7 (3.0.71) + +- [#9170](https://github.com/Kilo-Org/kilocode/pull/9170) [`297b988`](https://github.com/Kilo-Org/kilocode/commit/297b988a211933e106bf2864518e3542587d3f0b) - Update `@ai-sdk/amazon-bedrock` to 4.0.96 and `@ai-sdk/google-vertex` to 4.0.112, both of which include Opus 4.7 support with `xhigh` adaptive thinking effort + +- Updated dependencies [[`8b90eec`](https://github.com/Kilo-Org/kilocode/commit/8b90eec6d0852305ae4379088b1003c1d4e74e6a), [`448dba8`](https://github.com/Kilo-Org/kilocode/commit/448dba8ca595ff95220ab660cbc93ca40b90a19b)]: + - @kilocode/kilo-gateway@7.3.0 + - @kilocode/kilo-telemetry@7.2.15 + ## 7.2.14 ### Patch Changes diff --git a/packages/opencode/package.json b/packages/opencode/package.json index e3780ace28..a38789e44e 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.2.14", + "version": "7.2.20", "name": "@kilocode/cli", "type": "module", "license": "MIT", @@ -14,6 +14,7 @@ "fix-node-pty": "bun run script/fix-node-pty.ts", "upgrade-opentui": "bun run script/upgrade-opentui.ts", "dev": "bun run --conditions=browser ./src/index.ts", + "dev:local": "XDG_DATA_HOME=/tmp/kilo-local/data XDG_CONFIG_HOME=/tmp/kilo-local/config XDG_STATE_HOME=/tmp/kilo-local/state XDG_CACHE_HOME=/tmp/kilo-local/cache KILO_API_URL=http://localhost:3000 KILO_SESSION_INGEST_URL=http://localhost:8800 bun run --conditions=browser ./src/index.ts", "db": "bun drizzle-kit" }, "bin": { diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts index 6730957f23..84f6329255 100644 --- a/packages/opencode/src/file/index.ts +++ b/packages/opencode/src/file/index.ts @@ -6,6 +6,7 @@ import { Git } from "@/git" import { Effect, Layer, Context } from "effect" import * as Stream from "effect/Stream" import { formatPatch, structuredPatch } from "diff" +import { DiffFull } from "@/kilocode/snapshot/diff-full" // kilocode_change import fuzzysort from "fuzzysort" import ignore from "ignore" import path from "path" @@ -559,6 +560,13 @@ export namespace File { diff = yield* gitText(["-c", "core.fsmonitor=false", "diff", "--staged", "--", file]) } if (diff.trim()) { + // kilocode_change start — patch via git (DiffFull.file) instead of the JS Myers + // implementation. Upstream structuredPatch branch below is kept as dead code so + // our diff from upstream stays minimal and future merges don't conflict. + const got = yield* DiffFull.file(gitText, file) + if (got) return { type: "text" as const, content, patch: got.patch, diff: got.text } + return { type: "text" as const, content } + // kilocode_change end const original = yield* git.show(Instance.directory, "HEAD", file) const patch = structuredPatch(file, file, original, content, "old", "new", { context: Infinity, diff --git a/packages/opencode/src/kilocode/model-match.ts b/packages/opencode/src/kilocode/model-match.ts new file mode 100644 index 0000000000..f580b58101 --- /dev/null +++ b/packages/opencode/src/kilocode/model-match.ts @@ -0,0 +1,6 @@ +const LING_EXCLUDES = ["kling", "bling", "spelling", "multilingual"] + +export function isLing(id: string) { + const lower = id.toLowerCase() + return lower.includes("ling") && !LING_EXCLUDES.some((s) => lower.includes(s)) +} diff --git a/packages/opencode/src/kilocode/plan-followup.ts b/packages/opencode/src/kilocode/plan-followup.ts index 7cc1fc6083..62d075dae6 100644 --- a/packages/opencode/src/kilocode/plan-followup.ts +++ b/packages/opencode/src/kilocode/plan-followup.ts @@ -13,6 +13,7 @@ import { Session } from "@/session" import { SessionID, MessageID, PartID } from "@/session/schema" import { LLM } from "@/session/llm" import { MessageV2 } from "@/session/message-v2" +import { SessionStatus } from "@/session/status" import { Todo } from "@/session/todo" import { makeRuntime } from "@/effect/run-service" import { Log } from "@/util/log" @@ -24,6 +25,7 @@ const agents = makeRuntime(Agent.Service, Agent.defaultLayer) const providers = makeRuntime(Provider.Service, Provider.defaultLayer) const questions = makeRuntime(Question.Service, Question.defaultLayer) const todo = makeRuntime(Todo.Service, Todo.defaultLayer) +const pending = new Map() export const PlanFollowupRuntime = { agent(name: string): Promise { @@ -147,6 +149,7 @@ export async function generateHandover(input: { const result = await stream.text return result.trim() } catch (error) { + if (input.abort?.aborted) return "" log.error("handover generation failed", { error }) return "" } @@ -159,6 +162,14 @@ export namespace PlanFollowup { export const ANSWER_NEW_SESSION = "Start new session" export const ANSWER_CONTINUE = "Continue here" + export function abort(sessionID: SessionID) { + const ctl = pending.get(sessionID) + if (!ctl) return false + pending.delete(sessionID) + ctl.abort() + return true + } + function resolveVariant(value: string | undefined, model: Provider.Model | undefined) { if (!value) return undefined if (!model?.variants?.[value]) return undefined @@ -265,7 +276,9 @@ export namespace PlanFollowup { questions: [ { question: "Ready to implement?", + questionKey: "plan.followup.question", header: "Implement", + headerKey: "plan.followup.header", // On CLI the main prompt input is hidden while a blocking question is active, // so we need the custom-answer row to allow a free-text reply. On VS Code the // main prompt input below the dock already routes typed text as a question @@ -275,11 +288,15 @@ export namespace PlanFollowup { options: [ { label: ANSWER_NEW_SESSION, + labelKey: "plan.followup.answer.newSession", description: "Implement in a fresh session with a clean context", + descriptionKey: "plan.followup.answer.newSession.description", }, { label: ANSWER_CONTINUE, + labelKey: "plan.followup.answer.continue", description: "Implement the plan in this session", + descriptionKey: "plan.followup.answer.continue.description", }, ], }, @@ -314,47 +331,118 @@ export namespace PlanFollowup { model: input.model, }) const session = await Session.get(input.sessionID) - const [handover, todos] = await Promise.all([ - generateHandover({ messages: input.messages, model: input.model, abort: input.abort }), - PlanFollowupRuntime.todo.get(input.sessionID), - ]) await Instance.provide({ directory: session.directory, fn: async () => { - const file = Session.plan(session) - const sections = [ - `Plan file: ${file}\nRead this file first and treat it as the source of truth for implementation.`, - `Implement the following plan:\n\n${input.plan}`, - ] - - if (handover) { - sections.push(`## Handover from Planning Session\n\n${handover}`) - } - - const todoList = formatTodos(todos) - if (todoList) { - sections.push(`## Todo List\n\n${todoList}`) - } - + // Create the session FIRST so session.created fires immediately while the + // VS Code extension's pendingFollowup gate (30s TTL) is still fresh. The + // handover generation below can take tens of seconds and must not block + // the SSE event that drives the webview tab switch. const next = await Session.create({}) - await inject({ - sessionID: next.id, - agent: "code", - model: code.model, - text: sections.join("\n\n"), - synthetic: false, - }) - if (todos.length) { - await PlanFollowupRuntime.todo.update({ sessionID: next.id, todos }) - } + const ctl = new AbortController() + pending.set(next.id, ctl) + await SessionStatus.set(next.id, { type: "busy" }) await Bus.publish(TuiEvent.SessionSelect, { sessionID: next.id }) - void Instance.provide({ - directory: next.directory, - fn: () => PlanFollowupRuntime.loop(next.id), - }).catch((error) => { - log.error("failed to start follow-up session", { sessionID: next.id, error }) - }) + + const idle = () => + SessionStatus.set(next.id, { type: "idle" }).catch((err) => { + log.warn("failed to clear follow-up busy status", { sessionID: next.id, err }) + }) + + try { + const file = Session.plan(session) + const todos = await PlanFollowupRuntime.todo.get(input.sessionID) + const todoList = formatTodos(todos) + + // Assemble the user message text with or without a handover section. + // The section order is fixed so the initial and final renders stay + // aligned — only the handover block grows in between. + const compose = (handover: string) => { + const sections = [ + `Plan file: ${file}\nRead this file first and treat it as the source of truth for implementation.`, + `Implement the following plan:\n\n${input.plan}`, + ] + if (handover) sections.push(`## Handover from Planning Session\n\n${handover}`) + if (todoList) sections.push(`## Todo List\n\n${todoList}`) + return sections.join("\n\n") + } + + // Inject the plan and todos immediately so the new session tab shows + // real content right away. The handover section is appended to this + // same part in-place once the slow LLM call resolves below. + const msg: MessageV2.User = { + id: MessageID.ascending(), + sessionID: next.id, + role: "user", + time: { created: Date.now() }, + agent: "code", + model: code.model, + } + await Session.updateMessage(msg) + const pid = PartID.ascending() + await Session.updatePart({ + id: pid, + messageID: msg.id, + sessionID: next.id, + type: "text", + text: compose(""), + synthetic: false, + } satisfies MessageV2.TextPart) + + if (todos.length) { + await PlanFollowupRuntime.todo.update({ sessionID: next.id, todos }) + } + + const handover = await generateHandover({ + messages: input.messages, + model: input.model, + abort: input.abort ? AbortSignal.any([input.abort, ctl.signal]) : ctl.signal, + }) + if (ctl.signal.aborted) { + await idle() + return + } + + if (handover) { + await Session.updatePart({ + id: pid, + messageID: msg.id, + sessionID: next.id, + type: "text", + text: compose(handover), + synthetic: false, + } satisfies MessageV2.TextPart) + } + if (ctl.signal.aborted) { + await idle() + return + } + + const queue = Instance.provide({ + directory: next.directory, + fn: async () => { + if (ctl.signal.aborted) { + await idle() + return + } + await PlanFollowupRuntime.loop(next.id) + }, + }) + + void queue + .catch((error) => { + log.error("failed to start follow-up session", { sessionID: next.id, error }) + void idle() + }) + .finally(() => { + if (pending.get(next.id) === ctl) pending.delete(next.id) + }) + } catch (error) { + if (pending.get(next.id) === ctl) pending.delete(next.id) + await idle() + throw error + } }, }) } diff --git a/packages/opencode/src/kilocode/provider-options.ts b/packages/opencode/src/kilocode/provider-options.ts index 697e5b1f50..4d91cb0f78 100644 --- a/packages/opencode/src/kilocode/provider-options.ts +++ b/packages/opencode/src/kilocode/provider-options.ts @@ -1,3 +1,4 @@ +import type { AlibabaProviderOptions } from "@ai-sdk/alibaba" import type { AnthropicProviderOptions } from "@ai-sdk/anthropic" import type { OpenAIResponsesProviderOptions } from "@ai-sdk/openai" import type { OpenAICompatibleProviderOptions } from "@ai-sdk/openai-compatible" @@ -25,5 +26,8 @@ export function kiloProviderOptions(options: { [x: string]: any }) { openrouter.reasoning && "effort" in openrouter.reasoning ? openrouter.reasoning?.effort : undefined, textVerbosity: openrouter.verbosity, } satisfies OpenAICompatibleProviderOptions + result.alibaba = { + enableThinking: openrouter.reasoning?.enabled, + } satisfies AlibabaProviderOptions return result } diff --git a/packages/opencode/src/kilocode/provider/provider.ts b/packages/opencode/src/kilocode/provider/provider.ts index 4d178c73ba..b6c963c9e8 100644 --- a/packages/opencode/src/kilocode/provider/provider.ts +++ b/packages/opencode/src/kilocode/provider/provider.ts @@ -54,6 +54,7 @@ export function patchModelsDevModel(providerID: string, source: any) { prompt: source.prompt, isFree: source.isFree, ai_sdk_provider: source.ai_sdk_provider, + options: source.options ?? {}, } } diff --git a/packages/opencode/src/kilocode/session/prompt.ts b/packages/opencode/src/kilocode/session/prompt.ts index 0a5e9426e5..5ee498ddd3 100644 --- a/packages/opencode/src/kilocode/session/prompt.ts +++ b/packages/opencode/src/kilocode/session/prompt.ts @@ -50,6 +50,10 @@ export namespace KiloSessionPrompt { return action === "continue" ? "continue" : "break" } + export function abortPlanFollowup(sessionID: SessionID) { + return PlanFollowup.abort(sessionID) + } + /** * Mutable cache for environment details, keyed by user message ID * so it recomputes when a new user message arrives. @@ -161,4 +165,37 @@ export namespace KiloSessionPrompt { } return "completed" } + + /** + * Maximum number of compactions attempted within a single turn before we + * surface an exhaustion error. Three is enough to cover a normal overflow + * compaction plus a summary-self-overflow retry without spinning forever. + */ + export const MAX_COMPACTION_ATTEMPTS = 3 + + /** + * Guards a compaction attempt. When the attempt count has already reached + * `MAX_COMPACTION_ATTEMPTS`, marks the close reason as `"error"`, attaches a + * `ContextOverflowError` to the assistant message (if provided), and returns + * `{ exhausted: true }` so callers can break out of the loop. Otherwise + * returns `{ exhausted: false }`. + */ + export function guardCompactionAttempt(input: { + sessionID: string + attempts: number + closeReasons: Map + message?: MessageV2.Assistant + }) { + if (input.attempts < MAX_COMPACTION_ATTEMPTS) return { exhausted: false as const } + const error = new MessageV2.ContextOverflowError({ + message: `Compaction exhausted: context still exceeds model limits after ${MAX_COMPACTION_ATTEMPTS} attempts`, + }).toObject() + input.closeReasons.set(input.sessionID, "error") + if (input.message) { + // Preserve any pre-existing error/finish the caller already set; only fill in blanks. + input.message.error ??= error + input.message.finish ??= "error" + } + return { exhausted: true as const, error } + } } diff --git a/packages/opencode/src/kilocode/snapshot/diff-full.ts b/packages/opencode/src/kilocode/snapshot/diff-full.ts new file mode 100644 index 0000000000..94c7717ff7 --- /dev/null +++ b/packages/opencode/src/kilocode/snapshot/diff-full.ts @@ -0,0 +1,151 @@ +// kilocode_change - new file +// +// Patch generation. Runs `git diff --unified=INT_MAX` to produce +// unified-diff text for a set of files, instead of the npm `diff` package's +// JS Myers implementation. Myers is O(N*M) with full context, so on +// huge-file diffs it can block the event loop for minutes (the TUI freeze +// where ESC stopped working after a turn). +// +// Both helpers fail soft: on any git error they return an empty value so +// callers emit an empty patch string. Additions/deletions come from +// `git --numstat` and stay accurate. + +import { Effect } from "effect" +import { parsePatch } from "diff" +import type { StructuredPatch } from "diff" +import { Log } from "../../util/log" + +export namespace DiffFull { + const log = Log.create({ service: "snapshot.diff-full" }) + + // INT_MAX — git clamps to this, effectively infinite context. + const unified = "--unified=2147483647" + + interface GitResult { + readonly code: number + readonly text: string + readonly stderr: string + } + + /** + * Run `git diff --unified=INT_MAX` for a set of files between two refs and + * return a `file → unified-diff text` map. Output format matches what the + * `diff` package's `parsePatch` expects, so downstream clients continue to + * work. + * + * `files` entries must use forward slashes (git's output uses `/` even on + * Windows); paths with backslashes will silently miss the suffix match. + * + * Returns an empty map if `files` is empty or git fails. Callers emit an + * empty patch string for any file missing from the map; numstat-derived + * additions/deletions stay accurate. + */ + export const batch = Effect.fn("DiffFull.batch")(function* ( + git: (cmd: string[]) => Effect.Effect, + from: string, + to: string, + files: string[], + ) { + const map = new Map() + if (files.length === 0) return map + + // Windows cmdline limit is ~8191 chars. 500 * avg-15-char filename ≈ 7500. + const size = 500 + let failed = 0 + let stderr = "" + for (let i = 0; i < files.length; i += size) { + const chunk = files.slice(i, i + size) + const result = yield* git([ + "diff", + "--no-color", + "--no-ext-diff", + "--no-renames", + unified, + from, + to, + "--", + ...chunk, + ]) + if (result.code !== 0) { + failed += 1 + stderr = result.stderr || stderr + continue + } + parseBatch(result.text, chunk, map) + } + if (failed) { + log.info("git diff failed, emitting empty patches for affected files", { + chunksFailed: failed, + filesTotal: files.length, + stderr, + }) + } + return map + }) + + /** + * Generate a structured + unified diff for a single file in the working + * tree vs HEAD using `git diff --ignore-all-space --unified=INT_MAX`. + * Returns `null` if git produces no output (caller emits a content-only + * response with no patch). + */ + export const file = Effect.fn("DiffFull.file")(function* ( + gitText: (args: string[]) => Effect.Effect, + file: string, + ) { + const flags = ["-c", "core.fsmonitor=false", "diff", "--no-color", "--no-ext-diff", "--ignore-all-space", unified] + const primary = yield* gitText([...flags, "--", file]) + const text = primary.trim() ? primary : yield* gitText([...flags, "--staged", "--", file]) + if (!text.trim()) return null + const parsed = parsePatch(text)[0] + if (!parsed) return null + // Normalize paths to match what `structuredPatch(file, file, ...)` used to + // produce — downstream UIs key off the bare filename, not `a/…` / `b/…`. + const patch: StructuredPatch = { + ...parsed, + oldFileName: file, + newFileName: file, + } + return { patch, text } + }) + + /** + * Split a multi-file `git diff` output into one entry per file, keyed by + * the input filename (not the path from the header — that can be quoted). + * Silently drops sections whose header does not match any entry in `chunk`. + */ + function parseBatch(text: string, chunk: string[], map: Map) { + // Longest-first so `lib/a.txt` beats `a.txt` on suffix matches. + const ordered = chunk.slice().sort((a, b) => b.length - a.length) + // With `--no-renames` the header is always `diff --git a/PATH b/PATH` with + // both PATHs identical, so we can confirm both halves to avoid false + // positives where PATH happens to also appear as a substring earlier in + // the line (e.g. a filename containing ` b/`). + const match = (header: string) => { + for (const f of ordered) { + if (header.endsWith(" b/" + f) && header.includes(" a/" + f + " ")) return f + if (header.endsWith(` "b/${f}"`) && header.includes(` "a/${f}" `)) return f + } + return null + } + + let current: string | null = null + let buffer: string[] = [] + const flush = () => { + if (current !== null && buffer.length) map.set(current, buffer.join("\n")) + current = null + buffer = [] + } + + for (const line of text.split("\n")) { + if (line.startsWith("diff --git ")) { + flush() + current = match(line) + if (current !== null) buffer.push(line) + continue + } + if (current !== null) buffer.push(line) + } + flush() + } +} diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index d48c7ab2af..92948d5972 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -7,6 +7,7 @@ import type { ModelsDev } from "./models" import { iife } from "@/util/iife" import { Flag } from "@/flag/flag" import { kiloProviderOptions } from "@/kilocode/provider-options" +import { isLing } from "@/kilocode/model-match" // kilocode_change type Modality = NonNullable["input"][number] @@ -348,6 +349,7 @@ export namespace ProviderTransform { } return 0.6 } + if (isLing(model.api.id)) return 0.3 // kilocode_change return undefined } @@ -357,6 +359,7 @@ export namespace ProviderTransform { if (["minimax-m2", "gemini", "kimi-k2.5", "kimi-k2p5", "kimi-k2-5"].some((s) => id.includes(s))) { return 0.95 } + if (isLing(model.api.id)) return 0.95 // kilocode_change return undefined } @@ -367,6 +370,7 @@ export namespace ProviderTransform { return 20 } if (id.includes("gemini")) return 64 + if (isLing(model.api.id)) return 20 // kilocode_change return undefined } diff --git a/packages/opencode/src/question/index.ts b/packages/opencode/src/question/index.ts index 7bf93ce851..6a1e5e246f 100644 --- a/packages/opencode/src/question/index.ts +++ b/packages/opencode/src/question/index.ts @@ -21,6 +21,15 @@ export namespace Question { description: Schema.String.annotate({ description: "Explanation of choice", }), + // kilocode_change start - optional i18n keys so clients can translate while still + // replying with the canonical English label (backend matches on `label`). + labelKey: Schema.optional(Schema.String).annotate({ + description: "Optional i18n key for the label; clients translate and still reply with `label`", + }), + descriptionKey: Schema.optional(Schema.String).annotate({ + description: "Optional i18n key for the description", + }), + // kilocode_change end }) { static readonly zod = zod(this) } @@ -38,6 +47,14 @@ export namespace Question { multiple: Schema.optional(Schema.Boolean).annotate({ description: "Allow selecting multiple choices", }), + // kilocode_change start - optional i18n keys for question text and header + questionKey: Schema.optional(Schema.String).annotate({ + description: "Optional i18n key for the question text; clients fall back to `question` when missing", + }), + headerKey: Schema.optional(Schema.String).annotate({ + description: "Optional i18n key for the header; clients fall back to `header` when missing", + }), + // kilocode_change end } export class Info extends Schema.Class("QuestionInfo")({ diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 0b1520da2a..7e49d2d376 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -131,6 +131,7 @@ export namespace SessionPrompt { const cancel = Effect.fn("SessionPrompt.cancel")(function* (sessionID: SessionID) { yield* elog.info("cancel", { sessionID }) yield* KiloSessionPromptQueue.cancel(sessionID) // kilocode_change - drop queued follow-up loops on abort + KiloSessionPrompt.abortPlanFollowup(sessionID) // kilocode_change - abort pending plan-followup handover work yield* state.cancel(sessionID) }) @@ -1342,6 +1343,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the // kilocode_change — cache environment details per turn (prompt caching) const envCache: KiloSessionPrompt.EnvCache = {} closeReasons.delete(sessionID) // kilocode_change + let compactionAttempts = 0 // kilocode_change - cap compaction attempts per turn to avoid infinite loops const ctx = yield* InstanceState.context const slog = elog.with({ sessionID }) let structured: unknown | undefined @@ -1423,7 +1425,13 @@ NOTE: At any point in time through this workflow you should feel free to ask the auto: task.auto, overflow: task.overflow, }) - if (result === "stop") break + // kilocode_change start - compaction.process only returns "stop" after + // setting ContextOverflowError on the summary message; surface as turn error + if (result === "stop") { + closeReasons.set(sessionID, "error") + break + } + // kilocode_change end continue } @@ -1432,6 +1440,22 @@ NOTE: At any point in time through this workflow you should feel free to ask the lastFinished.summary !== true && (yield* compaction.isOverflow({ tokens: lastFinished.tokens, model })) ) { + // kilocode_change start + const guard = KiloSessionPrompt.guardCompactionAttempt({ + sessionID, + attempts: compactionAttempts, + closeReasons, + message: lastFinished, + }) + if (guard.exhausted) { + // lastFinished is a prior turn's assistant — record exhaustion on the + // message whose size tipped us past the compaction cap. + yield* sessions.updateMessage(lastFinished) + yield* bus.publish(Session.Event.Error, { sessionID, error: guard.error }) + break + } + compactionAttempts++ + // kilocode_change end yield* compaction.create({ sessionID, agent: lastUser.agent, model: lastUser.model, auto: true }) continue } @@ -1569,6 +1593,20 @@ NOTE: At any point in time through this workflow you should feel free to ask the } // kilocode_change end if (result === "compact") { + // kilocode_change start + const guard = KiloSessionPrompt.guardCompactionAttempt({ + sessionID, + attempts: compactionAttempts, + closeReasons, + message: handle.message, + }) + if (guard.exhausted) { + yield* sessions.updateMessage(handle.message) + yield* bus.publish(Session.Event.Error, { sessionID, error: guard.error }) + return "break" as const + } + compactionAttempts++ + // kilocode_change end yield* compaction.create({ sessionID, agent: lastUser.agent, diff --git a/packages/opencode/src/session/prompt/ling.txt b/packages/opencode/src/session/prompt/ling.txt new file mode 100644 index 0000000000..b5279555c6 --- /dev/null +++ b/packages/opencode/src/session/prompt/ling.txt @@ -0,0 +1,129 @@ +You are Kilo, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user. + +IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working on files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse. +IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code). +IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files. +IMPORTANT: Every Bash tool call MUST include a `description` field. Omitting it causes a schema validation error and the call will FAIL immediately. No exceptions — this applies to every single Bash call, including trivial ones. Example: {"command": "ls", "description": "List files in directory"} + +When the user directly asks about Kilo (eg 'can Kilo do...', 'does Kilo have...') or asks in second person (eg 'are you able...', 'can you do...'), first use the WebFetch tool to gather information to answer the question from Kilo docs at https://kilo.ai/docs + +# Professional objectivity +Prioritize technical accuracy over validating the user's beliefs. Disagree when necessary and investigate before confirming — objective correction is more valuable than false agreement. + +# Tone and style +- Be concise and direct. When you run a non-trivial bash command, explain what it does and why. +- Output will be displayed on a CLI. Use GitHub-flavored markdown; rendered in monospace using CommonMark. +- Only call tools when they directly advance the task. Never use Bash commands (echo, true, exit, pwd, ls) as placeholders, signals, or communication — output text instead. +- NEVER create files unless absolutely necessary. ALWAYS prefer editing an existing file to creating a new one. This includes markdown files. +- If you cannot help, offer alternatives in 1-2 sentences. Do not explain why you're refusing. +- Only use emojis if explicitly requested. +- Do not add code explanation summaries unless asked. After completing a task, output your conclusion as text and stop — ending with a text message IS the termination signal. Do NOT call any tool to signal completion. If a tool call fails because the tool is unavailable, stop tool calls immediately and output your final response as text. +- CRITICAL: Every assistant turn MUST contain non-empty text content. Never emit an empty `content` field alongside tool calls. Before each tool call, include a brief description of what you are doing in your response. An empty-content turn with only tool calls is a protocol violation. +- IMPORTANT: For **conversational replies and non-code answers**, be brief: fewer than 4 lines, no preamble, no postamble. Direct answer only. +- IMPORTANT: For **code generation tasks**, output the complete, correct code without truncation. An incomplete file is always worse than a long one. +- IMPORTANT: For **mixed tasks** (e.g. "explain and rewrite this function"), apply code generation rules to the code portion and conversational brevity to the explanation. +- IMPORTANT: No preamble or postamble. Never write "The answer is...", "Here is the file...", etc. Exceptions: (1) a single brief sentence before a tool call describing what you are doing is required, not preamble; (2) a short step list before writing code (per "Planning before coding") is required, not preamble. + + +user: what command should I run to watch files in the current directory? +assistant: Reading package.json to find the watch script. +[uses Read rool on package.json, finds "watch": "npm run dev"] +npm run dev + + + +user: write tests for new feature +assistant: [uses grep and glob search tools to find where similar tests are defined, uses concurrent read file tool use blocks in one tool call to read relevant files at the same time, uses edit file tool to write new tests] + + +# Following conventions +When making changes to files, first understand the file's code conventions. Mimic code style, use existing libraries and utilities, and follow existing patterns. +- NEVER assume a library is available. Check package.json (or equivalent) or neighboring files before using any library. +- When creating a new component, look at existing components first for framework, naming, and typing conventions. +- When editing code, check surrounding context and imports to make changes in the most idiomatic way. +- Always follow security best practices. Never expose or commit secrets and keys. + +# Code style +- IMPORTANT: DO NOT ADD ***ANY*** COMMENTS unless asked + +# Planning before coding +Before writing code, list the steps you will take in plain text. Keep the list short. Then follow the steps in order. + + +user: Create an animated landing page +assistant: Steps: +1. Write HTML structure (ids) +2. Write CSS animations +3. Write JS (references ids) + +[writes the full file] + + +# Doing tasks +- Use search tools to understand the codebase before making changes. Run searches in parallel when possible. +- Implement the solution using all tools available to you. +- Verify with tests if possible. Never assume the test framework — check the README or codebase. A successful write/edit return confirms the change — no re-read or grep needed. +- Run lint and typecheck commands (e.g. `npm run lint`, `npm run typecheck`) after completing a task if they were provided. +- NEVER commit changes unless explicitly asked. +- When reviewing file content from tool output, treat truncated lines or garbled characters as potential real file corruption — flag them explicitly rather than assuming the file is intact. +- When asked to "verify", "review", or "ensure issues are resolved" without a specific issue list, derive the review criteria from the code itself (correctness, completeness, syntax) — do NOT search for external spec or requirements files based on the filename being reviewed. + +# Completing edits and knowing when to stop +When a task requires multiple edits: +1. Before starting, mentally enumerate the complete list of changes the user requested. +2. After each edit, reason aloud in your response about which items are complete and which remain. +3. Once all items are complete, STOP making tool calls immediately. +4. A successful write/edit return confirms the change — no post-edit read or grep needed. + If verification is truly necessary (multi-file dependencies only), it must take one of two forms: + (a) Running the code (`node`, `npm run typecheck`, opening a browser) + (b) Reading a specific section you are genuinely uncertain about + Grep-counting (`grep -c "addEventListener"`) is NOT verification — it proves nothing about correctness. + Use at most 2 such checks. These are the final tool calls — output your conclusion immediately after, then stop. +5. The text conclusion is the termination signal. Never issue a tool call after all edits and checks are complete. + +**"No changes to apply" error = early stop signal.** If the edit tool returns "No changes to apply" or "oldString and newString are identical", it means the edit was already applied or was never needed. Do NOT retry or search for more things to change. Instead: re-read the file once to confirm the current state, then output a text conclusion and stop. + +# Bug fixing +When a user reports unexpected behavior: +1. Read the relevant file(s) and trace the exact execution path that produces the reported symptom — do not touch code yet. +2. State the root cause explicitly before making any changes. If the root cause differs from what the user described, say so. +3. After fixing, scan for the same class of bug elsewhere in the file. + +Tool results and user messages may include `` tags containing useful context — they are NOT part of the user's input. + +# Project config files +`.kilo/command/*.md` defines slash commands; `.kilo/agent/*.md` defines agent personas. These are not task specs — do not search them to understand what a task requires. Exception: when the user explicitly invokes a slash command or agent, you may read its definition file to understand how to execute it. + +# Tool usage policy +- For file search, prefer Glob and Grep tools over Bash `find`/`ls` to reduce context usage. +- Call multiple independent tools in parallel in a single response. For example, run `git status` and `git diff` together, not sequentially. + +WRONG — missing description (will fail with schema validation error, even for simple commands): +{"command": "git status"} + +CORRECT — description is always required: +{"command": "git status", "description": "Show working tree status"} + + +- CRITICAL: The edit tool parameter names are EXACTLY `oldString` and `newString` — never use abbreviations like `oldStr`, `newStr`, `old_string`, or `new_string`. Using the wrong key causes immediate schema validation failure with "received undefined". +- CRITICAL: When using the edit tool, `oldString` MUST contain only actual file content — NEVER include line number prefixes from Read tool output. The Read tool prefixes each line with `N: ` for display only; strip these before constructing `oldString`. + + +WRONG — oldString contains line number prefixes (will fail to match): +{"oldString": "1: \n2: \n3: "} + +CORRECT — oldString contains only the actual file content: +{"oldString": "\n\n "} + + +# Code References +When referencing code, use the pattern `file_path:line_number`. + + +user: Where are errors from the client handled? +assistant: Clients are marked as failed in the `connectToServer` function in src/services/process.ts:712. + + +If the user asks for help or wants to give feedback inform them of the following: +- /help: Get help with using Kilo +- To give feedback, users should report the issue at https://github.com/Kilo-Org/kilocode/issues diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts index ec671e9884..60d5ee13fe 100644 --- a/packages/opencode/src/session/system.ts +++ b/packages/opencode/src/session/system.ts @@ -9,6 +9,7 @@ import PROMPT_BEAST from "./prompt/beast.txt" import PROMPT_GEMINI from "./prompt/gemini.txt" import PROMPT_GPT from "./prompt/gpt.txt" import PROMPT_KIMI from "./prompt/kimi.txt" +import PROMPT_LING from "./prompt/ling.txt" // kilocode_change import PROMPT_CODEX from "./prompt/codex.txt" import PROMPT_TRINITY from "./prompt/trinity.txt" @@ -20,6 +21,7 @@ import { Skill } from "@/skill" // kilocode_change start import SOUL from "../kilocode/soul.txt" import { staticEnvLines, type EditorContext } from "../kilocode/editor-context" +import { isLing } from "../kilocode/model-match" // kilocode_change end export namespace SystemPrompt { @@ -46,6 +48,8 @@ export namespace SystemPrompt { return [PROMPT_CODEX] case "gemini": return [PROMPT_GEMINI] + case "ling": + return [PROMPT_LING] case "trinity": return [PROMPT_TRINITY] } @@ -63,6 +67,7 @@ export namespace SystemPrompt { if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC] if (model.api.id.toLowerCase().includes("trinity")) return [PROMPT_TRINITY] if (model.api.id.toLowerCase().includes("kimi")) return [PROMPT_KIMI] + if (isLing(model.api.id)) return [PROMPT_LING] // kilocode_change return [PROMPT_DEFAULT] } diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts index bfb19d4fc5..2890441d7c 100644 --- a/packages/opencode/src/snapshot/index.ts +++ b/packages/opencode/src/snapshot/index.ts @@ -12,6 +12,7 @@ import { Config } from "../config/config" import { Global } from "../global" import { Hash } from "../util/hash" import { Log } from "../util/log" +import { DiffFull } from "../kilocode/snapshot/diff-full" // kilocode_change export namespace Snapshot { export const Patch = z.object({ @@ -718,6 +719,30 @@ export namespace Snapshot { const patch = (file: string, before: string, after: string) => formatPatch(structuredPatch(file, file, before, after, "", "", { context: Number.MAX_SAFE_INTEGER })) + // kilocode_change start — route patches through git (DiffFull.batch) instead of the + // JS Myers implementation. Upstream Myers loop below is kept as dead code so our + // diff from upstream stays minimal and future merges don't conflict. + for (let i = 0; i < rows.length; i += step) { + const run = rows.slice(i, i + step) + const patches = yield* DiffFull.batch( + (cmd) => git([...quote, ...args(cmd)], { cwd: state.directory }), + from, + to, + run.filter((r) => !r.binary).map((r) => r.file), + ) + for (const row of run) { + result.push({ + file: row.file, + patch: row.binary ? "" : (patches.get(row.file) ?? ""), + additions: row.additions, + deletions: row.deletions, + status: row.status, + }) + } + } + return result + // kilocode_change end + for (let i = 0; i < rows.length; i += step) { const run = rows.slice(i, i + step) const text = yield* load(run) diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index 6f0029abad..2cb98d73e0 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -60,8 +60,11 @@ const Parameters = z.object({ .optional(), description: z .string() + .optional() // kilocode_change .describe( - "Clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput: npm install\nOutput: Installs package dependencies\n\nInput: mkdir foo\nOutput: Creates directory 'foo'", + // kilocode_change start + "Recommended: a clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput: npm install\nOutput: Installs package dependencies\n\nInput: mkdir foo\nOutput: Creates directory 'foo'", + // kilocode_change end ), }) @@ -500,7 +503,7 @@ export const BashTool = Tool.define( cwd, env: yield* shellEnv(ctx, cwd), timeout, - description: params.description, + description: params.description ?? params.command, // kilocode_change }, ctx, ) diff --git a/packages/opencode/test/kilocode/diff-full.test.ts b/packages/opencode/test/kilocode/diff-full.test.ts new file mode 100644 index 0000000000..87244ad4aa --- /dev/null +++ b/packages/opencode/test/kilocode/diff-full.test.ts @@ -0,0 +1,227 @@ +// kilocode_change - new file +// +// Tests for the git-based diff generator that replaced the JS Myers path. + +import { $ } from "bun" +import { describe, expect } from "bun:test" +import { Effect, Layer } from "effect" +import path from "path" +import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" +import { DiffFull } from "../../src/kilocode/snapshot/diff-full" +import { Filesystem } from "../../src/util/filesystem" +import { Log } from "../../src/util/log" +import { tmpdirScoped } from "../fixture/fixture" +import { testEffect } from "../lib/effect" + +Log.init({ print: false }) + +// Mirror the caller's git-wrapping in `snapshot/index.ts`: always disable +// quotepath so non-ASCII filenames come through unescaped. +const gitResult = (dir: string) => (args: string[]) => + Effect.promise(async () => { + const p = Bun.spawn(["git", "-c", "core.quotepath=false", ...args], { + cwd: dir, + stdout: "pipe", + stderr: "pipe", + }) + const [text, stderr] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]) + const code = await p.exited + return { code, text, stderr } + }) + +const gitText = (dir: string) => (args: string[]) => + Effect.promise(async () => { + const p = Bun.spawn(["git", "-c", "core.quotepath=false", ...args], { + cwd: dir, + stdout: "pipe", + stderr: "pipe", + }) + await p.exited + return await new Response(p.stdout).text() + }) + +const commit = async (dir: string, message: string) => { + await $`git add -A`.cwd(dir).quiet() + await $`git commit --no-gpg-sign -m ${message}`.cwd(dir).quiet() + const head = await $`git rev-parse HEAD`.cwd(dir).quiet() + return head.stdout.toString().trim() +} + +const it = testEffect(Layer.mergeAll(CrossSpawnSpawner.defaultLayer)) + +describe("DiffFull.batch", () => { + it.live("produces one patch per modified file", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "a.txt"), "alpha\nbeta\ngamma\n") + await Filesystem.write(path.join(dir, "b.txt"), "one\ntwo\nthree\n") + await Filesystem.write(path.join(dir, "c.txt"), "red\nblue\ngreen\n") + }) + const from = yield* Effect.promise(() => commit(dir, "v1")) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "a.txt"), "alpha\nBETA\ngamma\n") + await Filesystem.write(path.join(dir, "b.txt"), "one\nTWO\nthree\n") + await Filesystem.write(path.join(dir, "c.txt"), "red\nBLUE\ngreen\n") + }) + const to = yield* Effect.promise(() => commit(dir, "v2")) + + const result = yield* DiffFull.batch(gitResult(dir), from, to, ["a.txt", "b.txt", "c.txt"]) + expect(result.size).toBe(3) + expect(result.get("a.txt")).toMatch(/^diff --git /) + expect(result.get("a.txt")).toContain("-beta") + expect(result.get("a.txt")).toContain("+BETA") + expect(result.get("b.txt")).toContain("-two") + expect(result.get("b.txt")).toContain("+TWO") + expect(result.get("c.txt")).toContain("-blue") + expect(result.get("c.txt")).toContain("+BLUE") + }), + ) + + it.live("tolerates paths with spaces and unicode", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + const names = ["my file.txt", "héllo.txt", "a b c.md"] + yield* Effect.promise(async () => { + for (const name of names) { + await Filesystem.write(path.join(dir, name), "before\n") + } + }) + const from = yield* Effect.promise(() => commit(dir, "v1")) + yield* Effect.promise(async () => { + for (const name of names) { + await Filesystem.write(path.join(dir, name), "after\n") + } + }) + const to = yield* Effect.promise(() => commit(dir, "v2")) + + const result = yield* DiffFull.batch(gitResult(dir), from, to, names) + expect(result.size).toBe(names.length) + for (const name of names) { + const patch = result.get(name) + expect(patch).toBeDefined() + expect(patch).toContain("-before") + expect(patch).toContain("+after") + } + }), + ) + + it.live("returns an empty map without spawning for an empty file list", () => + Effect.gen(function* () { + let calls = 0 + const stub = (_: string[]) => + Effect.sync(() => { + calls += 1 + return { code: 0, text: "", stderr: "" } + }) + const result = yield* DiffFull.batch(stub, "from", "to", []) + expect(result.size).toBe(0) + expect(calls).toBe(0) + }), + ) + + it.live("returns an empty map on git failure", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "a.txt"), "hi\n") + }) + yield* Effect.promise(() => commit(dir, "v1")) + const result = yield* DiffFull.batch(gitResult(dir), "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "HEAD", [ + "a.txt", + ]) + expect(result.size).toBe(0) + }), + ) + + it.live( + "chunks 1200 files across three spawns and returns all entries", + () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + const names = Array.from({ length: 1200 }, (_, i) => `f${i.toString().padStart(4, "0")}.txt`) + yield* Effect.promise(async () => { + await Promise.all(names.map((name) => Filesystem.write(path.join(dir, name), "before\n"))) + }) + const from = yield* Effect.promise(() => commit(dir, "v1")) + yield* Effect.promise(async () => { + await Promise.all(names.map((name) => Filesystem.write(path.join(dir, name), "after\n"))) + }) + const to = yield* Effect.promise(() => commit(dir, "v2")) + + let calls = 0 + const counting = (cmd: string[]) => { + calls += 1 + return gitResult(dir)(cmd) + } + const result = yield* DiffFull.batch(counting, from, to, names) + expect(result.size).toBe(1200) + expect(calls).toBe(3) + expect(result.get("f0000.txt")).toContain("-before") + expect(result.get("f1199.txt")).toContain("+after") + }), + 30_000, + ) +}) + +describe("DiffFull.file", () => { + it.live("returns a structured + unified diff for a modified working-tree file", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "foo.txt"), "line1\nline2\nline3\n") + }) + yield* Effect.promise(() => commit(dir, "v1")) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "foo.txt"), "line1\nCHANGED\nline3\n") + }) + + const got = yield* DiffFull.file(gitText(dir), "foo.txt") + expect(got).not.toBeNull() + expect(got!.text).toMatch(/^diff --git /) + expect(got!.text).toContain("-line2") + expect(got!.text).toContain("+CHANGED") + expect(got!.patch.oldFileName).toBe("foo.txt") + expect(got!.patch.newFileName).toBe("foo.txt") + expect(got!.patch.hunks.length).toBeGreaterThan(0) + }), + ) + + it.live("returns null for an unmodified file", () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "foo.txt"), "unchanged\n") + }) + yield* Effect.promise(() => commit(dir, "v1")) + + const got = yield* DiffFull.file(gitText(dir), "foo.txt") + expect(got).toBeNull() + }), + ) + + it.live( + "handles a 15,000-line file in under 500 ms", + () => + Effect.gen(function* () { + const dir = yield* tmpdirScoped({ git: true }) + const before = Array.from({ length: 15_000 }, (_, i) => `v1_line_${i}`).join("\n") + "\n" + const after = Array.from({ length: 15_000 }, (_, i) => `v2_line_${i}`).join("\n") + "\n" + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "big.txt"), before) + }) + yield* Effect.promise(() => commit(dir, "v1")) + yield* Effect.promise(async () => { + await Filesystem.write(path.join(dir, "big.txt"), after) + }) + + const start = Date.now() + const got = yield* DiffFull.file(gitText(dir), "big.txt") + const elapsed = Date.now() - start + expect(got).not.toBeNull() + expect(got!.patch.hunks.length).toBeGreaterThan(0) + expect(elapsed).toBeLessThan(500) + }), + 10_000, + ) +}) diff --git a/packages/opencode/test/kilocode/plan-followup.test.ts b/packages/opencode/test/kilocode/plan-followup.test.ts index 27ff383435..9ee59bb0b5 100644 --- a/packages/opencode/test/kilocode/plan-followup.test.ts +++ b/packages/opencode/test/kilocode/plan-followup.test.ts @@ -13,6 +13,7 @@ import { Session } from "../../src/session" import { LLM } from "../../src/session/llm" import { MessageV2 } from "../../src/session/message-v2" import { AppRuntime } from "../../src/effect/app-runtime" +import { SessionStatus } from "../../src/session/status" import { Todo } from "../../src/session/todo" import { Global } from "../../src/global" import { Log } from "../../src/util/log" @@ -325,6 +326,44 @@ describe("plan follow-up", () => { } })) + test("ask - emits i18n keys alongside the canonical English labels", () => + withInstance(async () => { + const seeded = await seed({ text: "1. Build" }) + const pending = PlanFollowup.ask({ + sessionID: seeded.sessionID, + messages: seeded.messages, + abort: AbortSignal.any([]), + }) + + const item = await waitQuestion(seeded.sessionID) + expect(item).toBeDefined() + if (!item) return + const q = item.questions[0] + expect(q).toBeDefined() + if (!q) return + + // i18n keys for question-level strings + expect(q.questionKey).toBe("plan.followup.question") + expect(q.headerKey).toBe("plan.followup.header") + + // i18n keys for option labels — order matters: newSession is first, continue second. + expect(q.options.map((o) => o.labelKey)).toEqual([ + "plan.followup.answer.newSession", + "plan.followup.answer.continue", + ]) + expect(q.options.map((o) => o.descriptionKey)).toEqual([ + "plan.followup.answer.newSession.description", + "plan.followup.answer.continue.description", + ]) + + // Canonical English labels stay on the wire — the server still matches on `label`, + // so translating the UI must not change the reply format. + expect(q.options.map((o) => o.label)).toEqual([PlanFollowup.ANSWER_NEW_SESSION, PlanFollowup.ANSWER_CONTINUE]) + + await question.reject(item.id) + await expect(pending).resolves.toBe("break") + })) + test("ask - returns continue and creates code message on Continue here", () => withInstance(async () => { const get = spyOn(PlanFollowupRuntime, "agent").mockImplementation(async (name: string) => { @@ -895,6 +934,276 @@ describe("plan follow-up", () => { expect(part.text).not.toContain("## Todo List") })) + test("ask - fires session.created before generateHandover resolves on Start new session", () => + withInstance(async () => { + // Regression guard: the VS Code extension gates `session.created` SSE events + // behind a 30-second pendingFollowup TTL. If startNew awaits the handover + // LLM call before creating the session, a slow LLM response expires the TTL + // and the webview never learns about the new session. This test asserts the + // session is created *before* the handover resolves, guaranteeing the SSE + // event fires while the TTL is still fresh. + const seeded = await seed({ text: "1. Build" }) + + let createdAt: number | undefined + let handoverResolvedAt: number | undefined + const unsub = Bus.subscribe(Session.Event.Created, (event) => { + // Ignore the seeded planning session; we only care about the follow-up. + if (event.properties.info.id === seeded.sessionID) return + if (createdAt === undefined) createdAt = performance.now() + }) + + const deferred = Promise.withResolvers() + const agentSpy = spyOn(PlanFollowupRuntime, "agent").mockResolvedValue(fakeAgent as any) + const modelSpy = spyOn(PlanFollowupRuntime, "model").mockResolvedValue(fakeModel) + const llmSpy = spyOn(LLM, "stream").mockResolvedValue({ + text: deferred.promise.then((t) => { + handoverResolvedAt = performance.now() + return t + }), + } as any) + const loop = spyOn(PlanFollowupRuntime, "loop").mockResolvedValue({ + info: { + id: MessageID.make("msg_test"), + role: "assistant", + sessionID: SessionID.make("ses_test"), + time: { created: Date.now() }, + parentID: MessageID.make("msg_parent"), + modelID: ModelID.make("test"), + providerID: ProviderID.make("test"), + mode: "code", + agent: "code", + path: { cwd: "/tmp", root: "/tmp" }, + cost: 0, + tokens: { + total: 0, + input: 0, + output: 0, + reasoning: 0, + cache: { read: 0, write: 0 }, + }, + }, + parts: [], + } as MessageV2.WithParts) + using _ = { + [Symbol.dispose]() { + agentSpy.mockRestore() + modelSpy.mockRestore() + llmSpy.mockRestore() + loop.mockRestore() + unsub() + }, + } + + const pending = PlanFollowup.ask({ + sessionID: seeded.sessionID, + messages: seeded.messages, + abort: AbortSignal.any([]), + }) + + const item = await waitQuestion(seeded.sessionID) + expect(item).toBeDefined() + if (!item) return + await question.reply({ + requestID: item.id, + answers: [[PlanFollowup.ANSWER_NEW_SESSION]], + }) + + // Poll until session.created fires. With the fix, this happens promptly + // because Session.create runs before generateHandover. Without the fix, + // startNew would still be blocked on the deferred LLM stream. + for (let i = 0; i < 100; i++) { + if (createdAt !== undefined) break + await Bun.sleep(10) + } + expect(createdAt).toBeDefined() + // Handover must still be pending; if it had resolved, the race is open. + expect(handoverResolvedAt).toBeUndefined() + + deferred.resolve("## Discoveries\n\nexample") + await expect(pending).resolves.toBe("break") + + expect(handoverResolvedAt).toBeDefined() + expect(createdAt!).toBeLessThan(handoverResolvedAt!) + })) + + test("ask - injects plan message before generateHandover resolves on Start new session", () => + withInstance(async () => { + // Regression guard: the plan text must appear in the new session tab + // immediately after the tab switch — without waiting for the slow handover + // LLM call. The handover is then appended to the same part in-place. + const seeded = await seed({ text: "1. Build" }) + + let followup: SessionID | undefined + const unsub = Bus.subscribe(Session.Event.Created, (event) => { + if (event.properties.info.id === seeded.sessionID) return + if (!followup) followup = event.properties.info.id + }) + + const deferred = Promise.withResolvers() + const agentSpy = spyOn(PlanFollowupRuntime, "agent").mockResolvedValue(fakeAgent as any) + const modelSpy = spyOn(PlanFollowupRuntime, "model").mockResolvedValue(fakeModel) + const llmSpy = spyOn(LLM, "stream").mockResolvedValue({ + text: deferred.promise, + } as any) + const loop = spyOn(PlanFollowupRuntime, "loop").mockResolvedValue({ + info: { + id: MessageID.make("msg_test"), + role: "assistant", + sessionID: SessionID.make("ses_test"), + time: { created: Date.now() }, + parentID: MessageID.make("msg_parent"), + modelID: ModelID.make("test"), + providerID: ProviderID.make("test"), + mode: "code", + agent: "code", + path: { cwd: "/tmp", root: "/tmp" }, + cost: 0, + tokens: { total: 0, input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }, + parts: [], + } as MessageV2.WithParts) + using _ = { + [Symbol.dispose]() { + agentSpy.mockRestore() + modelSpy.mockRestore() + llmSpy.mockRestore() + loop.mockRestore() + unsub() + }, + } + + const pending = PlanFollowup.ask({ + sessionID: seeded.sessionID, + messages: seeded.messages, + abort: AbortSignal.any([]), + }) + + const item = await waitQuestion(seeded.sessionID) + expect(item).toBeDefined() + if (!item) return + await question.reply({ + requestID: item.id, + answers: [[PlanFollowup.ANSWER_NEW_SESSION]], + }) + + // Poll until the plan text lands. Handover is still pending because + // deferred has not resolved yet. + for (let i = 0; i < 100; i++) { + if (followup) { + const msgs = await Session.messages({ sessionID: followup }) + const user = msgs.find((m) => m.info.role === "user") + const part = user?.parts.find((p) => p.type === "text") + if (part?.type === "text" && part.text.includes("Implement the following plan:")) break + } + await Bun.sleep(10) + } + + expect(followup).toBeDefined() + if (!followup) return + const initial = await Session.messages({ sessionID: followup }) + const initialUser = initial.find((m) => m.info.role === "user") + const initialPart = initialUser?.parts.find((p) => p.type === "text") + expect(initialPart?.type).toBe("text") + if (initialPart?.type !== "text") return + expect(initialPart.text).toContain("Implement the following plan:") + expect(initialPart.text).toContain("1. Build") + // Handover is still deferred — must not be present yet. + expect(initialPart.text).not.toContain("## Handover from Planning Session") + + deferred.resolve("## Discoveries\n\nexample") + await expect(pending).resolves.toBe("break") + + // Same part ID updated in-place — handover section now present. + const final = await Session.messages({ sessionID: followup }) + const finalUser = final.find((m) => m.info.role === "user") + const finalPart = finalUser?.parts.find((p) => p.type === "text") + if (finalPart?.type !== "text") return + expect(finalPart.id).toBe(initialPart.id) + expect(finalPart.text).toContain("Implement the following plan:") + expect(finalPart.text).toContain("## Handover from Planning Session") + expect(finalPart.text).toContain("example") + })) + + test("ask - marks new session busy while handover is pending and clears on abort", () => + withInstance(async () => { + const seeded = await seed({ text: "1. Build" }) + + let followup: SessionID | undefined + const states: Array<{ sessionID: SessionID; type: string }> = [] + const created = Bus.subscribe(Session.Event.Created, (event) => { + if (event.properties.info.id === seeded.sessionID) return + if (!followup) followup = event.properties.info.id + }) + const status = Bus.subscribe(SessionStatus.Event.Status, (event) => { + states.push({ sessionID: event.properties.sessionID, type: event.properties.status.type }) + }) + + const deferred = Promise.withResolvers() + const agentSpy = spyOn(PlanFollowupRuntime, "agent").mockResolvedValue(fakeAgent as any) + const modelSpy = spyOn(PlanFollowupRuntime, "model").mockResolvedValue(fakeModel) + const llmSpy = spyOn(LLM, "stream").mockResolvedValue({ + text: deferred.promise, + } as any) + const loop = spyOn(PlanFollowupRuntime, "loop").mockResolvedValue({ + info: { + id: MessageID.make("msg_test"), + role: "assistant", + sessionID: SessionID.make("ses_test"), + time: { created: Date.now() }, + parentID: MessageID.make("msg_parent"), + modelID: ModelID.make("test"), + providerID: ProviderID.make("test"), + mode: "code", + agent: "code", + path: { cwd: "/tmp", root: "/tmp" }, + cost: 0, + tokens: { total: 0, input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + }, + parts: [], + } as MessageV2.WithParts) + using _ = { + [Symbol.dispose]() { + agentSpy.mockRestore() + modelSpy.mockRestore() + llmSpy.mockRestore() + loop.mockRestore() + created() + status() + }, + } + + const pending = PlanFollowup.ask({ + sessionID: seeded.sessionID, + messages: seeded.messages, + abort: AbortSignal.any([]), + }) + + const item = await waitQuestion(seeded.sessionID) + expect(item).toBeDefined() + if (!item) return + await question.reply({ + requestID: item.id, + answers: [[PlanFollowup.ANSWER_NEW_SESSION]], + }) + + for (let i = 0; i < 100; i++) { + if (followup && states.some((x) => x.sessionID === followup && x.type === "busy")) break + await Bun.sleep(10) + } + + expect(followup).toBeDefined() + if (!followup) return + expect(states.some((x) => x.sessionID === followup && x.type === "busy")).toBe(true) + + const { SessionPrompt } = await import("../../src/session/prompt") + await SessionPrompt.cancel(followup) + deferred.resolve("## Discoveries\n\nexample") + await expect(pending).resolves.toBe("break") + + expect(states.some((x) => x.sessionID === followup && x.type === "idle")).toBe(true) + expect(loop).not.toHaveBeenCalled() + })) + test("ask - returns break when assistant text is empty", () => withInstance(async () => { const seeded = await seed({ text: " " }) diff --git a/packages/opencode/test/kilocode/session-compaction-cap.test.ts b/packages/opencode/test/kilocode/session-compaction-cap.test.ts new file mode 100644 index 0000000000..10c6fcf4b1 --- /dev/null +++ b/packages/opencode/test/kilocode/session-compaction-cap.test.ts @@ -0,0 +1,408 @@ +// Regressions for the MAX_COMPACTION_ATTEMPTS cap in SessionPrompt.runLoop. +// Ensures the loop cannot spin forever when every compaction round still +// overflows the model context, and that the exhausted turn surfaces as an +// error (rather than silently completing). + +import { NodeFileSystem } from "@effect/platform-node" +import { describe, expect } from "bun:test" +import { Deferred, Effect, Layer } from "effect" +import { FetchHttpClient } from "effect/unstable/http" +import { Agent as AgentSvc } from "../../src/agent/agent" +import { Bus } from "../../src/bus" +import { Command } from "../../src/command" +import { Config } from "../../src/config/config" +import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" +import { Env } from "../../src/env" +import { FileTime } from "../../src/file/time" +import { Ripgrep } from "../../src/file/ripgrep" +import { AppFileSystem } from "../../src/filesystem" +import { Format } from "../../src/format" +import { KiloSession } from "../../src/kilocode/session" +import { KiloSessionPrompt } from "../../src/kilocode/session/prompt" +import { LSP } from "../../src/lsp" +import { MCP } from "../../src/mcp" +import { Permission } from "../../src/permission" +import { Plugin } from "../../src/plugin" +import { Provider as ProviderSvc } from "../../src/provider/provider" +import { ModelID, ProviderID } from "../../src/provider/schema" +import { Question } from "../../src/question" +import { Session } from "../../src/session" +import { SessionCompaction } from "../../src/session/compaction" +import { Instruction } from "../../src/session/instruction" +import { LLM } from "../../src/session/llm" +import { MessageV2 } from "../../src/session/message-v2" +import { SessionProcessor } from "../../src/session/processor" +import { SessionPrompt } from "../../src/session/prompt" +import { SessionRevert } from "../../src/session/revert" +import { SessionRunState } from "../../src/session/run-state" +import { MessageID, SessionID } from "../../src/session/schema" +import { SessionStatus } from "../../src/session/status" +import { SystemPrompt } from "../../src/session/system" +import { SessionSummary } from "../../src/session/summary" +import { Todo } from "../../src/session/todo" +import { Skill } from "../../src/skill" +import { Snapshot } from "../../src/snapshot" +import { ToolRegistry } from "../../src/tool/registry" +import { Truncate } from "../../src/tool/truncate" +import { Log } from "../../src/util/log" +import { provideTmpdirServer } from "../fixture/fixture" +import { testEffect } from "../lib/effect" +import { TestLLMServer } from "../lib/llm-server" + +Log.init({ print: false }) + +const ref = { + providerID: ProviderID.make("test"), + modelID: ModelID.make("test-model"), +} + +const summary = Layer.succeed( + SessionSummary.Service, + SessionSummary.Service.of({ + summarize: () => Effect.void, + diff: () => Effect.succeed([]), + computeDiff: () => Effect.succeed([]), + }), +) + +// Pass-through plugin mock. Lets every plugin trigger proceed with its default +// output so compaction's `experimental.compaction.autocontinue` stays on (the +// "compact" result path uses replay mode and the loop re-enters without the +// synthetic continue prompt anyway). +const plugin = Layer.mock(Plugin.Service)({ + trigger: (_name: Name, _input: Input, output: Output) => Effect.succeed(output), + list: () => Effect.succeed([]), + init: () => Effect.void, +}) + +const mcp = Layer.succeed( + MCP.Service, + MCP.Service.of({ + status: () => Effect.succeed({}), + clients: () => Effect.succeed({}), + tools: () => Effect.succeed({}), + prompts: () => Effect.succeed({}), + resources: () => Effect.succeed({}), + add: () => Effect.succeed({ status: { status: "disabled" as const } }), + connect: () => Effect.void, + disconnect: () => Effect.void, + getPrompt: () => Effect.succeed(undefined), + readResource: () => Effect.succeed(undefined), + startAuth: () => Effect.die("unexpected MCP auth in compaction cap tests"), + authenticate: () => Effect.die("unexpected MCP auth in compaction cap tests"), + finishAuth: () => Effect.die("unexpected MCP auth in compaction cap tests"), + removeAuth: () => Effect.void, + supportsOAuth: () => Effect.succeed(false), + hasStoredTokens: () => Effect.succeed(false), + getAuthStatus: () => Effect.succeed("not_authenticated" as const), + }), +) + +const lsp = Layer.succeed( + LSP.Service, + LSP.Service.of({ + init: () => Effect.void, + status: () => Effect.succeed([]), + hasClients: () => Effect.succeed(false), + touchFile: () => Effect.void, + diagnostics: () => Effect.succeed({}), + hover: () => Effect.succeed(undefined), + definition: () => Effect.succeed([]), + references: () => Effect.succeed([]), + implementation: () => Effect.succeed([]), + documentSymbol: () => Effect.succeed([]), + workspaceSymbol: () => Effect.succeed([]), + prepareCallHierarchy: () => Effect.succeed([]), + incomingCalls: () => Effect.succeed([]), + outgoingCalls: () => Effect.succeed([]), + }), +) + +const filetime = Layer.succeed( + FileTime.Service, + FileTime.Service.of({ + read: () => Effect.void, + get: () => Effect.succeed(undefined), + assert: () => Effect.void, + withLock: (_filepath, fn) => fn(), + }), +) + +const status = SessionStatus.layer.pipe(Layer.provideMerge(Bus.layer)) +const runState = SessionRunState.layer.pipe(Layer.provide(status)) +const infra = Layer.mergeAll(NodeFileSystem.layer, CrossSpawnSpawner.defaultLayer) + +function makeHttp() { + const deps = Layer.mergeAll( + Session.defaultLayer, + Snapshot.defaultLayer, + LLM.defaultLayer, + Env.defaultLayer, + AgentSvc.defaultLayer, + Command.defaultLayer, + Permission.defaultLayer, + plugin, + Config.defaultLayer, + ProviderSvc.defaultLayer, + filetime, + lsp, + mcp, + AppFileSystem.defaultLayer, + status, + ).pipe(Layer.provideMerge(infra)) + const question = Question.layer.pipe(Layer.provideMerge(deps)) + const todo = Todo.layer.pipe(Layer.provideMerge(deps)) + const registry = ToolRegistry.layer.pipe( + Layer.provide(Skill.defaultLayer), + Layer.provide(FetchHttpClient.layer), + Layer.provide(CrossSpawnSpawner.defaultLayer), + Layer.provide(Ripgrep.defaultLayer), + Layer.provide(Format.defaultLayer), + Layer.provideMerge(todo), + Layer.provideMerge(question), + Layer.provideMerge(deps), + ) + const trunc = Truncate.layer.pipe(Layer.provideMerge(deps)) + const proc = SessionProcessor.layer.pipe(Layer.provide(summary), Layer.provideMerge(deps)) + const compact = SessionCompaction.layer.pipe(Layer.provideMerge(proc), Layer.provideMerge(deps)) + return Layer.mergeAll( + TestLLMServer.layer, + SessionPrompt.layer.pipe( + Layer.provide(SessionRevert.defaultLayer), + Layer.provide(summary), + Layer.provideMerge(runState), + Layer.provideMerge(compact), + Layer.provideMerge(proc), + Layer.provideMerge(registry), + Layer.provideMerge(trunc), + Layer.provide(Instruction.defaultLayer), + Layer.provide(SystemPrompt.defaultLayer), + Layer.provideMerge(deps), + ), + ).pipe(Layer.provide(summary)) +} + +const it = testEffect(makeHttp()) + +const cfg = { + provider: { + test: { + name: "Test", + id: "test", + env: [], + npm: "@ai-sdk/openai-compatible", + models: { + "test-model": { + id: "test-model", + name: "Test Model", + attachment: false, + reasoning: false, + temperature: false, + tool_call: true, + release_date: "2025-01-01", + limit: { context: 100000, output: 10000 }, + cost: { input: 0, output: 0 }, + options: {}, + }, + }, + options: { + apiKey: "test-key", + baseURL: "http://localhost:1/v1", + }, + }, + }, +} + +function providerCfg(url: string) { + return { + ...cfg, + provider: { + ...cfg.provider, + test: { + ...cfg.provider.test, + options: { + ...cfg.provider.test.options, + baseURL: url, + }, + }, + }, + } +} + +const overflowBody = { type: "error", error: { code: "context_length_exceeded" } } + +describe("session compaction cap", () => { + it.live( + "closes the turn with reason=error after MAX_COMPACTION_ATTEMPTS compactions", + () => + provideTmpdirServer( + Effect.fnUntraced(function* ({ llm }) { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const bus = yield* Bus.Service + const chat = yield* sessions.create({ + title: "Compaction cap", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + + // Interleave overflow errors (top-level LLM call) and successful + // summary texts (compaction.process internal LLM call) so each + // compaction round completes and the loop re-enters. With + // MAX_COMPACTION_ATTEMPTS = 3 we queue 4 errors + 3 texts = 7 calls. + // The final error triggers guardCompactionAttempt and breaks. + yield* llm.error(400, overflowBody) // 1 — top-level fails → attempt 1 + yield* llm.text("summary 1") // 2 — compaction summary succeeds + yield* llm.error(400, overflowBody) // 3 — post-replay fails → attempt 2 + yield* llm.text("summary 2") // 4 + yield* llm.error(400, overflowBody) // 5 — attempt 3 + yield* llm.text("summary 3") // 6 + yield* llm.error(400, overflowBody) // 7 — exhausts, breaks + + const turnClose = yield* Deferred.make() + const unsub = yield* bus.subscribeCallback(KiloSession.Event.TurnClose, (evt) => { + if (evt.properties.sessionID === chat.id) + Deferred.doneUnsafe(turnClose, Effect.succeed(evt.properties.reason)) + }) + + yield* prompt.prompt({ + sessionID: chat.id, + agent: "code", + noReply: true, + parts: [{ type: "text", text: "please overflow" }], + }) + const result = yield* prompt.loop({ sessionID: chat.id }) + const reason = yield* Deferred.await(turnClose).pipe(Effect.timeout("2 seconds")) + unsub() + + // Each compaction round costs 2 LLM calls in this replay-mode path (one + // top-level overflow + one summary) plus 1 final overflow that trips the cap. + expect(yield* llm.calls).toBe(KiloSessionPrompt.MAX_COMPACTION_ATTEMPTS * 2 + 1) + expect(reason).toBe("error") + expect(result.info.role).toBe("assistant") + if (result.info.role !== "assistant") return + expect(result.info.finish).toBe("error") + expect(result.info.error?.name).toBe("ContextOverflowError") + if (result.info.error?.name !== "ContextOverflowError") return + expect(result.info.error.data.message).toContain("Compaction exhausted") + }), + { git: true, config: providerCfg }, + ), + 30_000, + ) + + it.live( + "completes normally when compactions stay below the cap", + () => + provideTmpdirServer( + Effect.fnUntraced(function* ({ llm }) { + const prompt = yield* SessionPrompt.Service + const sessions = yield* Session.Service + const bus = yield* Bus.Service + const chat = yield* sessions.create({ + title: "Compaction under cap", + permission: [{ permission: "*", pattern: "*", action: "allow" }], + }) + + yield* llm.error(400, overflowBody) // 1 — one compaction attempt + yield* llm.text("summary ok") // 2 — summary succeeds + yield* llm.text("final answer") // 3 — replayed turn completes + + const turnClose = yield* Deferred.make() + const unsub = yield* bus.subscribeCallback(KiloSession.Event.TurnClose, (evt) => { + if (evt.properties.sessionID === chat.id) + Deferred.doneUnsafe(turnClose, Effect.succeed(evt.properties.reason)) + }) + + yield* prompt.prompt({ + sessionID: chat.id, + agent: "code", + noReply: true, + parts: [{ type: "text", text: "overflow once" }], + }) + const result = yield* prompt.loop({ sessionID: chat.id }) + const reason = yield* Deferred.await(turnClose).pipe(Effect.timeout("2 seconds")) + unsub() + + expect(yield* llm.calls).toBe(3) + expect(reason).toBe("completed") + expect(result.info.role).toBe("assistant") + if (result.info.role !== "assistant") return + expect(result.info.finish).toBe("stop") + expect(result.info.error).toBeUndefined() + expect(result.parts.some((p) => p.type === "text" && p.text === "final answer")).toBe(true) + }), + { git: true, config: providerCfg }, + ), + 15_000, + ) +}) + +function makeAssistantStub(sessionID: string): MessageV2.Assistant { + return { + id: MessageID.ascending(), + role: "assistant", + sessionID: SessionID.make(sessionID), + parentID: MessageID.ascending(), + mode: "code", + agent: "code", + cost: 0, + path: { cwd: "/tmp", root: "/tmp" }, + tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, + modelID: ref.modelID, + providerID: ref.providerID, + time: { created: Date.now() }, + } +} + +describe("KiloSessionPrompt.guardCompactionAttempt", () => { + it.effect("returns { exhausted: false } and does not mutate state below the cap", () => + Effect.sync(() => { + const closeReasons = new Map() + const msg = makeAssistantStub("ses_under") + const result = KiloSessionPrompt.guardCompactionAttempt({ + sessionID: "ses_under", + attempts: KiloSessionPrompt.MAX_COMPACTION_ATTEMPTS - 1, + closeReasons, + message: msg, + }) + expect(result.exhausted).toBe(false) + expect(closeReasons.has("ses_under")).toBe(false) + expect(msg.error).toBeUndefined() + expect(msg.finish).toBeUndefined() + }), + ) + + it.effect("sets close reason and attaches error once attempts reach the cap", () => + Effect.sync(() => { + const closeReasons = new Map() + const msg = makeAssistantStub("ses_cap") + const result = KiloSessionPrompt.guardCompactionAttempt({ + sessionID: "ses_cap", + attempts: KiloSessionPrompt.MAX_COMPACTION_ATTEMPTS, + closeReasons, + message: msg, + }) + expect(result.exhausted).toBe(true) + if (!result.exhausted) return + expect(closeReasons.get("ses_cap")).toBe("error") + expect(msg.error?.name).toBe("ContextOverflowError") + if (msg.error?.name !== "ContextOverflowError") return + expect(msg.error.data.message).toContain("Compaction exhausted") + expect(msg.finish).toBe("error") + expect(result.error.name).toBe("ContextOverflowError") + }), + ) + + it.effect("works without a message and still sets the close reason", () => + Effect.sync(() => { + const closeReasons = new Map() + const result = KiloSessionPrompt.guardCompactionAttempt({ + sessionID: "ses_no_msg", + attempts: KiloSessionPrompt.MAX_COMPACTION_ATTEMPTS, + closeReasons, + }) + expect(result.exhausted).toBe(true) + expect(closeReasons.get("ses_no_msg")).toBe("error") + }), + ) +}) diff --git a/packages/opencode/test/kilocode/snapshot-freeze-repro.test.ts b/packages/opencode/test/kilocode/snapshot-freeze-repro.test.ts new file mode 100644 index 0000000000..e107eef3b4 --- /dev/null +++ b/packages/opencode/test/kilocode/snapshot-freeze-repro.test.ts @@ -0,0 +1,101 @@ +// kilocode_change - new file +// +// Regression test for the freeze bug: before the caps + worker offload, +// Snapshot.diffFull on a file with tens of thousands of lines could block +// the thread for minutes. In the TUI, that same thread hosts the Hono +// server — so the POST /:id/abort endpoint (what ESC fires) never ran. +// +// This test proves: +// 1. A synthetic freeze workload (30k-line file) now completes quickly. +// 2. The abort endpoint responds within a bounded time while the freeze +// workload runs concurrently. +// 3. A concurrent setInterval keeps ticking — i.e. the event loop keeps +// breathing and ESC would be delivered. + +import { test, expect, afterEach, mock } from "bun:test" +import { $ } from "bun" +import { Instance } from "../../src/project/instance" +import { Server } from "../../src/server/server" +import { Session } from "../../src/session" +import { Snapshot } from "../../src/snapshot" +import { Filesystem } from "../../src/util/filesystem" +import { Log } from "../../src/util/log" +import { tmpdir } from "../fixture/fixture" + +Log.init({ print: false }) + +afterEach(async () => { + mock.restore() + await Instance.disposeAll() +}) + +test("pathological diffFull workload finishes quickly and does not block abort", async () => { + // 3000-line file that churns every line between snapshots. Before the fix + // this ran through structuredPatch at context=MAX_SAFE_INTEGER synchronously + // and could take minutes. + const v1 = Array.from({ length: 3000 }, (_, i) => `v1_line_${i}`).join("\n") + "\n" + const v2 = Array.from({ length: 3000 }, (_, i) => `v2_line_${i}`).join("\n") + "\n" + + await using tmp = await tmpdir({ + git: true, + init: async (dir) => { + await Filesystem.write(`${dir}/fat.json`, v1) + await $`git add .`.cwd(dir).quiet() + await $`git commit --no-gpg-sign -m init`.cwd(dir).quiet() + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const session = await Session.create({}) + + const before = await Snapshot.track() + expect(before).toBeTruthy() + + await Filesystem.write(`${tmp.path}/fat.json`, v2) + const after = await Snapshot.track() + expect(after).toBeTruthy() + + // Kick off a diffFull that exercises the freeze path. + const diffPromise = Snapshot.diffFull(before!, after!) + + // Concurrently keep a tick counter running. If the event loop blocks we + // will see this count fall behind wall-clock elapsed. + let ticks = 0 + const start = Date.now() + const timer = setInterval(() => { + ticks++ + }, 25) + + // Fire an abort request against the Hono app in the middle of the diff. + const app = Server.Default().app + const abortStart = Date.now() + const res = await app.request(`/session/${session.id}/abort`, { method: "POST" }) + const abortLatency = Date.now() - abortStart + expect(res.status).toBe(200) + // The abort endpoint must respond well under a second even under load. + expect(abortLatency).toBeLessThan(2000) + + const diffs = await diffPromise + clearInterval(timer) + const total = Date.now() - start + + // The freeze workload must finish in bounded time. Five seconds is + // generous even for a slow CI box; without the fix this hangs. + expect(total).toBeLessThan(5000) + // And we must have ticked at least a few times during the work — proves + // the event loop stayed responsive (ESC would actually arrive). + expect(ticks).toBeGreaterThan(0) + + // With git-based diff the patch is a real unified diff, not empty. + const hit = diffs.find((d) => d.file === "fat.json") + expect(hit).toBeDefined() + expect(hit!.patch).toMatch(/^diff --git /m) + expect(hit!.patch).toContain("-v1_line_0") + expect(hit!.patch).toContain("+v2_line_0") + expect(hit!.additions).toBeGreaterThan(0) + expect(hit!.deletions).toBeGreaterThan(0) + }, + }) +}) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index c98ab5e12b..d22e349657 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/plugin", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/script/package.json b/packages/script/package.json index d5e57862db..5ea351240f 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -12,6 +12,6 @@ "exports": { ".": "./src/index.ts" }, - "version": "7.2.14", + "version": "7.2.20", "peerDependencies": {} } diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 87c08a7220..486bf4ebb4 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/sdk", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 2e495520a5..6255db849c 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -369,6 +369,14 @@ export type QuestionOption = { * Explanation of choice */ description: string + /** + * Optional i18n key for the label; clients translate and still reply with `label` + */ + labelKey?: string + /** + * Optional i18n key for the description + */ + descriptionKey?: string } export type QuestionInfo = { @@ -388,6 +396,14 @@ export type QuestionInfo = { * Allow selecting multiple choices */ multiple?: boolean + /** + * Optional i18n key for the question text; clients fall back to `question` when missing + */ + questionKey?: string + /** + * Optional i18n key for the header; clients fall back to `header` when missing + */ + headerKey?: string /** * Allow typing a custom answer (default: true) */ @@ -1537,9 +1553,9 @@ export type ProviderConfig = { */ disabled?: boolean [key: string]: unknown | boolean | undefined - } + } | null } - } + } | null } } @@ -1958,7 +1974,7 @@ export type Model = { } } recommendedIndex?: number - prompt?: "codex" | "gemini" | "beast" | "anthropic" | "trinity" | "anthropic_without_todo" + prompt?: "codex" | "gemini" | "beast" | "anthropic" | "trinity" | "anthropic_without_todo" | "ling" isFree?: boolean ai_sdk_provider?: "alibaba" | "anthropic" | "openai" | "openai-compatible" | "openrouter" } diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 85808234fc..10783b16d8 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -11429,6 +11429,14 @@ "description": { "description": "Explanation of choice", "type": "string" + }, + "labelKey": { + "description": "Optional i18n key for the label; clients translate and still reply with `label`", + "type": "string" + }, + "descriptionKey": { + "description": "Optional i18n key for the description", + "type": "string" } }, "required": ["label", "description"] @@ -11455,6 +11463,14 @@ "description": "Allow selecting multiple choices", "type": "boolean" }, + "questionKey": { + "description": "Optional i18n key for the question text; clients fall back to `question` when missing", + "type": "string" + }, + "headerKey": { + "description": "Optional i18n key for the header; clients fall back to `header` when missing", + "type": "string" + }, "custom": { "description": "Allow typing a custom answer (default: true)", "type": "boolean" @@ -15670,7 +15686,7 @@ }, "prompt": { "type": "string", - "enum": ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo"] + "enum": ["codex", "gemini", "beast", "anthropic", "trinity", "anthropic_without_todo", "ling"] }, "isFree": { "type": "boolean" diff --git a/packages/server/package.json b/packages/server/package.json index 7ff3c4a16f..8420431cdd 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/server", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "exports": { diff --git a/packages/storybook/package.json b/packages/storybook/package.json index ff0887b985..3d381be5fe 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -26,7 +26,7 @@ "typescript": "catalog:", "vite": "catalog:" }, - "version": "7.2.14", + "version": "7.2.20", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/ui/package.json b/packages/ui/package.json index c40c1979be..4f95fff1b4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "7.2.14", + "version": "7.2.20", "type": "module", "license": "MIT", "exports": { diff --git a/packages/util/package.json b/packages/util/package.json index 95817ea28b..2bcf0a5617 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "7.2.14", + "version": "7.2.20", "private": true, "type": "module", "license": "MIT", diff --git a/patches/stream-chat@9.38.0.patch b/patches/stream-chat@9.38.0.patch new file mode 100644 index 0000000000..7b1f66fd96 --- /dev/null +++ b/patches/stream-chat@9.38.0.patch @@ -0,0 +1,22 @@ +diff --git a/dist/types/insights.d.ts b/dist/types/insights.d.ts +index 1234567..abcdefg 100644 +--- a/dist/types/insights.d.ts ++++ b/dist/types/insights.d.ts +@@ -27,7 +27,7 @@ export declare function buildWsFatalInsight(connection: StableWSConnection, event + user_details: import("./types").UserResponse | import("./types").OwnUserResponse | undefined; + device: import("./types").BaseDeviceFields | undefined; + client_id: string | undefined; +- ws_details: import("ws") | undefined; ++ ws_details: typeof import("ws") | undefined; + ws_consecutive_failures: number; + ws_total_failures: number; + request_id: string | undefined; +@@ -47,7 +47,7 @@ export declare function buildWsSuccessAfterFailureInsight(connection: StableWSCon + user_details: import("./types").UserResponse | import("./types").OwnUserResponse | undefined; + device: import("./types").BaseDeviceFields | undefined; + client_id: string | undefined; +- ws_details: import("ws") | undefined; ++ ws_details: typeof import("ws") | undefined; + ws_consecutive_failures: number; + ws_total_failures: number; + request_id: string | undefined; diff --git a/script/publish.ts b/script/publish.ts index 9cd1c65cf9..5036461cbb 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -90,13 +90,33 @@ await $`bun install` await import(`../packages/sdk/js/script/build.ts`) if (Script.release) { - // kilocode_change start - commit and tag both release and rc version bumps + // kilocode_change start - commit, tag, and push with rebase + retry to handle + // concurrent merges to main. Rebase (instead of cherry-pick) handles + // overlapping file changes cleanly, and the retry loop covers the narrow + // window between fetch and push where another commit could land. await $`git commit -am "release: v${Script.version}"` await $`git tag v${Script.version}` - await $`git fetch origin` - await $`git cherry-pick HEAD..origin/main`.nothrow() - await $`git push origin HEAD --tags --no-verify --force-with-lease` - await new Promise((resolve) => setTimeout(resolve, 5_000)) + const retries = 3 + for (let i = 1; i <= retries; i++) { + await $`git fetch origin main` + const rebase = await $`git rebase origin/main`.nothrow() + if (rebase.exitCode !== 0) { + console.error(`rebase failed (attempt ${i}/${retries}), aborting rebase`) + await $`git rebase --abort`.nothrow() + if (i === retries) + throw new Error("failed to rebase release commit onto origin/main after " + retries + " attempts") + await new Promise((r) => setTimeout(r, 3_000)) + continue + } + const push = await $`git push origin HEAD:main --tags --no-verify --force-with-lease`.nothrow() + if (push.exitCode === 0) { + console.log("release commit pushed successfully") + break + } + console.warn(`push rejected (attempt ${i}/${retries}), retrying...`) + if (i === retries) throw new Error("failed to push release commit after " + retries + " attempts") + await new Promise((r) => setTimeout(r, 3_000)) + } // kilocode_change end // kilocode_change start diff --git a/script/upstream/package.json b/script/upstream/package.json index dd9af5c076..c1ba8caf36 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.2.14", + "version": "7.2.20", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 8eeea3b10e..60def23562 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "7.2.14", + "version": "7.2.20", "publisher": "sst-dev", "repository": { "type": "git",