diff --git a/.changeset/bright-brains-title.md b/.changeset/bright-brains-title.md deleted file mode 100644 index 26a31e69037..00000000000 --- a/.changeset/bright-brains-title.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kilocode/kilo-ui": patch ---- - -Show the first leading reasoning title in each block header without repeating it in the expanded body, while keeping untitled blocks unchanged. diff --git a/.changeset/calm-responses-stay.md b/.changeset/calm-responses-stay.md deleted file mode 100644 index 66672296be8..00000000000 --- a/.changeset/calm-responses-stay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Keep final streamed responses visible during session reconciliation. diff --git a/.changeset/mention-chip-style.md b/.changeset/mention-chip-style.md deleted file mode 100644 index 9621f918cb2..00000000000 --- a/.changeset/mention-chip-style.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": minor ---- - -Render file mentions as styled chips with click-to-open in both the chat input and sent user messages, with atomic backspace removal, arrow key skipping, selection snapping, and mention formatting preserved after reverting a session. diff --git a/.changeset/steady-voices-config.md b/.changeset/steady-voices-config.md deleted file mode 100644 index fe9c46b2334..00000000000 --- a/.changeset/steady-voices-config.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Persist Speech to Text experimental settings through Kilo config instead of VS Code settings. diff --git a/.changeset/tree-sitter-wasm-path.md b/.changeset/tree-sitter-wasm-path.md deleted file mode 100644 index 3b584fc21ab..00000000000 --- a/.changeset/tree-sitter-wasm-path.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@kilocode/cli": patch -"kilo-code": patch ---- - -Resolve bundled tree-sitter WASM resources from the installed CLI layout so codebase indexing works in packaged CLI and VS Code builds. diff --git a/.changeset/tui-dialog-vertical-centering.md b/.changeset/tui-dialog-vertical-centering.md new file mode 100644 index 00000000000..34176e9928f --- /dev/null +++ b/.changeset/tui-dialog-vertical-centering.md @@ -0,0 +1,5 @@ +--- +"@kilocode/cli": patch +--- + +Vertically center TUI dialogs on screen diff --git a/.changeset/wise-kites-smile.md b/.changeset/wise-kites-smile.md deleted file mode 100644 index 4630adf3c9f..00000000000 --- a/.changeset/wise-kites-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"kilo-code": patch ---- - -Fix stale indexing status updates in the VS Code extension on Windows so Settings and the chat indicator refresh while indexing progresses. Directory matching for indexing SSE events now handles Windows path casing, and indexing status pushes are no longer dropped if they arrive before the initial config payload. diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 34f35c22ce0..93f79d63cb9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -175,6 +175,7 @@ jobs: cli_version: ${{ needs.version.outputs.version }} secrets: inherit # kilocode_change end + publish: needs: - version @@ -208,6 +209,7 @@ jobs: with: node-version: "24" registry-url: "https://registry.npmjs.org" + package-manager-cache: false # kilocode_change - name: Install @vscode/vsce run: bun install -g @vscode/vsce @@ -265,7 +267,6 @@ jobs: GH_REPO: ${{ github.repository }} AUR_KEY: ${{ secrets.AUR_KEY }} GITHUB_TOKEN: ${{ steps.committer.outputs.token }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_CONFIG_PROVENANCE: true VSCE_PAT: ${{ secrets.VSCE_TOKEN }} OPENVSX_TOKEN: ${{ secrets.OVSX_TOKEN }} diff --git a/bun.lock b/bun.lock index ef88d343407..2c2605201ee 100644 --- a/bun.lock +++ b/bun.lock @@ -28,12 +28,12 @@ "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.8.13", + "turbo": "2.9.14", }, }, "packages/core": { "name": "@opencode-ai/core", - "version": "7.3.2", + "version": "7.3.6", "bin": { "opencode": "./bin/opencode", }, @@ -68,7 +68,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -98,7 +98,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@ai-sdk/alibaba": "1.0.17", "@ai-sdk/anthropic": "3.0.71", @@ -134,7 +134,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.3.2", + "version": "7.3.6", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -144,7 +144,7 @@ }, "packages/kilo-indexing": { "name": "@kilocode/kilo-indexing", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@aws-sdk/client-bedrock-runtime": "3.1005.0", "@aws-sdk/credential-provider-ini": "3.972.31", @@ -179,7 +179,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "posthog-node": "4.4.0", @@ -193,7 +193,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "0.13.11", @@ -230,7 +230,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-gateway": "workspace:*", @@ -293,7 +293,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.3.2", + "version": "7.3.6", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -451,7 +451,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@kilocode/sdk": "workspace:*", "effect": "catalog:", @@ -476,7 +476,7 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "semver": "^7.6.3", }, @@ -487,7 +487,7 @@ }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "cross-spawn": "catalog:", }, @@ -502,7 +502,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.3.2", + "version": "7.3.6", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -525,7 +525,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.3.2", + "version": "7.3.6", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -614,7 +614,7 @@ "@openauthjs/openauth": "0.0.0-20250322224806", "@opentui/core": "0.2.2", "@opentui/solid": "0.2.2", - "@pierre/diffs": "1.1.0-beta.18", + "@pierre/diffs": "1.1.22", "@playwright/test": "1.59.1", "@solid-primitives/storage": "4.3.3", "@solidjs/meta": "0.29.4", @@ -1644,9 +1644,9 @@ "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA=="], - "@pierre/diffs": ["@pierre/diffs@1.1.0-beta.18", "", { "dependencies": { "@pierre/theme": "0.0.22", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-7ZF3YD9fxdbYsPnltz5cUqHacN7ztp8RX/fJLxwv8wIEORpP4+7dHz1h/qx3o4EW2xUrIhmbM8ImywLasB787Q=="], + "@pierre/diffs": ["@pierre/diffs@1.1.22", "", { "dependencies": { "@pierre/theme": "0.0.28", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-1Iv7kdl6OABFCd1n2HQbGUiRHouXPaHoIjcb7Lwg8zeJKY5ph+cESFcGEyIiwW0NCbKGtYS2bTnXmI+Eze5dwg=="], - "@pierre/theme": ["@pierre/theme@0.0.22", "", {}, "sha512-ePUIdQRNGjrveELTU7fY89Xa7YGHHEy5Po5jQy/18lm32eRn96+tnYJEtFooGdffrx55KBUtOXfvVy/7LDFFhA=="], + "@pierre/theme": ["@pierre/theme@0.0.28", "", {}, "sha512-1j/H/fECBuc9dEvntdWI+l435HZapw+RCJTlqCA6BboQ5TjlnE005j/ROWutXIs8aq5OAc82JI2Kwk4A1WWBgw=="], "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], @@ -2028,6 +2028,18 @@ "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.9.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A=="], + + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.9.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw=="], + + "@turbo/linux-64": ["@turbo/linux-64@2.9.14", "", { "os": "linux", "cpu": "x64" }, "sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA=="], + + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.9.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g=="], + + "@turbo/windows-64": ["@turbo/windows-64@2.9.14", "", { "os": "win32", "cpu": "x64" }, "sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A=="], + + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.9.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], @@ -4296,19 +4308,7 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.8.13", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.13", "turbo-darwin-arm64": "2.8.13", "turbo-linux-64": "2.8.13", "turbo-linux-arm64": "2.8.13", "turbo-windows-64": "2.8.13", "turbo-windows-arm64": "2.8.13" }, "bin": { "turbo": "bin/turbo" } }, "sha512-nyM99hwFB9/DHaFyKEqatdayGjsMNYsQ/XBNO6MITc7roncZetKb97MpHxWf3uiU+LB9c9HUlU3Jp2Ixei2k1A=="], - - "turbo-darwin-64": ["turbo-darwin-64@2.8.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-PmOvodQNiOj77+Zwoqku70vwVjKzL34RTNxxoARjp5RU5FOj/CGiC6vcDQhNtFPUOWSAaogHF5qIka9TBhX4XA=="], - - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kI+anKcLIM4L8h+NsM7mtAUpElkCOxv5LgiQVQR8BASyDFfc8Efj5kCk3cqxuxOvIqx0sLfCX7atrHQ2kwuNJQ=="], - - "turbo-linux-64": ["turbo-linux-64@2.8.13", "", { "os": "linux", "cpu": "x64" }, "sha512-j29KnQhHyzdzgCykBFeBqUPS4Wj7lWMnZ8CHqytlYDap4Jy70l4RNG46pOL9+lGu6DepK2s1rE86zQfo0IOdPw=="], - - "turbo-linux-arm64": ["turbo-linux-arm64@2.8.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEl1YocXGZDRDh28doOUn49QwNe82kXljO1HXApjU0LapkDiGpfl3jkAlPKxEkGDSYWc8MH5Ll8S16Rf5tEBYg=="], - - "turbo-windows-64": ["turbo-windows-64@2.8.13", "", { "os": "win32", "cpu": "x64" }, "sha512-717bVk1+Pn2Jody7OmWludhEirEe0okoj1NpRbSm5kVZz/yNN/jfjbxWC6ilimXMz7xoMT3IDfQFJsFR3PMANA=="], - - "turbo-windows-arm64": ["turbo-windows-arm64@2.8.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-R819HShLIT0Wj6zWVnIsYvSNtRNj1q9VIyaUz0P24SMcLCbQZIm1sV09F4SDbg+KCCumqD2lcaR2UViQ8SnUJA=="], + "turbo": ["turbo@2.9.14", "", { "optionalDependencies": { "@turbo/darwin-64": "2.9.14", "@turbo/darwin-arm64": "2.9.14", "@turbo/linux-64": "2.9.14", "@turbo/linux-arm64": "2.9.14", "@turbo/windows-64": "2.9.14", "@turbo/windows-arm64": "2.9.14" }, "bin": { "turbo": "bin/turbo" } }, "sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw=="], "turndown": ["turndown@7.2.0", "", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A=="], diff --git a/nix/hashes.json b/nix/hashes.json index 2cebfd1e2e5..ac1138ed240 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-lENbjYvGZewVWQcr7zXJn+v1hrvipHEnjE1yS+kEwLs=", - "aarch64-linux": "sha256-yqTdPGtoLEOaFc7PhBFRiS/6gI3xUgHG/cQcULKytyM=", - "aarch64-darwin": "sha256-lyn6yjD8qv2KwIDwlA8LXBPkcHTCZCtXIsktK5acoXM=", - "x86_64-darwin": "sha256-diaLa3lmWzLcm4TeAwH1hFIqQYQQUcG4YD306vQWCqA=" + "x86_64-linux": "sha256-1GI3/cmf3ne+dxfEHzp7EzvEO0GzjgXtlilFGzV73hc=", + "aarch64-linux": "sha256-lHO7dmc1inyzFjAgoU7hyNUHldcrWOFu6eeBL1NaB14=", + "aarch64-darwin": "sha256-9j9ZdIZ6TD9F1GioHSRynaPjNHENdrl2sgMI93P2QhA=", + "x86_64-darwin": "sha256-3qKN9xzg2TzhnxX/zhwtP5V0152d5bfnn3hlctv8IJI=" } } diff --git a/package.json b/package.json index d80c3ada927..ac9b966c352 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@tsconfig/bun": "1.0.9", "@cloudflare/workers-types": "4.20251008.0", "@openauthjs/openauth": "0.0.0-20250322224806", - "@pierre/diffs": "1.1.0-beta.18", + "@pierre/diffs": "1.1.22", "opentui-spinner": "0.0.6", "@solid-primitives/storage": "4.3.3", "@tailwindcss/vite": "4.1.11", @@ -91,7 +91,7 @@ "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", - "turbo": "2.8.13", + "turbo": "2.9.14", "@types/bun": "catalog:", "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.27.10" @@ -145,6 +145,6 @@ "@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" }, - "version": "7.3.2", + "version": "7.3.6", "peerDependencies": {} } diff --git a/packages/core/package.json b/packages/core/package.json index 169fa72b579..49dd3f392b1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.2", + "version": "7.3.6", "name": "@opencode-ai/core", "type": "module", "license": "MIT", diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index f6e81fc8a8d..777f80fac8b 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 = "7.3.2" +version = "7.3.6" 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/v7.3.2/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.6/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.2/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.6/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.2/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.6/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/v7.3.2/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.6/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/v7.3.2/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.3.6/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index ba36f8513d6..94cb73a1ba0 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.3.2", + "version": "7.3.6", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", diff --git a/packages/kilo-docs/pages/collaborate/teams/billing.md b/packages/kilo-docs/pages/collaborate/teams/billing.md index 545c8887818..c8b89f50c98 100644 --- a/packages/kilo-docs/pages/collaborate/teams/billing.md +++ b/packages/kilo-docs/pages/collaborate/teams/billing.md @@ -68,7 +68,7 @@ To fill empty seats or remove members ahead of seat deletion, see the [team mana ## Automatic Top-Up -Ensure your team has uninterrupted access to Kilo Code by enabling Automatic Top-Up. This feature keeps your organization's balance funded so you never have to worry about manual recharges. +Ensure your team has uninterrupted access to Kilo Code by enabling [Automatic Top-Up](https://kilo.ai/features/auto-top-ups). This feature keeps your organization's balance funded so you never have to worry about manual recharges. Auto top-up is also available for individual accounts — see [Adding Credits](/docs/getting-started/adding-credits) for details. ### How It Works diff --git a/packages/kilo-docs/pages/getting-started/adding-credits.md b/packages/kilo-docs/pages/getting-started/adding-credits.md index f5c89de697c..a8b021abcea 100644 --- a/packages/kilo-docs/pages/getting-started/adding-credits.md +++ b/packages/kilo-docs/pages/getting-started/adding-credits.md @@ -9,9 +9,9 @@ Once you've used any initial free Kilo Credits, you can easily add more: - Subscribe to the [Kilo Pass](https://kilo.ai/features/kilo-pass), the most cost effective way to add credits. - Purchase additional credits as a one-time transaction. -- Enable automatic top-up, which purchases additional credits when your balance is below $5. +- Enable [automatic top-up](https://kilo.ai/features/auto-top-ups), which purchases additional credits when your balance runs low. Auto top-up is available for both individual and organization accounts. -These options are available to purchase from your [personal profile page](https://app.kilo.ai/profile). +These options are available to purchase from your [personal profile page](https://app.kilo.ai/profile). Organization owners can manage credits and auto top-up from the [Organization dashboard](https://app.kilo.ai). You can also use subscriptions or credits you may have purchased directly with an AI provider by adding your keys on the [Bring your own Key (BYOK)](https://app.kilo.ai/byok) settings screen. For setup details and supported providers, see [AI Providers documentation](/docs/ai-providers). If your provider is not yet supported, you can also [directly connect your provider](/docs/getting-started/setup-authentication) in the extension and CLI. diff --git a/packages/kilo-docs/previous-docs-redirects.js b/packages/kilo-docs/previous-docs-redirects.js index 1d872b63f5d..270e4874ccf 100644 --- a/packages/kilo-docs/previous-docs-redirects.js +++ b/packages/kilo-docs/previous-docs-redirects.js @@ -871,4 +871,10 @@ module.exports = [ basePath: false, permanent: true, }, + { + source: "/auto-top-ups", + destination: "https://kilo.ai/features/auto-top-ups", + basePath: false, + permanent: true, + }, ] diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png index a17e69d6219..db19d08e861 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png +++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/composite-webview/permission-dock-apply-patch-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7aa0924c6679cbff6e816dd86371a2d483afb7f0840824503ef4ba325c25d6c5 -size 26282 +oid sha256:97728b91ed1c92556abfde08824b91536e87cc7afa4d121bb5b1b488946c1d05 +size 26009 diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/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 index cdca3764fb9..0aadc161dc2 100644 --- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/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 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f28a551185ec9d7607d02295803b155e0f7bac378fcefdf0996c6ca51c0afad6 -size 21892 +oid sha256:7b8e9f6e0b9a9a62efc9b1e807936049c7627674ba241239dfd777698f951acc +size 21820 diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index 03a70348f33..54a6b291cab 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.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration", diff --git a/packages/kilo-i18n/package.json b/packages/kilo-i18n/package.json index 39c5f207666..ad511605a08 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.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-indexing/package.json b/packages/kilo-indexing/package.json index 167b2316bf7..d69db49cec3 100644 --- a/packages/kilo-indexing/package.json +++ b/packages/kilo-indexing/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-indexing", - "version": "7.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "description": "Standalone indexing engine and host helpers for Kilo Code", diff --git a/packages/kilo-indexing/src/indexing/config-manager.ts b/packages/kilo-indexing/src/indexing/config-manager.ts index 1c5124de2dd..fd8c63210d9 100644 --- a/packages/kilo-indexing/src/indexing/config-manager.ts +++ b/packages/kilo-indexing/src/indexing/config-manager.ts @@ -302,10 +302,9 @@ export class CodeIndexConfigManager { } public get currentModelDimension(): number | undefined { + if (this.modelDimension && this.modelDimension > 0) return this.modelDimension const id = this.modelId ?? getDefaultModelId(this.embedderProvider) - const dim = getModelDimension(this.embedderProvider, id) - if (!dim && this.modelDimension && this.modelDimension > 0) return this.modelDimension - return dim + return getModelDimension(this.embedderProvider, id) } public get currentSearchMinScore(): number { diff --git a/packages/kilo-indexing/src/indexing/embedders/openrouter.ts b/packages/kilo-indexing/src/indexing/embedders/openrouter.ts index c055964a5c3..bc8deea083a 100644 --- a/packages/kilo-indexing/src/indexing/embedders/openrouter.ts +++ b/packages/kilo-indexing/src/indexing/embedders/openrouter.ts @@ -25,7 +25,8 @@ interface EmbeddingItem { } interface OpenRouterEmbeddingResponse { - data: EmbeddingItem[] + data?: EmbeddingItem[] + error?: string | { code?: string | number; message?: string } usage?: { prompt_tokens?: number total_tokens?: number @@ -193,10 +194,7 @@ export class OpenRouterEmbedder implements IEmbedder { const requestParams: any = { input: batchTexts, model: model, - // OpenAI package (as of v4.78.1) has a parsing issue that truncates embedding dimensions to 256 - // when processing numeric arrays, which breaks compatibility with models using larger dimensions. - // By requesting base64 encoding, we bypass the package's parser and handle decoding ourselves. - encoding_format: "base64", + encoding_format: "float", } if (this.dimensions !== undefined) { @@ -213,8 +211,24 @@ export class OpenRouterEmbedder implements IEmbedder { } const response = (await this.embeddingsClient.embeddings.create(requestParams)) as OpenRouterEmbeddingResponse + const err = response.error + const msg = typeof err === "string" ? err : err?.message + const code = typeof err === "object" && err ? err.code : undefined + if (!response.data || response.data.length === 0) { + log.warn("OpenRouter embedder batch returned invalid response", { + location: "OpenRouterEmbedder:_embedBatchWithRetries", + model, + dimensions: this.dimensions, + provider: this.specificProvider, + code, + err: msg, + }) + const invalid = new Error(msg ?? "Invalid response from OpenRouter embedding endpoint") as HttpError + invalid.status = typeof code === "number" ? code : 422 + throw invalid + } - // Convert base64 embeddings to float32 arrays + // Normalize base64 embeddings if OpenRouter returns them despite the float request. const processedEmbeddings = response.data.map((item: EmbeddingItem) => { if (typeof item.embedding === "string") { const buffer = Buffer.from(item.embedding, "base64") @@ -292,7 +306,7 @@ export class OpenRouterEmbedder implements IEmbedder { const requestParams: any = { input: testTexts, model: modelToUse, - encoding_format: "base64", + encoding_format: "float", } if (this.dimensions !== undefined) { @@ -315,6 +329,18 @@ export class OpenRouterEmbedder implements IEmbedder { // Check if we got a valid response if (!response?.data || response.data.length === 0) { + const err = response?.error + const msg = typeof err === "string" ? err : err?.message + const code = typeof err === "object" && err ? err.code : undefined + log.warn("OpenRouter embedder validation returned invalid response", { + location: "OpenRouterEmbedder:validateConfiguration", + model: modelToUse, + dimensions: this.dimensions, + provider: this.specificProvider, + dataCount: response?.data?.length ?? 0, + code, + err: msg, + }) return { valid: false, error: "Invalid response from OpenRouter embedding endpoint", diff --git a/packages/kilo-indexing/src/indexing/embedding-profile.ts b/packages/kilo-indexing/src/indexing/embedding-profile.ts index 843288e80a9..9d37d8eacb2 100644 --- a/packages/kilo-indexing/src/indexing/embedding-profile.ts +++ b/packages/kilo-indexing/src/indexing/embedding-profile.ts @@ -20,7 +20,7 @@ export function resolveEmbeddingProfile( modelDimension?: number, ): EmbeddingProfile | undefined { const id = modelId ?? getDefaultModelId(provider) - const dim = getModelDimension(provider, id) ?? parseDimension(modelDimension) + const dim = parseDimension(modelDimension) ?? getModelDimension(provider, id) if (!dim) return undefined return { provider, diff --git a/packages/kilo-indexing/src/indexing/model-registry.ts b/packages/kilo-indexing/src/indexing/model-registry.ts index 12a427d210b..d02b488cbe1 100644 --- a/packages/kilo-indexing/src/indexing/model-registry.ts +++ b/packages/kilo-indexing/src/indexing/model-registry.ts @@ -48,6 +48,7 @@ const profiles: Record> = { openrouter: { "openai/text-embedding-3-small": { dimension: 1536, scoreThreshold: 0.4 }, "openai/text-embedding-3-large": { dimension: 3072, scoreThreshold: 0.4 }, + "google/gemini-embedding-2-preview": { dimension: 3072, scoreThreshold: 0.35 }, }, "openai-compatible": {}, "vercel-ai-gateway": { diff --git a/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts b/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts index cc56020ab7f..4ba3338df49 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/config-manager.test.ts @@ -83,6 +83,20 @@ describe("CodeIndexConfigManager", () => { expect(cfg.currentModelDimension).toBe(2048) }) + test("uses configured dimension before static model metadata", () => { + const cfg = new CodeIndexConfigManager( + createInput({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "google/gemini-embedding-2-preview", + modelDimension: 1536, + }), + ) + + expect(cfg.currentModelDimension).toBe(1536) + }) + describe("loadConfiguration restart checks", () => { test("requires restart when model changes with same dimension", () => { const cfg = new CodeIndexConfigManager(createInput({ modelId: "text-embedding-3-small" })) diff --git a/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts b/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts index 729e5c77875..098dd007508 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/embedders/openrouter.test.ts @@ -68,14 +68,10 @@ describe("OpenRouterEmbedder", () => { }) test("should create embeddings successfully", async () => { - // Create base64 encoded embedding with values that can be exactly represented in Float32 - const testEmbedding = new Float32Array([0.25, 0.5, 0.75]) - const base64String = Buffer.from(testEmbedding.buffer).toString("base64") - const mockResponse = { data: [ { - embedding: base64String, + embedding: [0.25, 0.5, 0.75], }, ], usage: { @@ -91,7 +87,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test text"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }) expect(result.embeddings).toHaveLength(1) expect(result.embeddings[0]).toEqual([0.25, 0.5, 0.75]) @@ -99,6 +95,20 @@ describe("OpenRouterEmbedder", () => { expect(result.usage?.totalTokens).toBe(5) }) + test("should not retry invalid responses without embedding data", async () => { + mockEmbeddingsCreate.mockResolvedValue({ + error: { + code: 404, + message: "No successful provider responses.", + }, + }) + + await expect(embedder.createEmbeddings(["test"])).rejects.toThrow( + "Embedding request failed after 3 attempts with status 404: No successful provider responses.", + ) + expect(mockEmbeddingsCreate).toHaveBeenCalledTimes(1) + }) + test("should handle multiple texts", async () => { const embedding1 = new Float32Array([0.25, 0.5]) const embedding2 = new Float32Array([0.75, 1.0]) @@ -156,7 +166,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: customModel, - encoding_format: "base64", + encoding_format: "float", }) }) @@ -187,7 +197,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", provider: { order: [specificProvider], only: [specificProvider], @@ -221,7 +231,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }) }) @@ -257,7 +267,7 @@ describe("OpenRouterEmbedder", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }) }) }) @@ -271,13 +281,10 @@ describe("OpenRouterEmbedder", () => { }) test("should validate configuration successfully", async () => { - const testEmbedding = new Float32Array([0.25, 0.5]) - const base64String = Buffer.from(testEmbedding.buffer).toString("base64") - const mockResponse = { data: [ { - embedding: base64String, + embedding: [0.25, 0.5], }, ], usage: { @@ -296,7 +303,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", }, { timeout: REMOTE_EMBEDDER_VALIDATION_TIMEOUT_MS, @@ -305,6 +312,20 @@ describe("OpenRouterEmbedder", () => { ) }) + test("should reject responses without embedding data", async () => { + mockEmbeddingsCreate.mockResolvedValue({ + error: { + code: 404, + message: "No successful provider responses.", + }, + }) + + const result = await embedder.validateConfiguration() + + expect(result.valid).toBe(false) + expect(result.error).toBe("Invalid response from OpenRouter embedding endpoint") + }) + test("should handle validation failure", async () => { const authError = new Error("Invalid API key") ;(authError as any).status = 401 @@ -346,7 +367,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", provider: { order: [specificProvider], only: [specificProvider], @@ -388,7 +409,7 @@ describe("OpenRouterEmbedder", () => { { input: ["test"], model: defaultModel, - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }, { diff --git a/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts b/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts index 67aff168c98..86d50ccc4a1 100644 --- a/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts +++ b/packages/kilo-indexing/test/kilocode/indexing/service-factory.test.ts @@ -149,11 +149,42 @@ describe("CodeIndexServiceFactory", () => { expect(mockEmbeddingsCreate).toHaveBeenCalledWith({ input: ["hello"], model: "openai/text-embedding-3-small", - encoding_format: "base64", + encoding_format: "float", dimensions: 1024, }) }) + test("creates vector store for OpenRouter Gemini embedding preview", () => { + const factory = createFactory({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "google/gemini-embedding-2-preview", + vectorStoreProvider: "lancedb", + }) + + const store = factory.createVectorStore() as unknown as { vectorSize: number } + + expect(store).toBeDefined() + expect(store.vectorSize).toBe(3072) + }) + + test("uses configured dimension before static model metadata for vector stores", () => { + const factory = createFactory({ + embedderProvider: "openrouter", + openAiKey: undefined, + openRouterApiKey: "or-test", + modelId: "openai/text-embedding-3-small", + modelDimension: 1024, + vectorStoreProvider: "lancedb", + }) + + const store = factory.createVectorStore() as unknown as { vectorSize: number } + + expect(store).toBeDefined() + expect(store.vectorSize).toBe(1024) + }) + test("creates Kilo embedder with Cloud-provided model", async () => { const factory = createFactory({ embedderProvider: "kilo", @@ -177,6 +208,7 @@ describe("CodeIndexServiceFactory", () => { input: ["hello"], model: "mistralai/mistral-embed-2312", encoding_format: "base64", + dimensions: 1024, }) }) }) diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index 16f1b153cf7..3a22d625cf0 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.3.2", + "version": "7.3.6", "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 b7a2af80538..454ecac6c61 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-ui/src/styles/vscode-bridge.css b/packages/kilo-ui/src/styles/vscode-bridge.css index 2fe4a041a01..35bb4f6e3bd 100644 --- a/packages/kilo-ui/src/styles/vscode-bridge.css +++ b/packages/kilo-ui/src/styles/vscode-bridge.css @@ -280,8 +280,8 @@ html[data-theme="kilo-vscode"] { --syntax-diff-unknown: var(--vscode-charts-red); /* ===== Pierre diff engine (theme its CSS vars to VS Code editor colors) ===== */ - --diffs-light-bg: var(--vscode-editor-background, #1e1e1e); - --diffs-dark-bg: var(--vscode-editor-background, #1e1e1e); + --diffs-light-bg: var(--background-stronger); + --diffs-dark-bg: var(--background-stronger); --diffs-bg-addition-override: color-mix( in lab, diff --git a/packages/kilo-vscode/CHANGELOG.md b/packages/kilo-vscode/CHANGELOG.md index 185ab0816b7..7163f5cbace 100644 --- a/packages/kilo-vscode/CHANGELOG.md +++ b/packages/kilo-vscode/CHANGELOG.md @@ -1,5 +1,39 @@ # kilo-code +## 7.3.5 + +### Patch Changes + +- [#10481](https://github.com/Kilo-Org/kilocode/pull/10481) [`15bdd0f`](https://github.com/Kilo-Org/kilocode/commit/15bdd0f96f3f6713b552436806f6e218528443ab) - Prevent VS Code local CLI reconnect flapping while the event stream is unavailable. + +- [#10479](https://github.com/Kilo-Org/kilocode/pull/10479) [`048338a`](https://github.com/Kilo-Org/kilocode/commit/048338a31422fd057bcaefc8db6c397cf33adff1) - Clear Agent Manager file diff previews stuck on `Loading diff...` when the active diff source stops or changes. + +- [#10480](https://github.com/Kilo-Org/kilocode/pull/10480) [`9067de0`](https://github.com/Kilo-Org/kilocode/commit/9067de039ed820eab757d1e798abe264315c6f02) - Improve VS Code diff rendering stability across review and chat surfaces. + +- Updated dependencies [[`205e22e`](https://github.com/Kilo-Org/kilocode/commit/205e22ee4672305d3cb2e0c34b607a4950f8f4e8), [`9067de0`](https://github.com/Kilo-Org/kilocode/commit/9067de039ed820eab757d1e798abe264315c6f02)]: + - @kilocode/kilo-indexing@7.3.5 + - @kilocode/kilo-ui@7.3.5 + - @opencode-ai/ui@7.3.5 + +## 7.3.3 + +### Minor Changes + +- [#10099](https://github.com/Kilo-Org/kilocode/pull/10099) [`47c8600`](https://github.com/Kilo-Org/kilocode/commit/47c8600b21dfc9ce5f9010a471e075af10867cf0) Thanks [@sylwester-liljegren](https://github.com/sylwester-liljegren)! - Render file mentions as styled chips with click-to-open in both the chat input and sent user messages, with atomic backspace removal, arrow key skipping, selection snapping, and mention formatting preserved after reverting a session. + +### Patch Changes + +- [#10450](https://github.com/Kilo-Org/kilocode/pull/10450) [`75f6819`](https://github.com/Kilo-Org/kilocode/commit/75f68190e45a4c10f72438d1cf6ab40730e865f8) - Keep final streamed responses visible during session reconciliation. + +- [#10440](https://github.com/Kilo-Org/kilocode/pull/10440) [`e739c29`](https://github.com/Kilo-Org/kilocode/commit/e739c29bb57262d7567be1a25b62a03460f6c8d1) - Persist Speech to Text experimental settings through Kilo config instead of VS Code settings. + +- [#10155](https://github.com/Kilo-Org/kilocode/pull/10155) [`371b7e8`](https://github.com/Kilo-Org/kilocode/commit/371b7e8ae6057f0fefae3982eee6923f2c0a61f0) - Resolve bundled tree-sitter WASM resources from the installed CLI layout so codebase indexing works in packaged CLI and VS Code builds. + +- [#9806](https://github.com/Kilo-Org/kilocode/pull/9806) [`c5903fd`](https://github.com/Kilo-Org/kilocode/commit/c5903fdc09b1cf731e538cd632b47e4befd8367a) Thanks [@shssoichiro](https://github.com/shssoichiro)! - Fix stale indexing status updates in the VS Code extension on Windows so Settings and the chat indicator refresh while indexing progresses. Directory matching for indexing SSE events now handles Windows path casing, and indexing status pushes are no longer dropped if they arrive before the initial config payload. + +- Updated dependencies [[`241efc6`](https://github.com/Kilo-Org/kilocode/commit/241efc6959ae1fe2fd2adc3533737ad0712983c5)]: + - @kilocode/kilo-ui@7.3.3 + ## 7.3.2 ### Patch Changes diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index f96723e8cbd..10ad4698fb7 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.3.2", + "version": "7.3.6", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/packages/kilo-vscode/script/local-bin.ts b/packages/kilo-vscode/script/local-bin.ts index 0c4beea4181..951d0f8ce46 100644 --- a/packages/kilo-vscode/script/local-bin.ts +++ b/packages/kilo-vscode/script/local-bin.ts @@ -23,6 +23,7 @@ const kiloVscodeDir = join(import.meta.dir, "..") const packagesDir = join(kiloVscodeDir, "..") const opencodeDir = join(packagesDir, "opencode") const coreDir = join(packagesDir, "core") +const indexingDir = join(packagesDir, "kilo-indexing") const targetBinDir = join(kiloVscodeDir, "bin") const binName = process.platform === "win32" ? "kilo.exe" : "kilo" @@ -37,7 +38,8 @@ async function cliSourceHash(): Promise { try { const opencodeResult = await $`git log -1 --format=%H -- .`.cwd(opencodeDir).quiet() const coreResult = await $`git log -1 --format=%H -- .`.cwd(coreDir).quiet() - return `${opencodeResult.text().trim()}-${coreResult.text().trim()}` || null + const indexingResult = await $`git log -1 --format=%H -- .`.cwd(indexingDir).quiet() + return `${opencodeResult.text().trim()}-${coreResult.text().trim()}-${indexingResult.text().trim()}` || null } catch { return null } @@ -47,7 +49,12 @@ async function isDirty(): Promise { try { const opencodeResult = await $`git status --porcelain -- .`.cwd(opencodeDir).quiet() const coreResult = await $`git status --porcelain -- .`.cwd(coreDir).quiet() - return opencodeResult.text().trim().length > 0 || coreResult.text().trim().length > 0 + const indexingResult = await $`git status --porcelain -- .`.cwd(indexingDir).quiet() + return ( + opencodeResult.text().trim().length > 0 || + coreResult.text().trim().length > 0 || + indexingResult.text().trim().length > 0 + ) } catch { return false } diff --git a/packages/kilo-vscode/src/diff/SourceController.ts b/packages/kilo-vscode/src/diff/SourceController.ts index 47d1a771471..11a51ed3449 100644 --- a/packages/kilo-vscode/src/diff/SourceController.ts +++ b/packages/kilo-vscode/src/diff/SourceController.ts @@ -181,8 +181,12 @@ export class SourceController { return } const diff = await source.fetchFile(file).catch(() => null) - // Drop the response if the source has been disposed/swapped while we waited. - if (this.epoch !== epoch) return + // Discard stale content after disposal/swap, but still complete the request + // so consumers can clear per-file loading state. + if (this.epoch !== epoch) { + this.send(this.messages.diffFile(source, file, null)) + return + } this.send(this.messages.diffFile(source, file, diff)) } diff --git a/packages/kilo-vscode/src/services/cli-backend/connection-service.ts b/packages/kilo-vscode/src/services/cli-backend/connection-service.ts index 3b5a9e0d950..768f6bb6c78 100644 --- a/packages/kilo-vscode/src/services/cli-backend/connection-service.ts +++ b/packages/kilo-vscode/src/services/cli-backend/connection-service.ts @@ -584,7 +584,8 @@ export class KiloConnectionService { this.sseClient = new SdkSSEAdapter(this.client) - // Wait until SSE actually reaches a terminal state before resolving connect(). + // Wait until SSE yields its first server event before resolving connect(). + // Initial stream failures are handled by the adapter reconnect loop. let resolveConnected: (() => void) | null = null let rejectConnected: ((error: Error) => void) | null = null const connectedPromise = new Promise((resolve, reject) => { @@ -601,11 +602,8 @@ export class KiloConnectionService { } }) - this.sseClient.onError((error) => { + this.sseClient.onError(() => { this.setState("error") - rejectConnected?.(error) - resolveConnected = null - rejectConnected = null }) // Wire SSE state → broadcast to all registered state listeners diff --git a/packages/kilo-vscode/src/services/cli-backend/sdk-sse-adapter.ts b/packages/kilo-vscode/src/services/cli-backend/sdk-sse-adapter.ts index 299a4a9453c..f2ba427c83f 100644 --- a/packages/kilo-vscode/src/services/cli-backend/sdk-sse-adapter.ts +++ b/packages/kilo-vscode/src/services/cli-backend/sdk-sse-adapter.ts @@ -15,9 +15,8 @@ export type SSEStateHandler = (state: "connecting" | "connected" | "disconnected * * In this VS Code extension context the connection is localhost (extension ↔ * child-process server), so zombie-connection scenarios are less likely than in - * a browser client (which goes through proxies/CDNs). We keep the heartbeat for - * consistency with the original strategy but use a generous 90 s timeout to - * avoid false-positive reconnections during idle periods. + * a browser client (which goes through proxies/CDNs). We still keep a heartbeat + * grace window so dead local streams recover without waiting indefinitely. * * NOTE on event coalescing: * The app batches rapid events into 16 ms windows before flushing to the UI. @@ -37,6 +36,7 @@ export class SdkSSEAdapter { // Reduced from 90s: with 90s a dead connection could linger for ~1.5 minutes. private static readonly HEARTBEAT_TIMEOUT_MS = 15_000 private static readonly RECONNECT_DELAY_MS = 250 + private static readonly MAX_RECONNECT_DELAY_MS = 5_000 constructor(private readonly client: KiloClient) {} @@ -126,8 +126,11 @@ export class SdkSSEAdapter { * Main reconnection loop — mirrors the pattern in `global-sdk.tsx`. */ private async consumeLoop(signal: AbortSignal): Promise { + let delay = SdkSSEAdapter.RECONNECT_DELAY_MS + while (!signal.aborted) { const attempt = new AbortController() + let ready = false // Forward the outer abort to the per-attempt controller so // `disconnect()` cancels the current fetch immediately. @@ -159,8 +162,7 @@ export class SdkSSEAdapter { }, }) - console.log("[Kilo New] SSE: ✅ Stream opened successfully") - this.notifyState("connected") + console.log("[Kilo New] SSE: ⏳ Waiting for first stream event") this.resetHeartbeat(attempt) for await (const event of events.stream) { @@ -170,6 +172,13 @@ export class SdkSSEAdapter { this.resetHeartbeat(attempt) + if (!ready) { + ready = true + delay = SdkSSEAdapter.RECONNECT_DELAY_MS + console.log("[Kilo New] SSE: ✅ Stream opened successfully") + this.notifyState("connected") + } + // The SDK yields GlobalEvent = { directory, payload: Event }. const globalEvent = event as GlobalEvent const type = (globalEvent.payload as { type: string }).type @@ -179,7 +188,9 @@ export class SdkSSEAdapter { this.notifyEvent(globalEvent.payload as Event, globalEvent.directory) } - console.log("[Kilo New] SSE: 📭 Stream ended normally") + console.log( + ready ? "[Kilo New] SSE: 📭 Stream ended normally" : "[Kilo New] SSE: 📭 Stream ended before first event", + ) } catch (error) { // Suppress AbortErrors — they are expected when the heartbeat timer // or reconnect() aborts the per-attempt controller. @@ -198,9 +209,11 @@ export class SdkSSEAdapter { break } - console.log(`[Kilo New] SSE: 🔄 Reconnecting in ${SdkSSEAdapter.RECONNECT_DELAY_MS}ms...`) + const wait = delay + delay = ready ? SdkSSEAdapter.RECONNECT_DELAY_MS : Math.min(delay * 2, SdkSSEAdapter.MAX_RECONNECT_DELAY_MS) + console.log(`[Kilo New] SSE: 🔄 Reconnecting in ${wait}ms...`) this.notifyState("connecting") - await new Promise((resolve) => setTimeout(resolve, SdkSSEAdapter.RECONNECT_DELAY_MS)) + await new Promise((resolve) => setTimeout(resolve, wait)) } this.notifyState("disconnected") diff --git a/packages/kilo-vscode/tests/package.json b/packages/kilo-vscode/tests/package.json index 269026892ef..fc975377adb 100644 --- a/packages/kilo-vscode/tests/package.json +++ b/packages/kilo-vscode/tests/package.json @@ -1,6 +1,6 @@ { "type": "module", - "version": "7.3.2", + "version": "7.3.6", "dependencies": {}, "devDependencies": {}, "peerDependencies": {} diff --git a/packages/kilo-vscode/tests/unit/sdk-sse-adapter.test.ts b/packages/kilo-vscode/tests/unit/sdk-sse-adapter.test.ts new file mode 100644 index 00000000000..5f54670d342 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/sdk-sse-adapter.test.ts @@ -0,0 +1,148 @@ +import { describe, expect, it } from "bun:test" +import type { KiloClient } from "@kilocode/sdk/v2/client" +import { KiloConnectionService } from "../../src/services/cli-backend/connection-service" +import { SdkSSEAdapter } from "../../src/services/cli-backend/sdk-sse-adapter" + +type Opts = { + onSseError?: (error: unknown) => void + signal?: AbortSignal +} + +type Stream = AsyncGenerator + +function client(open: (opts: Opts) => Stream): KiloClient { + return { + global: { + event: async (opts: Opts) => ({ stream: open(opts) }), + }, + } as unknown as KiloClient +} + +function event() { + return { + directory: "/repo", + payload: { + id: "evt_connected", + type: "server.connected", + properties: {}, + }, + } +} + +function wait(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) +} + +function aborted(signal?: AbortSignal) { + if (!signal || signal.aborted) return Promise.resolve() + return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true })) +} + +describe("SdkSSEAdapter", () => { + it("reports connected only after the first SSE event arrives", async () => { + let release = () => {} + const gate = new Promise((resolve) => { + release = resolve + }) + const adapter = new SdkSSEAdapter( + client(async function* (opts) { + await gate + yield event() + await aborted(opts.signal) + }), + ) + const states: string[] = [] + const connected = new Promise((resolve) => { + adapter.onStateChange((state) => { + states.push(state) + if (state === "connected") resolve() + }) + }) + + adapter.connect() + await wait(10) + + expect(states).toEqual(["connecting"]) + + release() + await connected + + expect(states).toEqual(["connecting", "connected"]) + adapter.disconnect() + }) + + it("backs off reconnects when an SSE fetch fails before opening", async () => { + const timer = globalThis.setTimeout + const delays: number[] = [] + let count = 0 + let finish = () => {} + const reached = new Promise((resolve) => { + finish = resolve + }) + globalThis.setTimeout = ((handler: TimerHandler, timeout?: number, ...args: unknown[]) => { + if (typeof timeout === "number" && timeout <= 5_000) { + delays.push(timeout) + return timer(handler, 0, ...args) + } + return timer(handler, timeout, ...args) + }) as typeof setTimeout + + const failing = new SdkSSEAdapter( + client((opts) => { + count += 1 + if (count === 3) finish() + return (async function* () { + opts.onSseError?.(new TypeError("fetch failed")) + })() + }), + ) + + try { + failing.connect() + await reached + failing.disconnect() + + expect(delays.slice(0, 2)).toEqual([250, 500]) + } finally { + failing.disconnect() + globalThis.setTimeout = timer + } + }) +}) + +describe("KiloConnectionService SSE startup", () => { + it("waits through an initial SSE fetch failure until the stream opens", async () => { + const original = globalThis.fetch + const chunk = new TextEncoder().encode( + 'data: {"payload":{"id":"evt_connected","type":"server.connected","properties":{}}}\n\n', + ) + let calls = 0 + globalThis.fetch = (async () => { + calls += 1 + if (calls === 1) throw new TypeError("fetch failed") + return new Response( + new ReadableStream({ + start(controller) { + controller.enqueue(chunk) + }, + }), + { + status: 200, + headers: { "content-type": "text/event-stream" }, + }, + ) + }) as typeof fetch + + const service = new KiloConnectionService({} as any) + ;(service as any).serverManager.getServer = async () => ({ port: 52512, password: "secret", process: {} }) + + try { + await expect(service.connect("/tmp/workspace")).resolves.toBeUndefined() + expect(calls).toBe(2) + expect(service.getConnectionState()).toBe("connected") + } finally { + service.dispose() + globalThis.fetch = original + } + }) +}) diff --git a/packages/kilo-vscode/tests/unit/source-controller.test.ts b/packages/kilo-vscode/tests/unit/source-controller.test.ts index f9a49cd2cbc..549fe75af02 100644 --- a/packages/kilo-vscode/tests/unit/source-controller.test.ts +++ b/packages/kilo-vscode/tests/unit/source-controller.test.ts @@ -345,6 +345,40 @@ describe("SourceController.requestFile", () => { controller.stop() }) + + it("posts null when a pending fetchFile result is invalidated by stop", async () => { + let release: () => void = () => {} + const workspace: DiffSource = { + descriptor: WORKSPACE_DESC, + async fetch() { + return { diffs: [] } + }, + async fetchFile() { + await new Promise((resolve) => (release = resolve)) + return { + file: "foo.ts", + before: "a", + after: "b", + additions: 1, + deletions: 1, + } + }, + } + const { controller, posted } = make({ workspace }) + + controller.setContext({ workspaceRoot: "/repo" }) + await controller.activate("workspace") + posted.length = 0 + const request = controller.requestFile("foo.ts") + controller.stop() + release() + await request + + const files = byType(posted, "diffViewer.diffFile") + expect(files).toHaveLength(1) + expect(files[0]!.file).toBe("foo.ts") + expect(files[0]!.diff).toBeNull() + }) }) describe("SourceController.reactivate", () => { diff --git a/packages/opencode/CHANGELOG.md b/packages/opencode/CHANGELOG.md index 9c2d7b240c3..9498768e1d4 100644 --- a/packages/opencode/CHANGELOG.md +++ b/packages/opencode/CHANGELOG.md @@ -1,5 +1,18 @@ # @kilocode/cli +## 7.3.5 + +### Patch Changes + +- Updated dependencies [[`205e22e`](https://github.com/Kilo-Org/kilocode/commit/205e22ee4672305d3cb2e0c34b607a4950f8f4e8)]: + - @kilocode/kilo-indexing@7.3.5 + +## 7.3.3 + +### Patch Changes + +- [#10155](https://github.com/Kilo-Org/kilocode/pull/10155) [`371b7e8`](https://github.com/Kilo-Org/kilocode/commit/371b7e8ae6057f0fefae3982eee6923f2c0a61f0) - Resolve bundled tree-sitter WASM resources from the installed CLI layout so codebase indexing works in packaged CLI and VS Code builds. + ## 7.3.2 ## 7.3.1 diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 1e1e9215392..6f21f816ac0 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.3.2", + "version": "7.3.6", "name": "@kilocode/cli", "type": "module", "license": "MIT", diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx index acbd5226d88..1c8f4b49233 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx @@ -39,9 +39,9 @@ export function Dialog( width={dimensions().width} height={dimensions().height} alignItems="center" + justifyContent="center" // kilocode_change position="absolute" zIndex={3000} - paddingTop={dimensions().height / 4} left={0} top={0} backgroundColor={RGBA.fromInts(0, 0, 0, 150)} diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 73540fe0104..fc4f927dbb9 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.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/script/package.json b/packages/script/package.json index be99266d290..28757a3da62 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -12,6 +12,6 @@ "exports": { ".": "./src/index.ts" }, - "version": "7.3.2", + "version": "7.3.6", "peerDependencies": {} } diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 3d7a8bec425..04e55307069 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.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/storybook/package.json b/packages/storybook/package.json index a1f1ecc9220..f4fd9d4e485 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -26,7 +26,7 @@ "typescript": "catalog:", "vite": "catalog:" }, - "version": "7.3.2", + "version": "7.3.6", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/ui/package.json b/packages/ui/package.json index 31a8546f89b..6c80a24c61c 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "7.3.2", + "version": "7.3.6", "type": "module", "license": "MIT", "exports": { diff --git a/script/upstream/package.json b/script/upstream/package.json index d24bd623acd..84191be749d 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.3.2", + "version": "7.3.6", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo",