Compare commits
179 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f08110d4d | |||
| d1e4844fbf | |||
| bf8064ddc4 | |||
| bbcf5f1aec | |||
| 89876b43b1 | |||
| d3411035d8 | |||
| 6238d69043 | |||
| 21ecdf5dc2 | |||
| f7c4f41b4b | |||
| 9aa32abe7b | |||
| 0619ad125c | |||
| 36e41096ec | |||
| 2379bf0836 | |||
| b212edcc21 | |||
| a6b569a4aa | |||
| 8744ff5645 | |||
| a46770079d | |||
| d30b20de6b | |||
| 1a455945bc | |||
| 4093d575c1 | |||
| 5bc453db7e | |||
| d2cca11144 | |||
| 854005e16d | |||
| 6e3c429be5 | |||
| eef24bb5ff | |||
| 6701f014e9 | |||
| d2c11bd641 | |||
| be120b5eec | |||
| 772b8689b2 | |||
| 764a642a2e | |||
| 2ac737ceba | |||
| d703ee482f | |||
| 6b610bb9a2 | |||
| 35008ef4b5 | |||
| b39006f562 | |||
| 2f394242ad | |||
| e909f207f1 | |||
| d475be7662 | |||
| 7c6a526b7e | |||
| d66054e958 | |||
| a06c331017 | |||
| 4f9f7c3483 | |||
| aac2685e92 | |||
| 1416ebc174 | |||
| c7c401a55b | |||
| b6739440af | |||
| 993ba69c0e | |||
| 309bcaa297 | |||
| e2e4520be3 | |||
| 72e9bd2ec1 | |||
| 594fb4b5d6 | |||
| 485fa9db52 | |||
| 8dcc40f01b | |||
| cb5e3cea23 | |||
| 8ddabbf84a | |||
| c520e4523a | |||
| 043c37ab7e | |||
| 3b7d0721f3 | |||
| 57ea8f1185 | |||
| a514530139 | |||
| 7f94b83893 | |||
| 29a6495d88 | |||
| f2b60c81dd | |||
| 00fa743efa | |||
| 8401ff4b70 | |||
| 776402da13 | |||
| 43ae6b2425 | |||
| c66c3118c3 | |||
| 0d1a1e1c2a | |||
| 9fbfb7ec34 | |||
| daee6b292e | |||
| a471173c9b | |||
| ed34c9f010 | |||
| 03e6adaaec | |||
| 85aeb6f6a6 | |||
| 9fb453a9af | |||
| 3a0ef619ed | |||
| aa52b851fd | |||
| 6b9f23ff00 | |||
| b3eab31a54 | |||
| 6337e0d517 | |||
| 71a0187412 | |||
| 48f4dc49ce | |||
| 0c691460e9 | |||
| 40e5cd57ac | |||
| 582566f3ec | |||
| 5808ab0042 | |||
| 92f5c74f20 | |||
| b1d5fa104f | |||
| 1bad5eb067 | |||
| bc3bb46aa0 | |||
| 2d2699f072 | |||
| b1ff1d607a | |||
| 7fc37ca2e3 | |||
| 5bdcd646bc | |||
| bb713c7c8c | |||
| 2943ef75fe | |||
| 1378c57501 | |||
| cb18296f88 | |||
| 658878a362 | |||
| cb13f4e715 | |||
| e2c2de2447 | |||
| b54840ace0 | |||
| 70f94c4054 | |||
| 4e0c912612 | |||
| 9193972c3b | |||
| 992a1bbbf1 | |||
| 5eac807d10 | |||
| 568d21a816 | |||
| cd36bfa973 | |||
| 1257c675b1 | |||
| 36c223b55c | |||
| 464c3e1541 | |||
| 277f45e249 | |||
| db96bd833c | |||
| 51430b228c | |||
| be398e935c | |||
| 2f56af1cf5 | |||
| 88ab67600d | |||
| e96d83ac7a | |||
| 6bf7d99d5a | |||
| d4231c20e3 | |||
| d9f7d602ee | |||
| 268f6b5306 | |||
| f9fce33c11 | |||
| 586bc2c730 | |||
| dda9d3498e | |||
| 81601ff715 | |||
| a11efbc1a9 | |||
| 442c843264 | |||
| 7194b2c6fd | |||
| f94689522f | |||
| 803dea9844 | |||
| 27a6b81816 | |||
| cf6997c109 | |||
| 3b35b06ee2 | |||
| 8fb1ef12b8 | |||
| 370e28f8a2 | |||
| f0d975d92b | |||
| ecd764be58 | |||
| 1a3ea9a3b1 | |||
| 8d6411a5fc | |||
| ca97194bae | |||
| 69f1ab3299 | |||
| d5bceac21e | |||
| 104c34ff49 | |||
| 0743eb16b6 | |||
| 20d17b48f0 | |||
| 72ce6fbb72 | |||
| 42e70cbdef | |||
| 25f3eac9a6 | |||
| db43f2bccd | |||
| 4fd19a1cd7 | |||
| 012b1a167a | |||
| 65432a1275 | |||
| 3a82fee72a | |||
| 0fd1a6f90f | |||
| 3c03da9a5f | |||
| 9a9d675ada | |||
| b2ff4b088a | |||
| d37105ae89 | |||
| 3bd21e9c3e | |||
| ca1a453107 | |||
| ee058154e8 | |||
| b19c4fc416 | |||
| 294846f706 | |||
| 52ef5c926f | |||
| a5e6ceb76e | |||
| 2d46b17f6c | |||
| 35dc27e805 | |||
| e3b9da27df | |||
| 62b2385eab | |||
| ff769cee01 | |||
| ead119e3c1 | |||
| 34d382fb52 | |||
| 15ecbee4e9 | |||
| 28d9ea3c31 | |||
| 1c98ba6f51 | |||
| cba4b1065e |
@@ -0,0 +1,25 @@
|
||||
name: Check Links
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, dev]
|
||||
pull_request:
|
||||
schedule:
|
||||
# Run daily at 9am UTC
|
||||
- cron: "0 9 * * *"
|
||||
workflow_dispatch: # Allow manual trigger
|
||||
|
||||
jobs:
|
||||
link-checker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Link Checker
|
||||
uses: lycheeverse/lychee-action@v2
|
||||
with:
|
||||
args: "**/*.md"
|
||||
workingDirectory: packages/kilo-docs
|
||||
fail: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,32 @@
|
||||
name: test-vscode
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- "packages/kilo-vscode/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- "packages/kilo-vscode/**"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
name: unit tests
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2404
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
|
||||
- name: Run unit tests
|
||||
working-directory: packages/kilo-vscode
|
||||
run: bun run test:unit
|
||||
@@ -6,6 +6,7 @@ Kilo CLI is an open source AI coding agent that generates code from natural lang
|
||||
- The default branch in this repo is `dev`.
|
||||
- Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
|
||||
- Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility.
|
||||
- You may be running in a git worktree. All changes must be made in your current working directory — never modify files in the main repo checkout.
|
||||
|
||||
## Build and Dev
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Contributing to Kilo CLI
|
||||
|
||||
See [the Documentation for details on contributing](https://kilo.ai/docs/extending/contributing-to-kilo).
|
||||
See [the Documentation for details on contributing](https://kilo.ai/docs/contributing).
|
||||
|
||||
## TL;DR
|
||||
|
||||
|
||||
@@ -1,88 +1 @@
|
||||
<p align="center">
|
||||
<a href="https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code"><img src="https://img.shields.io/badge/VS_Code_Marketplace-007ACC?style=flat&logo=visualstudiocode&logoColor=white" alt="VS Code Marketplace"></a>
|
||||
<a href="https://x.com/kilocode"><img src="https://img.shields.io/badge/kilocode-000000?style=flat&logo=x&logoColor=white" alt="X (Twitter)"></a>
|
||||
<a href="https://blog.kilo.ai"><img src="https://img.shields.io/badge/Blog-555?style=flat&logo=substack&logoColor=white" alt="Substack Blog"></a>
|
||||
<a href="https://kilo.ai/discord"><img src="https://img.shields.io/badge/Join%20Discord-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"></a>
|
||||
<a href="https://www.reddit.com/r/kilocode/"><img src="https://img.shields.io/badge/Join%20r%2Fkilocode-D84315?style=flat&logo=reddit&logoColor=white" alt="Reddit"></a>
|
||||
</p>
|
||||
|
||||
# 🚀 Kilo
|
||||
|
||||
> Kilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.
|
||||
> #1 on OpenRouter. 1.5M+ Kilo Coders. 25T+ tokens processed
|
||||
|
||||
- ✨ Generate code from natural language
|
||||
- ✅ Checks its own work
|
||||
- 🧪 Run terminal commands
|
||||
- 🌐 Automate the browser
|
||||
- ⚡ Inline autocomplete suggestions
|
||||
- 🤖 Latest AI models
|
||||
- 🎁 API keys optional
|
||||
- 💡 **Get $20 in bonus credits when you top-up for the first time** Credits can be used with 500+ models like Gemini 3 Pro, Claude 4.5 Sonnet & Opus, and GPT-5
|
||||
|
||||
<p align="center">
|
||||
<img src="https://media.githubusercontent.com/media/Kilo-Org/kilocode/main/kilo.gif" width="100%" />
|
||||
</p>
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [VS Code Marketplace](https://kilo.ai/vscode-marketplace?utm_source=Readme) (download)
|
||||
- Install CLI: `npm install -g @kilocode/cli`
|
||||
- [Official Kilo.ai Home page](https://kilo.ai) (learn more)
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Code Generation:** Kilo can generate code using natural language.
|
||||
- **Inline Autocomplete:** Get intelligent code completions as you type, powered by AI.
|
||||
- **Task Automation:** Kilo can automate repetitive coding tasks to save time.
|
||||
- **Automated Refactoring:** Kilo can refactor and improve existing code efficiently.
|
||||
- **MCP Server Marketplace**: Kilo can easily find, and use MCP servers to extend the agent capabilities.
|
||||
- **Multi Mode**: Plan with Architect, Code with Coder, and Debug with Debugger, and make your own custom modes.
|
||||
|
||||
## Get Started in Visual Studio Code
|
||||
|
||||
1. Install the Kilo Code extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code).
|
||||
2. Create your account to access 500+ cutting-edge AI models including Gemini 3 Pro, Claude 4.5 Sonnet & Opus, and GPT-5 – with transparent pricing that matches provider rates exactly.
|
||||
3. Start coding with AI that adapts to your workflow. Watch our quick-start guide to see Kilo in action:
|
||||
|
||||
[](https://youtu.be/pqGfYXgrhig)
|
||||
|
||||
## Get Started with the CLI
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install -g @kilocode/cli
|
||||
|
||||
# Or run directly with npx
|
||||
npx @kilocode/cli
|
||||
```
|
||||
|
||||
Then run `kilo` in any project directory to start.
|
||||
|
||||
### Autonomous Mode (CI/CD)
|
||||
|
||||
Use the `--auto` flag with `kilo run` to enable fully autonomous operation without user interaction. This is ideal for CI/CD pipelines and automated workflows:
|
||||
|
||||
```bash
|
||||
kilo run --auto "run tests and fix any failures"
|
||||
```
|
||||
|
||||
**Important:** The `--auto` flag disables all permission prompts and allows the agent to execute any action without confirmation. Only use this in trusted environments like CI/CD pipelines.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions from developers, writers, and enthusiasts!
|
||||
To get started, please read our [Contributing Guide](/CONTRIBUTING.md). It includes details on setting up your environment, coding standards, types of contribution and how to submit pull requests.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Our community is built on respect, inclusivity, and collaboration. Please review our [Code of Conduct](/CODE_OF_CONDUCT.md) to understand the expectations for all contributors and community members.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License.
|
||||
You’re free to use, modify, and distribute this code, including for commercial purposes as long as you include proper attribution and license notices. See [License](/LICENSE).
|
||||
|
||||
### Where did Kilo CLI come from?
|
||||
|
||||
Kilo CLI is a fork of [OpenCode](https://github.com/anomalyco/opencode), enhanced to work within the Kilo agentic engineering platform.
|
||||
This repo has been moved to https://github.com/Kilo-Org/kilocode
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
@@ -75,7 +75,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@opencode-ai/app": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
@@ -108,7 +108,7 @@
|
||||
},
|
||||
"packages/kilo-docs": {
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@docsearch/css": "^4",
|
||||
"@docsearch/js": "^4",
|
||||
@@ -136,7 +136,7 @@
|
||||
},
|
||||
"packages/kilo-gateway": {
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "1.0.0-alpha.1",
|
||||
"@kilocode/plugin": "workspace:*",
|
||||
@@ -168,7 +168,7 @@
|
||||
},
|
||||
"packages/kilo-i18n": {
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
@@ -178,7 +178,7 @@
|
||||
},
|
||||
"packages/kilo-telemetry": {
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
@@ -198,7 +198,7 @@
|
||||
},
|
||||
"packages/kilo-ui": {
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "0.13.11",
|
||||
},
|
||||
@@ -221,13 +221,14 @@
|
||||
},
|
||||
"packages/kilo-vscode": {
|
||||
"name": "kilo-code",
|
||||
"version": "7.0.24",
|
||||
"version": "7.0.25",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.39.0",
|
||||
"@kilocode/kilo-i18n": "workspace:*",
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@thisbeyond/solid-dnd": "0.7.5",
|
||||
"diff": "^7.0.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"eventsource": "^2.0.2",
|
||||
@@ -264,7 +265,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "@kilocode/cli",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"bin": {
|
||||
"kilo": "./bin/kilo",
|
||||
"kilocode": "./bin/kilocode",
|
||||
@@ -374,7 +375,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@kilocode/plugin",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
@@ -388,14 +389,14 @@
|
||||
},
|
||||
"packages/script": {
|
||||
"name": "@opencode-ai/script",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"devDependencies": {
|
||||
"@types/bun": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@kilocode/sdk",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.90.10",
|
||||
"@tsconfig/node22": "catalog:",
|
||||
@@ -406,7 +407,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -448,7 +449,7 @@
|
||||
},
|
||||
"packages/util": {
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"dependencies": {
|
||||
"zod": "catalog:",
|
||||
},
|
||||
|
||||
Generated
+3
-3
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1770073757,
|
||||
"narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=",
|
||||
"lastModified": 1771207753,
|
||||
"narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "47472570b1e607482890801aeaf29bfb749884f6",
|
||||
"rev": "d1c15b7d5806069da59e819999d70e1cec0760bf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
unzip
|
||||
gnutar
|
||||
gzip
|
||||
ripgrep
|
||||
kilo-dev
|
||||
kilo-install-bin
|
||||
kilo-bin
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-LVuT8+lBSeogRYQQHruUJJBeSRw9jd3arXy1GLzg9JM=",
|
||||
"aarch64-linux": "sha256-QDTbTB4Lcc9u5MdEdZZ07GBBbLQkcl2NrwvxRc5WMsk=",
|
||||
"aarch64-darwin": "sha256-skuEhDRrT585MJL58SpPOqnz0ivrlzShCRkA2f/YIxU=",
|
||||
"x86_64-darwin": "sha256-Ocf8Mq9dgniaUlUAs0D/ygggh9ozVr8FydkgDsCsEPI="
|
||||
"x86_64-linux": "sha256-V1SML9naH7HShbdovoQIUc46rH6YNgFF9MSTw95k0fU=",
|
||||
"aarch64-linux": "sha256-wddgxfbK7v7O/zsdbx0e/TNYAw0KzzxyQbuUdwudf/Y=",
|
||||
"aarch64-darwin": "sha256-y7bMXWMSiHTHfKKiJ+c/2WRJmc7mCw2o601Ny8W5Zzs=",
|
||||
"x86_64-darwin": "sha256-hXdKlmVFWq2C0kJWgO1+g82B+/fvn9CG/JQyR31QtzY="
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -102,6 +102,6 @@
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch"
|
||||
},
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ import { test, expect } from "../fixtures"
|
||||
import { promptSelector } from "../selectors"
|
||||
import { closeDialog, openSettings, clickListItem } from "../actions"
|
||||
|
||||
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change start
|
||||
test.skip("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change end
|
||||
await gotoSession()
|
||||
|
||||
await page.locator(promptSelector).click()
|
||||
|
||||
@@ -2,7 +2,9 @@ import { test, expect } from "../fixtures"
|
||||
import { promptSelector } from "../selectors"
|
||||
import { closeDialog, openSettings } from "../actions"
|
||||
|
||||
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change start
|
||||
test.skip("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change end
|
||||
await gotoSession()
|
||||
|
||||
await page.locator(promptSelector).click()
|
||||
@@ -60,7 +62,9 @@ test("hiding a model removes it from the model picker", async ({ page, gotoSessi
|
||||
await expect(pickerAgain).toHaveCount(0)
|
||||
})
|
||||
|
||||
test("showing a hidden model restores it to the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change start
|
||||
test.skip("showing a hidden model restores it to the model picker", async ({ page, gotoSession }) => {
|
||||
// kilocode_change end
|
||||
await gotoSession()
|
||||
|
||||
await page.locator(promptSelector).click()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "kilo"
|
||||
name = "Kilo"
|
||||
description = "The open source coding agent."
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/Kilo-Org/kilo"
|
||||
@@ -11,26 +11,26 @@ name = "Kilo"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -8,4 +8,5 @@ screenshots/
|
||||
.beads/
|
||||
.env
|
||||
next-env.d.ts
|
||||
tsconfig.tsbuildinfo
|
||||
tsconfig.tsbuildinfo
|
||||
lycheeout.*
|
||||
@@ -1,55 +0,0 @@
|
||||
# Full Next.js example
|
||||
|
||||
This is a full-featured boilerplate for a creating a documentation website using Markdoc and Next.js.
|
||||
|
||||
<img width="2032" alt="image" src="https://user-images.githubusercontent.com/62121649/174916143-16f18270-0463-402c-8b48-33c627ea7a7e.png">
|
||||
|
||||
## Setup
|
||||
|
||||
First, clone this repo and install the dependencies required:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
# or
|
||||
yarn install
|
||||
```
|
||||
|
||||
Then, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `index.md`. The page auto-updates as you edit the file.
|
||||
|
||||
## Deploy
|
||||
|
||||
The quickest way to deploy your own version of this boilerplate is by deploying it with [Vercel](https://vercel.com) or [Netlify](https://www.netlify.com/) by clicking one of the buttons below.
|
||||
|
||||
### Deploy with Vercel
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/markdoc/next.js-starter)
|
||||
|
||||
### Deploy to Netlify
|
||||
|
||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/markdoc/next.js-starter)
|
||||
|
||||
## Contributing
|
||||
|
||||
When making documentation _only_ changes, use branch names prefixed with `docs/`:
|
||||
|
||||
```bash
|
||||
git checkout -b docs/your-change-description
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
- `docs/add-mcp-tutorial`
|
||||
- `docs/fix-installation-steps`
|
||||
- `docs/update-api-reference`
|
||||
|
||||
For full contribution guidelines, see the [Contributing Guide](https://kilo.ai/docs/contributing).
|
||||
@@ -34,10 +34,6 @@ export const ContributingNav: NavSection[] = [
|
||||
href: "/contributing/architecture/agent-observability",
|
||||
children: "Agent Observability",
|
||||
},
|
||||
{
|
||||
href: "/contributing/architecture/annual-billing",
|
||||
children: "Annual Billing",
|
||||
},
|
||||
{
|
||||
href: "/contributing/architecture/benchmarking",
|
||||
children: "Benchmarking",
|
||||
|
||||
@@ -41,7 +41,6 @@ export const CustomizeNav: NavSection[] = [
|
||||
href: "/customize/context/kilocodeignore",
|
||||
children: ".kilocodeignore",
|
||||
},
|
||||
{ href: "/customize/context/memory-bank", children: "Memory Bank" },
|
||||
{
|
||||
href: "/customize/context/large-projects",
|
||||
children: "Large Projects",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
root_dir = "."
|
||||
fallback_extensions = ["md"]
|
||||
remap = ["kilo-docs/docs kilo-docs/pages"]
|
||||
|
||||
format = "detailed"
|
||||
max_redirects = 2
|
||||
exclude_path = ["node_modules"]
|
||||
|
||||
accept = [
|
||||
"200",
|
||||
"403",
|
||||
"429",
|
||||
"301",
|
||||
"307",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
'\.png$',
|
||||
'https://synthetic.new/user-settings/api',
|
||||
'https://platform.slack-edge.com/img/add_to_slack.png',
|
||||
'https://console.groq.com/pages/models',
|
||||
'https://glama.ai/settings/gateway/api-keys',
|
||||
'^https?://(api|console)\.mistral\.ai',
|
||||
'^https?://(app|console)\.requesty\.ai',
|
||||
'^https?://(cloud|console)\.google\.ai',
|
||||
'https://opencode.ai/pages/config',
|
||||
'^localhost:3000/'
|
||||
]
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --webpack --port 3002",
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
|
||||
posthog.capture("$pageview")
|
||||
}, [])
|
||||
|
||||
// Close mobile menu on route change and track pageviews
|
||||
// Close mobile menu on route change, track pageviews, and reset scroll position
|
||||
useEffect(() => {
|
||||
const handleRouteChange = () => {
|
||||
setIsMobileMenuOpen(false)
|
||||
@@ -81,6 +81,11 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
|
||||
|
||||
const handleRouteComplete = () => {
|
||||
posthog.capture("$pageview")
|
||||
// Reset scroll position of the main content container on navigation
|
||||
const mainContent = document.querySelector(".main-content")
|
||||
if (mainContent) {
|
||||
mainContent.scrollTop = 0
|
||||
}
|
||||
}
|
||||
|
||||
router.events.on("routeChangeStart", handleRouteChange)
|
||||
@@ -175,7 +180,7 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
|
||||
<div className="article-content flex column mt-5">
|
||||
<Component {...pageProps} />
|
||||
</div>
|
||||
<div className="right-sidebar">
|
||||
<div className="right-sidebar" key={router.asPath}>
|
||||
{markdoc && <CopyPageButton />}
|
||||
<TableOfContents toc={toc} />
|
||||
</div>
|
||||
|
||||
@@ -25,4 +25,4 @@ Kilo Code supports Google's Gemini family of models through the Google AI Gemini
|
||||
## Tips and Notes
|
||||
|
||||
- **Pricing:** Gemini API usage is priced based on input and output tokens. Refer to the [Gemini pricing page](https://ai.google.dev/pricing) for detailed information.
|
||||
- **Codebase Indexing:** The `gemini-embedding-001` model is specifically supported for [codebase indexing](/docs/features/codebase-indexing), providing high-quality embeddings for semantic code search.
|
||||
- **Codebase Indexing:** The `gemini-embedding-001` model is specifically supported for [codebase indexing](/docs/customize/context/codebase-indexing), providing high-quality embeddings for semantic code search.
|
||||
|
||||
@@ -70,4 +70,4 @@ With the Kilo Code provider, if you sign up with Google you can also connect oth
|
||||
- **Latest Models:** Automatic access to the most current frontier coding models
|
||||
- **Support Available:** Contact [hi@kilo.ai](mailto:hi@kilo.ai) for questions about pricing or tokens
|
||||
|
||||
For detailed setup instructions, see [Setting up Kilo Code](/docs/getting-started/setting-up).
|
||||
For detailed setup instructions, see [Setting up Kilo Code](/docs/getting-started/setup-authentication).
|
||||
|
||||
@@ -27,4 +27,3 @@ MiniMax is a global AI foundation model company focused on fast, cost-efficient
|
||||
- **Performance:** MiniMax M2.1 emphasizes fast inference, strong coding ability, and exceptional tool-calling performance.
|
||||
- **Context Window:** MiniMax models support ultra-long context windows suitable for large codebases and agent workflows.
|
||||
- **Pricing:** Pricing varies by model, with input costs ranging from $0.20 to $0.30 per million tokens and output costs from $1.10 to $2.20 per million tokens. Refer to the MiniMax documentation for the most current pricing information.
|
||||
- **MiniMax M2.1** is currently available for free exclusively for [Kilo for Slack](/docs/slack).
|
||||
|
||||
@@ -4,7 +4,7 @@ sidebar_label: VS Code Language Model API
|
||||
|
||||
# Using VS Code Language Model API With Kilo Code
|
||||
|
||||
Kilo Code includes _experimental_ support for the [VS Code Language Model API](https://code.visualstudio.com/api/language-extensions/language-model-access). This API allows extensions to provide access to language models directly within VS Code. This means you can potentially use models from:
|
||||
Kilo Code includes _experimental_ support for the [VS Code Language Model API](https://code.visualstudio.com/docs/copilot/customization/language-models). This API allows extensions to provide access to language models directly within VS Code. This means you can potentially use models from:
|
||||
|
||||
- **GitHub Copilot:** If you have a Copilot subscription and the extension installed.
|
||||
- **Other VS Code Extensions:** Any extension that implements the Language Model API.
|
||||
|
||||
@@ -194,4 +194,4 @@ For additional support:
|
||||
|
||||
- Visit the [ZenMux documentation](https://zenmux.ai/docs)
|
||||
- Contact ZenMux support through their dashboard
|
||||
- Check the [Kilo Code GitHub repository](https://github.com/kilocode/kilocode) for integration-specific issues
|
||||
- Check the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilo) for integration-specific issues
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import { Nav } from "../../lib/nav"
|
||||
import type { NavLink, NavSection } from "../../lib/types"
|
||||
|
||||
/**
|
||||
* Recursively finds all markdown files in a directory
|
||||
@@ -37,6 +39,51 @@ function filePathToUrlPath(filePath: string, pagesDir: string): string {
|
||||
return "/" + relativePath
|
||||
}
|
||||
|
||||
function extractFrontmatterTitle(content: string): string | null {
|
||||
const match = content.match(/^---\n[\s\S]*?^title:\s*"?([^"\n]+)"?\s*$[\s\S]*?^---\n/m)
|
||||
if (!match) return null
|
||||
return match[1]?.trim() || null
|
||||
}
|
||||
|
||||
function buildTitleMap(markdownFiles: string[], pagesDir: string) {
|
||||
const map = new Map<string, string>()
|
||||
|
||||
for (const filePath of markdownFiles) {
|
||||
const urlPath = filePathToUrlPath(filePath, pagesDir)
|
||||
const content = fs.readFileSync(filePath, "utf-8")
|
||||
const title = extractFrontmatterTitle(content)
|
||||
if (title) {
|
||||
map.set(urlPath, title)
|
||||
}
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
function addNavLink(items: string[], link: NavLink, baseUrl: string, depth: number, titleMap: Map<string, string>) {
|
||||
const indent = " ".repeat(depth)
|
||||
const rawUrl = `${baseUrl}/api/raw-markdown?path=${encodeURIComponent(link.href)}`
|
||||
const title = titleMap.get(link.href) || link.children
|
||||
items.push(`${indent}- [${title}](${rawUrl})`)
|
||||
|
||||
if (link.subLinks) {
|
||||
for (const subLink of link.subLinks) {
|
||||
addNavLink(items, subLink, baseUrl, depth + 1, titleMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNavSection(items: string[], section: NavSection, baseUrl: string, titleMap: Map<string, string>) {
|
||||
items.push(`### ${section.title}`)
|
||||
items.push("")
|
||||
|
||||
for (const link of section.links) {
|
||||
addNavLink(items, link, baseUrl, 0, titleMap)
|
||||
}
|
||||
|
||||
items.push("")
|
||||
}
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" })
|
||||
@@ -58,6 +105,38 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
"This file contains the complete documentation for Kilo Code, the leading open source agentic engineering platform.",
|
||||
)
|
||||
sections.push("")
|
||||
const protocol = req.headers["x-forwarded-proto"] || "https"
|
||||
const host = req.headers.host || "kilo.ai"
|
||||
const baseUrl = `${protocol}://${host}`
|
||||
const titleMap = buildTitleMap(markdownFiles, pagesDir)
|
||||
|
||||
sections.push("## Page Index")
|
||||
sections.push("")
|
||||
sections.push("Each page is available as raw markdown via the /api/raw-markdown endpoint.")
|
||||
sections.push("")
|
||||
|
||||
const navGroups = [
|
||||
{ title: "Getting Started", nav: Nav.GettingStartedNav },
|
||||
{ title: "Code with AI", nav: Nav.CodeWithAiNav },
|
||||
{ title: "Customize", nav: Nav.CustomizeNav },
|
||||
{ title: "Collaborate", nav: Nav.CollaborateNav },
|
||||
{ title: "Automate", nav: Nav.AutomateNav },
|
||||
{ title: "Deploy & Secure", nav: Nav.DeploySecureNav },
|
||||
{ title: "Contributing", nav: Nav.ContributingNav },
|
||||
{ title: "AI Providers", nav: Nav.AiProvidersNav },
|
||||
{ title: "Gateway", nav: Nav.GatewayNav },
|
||||
{ title: "Tools", nav: Nav.ToolsNav },
|
||||
]
|
||||
|
||||
for (const group of navGroups) {
|
||||
sections.push(`## ${group.title}`)
|
||||
sections.push("")
|
||||
|
||||
for (const section of group.nav) {
|
||||
addNavSection(sections, section, baseUrl, titleMap)
|
||||
}
|
||||
}
|
||||
|
||||
sections.push("---")
|
||||
sections.push("")
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ This page reflects the actual implementation in the extension.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Install/update the Kilo Code CLI (latest) — see [CLI setup](/docs/cli)
|
||||
- Install/update the Kilo Code CLI (latest) — see [CLI setup](/docs/code-with-ai/platforms/cli)
|
||||
- Open a project in VS Code (workspace required)
|
||||
- Authentication: You must be logged in via the extension settings OR use CLI with kilocode as provider (see [Authentication Requirements](#authentication-requirements))
|
||||
|
||||
@@ -102,7 +102,7 @@ The Agent Manager requires proper authentication for full functionality, includi
|
||||
2. **CLI with Kilo Code Provider**
|
||||
- Use the CLI configured with `kilocode` as the provider
|
||||
- Run `kilocode config` to set up authentication
|
||||
- See [CLI setup](/docs/cli) for details
|
||||
- See [CLI setup](/docs/code-with-ai/platforms/cli) for details
|
||||
|
||||
### BYOK Limitations
|
||||
|
||||
@@ -131,7 +131,7 @@ Message transcripts are fetched from a signed blob and exclude internal checkpoi
|
||||
## Troubleshooting
|
||||
|
||||
- CLI not found or outdated
|
||||
- Install/update the CLI: [CLI setup](/docs/cli)
|
||||
- Install/update the CLI: [CLI setup](/docs/code-with-ai/platforms/cli)
|
||||
- If you see an "unknown option --json-io" error, update to the latest CLI
|
||||
- "Please open a folder…" error
|
||||
- The Agent Manager requires a VS Code workspace folder
|
||||
@@ -146,6 +146,6 @@ Message transcripts are fetched from a signed blob and exclude internal checkpoi
|
||||
|
||||
## Related features
|
||||
|
||||
- [Sessions](/docs/advanced-usage/sessions)
|
||||
- [Auto-approving Actions](/docs/features/auto-approving-actions)
|
||||
- [CLI](/docs/cli)
|
||||
- [Sessions](/docs/collaborate/sessions-sharing)
|
||||
- [Auto-approving Actions](/docs/getting-started/settings/auto-approving-actions)
|
||||
- [CLI](/docs/code-with-ai/platforms/cli)
|
||||
|
||||
@@ -30,8 +30,8 @@ Kilo Code currently supports two main local model providers:
|
||||
|
||||
For detailed setup instructions, see:
|
||||
|
||||
- [Setting up Ollama](/docs/providers/ollama)
|
||||
- [Setting up LM Studio](/docs/providers/lmstudio)
|
||||
- [Setting up Ollama](/docs/ai-providers/ollama)
|
||||
- [Setting up LM Studio](/docs/ai-providers/lmstudio)
|
||||
|
||||
Both providers offer similar capabilities but with different user interfaces and workflows. Ollama provides more control through its command-line interface, while LM Studio offers a more user-friendly graphical interface.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Terminal Shell Integration is a key feature that enables Kilo Code to execute co
|
||||
|
||||
Shell integration is automatically enabled in Kilo Code and connects directly to your terminal's command execution lifecycle without requiring any setup from you. This built-in feature allows Kilo Code to:
|
||||
|
||||
- Execute commands on your behalf through the [`execute_command`](/docs/features/tools/execute-command) tool
|
||||
- Execute commands on your behalf through the [`execute_command`](/docs/automate/tools/execute-command) tool
|
||||
- Read command output in real-time without manual copy-pasting
|
||||
- Automatically detect and fix errors in running applications
|
||||
- Observe command exit codes to determine success or failure
|
||||
|
||||
@@ -86,4 +86,4 @@ This safety mechanism ensures you maintain control over which files are modified
|
||||
|
||||
## Learn More About Tools
|
||||
|
||||
For more detailed information about each tool, including complete parameter references and advanced usage patterns, see the [Tool Use Overview](/docs/features/tools/tool-use-overview) documentation.
|
||||
For more detailed information about each tool, including complete parameter references and advanced usage patterns, see the [Tool Use Overview](/docs/automate/tools) documentation.
|
||||
|
||||
@@ -58,6 +58,22 @@ Once created, you can control your instance from the dashboard.
|
||||
| **Settings** | Model configuration and instance parameters |
|
||||
| **Actions** | Quick actions and connected platform management |
|
||||
|
||||
### Changelog
|
||||
|
||||
Your instance page includes a changelog with recent KiloClaw platform updates.
|
||||
|
||||
Each changelog entry is labeled by update type:
|
||||
|
||||
- **Feature** — New capability or enhancement
|
||||
- **Bug** — Fix for incorrect or broken behavior
|
||||
|
||||
Some entries also include a redeploy label:
|
||||
|
||||
- **Redeploy required** — You must redeploy your instance to fully take advantage of the change
|
||||
- **Redeploy suggested** — Redeploy is optional and only needed if you want to use the new behavior
|
||||
|
||||
For example, if you manually configured a channel such as Telegram, and would prefer to have KiloClaw manage the channel for you, you would need to redeploy.
|
||||
|
||||
## Accessing Your Agent
|
||||
|
||||
To connect to your agent's web interface:
|
||||
|
||||
@@ -170,7 +170,7 @@ To set the maximum time to wait for a response after a tool call to the MCP serv
|
||||
|
||||
MCP tool auto-approval works on a per-tool basis and is disabled by default. To configure auto-approval:
|
||||
|
||||
1. First enable the global "Use MCP servers" auto-approval option in [auto-approving-actions](/docs/features/auto-approving-actions)
|
||||
1. First enable the global "Use MCP servers" auto-approval option in [auto-approving-actions](/docs/getting-started/settings/auto-approving-actions)
|
||||
2. Navigate to Settings > Agent Behaviour > MCP Servers, then locate the specific tool you want to auto-approve
|
||||
3. Check the `Always allow` checkbox next to the tool name
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# codebase_search
|
||||
|
||||
{% callout type="info" title="Setup Required" %}
|
||||
The `codebase_search` tool is part of the [Codebase Indexing](/docs/features/codebase-indexing) feature. It requires additional setup including an embedding provider and vector database.
|
||||
The `codebase_search` tool is part of the [Codebase Indexing](/docs/customize/context/codebase-indexing) feature. It requires additional setup including an embedding provider and vector database.
|
||||
{% /callout %}
|
||||
|
||||
The `codebase_search` tool performs semantic searches across your entire codebase using AI embeddings. Unlike traditional text-based search, it understands the meaning of your queries and finds relevant code even when exact keywords don't match.
|
||||
|
||||
@@ -15,22 +15,22 @@ Tools are organized into logical groups based on their functionality:
|
||||
|
||||
| Category | Purpose | Tools | Common Use |
|
||||
| ------------------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
|
||||
| **Read Group** | File system reading and searching | [read_file](/docs/features/tools/read-file), [search_files](/docs/features/tools/search-files), [list_files](/docs/features/tools/list-files), [list_code_definition_names](/docs/features/tools/list-code-definition-names) | Code exploration and analysis |
|
||||
| **Edit Group** | File system modifications | [apply_diff](/docs/features/tools/apply-diff), [delete_file](/docs/features/tools/delete-file), [write_to_file](/docs/features/tools/write-to-file) | Code changes and file manipulation |
|
||||
| **Browser Group** | Web automation | [browser_action](/docs/features/tools/browser-action) | Web testing and interaction |
|
||||
| **Command Group** | System command execution | [execute_command](/docs/features/tools/execute-command) | Running scripts, building projects |
|
||||
| **MCP Group** | External tool integration | [use_mcp_tool](/docs/features/tools/use-mcp-tool), [access_mcp_resource](/docs/features/tools/access-mcp-resource) | Specialized functionality through external servers |
|
||||
| **Workflow Group** | Mode and task management | [switch_mode](/docs/features/tools/switch-mode), [new_task](/docs/features/tools/new-task), [ask_followup_question](/docs/features/tools/ask-followup-question), [attempt_completion](/docs/features/tools/attempt-completion), [update_todo_list](/docs/features/tools/update-todo-list) | Context switching and task organization |
|
||||
| **Read Group** | File system reading and searching | [read_file](/docs/automate/tools/read-file), [search_files](/docs/automate/tools/search-files), [list_files](/docs/automate/tools/list-files), [list_code_definition_names](/docs/automate/tools/list-code-definition-names) | Code exploration and analysis |
|
||||
| **Edit Group** | File system modifications | [apply_diff](/docs/automate/tools/apply-diff), [delete_file](/docs/automate/tools/delete-file), [write_to_file](/docs/automate/tools/write-to-file) | Code changes and file manipulation |
|
||||
| **Browser Group** | Web automation | [browser_action](/docs/automate/tools/browser-action) | Web testing and interaction |
|
||||
| **Command Group** | System command execution | [execute_command](/docs/automate/tools/execute-command) | Running scripts, building projects |
|
||||
| **MCP Group** | External tool integration | [use_mcp_tool](/docs/automate/tools/use-mcp-tool), [access_mcp_resource](/docs/automate/tools/access-mcp-resource) | Specialized functionality through external servers |
|
||||
| **Workflow Group** | Mode and task management | [switch_mode](/docs/automate/tools/switch-mode), [new_task](/docs/automate/tools/new-task), [ask_followup_question](/docs/automate/tools/ask-followup-question), [attempt_completion](/docs/automate/tools/attempt-completion), [update_todo_list](/docs/automate/tools/update-todo-list) | Context switching and task organization |
|
||||
|
||||
### Always Available Tools
|
||||
|
||||
Certain tools are accessible regardless of the current mode:
|
||||
|
||||
- [ask_followup_question](/docs/features/tools/ask-followup-question): Gather additional information from users
|
||||
- [attempt_completion](/docs/features/tools/attempt-completion): Signal task completion
|
||||
- [switch_mode](/docs/features/tools/switch-mode): Change operational modes
|
||||
- [new_task](/docs/features/tools/new-task): Create subtasks
|
||||
- [update_todo_list](/docs/features/tools/update-todo-list): Manage step-by-step task tracking
|
||||
- [ask_followup_question](/docs/automate/tools/ask-followup-question): Gather additional information from users
|
||||
- [attempt_completion](/docs/automate/tools/attempt-completion): Signal task completion
|
||||
- [switch_mode](/docs/automate/tools/switch-mode): Change operational modes
|
||||
- [new_task](/docs/automate/tools/new-task): Create subtasks
|
||||
- [update_todo_list](/docs/automate/tools/update-todo-list): Manage step-by-step task tracking
|
||||
|
||||
## Available Tools
|
||||
|
||||
@@ -38,47 +38,47 @@ Certain tools are accessible regardless of the current mode:
|
||||
|
||||
These tools help Kilo Code understand your code and project:
|
||||
|
||||
- [read_file](/docs/features/tools/read-file) - Examines the contents of files
|
||||
- [search_files](/docs/features/tools/search-files) - Finds patterns across multiple files
|
||||
- [list_files](/docs/features/tools/list-files) - Maps your project's file structure
|
||||
- [list_code_definition_names](/docs/features/tools/list-code-definition-names) - Creates a structural map of your code
|
||||
- [read_file](/docs/automate/tools/read-file) - Examines the contents of files
|
||||
- [search_files](/docs/automate/tools/search-files) - Finds patterns across multiple files
|
||||
- [list_files](/docs/automate/tools/list-files) - Maps your project's file structure
|
||||
- [list_code_definition_names](/docs/automate/tools/list-code-definition-names) - Creates a structural map of your code
|
||||
|
||||
### Edit Tools
|
||||
|
||||
These tools help Kilo Code make changes to your code:
|
||||
|
||||
- [apply_diff](/docs/features/tools/apply-diff) - Makes precise, surgical changes to your code
|
||||
- [delete_file](/docs/features/tools/delete-file) - Removes files from your workspace
|
||||
- [write_to_file](/docs/features/tools/write-to-file) - Creates new files or completely rewrites existing ones
|
||||
- [apply_diff](/docs/automate/tools/apply-diff) - Makes precise, surgical changes to your code
|
||||
- [delete_file](/docs/automate/tools/delete-file) - Removes files from your workspace
|
||||
- [write_to_file](/docs/automate/tools/write-to-file) - Creates new files or completely rewrites existing ones
|
||||
|
||||
### Browser Tools
|
||||
|
||||
These tools help Kilo Code interact with web applications:
|
||||
|
||||
- [browser_action](/docs/features/tools/browser-action) - Automates browser interactions
|
||||
- [browser_action](/docs/automate/tools/browser-action) - Automates browser interactions
|
||||
|
||||
### Command Tools
|
||||
|
||||
These tools help Kilo Code execute commands:
|
||||
|
||||
- [execute_command](/docs/features/tools/execute-command) - Runs system commands and programs
|
||||
- [execute_command](/docs/automate/tools/execute-command) - Runs system commands and programs
|
||||
|
||||
### MCP Tools
|
||||
|
||||
These tools help Kilo Code connect with external services:
|
||||
|
||||
- [use_mcp_tool](/docs/features/tools/use-mcp-tool) - Uses specialized external tools
|
||||
- [access_mcp_resource](/docs/features/tools/access-mcp-resource) - Accesses external data sources
|
||||
- [use_mcp_tool](/docs/automate/tools/use-mcp-tool) - Uses specialized external tools
|
||||
- [access_mcp_resource](/docs/automate/tools/access-mcp-resource) - Accesses external data sources
|
||||
|
||||
### Workflow Tools
|
||||
|
||||
These tools help manage the conversation and task flow:
|
||||
|
||||
- [ask_followup_question](/docs/features/tools/ask-followup-question) - Gets additional information from you
|
||||
- [attempt_completion](/docs/features/tools/attempt-completion) - Presents final results
|
||||
- [switch_mode](/docs/features/tools/switch-mode) - Changes to a different mode for specialized tasks
|
||||
- [new_task](/docs/features/tools/new-task) - Creates a new subtask
|
||||
- [update_todo_list](/docs/features/tools/update-todo-list) - Tracks task progress with step-by-step checklists
|
||||
- [ask_followup_question](/docs/automate/tools/ask-followup-question) - Gets additional information from you
|
||||
- [attempt_completion](/docs/automate/tools/attempt-completion) - Presents final results
|
||||
- [switch_mode](/docs/automate/tools/switch-mode) - Changes to a different mode for specialized tasks
|
||||
- [new_task](/docs/automate/tools/new-task) - Creates a new subtask
|
||||
- [update_todo_list](/docs/automate/tools/update-todo-list) - Tracks task progress with step-by-step checklists
|
||||
|
||||
## Tool Calling Mechanism
|
||||
|
||||
@@ -211,24 +211,24 @@ Tools are made available based on the current mode:
|
||||
1. **Information Gathering**
|
||||
|
||||
```
|
||||
[ask_followup_question](/docs/features/tools/ask-followup-question) → [read_file](/docs/features/tools/read-file) → [search_files](/docs/features/tools/search-files)
|
||||
[ask_followup_question](/docs/automate/tools/ask-followup-question) → [read_file](/docs/automate/tools/read-file) → [search_files](/docs/automate/tools/search-files)
|
||||
```
|
||||
|
||||
2. **Code Modification**
|
||||
|
||||
```
|
||||
[read_file](/docs/features/tools/read-file) → [apply_diff](/docs/features/tools/apply-diff) → [attempt_completion](/docs/features/tools/attempt-completion)
|
||||
[read_file](/docs/automate/tools/read-file) → [apply_diff](/docs/automate/tools/apply-diff) → [attempt_completion](/docs/automate/tools/attempt-completion)
|
||||
```
|
||||
|
||||
3. **Task Management**
|
||||
|
||||
```
|
||||
[new_task](/docs/features/tools/new-task) → [switch_mode](/docs/features/tools/switch-mode) → [execute_command](/docs/features/tools/execute-command)
|
||||
[new_task](/docs/automate/tools/new-task) → [switch_mode](/docs/automate/tools/switch-mode) → [execute_command](/docs/automate/tools/execute-command)
|
||||
```
|
||||
|
||||
4. **Progress Tracking**
|
||||
```
|
||||
[update_todo_list](/docs/features/tools/update-todo-list) → [execute_command](/docs/features/tools/execute-command) → [update_todo_list](/docs/features/tools/update-todo-list)
|
||||
[update_todo_list](/docs/automate/tools/update-todo-list) → [execute_command](/docs/automate/tools/execute-command) → [update_todo_list](/docs/automate/tools/update-todo-list)
|
||||
```
|
||||
|
||||
## Error Handling and Recovery
|
||||
|
||||
@@ -10,7 +10,7 @@ description: "Learn how to use the Kilo Code chat interface effectively"
|
||||
{% /callout %}
|
||||
|
||||
{% callout type="note" title="Prefer quick completions?" %}
|
||||
If you're typing code in the editor and want AI to finish your line or block, check out [Autocomplete](/docs/basic-usage/autocomplete) instead. Chat is best for larger tasks, explanations, and multi-file changes.
|
||||
If you're typing code in the editor and want AI to finish your line or block, check out [Autocomplete](/docs/code-with-ai/features/autocomplete) instead. Chat is best for larger tasks, explanations, and multi-file changes.
|
||||
{% /callout %}
|
||||
|
||||
## Quick Setup
|
||||
@@ -41,7 +41,7 @@ Find the Kilo Code icon ({% kilo-code-icon /%}) in VS Code's Primary Side Bar. C
|
||||
{% callout type="info" title="Chat vs Autocomplete" %}
|
||||
**Use chat** when you need to describe what you want, ask questions, or make changes across multiple files.
|
||||
|
||||
**Use [autocomplete](/docs/basic-usage/autocomplete)** when you're already typing code and want the AI to finish your thought inline.
|
||||
**Use [autocomplete](/docs/code-with-ai/features/autocomplete)** when you're already typing code and want the AI to finish your thought inline.
|
||||
{% /callout %}
|
||||
|
||||
## The Chat Interface
|
||||
@@ -73,19 +73,19 @@ Find the Kilo Code icon ({% kilo-code-icon /%}) in VS Code's Primary Side Bar. C
|
||||
|
||||
## Common Mistakes to Avoid
|
||||
|
||||
| Instead of this... | Try this |
|
||||
| --------------------------------- | ------------------------------------------------------------------------- |
|
||||
| "Fix the code" | "Fix the bug in `calculateTotal` that returns incorrect results" |
|
||||
| Assuming Kilo knows context | Use `@` to reference specific files |
|
||||
| Multiple unrelated tasks | Submit one focused request at a time |
|
||||
| Technical jargon overload | Clear, straightforward language works best |
|
||||
| Using chat for tiny code changes. | Use [autocomplete](/docs/basic-usage/autocomplete) for inline completions |
|
||||
| Instead of this... | Try this |
|
||||
| --------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| "Fix the code" | "Fix the bug in `calculateTotal` that returns incorrect results" |
|
||||
| Assuming Kilo knows context | Use `@` to reference specific files |
|
||||
| Multiple unrelated tasks | Submit one focused request at a time |
|
||||
| Technical jargon overload | Clear, straightforward language works best |
|
||||
| Using chat for tiny code changes. | Use [autocomplete](/docs/code-with-ai/features/autocomplete) for inline completions |
|
||||
|
||||
**Why it matters:** Kilo Code works best when you communicate like you're talking to a smart teammate who needs clear direction.
|
||||
|
||||
## Suggested Responses
|
||||
|
||||
When Kilo Code needs more information to complete a task, it uses the [`ask_followup_question`](/docs/features/tools/ask-followup-question) tool. To make responding easier and faster, Kilo Code often provides suggested answers alongside the question.
|
||||
When Kilo Code needs more information to complete a task, it uses the [`ask_followup_question`](/docs/automate/tools/ask-followup-question) tool. To make responding easier and faster, Kilo Code often provides suggested answers alongside the question.
|
||||
|
||||
{% image src="/docs/img/suggested-responses/suggested-responses.png" alt="Example of Kilo Code asking a question with suggested response buttons below it" width="800" caption="Suggested responses appear as clickable buttons below questions" /%}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ When you need more capability than free models provide, these options deliver ex
|
||||
**Strategic file mentions:**
|
||||
|
||||
- Only include files directly relevant to the task
|
||||
- Use [`@folder/`](/docs/basic-usage/context-mentions) for broad context, specific files for targeted work
|
||||
- Use [`@folder/`](/docs/code-with-ai/agents/context-mentions) for broad context, specific files for targeted work
|
||||
|
||||
### Model Switching Strategies
|
||||
|
||||
@@ -233,7 +233,7 @@ When you need more capability than free models provide, these options deliver ex
|
||||
|
||||
**Optimize conversation length:**
|
||||
|
||||
- Use [Checkpoints](/docs/features/checkpoints) to reset context
|
||||
- Use [Checkpoints](/docs/code-with-ai/features/checkpoints) to reset context
|
||||
- Start fresh conversations for unrelated tasks
|
||||
- Archive completed work
|
||||
|
||||
@@ -257,19 +257,19 @@ When you need more capability than free models provide, these options deliver ex
|
||||
|
||||
**Free tier foundation:**
|
||||
|
||||
- [OpenRouter](/docs/providers/openrouter) - Free models
|
||||
- [Groq](/docs/providers/groq) - Fast inference for supported models
|
||||
- [OpenRouter](/docs/ai-providers/openrouter) - Free models
|
||||
- [Groq](/docs/ai-providers/groq) - Fast inference for supported models
|
||||
- [Z.ai](https://z.ai/model-api) - Provides a free model GLM-4.5-Flash
|
||||
|
||||
**Budget tier options:**
|
||||
|
||||
- [DeepSeek](/docs/providers/deepseek) - Excellent value models
|
||||
- [Mistral](/docs/providers/mistral) - Specialized coding models
|
||||
- [DeepSeek](/docs/ai-providers/deepseek) - Excellent value models
|
||||
- [Mistral](/docs/ai-providers/mistral) - Specialized coding models
|
||||
|
||||
**Premium tier backup:**
|
||||
|
||||
- [Anthropic](/docs/providers/anthropic) - Claude for complex reasoning
|
||||
- [OpenAI](/docs/providers/openai) - GPT-4 for critical tasks
|
||||
- [Anthropic](/docs/ai-providers/anthropic) - Claude for complex reasoning
|
||||
- [OpenAI](/docs/ai-providers/openai) - GPT-4 for critical tasks
|
||||
|
||||
## Measuring Success
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ One thing that doesn't change: context window size matters for your workflow.
|
||||
- **Large codebases**: 256K+ tokens helps with cross-system understanding
|
||||
- **Massive systems**: 1M+ token models exist but effectiveness degrades at the extremes
|
||||
|
||||
Check [our provider docs](/docs/basic-usage/connecting-providers) for specific context limits on each model.
|
||||
Check [our provider docs](/docs/ai-providers) for specific context limits on each model.
|
||||
|
||||
{% callout type="tip" %}
|
||||
**Be thoughtful about Max Tokens settings for thinking models.** Every token you allocate to output takes away from space available to store conversation history. Consider only using high `Max Tokens` / `Max Thinking Tokens` settings with modes like Architect and Debug, and keeping Code mode at 16k max tokens or less.
|
||||
|
||||
@@ -25,7 +25,7 @@ Orchestrator Mode (formerly known as Boomerang Tasks) allows you to break down c
|
||||
|
||||
## Key Considerations
|
||||
|
||||
- **Approval Required:** By default, you must approve the creation and completion of each subtask. This can be automated via the [Auto-Approving Actions](/docs/features/auto-approving-actions#subtasks) settings if desired.
|
||||
- **Approval Required:** By default, you must approve the creation and completion of each subtask. This can be automated via the [Auto-Approving Actions](/docs/getting-started/settings/auto-approving-actions#subtasks) settings if desired.
|
||||
- **Context Isolation and Transfer:** Each subtask operates in complete isolation with its own conversation history. It does not automatically inherit the parent's context. Information must be explicitly passed:
|
||||
- **Down:** Via the initial instructions provided when the subtask is created.
|
||||
- **Up:** Via the final summary provided when the subtask finishes. Be mindful that only this summary returns to the parent.
|
||||
@@ -37,6 +37,6 @@ Orchestrator Mode provides a powerful way to manage complex development workflow
|
||||
Use subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.
|
||||
{% /callout %}
|
||||
|
||||
1. This context is passed via the `message` parameter of the [`new_task`](/docs/features/tools/new-task) tool.
|
||||
2. The mode for the subtask is specified via the `mode` parameter of the [`new_task`](/docs/features/tools/new-task) tool during initiation.
|
||||
3. This summary is passed via the `result` parameter of the [`attempt_completion`](/docs/features/tools/attempt-completion) tool when the subtask finishes.
|
||||
1. This context is passed via the `message` parameter of the [`new_task`](/docs/automate/tools/new-task) tool.
|
||||
2. The mode for the subtask is specified via the `mode` parameter of the [`new_task`](/docs/automate/tools/new-task) tool during initiation.
|
||||
3. This summary is passed via the `result` parameter of the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool when the subtask finishes.
|
||||
|
||||
@@ -114,4 +114,4 @@ If using Cursor, go to **Settings** > **Cursor Settings** > **Tab**, and toggle
|
||||
|
||||
## Related Features
|
||||
|
||||
- [Code Actions](/docs/features/code-actions) - Context menu options for common coding tasks
|
||||
- [Code Actions](/docs/code-with-ai/features/code-actions) - Context menu options for common coding tasks
|
||||
|
||||
@@ -23,7 +23,7 @@ When **Enable editing through diffs** is checked:
|
||||
2. **Prevents Truncated Writes**: The system automatically detects and rejects attempts by the AI to write incomplete file content, which can happen with large files or complex instructions. This helps prevent corrupted files.
|
||||
|
||||
{% callout type="note" title="Disabling Fast Edits" %}
|
||||
If you uncheck **Enable editing through diffs**, Kilo will revert to writing the entire file content for every edit using the [`write_to_file`](/docs/features/tools/write-to-file) tool, instead of applying targeted changes with [`apply_diff`](/docs/features/tools/apply-diff). This full-write approach is generally slower for modifying existing files and leads to higher token usage.
|
||||
If you uncheck **Enable editing through diffs**, Kilo will revert to writing the entire file content for every edit using the [`write_to_file`](/docs/automate/tools/write-to-file) tool, instead of applying targeted changes with [`apply_diff`](/docs/automate/tools/apply-diff). This full-write approach is generally slower for modifying existing files and leads to higher token usage.
|
||||
{% /callout %}
|
||||
|
||||
## Match Precision
|
||||
|
||||
@@ -21,7 +21,7 @@ description: "Track and manage tasks with AI-generated todo lists"
|
||||
|
||||
**Manual triggers**:
|
||||
|
||||
- Ask Kilo to "use the [update_todo_list tool](/docs/features/tools/update-todo-list)"
|
||||
- Ask Kilo to "use the [update_todo_list tool](/docs/automate/tools/update-todo-list)"
|
||||
- Say "create a todo list"
|
||||
|
||||
**The bottom line**: Kilo decides what goes in the list, but you can provide feedback during approval dialogs.
|
||||
@@ -30,7 +30,7 @@ description: "Track and manage tasks with AI-generated todo lists"
|
||||
|
||||
## How todo lists are updated
|
||||
|
||||
Todo lists are managed with the [`update_todo_list` tool](/docs/features/tools/update-todo-list). Each time Kilo updates the list, it replaces the entire checklist with the latest view of the task.
|
||||
Todo lists are managed with the [`update_todo_list` tool](/docs/automate/tools/update-todo-list). Each time Kilo updates the list, it replaces the entire checklist with the latest view of the task.
|
||||
|
||||
Kilo updates the list when:
|
||||
|
||||
@@ -113,7 +113,7 @@ You can disable todo lists in Settings -> Advanced -> **Enable todo list tool**.
|
||||
|
||||
**When to use it**: Long workflows where constant interruptions slow you down.
|
||||
|
||||
**How to enable it**: Check the [Update Todo List auto-approval settings](/docs/features/auto-approving-actions#update-todo-list).
|
||||
**How to enable it**: Check the [Update Todo List auto-approval settings](/docs/getting-started/settings/auto-approving-actions#update-todo-list).
|
||||
|
||||
**The catch**: Less control, but faster execution.
|
||||
{% /callout %}
|
||||
|
||||
@@ -167,7 +167,7 @@ Review your code locally before pushing — catch issues early without waiting f
|
||||
Configuration is managed through:
|
||||
|
||||
- `/connect` command for provider setup (interactive)
|
||||
- Config files in **`~/.config/kilo/`**: the CLI (Kilo CLI 1.0 from [Kilo-Org/kilo](https://github.com/Kilo-Org/kilo)) merges `config.json`, `opencode.json`, and `opencode.jsonc`. Use **`opencode.json`** (or `opencode.jsonc`) for provider, model, permission, and **MCP** settings. Restart the CLI after editing. See [Using MCP in the CLI](/automate/mcp/using-in-cli) for MCP config format.
|
||||
- Config files in **`~/.config/kilo/`**: the CLI (Kilo CLI 1.0 from [Kilo-Org/kilo](https://github.com/Kilo-Org/kilo)) merges `config.json`, `opencode.json`, and `opencode.jsonc`. Use **`opencode.json`** (or `opencode.jsonc`) for provider, model, permission, and **MCP** settings. Restart the CLI after editing. See [Using MCP in the CLI](/docs/automate/mcp/using-in-cli) for MCP config format.
|
||||
- `kilo auth` for credential management
|
||||
|
||||
## Slash Commands
|
||||
@@ -345,20 +345,6 @@ Use `{env:VARIABLE_NAME}` syntax in config files to reference environment variab
|
||||
|
||||
For full details on all configuration options including compaction, file watchers, plugins, and experimental features, see the [OpenCode Config documentation](https://opencode.ai/docs/config).
|
||||
|
||||
## Config reference for providers
|
||||
|
||||
Kilo gives you the ability to bring your own keys for a number of model providers and AI gateways, like OpenRouter and Vercel AI Gateway. Each provider has unique configuration options and some let you set environment variables.
|
||||
|
||||
You can reference the [Provider Configuration Guide](https://github.com/Kilo-Org/kilocode/blob/main/cli/docs/PROVIDER_CONFIGURATION.md) for examples (same config format; for Kilo CLI 1.0 the file is `~/.config/kilo/opencode.json`). You can also run:
|
||||
|
||||
`kilo config`
|
||||
|
||||
to complete configuration with an interactive workflow on the command line.
|
||||
|
||||
{% callout type="tip" %}
|
||||
You can also use the `/config` slash command during an interactive session, which is equivalent to running `kilocode config`.
|
||||
{% /callout %}
|
||||
|
||||
## Interactive Mode
|
||||
|
||||
Interactive mode is the default mode when running Kilo Code without the `--auto` flag, designed to work interactively with a user through the console.
|
||||
|
||||
@@ -85,6 +85,15 @@ You can customize each Cloud Agent session by also defining env vars and startup
|
||||
- Bootstrapping tooling
|
||||
- Running setup scripts
|
||||
|
||||
### Setup Commands vs `.kilocode/setup-script`
|
||||
|
||||
- Cloud Agent executes **Setup Commands** configured in the Cloud UI/profile.
|
||||
- Cloud Agent does **not** automatically discover or run `.kilocode/setup-script`.
|
||||
- If you want to use `.kilocode/setup-script` in Cloud Agent, call it explicitly from Setup Commands, for example: `bash .kilocode/setup-script`.
|
||||
- If both are present, execution order is:
|
||||
1. Setup Commands (in the order you define them)
|
||||
2. Anything those commands invoke (such as `.kilocode/setup-script`)
|
||||
|
||||
## Skills
|
||||
|
||||
Cloud Agents support project-level [skills](/docs/code-with-ai/platforms/cli#skills) stored in your repository. When your repo is cloned, any skills in `.kilocode/skills/` are automatically available.
|
||||
|
||||
@@ -71,7 +71,7 @@ Low Depth indicates that developers may be trying AI but not trusting or shippin
|
||||
|
||||
**Actions:**
|
||||
|
||||
1. Enable [Managed Indexing](/docs/advanced-usage/managed-indexing) to improve context quality
|
||||
1. Enable [Managed Indexing](/docs/deploy-secure/managed-indexing) to improve context quality
|
||||
2. Review whether suggestions are relevant to your codebase
|
||||
3. Introduce chained workflows to increase multi-stage usage
|
||||
|
||||
@@ -235,6 +235,6 @@ Additional views for comparing multiple teams within an organization are planned
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Understand what each dimension measures](/docs/plans/adoption-dashboard/understanding-your-score)
|
||||
- [Learn strategies to improve your score](/docs/plans/adoption-dashboard/improving-your-score)
|
||||
- [Return to the dashboard overview](/docs/plans/adoption-dashboard/overview)
|
||||
- [Understand what each dimension measures](/docs/collaborate/adoption-dashboard/understanding-your-score)
|
||||
- [Learn strategies to improve your score](/docs/collaborate/adoption-dashboard/improving-your-score)
|
||||
- [Return to the dashboard overview](/docs/collaborate/adoption-dashboard/overview)
|
||||
|
||||
@@ -73,7 +73,7 @@ Linking coding → review → deploy actions significantly boosts your Depth sco
|
||||
|
||||
If acceptance rates are low, the issue is often context. The AI is making suggestions without understanding your codebase.
|
||||
|
||||
**Action:** Enable [Managed Indexing](/docs/advanced-usage/managed-indexing) to give the model vector-backed search across your repository.
|
||||
**Action:** Enable [Managed Indexing](/docs/deploy-secure/managed-indexing) to give the model vector-backed search across your repository.
|
||||
|
||||
Better context leads to:
|
||||
|
||||
@@ -86,7 +86,7 @@ Better context leads to:
|
||||
|
||||
Generated code that never runs is hard to trust. Teams that can verify AI output against live environments tend to retain more of that code long-term.
|
||||
|
||||
**Action:** Use [Kilo Deploy](/docs/advanced-usage/deploy) to spin up live URLs for branches, allowing your team to verify changes before merging.
|
||||
**Action:** Use [Kilo Deploy](/docs/deploy-secure/deploy) to spin up live URLs for branches, allowing your team to verify changes before merging.
|
||||
|
||||
---
|
||||
|
||||
@@ -190,5 +190,5 @@ Other ways to spread usage:
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
|
||||
- [Return to the dashboard overview](/docs/plans/adoption-dashboard/overview)
|
||||
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
|
||||
- [Return to the dashboard overview](/docs/collaborate/adoption-dashboard/overview)
|
||||
|
||||
@@ -92,6 +92,6 @@ Click on any dimension card to view detailed analysis and improvement suggestion
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Understand what each dimension measures](/docs/plans/adoption-dashboard/understanding-your-score)
|
||||
- [Learn strategies to improve your score](/docs/plans/adoption-dashboard/improving-your-score)
|
||||
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
|
||||
- [Understand what each dimension measures](/docs/collaborate/adoption-dashboard/understanding-your-score)
|
||||
- [Learn strategies to improve your score](/docs/collaborate/adoption-dashboard/improving-your-score)
|
||||
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
|
||||
|
||||
@@ -147,5 +147,5 @@ Individual scores are most useful for personal development and self-assessment,
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Learn strategies to improve each dimension](/docs/plans/adoption-dashboard/improving-your-score)
|
||||
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
|
||||
- [Learn strategies to improve each dimension](/docs/collaborate/adoption-dashboard/improving-your-score)
|
||||
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
|
||||
|
||||
@@ -46,5 +46,5 @@ Here is the list of all events included in the Kilo Code audit logs:
|
||||
- Organization: Create, Settings Change, Purchase Credits
|
||||
- Organization Member: Remove, Change Role
|
||||
- User: Login, Logout, Accept Invite, Send Invite, Revoke Invite
|
||||
- [Custom Modes](/docs/plans/custom-modes): Create, Update, Delete
|
||||
- [SSO](/docs/plans/enterprise/SSO) (Enterprise Only): Auto Provision, Set Domain, Remove Domain
|
||||
- [Custom Modes](/docs/collaborate/teams/custom-modes-org): Create, Update, Delete
|
||||
- [SSO](/docs/collaborate/enterprise/sso) (Enterprise Only): Auto Provision, Set Domain, Remove Domain
|
||||
|
||||
@@ -57,7 +57,7 @@ Switch to **Kilo Teams** or **Kilo Enterprise** from other AI coding tools and e
|
||||
|
||||
**Step 2: Kilo Setup**
|
||||
|
||||
1. **Create organization** at [app.kilocode.com](https://app.kilocode.com)
|
||||
1. **Create organization** at [app.kilo.ai](https://app.kilo.ai)
|
||||
2. **Subscribe to Teams ($15/user/month)** or **Enterprise ([Contact Sales](https://kilo.ai/contact-sales))**
|
||||
3. **Configure team settings** and usage policies
|
||||
4. **Purchase initial AI credits** based on usage estimates
|
||||
@@ -355,7 +355,7 @@ Kilo Code also supports mode-specific rules (`.kilocode/rules-{mode}/`), which C
|
||||
- **Discord:** Join our migration support channel
|
||||
- **Consultation:** Schedule free migration planning call
|
||||
- **Documentation:**
|
||||
- [Business migration guide](/docs/plans/migration) (this page)
|
||||
- [Business migration guide](/docs/collaborate/enterprise/migration) (this page)
|
||||
- [Technical migration guide](/docs/getting-started/migrating) (rules and configurations)
|
||||
|
||||
## Success Stories
|
||||
@@ -383,9 +383,9 @@ Kilo Code also supports mode-specific rules (`.kilocode/rules-{mode}/`), which C
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Get started with your team](/docs/plans/getting-started)
|
||||
- [Explore team management features](/docs/plans/team-management)
|
||||
- [Understand billing and pricing](/docs/plans/billing)
|
||||
- [Get started with your team](/docs/collaborate/teams/getting-started)
|
||||
- [Explore team management features](/docs/collaborate/teams/team-management)
|
||||
- [Understand billing and pricing](/docs/collaborate/teams/billing)
|
||||
- [Migrate your rules and configurations](/docs/getting-started/migrating) (technical guide)
|
||||
|
||||
Ready to make the switch? Contact our migration team at migrations@kilo.ai to plan your transition to transparent AI coding.
|
||||
|
||||
@@ -41,5 +41,5 @@ Fill in your contact information and someone from our team will reach out soon t
|
||||
After enabling SSO:
|
||||
|
||||
- Invite new users with their company email domain.
|
||||
- Manage team access and roles from the **[Organization](/docs/plans/dashboard)** tab.
|
||||
- View user activity across the team in the **[Audit Logs](/docs/plans/enterprise/audit-logs)** tab
|
||||
- Manage team access and roles from the **[Organization](/docs/collaborate/adoption-dashboard/overview)** tab.
|
||||
- View user activity across the team in the **[Audit Logs](/docs/collaborate/enterprise/audit-logs)** tab
|
||||
|
||||
@@ -129,7 +129,7 @@ All costs are displayed in USD with detailed precision, helping you:
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Manage team billing settings](/docs/plans/billing)
|
||||
- [Configure team roles and permissions](/docs/plans/team-management)
|
||||
- [Manage team billing settings](/docs/collaborate/teams/billing)
|
||||
- [Configure team roles and permissions](/docs/collaborate/teams/team-management)
|
||||
|
||||
The usage analytics provide the insights needed to optimize your team's AI usage while maintaining visibility into costs and activity patterns.
|
||||
|
||||
@@ -21,7 +21,7 @@ Organization Owners can purchase Kilo credits on the [Organization dashboard](ht
|
||||
|
||||
Organization credits are purchased on behalf of all users in the organization. Every member of the organization can use the credits in the organization's balance with the Kilo Code model provider.
|
||||
|
||||
Using organization credits works exactly like spending [individual credits](/docs/basic-usage/adding-credits), except that the credits come from the organization's credit balance, rather than the individuals.
|
||||
Using organization credits works exactly like spending [individual credits](/docs/getting-started/adding-credits), except that the credits come from the organization's credit balance, rather than the individuals.
|
||||
|
||||
### Buying Organization Credits
|
||||
|
||||
@@ -47,7 +47,7 @@ You can remove empty seats at any time. Your next payment will reflect the small
|
||||
|
||||
Your next billing date will not change.
|
||||
|
||||
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/plans/team-management) page.
|
||||
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/collaborate/teams/team-management) page.
|
||||
|
||||
### Adding Seats
|
||||
|
||||
@@ -64,7 +64,7 @@ To fill empty seats or remove members ahead of seat deletion, see the [team mana
|
||||
3. **Select seats to remove** (must remove team members first)
|
||||
4. **Confirm reduction**
|
||||
|
||||
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/plans/team-management) page.
|
||||
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/collaborate/teams/team-management) page.
|
||||
|
||||
## Invoices
|
||||
|
||||
@@ -81,6 +81,6 @@ If payment fails repeatedly:
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Explore usage analytics](/docs/plans/analytics)
|
||||
- [Learn about team roles and permissions](/docs/plans/team-management)
|
||||
- [Learn about team management](/docs/plans/team-management)
|
||||
- [Explore usage analytics](/docs/collaborate/teams/analytics)
|
||||
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
|
||||
- [Learn about team management](/docs/collaborate/teams/team-management)
|
||||
|
||||
@@ -162,6 +162,6 @@ Manage your Kilo Teams plan and seat allocation.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Learn about team management](/docs/plans/team-management)
|
||||
- [Understand billing and credits](/docs/plans/billing)
|
||||
- [Explore usage analytics](/docs/plans/analytics)
|
||||
- [Learn about team management](/docs/collaborate/teams/team-management)
|
||||
- [Understand billing and credits](/docs/collaborate/teams/billing)
|
||||
- [Explore usage analytics](/docs/collaborate/teams/analytics)
|
||||
|
||||
@@ -76,6 +76,6 @@ You can find the dedicated Teams support methods directly on your Organization's
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Learn about team roles and permissions](/docs/plans/team-management)
|
||||
- [Explore the dashboard features](/docs/plans/dashboard)
|
||||
- [Set up team management policies](/docs/plans/team-management)
|
||||
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
|
||||
- [Explore the dashboard features](/docs/collaborate/adoption-dashboard/overview)
|
||||
- [Set up team management policies](/docs/collaborate/teams/team-management)
|
||||
|
||||
@@ -11,7 +11,7 @@ Owners have full administrative oversight including billing, seat allocation, an
|
||||
|
||||
Only Owners can conduct team management activities.
|
||||
|
||||
Members can use the Kilo Code extension and see data on the team's usage in the [usage dashboard](/docs/plans/analytics).
|
||||
Members can use the Kilo Code extension and see data on the team's usage in the [usage dashboard](/docs/collaborate/teams/analytics).
|
||||
|
||||
## Adding Team Members
|
||||
|
||||
@@ -53,8 +53,8 @@ The Organization tab shows:
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Understand billing and credits](/docs/plans/billing)
|
||||
- [Explore usage analytics](/docs/plans/analytics)
|
||||
- [Learn about team roles and permissions](/docs/plans/team-management)
|
||||
- [Understand billing and credits](/docs/collaborate/teams/billing)
|
||||
- [Explore usage analytics](/docs/collaborate/teams/analytics)
|
||||
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
|
||||
|
||||
Effective team management ensures your organization maximizes the benefits of AI-assisted development while maintaining cost control and security.
|
||||
|
||||
@@ -11,7 +11,6 @@ These pages document the architecture and design of current or planned features,
|
||||
| ---------------------------------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| [Agent Observability](/docs/contributing/architecture/agent-observability) | Observability and monitoring for agentic systems |
|
||||
| [Benchmarking](/docs/contributing/architecture/benchmarking) | Benchmarking Kilo Code across models and agents |
|
||||
| [Annual Billing](/docs/contributing/architecture/annual-billing) | Annual subscription billing |
|
||||
| [Enterprise MCP Controls](/docs/contributing/architecture/enterprise-mcp-controls) | Admin controls for MCP server allowlists |
|
||||
| [MCP OAuth Authorization](/docs/contributing/architecture/mcp-oauth-authorization) | OAuth 2.1-based authorization for MCP servers |
|
||||
| [Onboarding Improvements](/docs/contributing/architecture/onboarding-improvements) | User onboarding and engagement features |
|
||||
|
||||
@@ -144,4 +144,4 @@ The project uses:
|
||||
## Further Reading
|
||||
|
||||
- [Development Environment](/docs/contributing/development-environment) - Setup guide
|
||||
- [Tools Reference](/docs/features/tools/tool-use-overview) - Available tools
|
||||
- [Tools Reference](/docs/automate/tools) - Available tools
|
||||
|
||||
@@ -9,8 +9,6 @@ description: "Set up your development environment for contributing"
|
||||
**New versions of the VS Code extension and CLI are being developed in [Kilo-Org/Kilo](https://github.com/Kilo-Org/Kilo)** (extension at `packages/kilo-vscode`, CLI at `packages/opencode`). For extension and CLI development, please head over to that repository.
|
||||
{% /callout %}
|
||||
|
||||
<!-- Please refer to the [DEVELOPMENT.md](https://github.com/Kilo-Org/kilocode/blob/main/DEVELOPMENT.md) guide in the main repository for detailed instructions on setting up the development environment. -->
|
||||
|
||||
This document will help you set up your development environment and understand how to work with the codebase. Whether you're fixing bugs, adding features, or just exploring the code, this guide will get you started.
|
||||
|
||||
## Prerequisites
|
||||
@@ -18,7 +16,7 @@ This document will help you set up your development environment and understand h
|
||||
Before you begin, make sure you have the following installed:
|
||||
|
||||
1. **Git** - For version control
|
||||
2. **Node.js** (version [v20.18.1](https://github.com/Kilo-Org/kilocode/blob/main/.nvmrc) or higher recommended) and npm
|
||||
2. **Node.js** (version v20.18.1 (See `.nvmrc` for latest) or higher recommended) and npm
|
||||
3. **Visual Studio Code** - Our recommended IDE for development
|
||||
|
||||
## Getting Started
|
||||
@@ -27,12 +25,12 @@ Before you begin, make sure you have the following installed:
|
||||
|
||||
1. **Fork and Clone the Repository**:
|
||||
- **Fork the Repository**:
|
||||
- Visit the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilocode)
|
||||
- Visit the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilo)
|
||||
- Click the "Fork" button in the top-right corner to create your own copy.
|
||||
- **Clone Your Fork**:
|
||||
```bash
|
||||
git clone https://github.com/[YOUR-USERNAME]/kilocode.git
|
||||
cd kilocode
|
||||
git clone https://github.com/[YOUR-USERNAME]/kilo.git
|
||||
cd kilo
|
||||
```
|
||||
Replace `[YOUR-USERNAME]` with your actual GitHub username.
|
||||
|
||||
@@ -52,7 +50,7 @@ While not strictly necessary for running the extension, these extensions are rec
|
||||
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Integrates ESLint into VS Code.
|
||||
- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Integrates Prettier into VS Code.
|
||||
|
||||
The full list of recommended extensions is [here](https://github.com/Kilo-Org/kilocode/blob/main/.vscode/extensions.json)
|
||||
The full list of recommended extensions is in `.vscode/extensions.json`
|
||||
|
||||
### Project Structure
|
||||
|
||||
@@ -151,7 +149,7 @@ E2E tests verify the extension works correctly within VSCode:
|
||||
npm run test:integration
|
||||
```
|
||||
|
||||
For more details on E2E tests, see [e2e/VSCODE_INTEGRATION_TESTS.md](https://github.com/Kilo-Org/kilocode/blob/main/e2e/VSCODE_INTEGRATION_TESTS.md).
|
||||
For more details on E2E tests, see e2e/VSCODE_INTEGRATION_TESTS
|
||||
|
||||
## Linting and Type Checking
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ If you need help with your contribution:
|
||||
|
||||
- Join our [Discord community](https://kilo.ai/discord) for real-time support
|
||||
- Ask questions on [GitHub Discussions](https://github.com/Kilo-Org/kilocode/discussions)
|
||||
- Visit our [Reddit community](https://www.reddit.com/r/KiloCode)
|
||||
- Visit our [Reddit community](https://www.reddit.com/r/kilocode)
|
||||
|
||||
## Recognition
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ You can configure context condensing thresholds and behavior on a per-profile ba
|
||||
### Maintaining Context Quality
|
||||
|
||||
- **Be specific in your initial task**: A clear task description helps create better summaries
|
||||
- **Use Memory Bank**: Combine with [Memory Bank](/docs/customize/context/memory-bank) for persistent project context that doesn't need to be condensed
|
||||
- **Use AGENTS.md**: Combine with [AGENTS.md](/docs/customize/agents-md) for persistent project context that doesn't need to be condensed
|
||||
- **Review the summary**: After condensing, the summary is visible in your chat history
|
||||
|
||||
## Troubleshooting
|
||||
@@ -97,6 +97,6 @@ If the condensed summary doesn't capture important details:
|
||||
|
||||
## Related Features
|
||||
|
||||
- [Memory Bank](/docs/customize/context/memory-bank) - Persistent context storage across sessions
|
||||
- [AGENTS.md](/docs/customize/agents-md) - Persistent context storage across sessions
|
||||
- [Large Projects](/docs/customize/context/large-projects) - Managing context for large codebases
|
||||
- [Codebase Indexing](/docs/customize/context/codebase-indexing) - Efficient code search and retrieval
|
||||
|
||||
@@ -21,7 +21,7 @@ Custom Instructions are IDE-wide and are applied across all workspaces and maint
|
||||
|
||||
{% image src="/docs/img/custom-instructions/custom-instructions.png" alt="Kilo Code Modes tab showing global custom instructions interface" width="600" caption="Kilo Code Modes tab showing global custom instructions interface" /%}
|
||||
|
||||
1. **Open Modes Tab:** Click the <Codicon name="organization" /> icon in the Kilo Code top menu bar
|
||||
1. **Open Modes Tab:** Click the <Codicon name="notebook" /> icon in the Kilo Code top menu bar
|
||||
2. **Find Section:** Find the "Custom Instructions for All Modes" section
|
||||
3. **Enter Instructions:** Enter your instructions in the text area
|
||||
4. **Save Changes:** Click "Done" to save your changes
|
||||
@@ -31,7 +31,7 @@ Custom Instructions are IDE-wide and are applied across all workspaces and maint
|
||||
Mode-specific instructions can be set using the Modes Tab
|
||||
|
||||
{% image src="/docs/img/custom-instructions/custom-instructions-3.png" alt="Kilo Code Modes tab showing mode-specific custom instructions interface" width="600" caption="Kilo Code Modes tab showing mode-specific custom instructions interface" /%}
|
||||
* **Open Tab:** Click the <Codicon name="organization" /> icon in the Kilo Code top menu bar
|
||||
* **Open Tab:** Click the <Codicon name="notebook" /> icon in the Kilo Code top menu bar
|
||||
* **Select Mode:** Under the Modes heading, click the button for the mode you want to customize
|
||||
* **Enter Instructions:** Enter your instructions in the text area under "Mode-specific Custom Instructions (optional)"
|
||||
* **Save Changes:** Click "Done" to save your changes
|
||||
@@ -40,9 +40,20 @@ Mode-specific instructions can be set using the Modes Tab
|
||||
If the mode itself is global (not workspace-specific), any custom instructions you set for it will also apply globally for that mode across all workspaces.
|
||||
{% /callout %}
|
||||
|
||||
## Mode-Specific Instructions from Files
|
||||
|
||||
For version-controlled mode instructions, use the mode rules file paths documented in [Custom Modes](/docs/customize/custom-modes#mode-specific-instructions-via-filesdirectories):
|
||||
|
||||
- Preferred: `.kilo/rules-{mode-slug}/` (directory)
|
||||
- Fallback: `.kilorules-{mode-slug}` (single file)
|
||||
|
||||
{% callout type="info" title="Legacy Naming Note" %}
|
||||
Older naming like `.clinerules-{mode-slug}` is not the recommended path for current Kilo mode-specific instructions.
|
||||
{% /callout %}
|
||||
|
||||
## Related Features
|
||||
|
||||
- [Custom Modes](/docs/customize/custom-modes)
|
||||
- [Custom Rules](/docs/customize/custom-rules)
|
||||
- [Settings Management](/docs/getting-started/settings)
|
||||
- [Auto-Approval Settings](/docs/features/auto-approving-actions)
|
||||
- [Auto-Approval Settings](/docs/getting-started/settings/auto-approving-actions)
|
||||
|
||||
@@ -74,7 +74,7 @@ Modes are managed from the Modes area in Kilo Code. Depending on your UI layout,
|
||||
|
||||
1. Open the Modes area from the mode selector in the chat panel (or via the <Codicon name="notebook" /> icon if shown)
|
||||
2. Click the Import Mode button (upload icon)
|
||||
3. Select the mode's YAML file
|
||||
3. Select the mode's YAML file (`.yaml`)
|
||||
4. Choose the import level:
|
||||
- **Project:** Available only in current workspace (saved to `.kilocodemodes` file)
|
||||
- **Global:** Available in all projects (saved to global settings)
|
||||
@@ -121,11 +121,16 @@ The interface provides fields for Name, Slug, Description, Save Location, Role D
|
||||
|
||||
You can directly edit the configuration files to create or modify custom modes. This method offers the most control over all properties. Kilo Code now supports both YAML (preferred) and JSON formats.
|
||||
|
||||
- **Global Modes:** Edit the `custom_modes.yaml` (preferred) or `custom_modes.json` file. Open the Modes area, click <Codicon name="gear" /> next to Global Modes, then choose "Edit Global Modes"
|
||||
- **Project Modes:** Edit the `.kilocodemodes` file (which can be YAML or JSON) in your project root. Open the Modes area, click <Codicon name="gear" /> next to Project Modes, then choose "Edit Project Modes"
|
||||
- **Global Modes:** Edit `custom_modes.yaml` (primary). `custom_modes.json` is a legacy fallback and may still exist in older setups.
|
||||
- **Project Modes:** Edit `.kilocodemodes` in your project root (YAML preferred; JSON still supported for compatibility).
|
||||
- **Open from UI:** Open the Modes area, click <Codicon name="gear" /> next to Global or Project Modes, then choose **Edit Global Modes** or **Edit Project Modes**.
|
||||
|
||||
These files define an array/list of custom modes.
|
||||
|
||||
{% callout type="info" title="Why JSON Files May Still Exist" %}
|
||||
If you see both YAML and JSON mode files, this is usually from legacy configuration. Kilo Code reads YAML first and does not keep both files synchronized line-by-line. In practice, edit YAML unless you have a specific reason to stay on JSON.
|
||||
{% /callout %}
|
||||
|
||||
## YAML Configuration Format (Preferred)
|
||||
|
||||
YAML is now the preferred format for defining custom modes due to better readability, comment support, and cleaner multi-line strings.
|
||||
|
||||
@@ -221,4 +221,4 @@ If your custom rules aren't being properly followed:
|
||||
- [Custom Modes](/docs/customize/custom-modes)
|
||||
- [Custom Instructions](/docs/customize/custom-instructions)
|
||||
- [Settings Management](/docs/getting-started/settings)
|
||||
- [Auto-Approval Settings](/docs/features/auto-approving-actions)
|
||||
- [Auto-Approval Settings](/docs/getting-started/settings/auto-approving-actions)
|
||||
|
||||
@@ -27,7 +27,7 @@ Help Kilo understand your codebase better:
|
||||
|
||||
- [**Codebase Indexing**](/docs/customize/context/codebase-indexing) - Build a semantic index of your code for better context awareness
|
||||
- [**Context Condensing**](/docs/customize/context/context-condensing) - Summarize older context to stay within limits
|
||||
- [**Memory Bank**](/docs/customize/context/memory-bank) - Store project context, decisions, and important information
|
||||
- [**AGENTS.md**](/docs/customize/agents-md) - Store project context, decisions, and important information
|
||||
- [**Large Projects**](/docs/customize/context/large-projects) - Best practices for working with monorepos and large codebases
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -13,7 +13,7 @@ Prompt engineering is the art of crafting effective instructions for AI models l
|
||||
- **Bad:** Fix the code.
|
||||
- **Good:** Fix the bug in the `calculateTotal` function that causes it to return incorrect results.
|
||||
|
||||
- **Provide Context:** Use [Context Mentions](/docs/basic-usage/context-mentions) to refer to specific files, folders, or problems.
|
||||
- **Provide Context:** Use [Context Mentions](/docs/code-with-ai/agents/context-mentions) to refer to specific files, folders, or problems.
|
||||
- **Good:** `@/src/utils.ts` Refactor the `calculateTotal` function to use async/await.
|
||||
|
||||
- **Break Down Tasks:** Divide complex tasks into smaller, well-defined steps.
|
||||
|
||||
@@ -26,10 +26,10 @@ Workflows are markdown files stored in `.kilocode/workflows/`:
|
||||
|
||||
Workflows can leverage:
|
||||
|
||||
- [Built-in tools](/docs/features/tools/tool-use-overview): [`read_file()`](/docs/features/tools/read-file), [`search_files()`](/docs/features/tools/search-files), [`execute_command()`](/docs/features/tools/execute-command)
|
||||
- [Built-in tools](/docs/automate/tools): [`read_file()`](/docs/automate/tools/read-file), [`search_files()`](/docs/automate/tools/search-files), [`execute_command()`](/docs/automate/tools/execute-command)
|
||||
- CLI tools: `gh`, `docker`, `npm`, custom scripts
|
||||
- [MCP integrations](/docs/automate/mcp/overview): Slack, databases, APIs
|
||||
- [Mode switching](/docs/code-with-ai/agents/using-modes): [`new_task()`](/docs/features/tools/new-task) for specialized contexts
|
||||
- [Mode switching](/docs/code-with-ai/agents/using-modes): [`new_task()`](/docs/automate/tools/new-task) for specialized contexts
|
||||
|
||||
## Common Workflow Patterns
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ description: "Get up and running with Kilo Code in minutes"
|
||||
|
||||
{% youtube url="https://www.youtube.com/watch?v=pO7zRLQS-p0" caption="This quick tour shows how Kilo Code handles a simple request from start to finish" /%}
|
||||
|
||||
After you [set up Kilo Code](/docs/getting-started/setting-up), follow these steps:
|
||||
After you [set up Kilo Code](/docs/getting-started/setup-authentication), follow these steps:
|
||||
|
||||
## Step by Step Guide
|
||||
|
||||
@@ -30,7 +30,7 @@ Type a clear, concise description of what you want Kilo Code to do in the chat b
|
||||
No special commands or syntax needed—just use plain English.
|
||||
|
||||
{% callout type="tip" title="Optional: Try Autocomplete" collapsed=true %}
|
||||
While chat is great for complex tasks, Kilo Code also offers **inline autocomplete** for quick code suggestions. Open any code file, start typing, and watch for ghost text suggestions. Press `Tab` to accept. [Learn more about Autocomplete →](/docs/basic-usage/autocomplete)
|
||||
While chat is great for complex tasks, Kilo Code also offers **inline autocomplete** for quick code suggestions. Open any code file, start typing, and watch for ghost text suggestions. Press `Tab` to accept. [Learn more about Autocomplete →](/docs/code-with-ai/features/autocomplete)
|
||||
{% /callout %}
|
||||
|
||||
{% image src="/docs/img/your-first-task/your-first-task-6.png" alt="Typing a task in the Kilo Code chat interface" width="500" caption="Enter your task in natural language - no special syntax required." /%}
|
||||
@@ -57,7 +57,7 @@ Kilo Code analyzes your request and proposes specific actions. These may include
|
||||
{% callout type="tip" %}
|
||||
The level of autonomy is configurable, allowing you to make the agent more or less autonomous.
|
||||
|
||||
You can learn more about [using modes](/docs/code-with-ai/agents/using-modes) and [auto-approving actions](/docs/features/auto-approving-actions).
|
||||
You can learn more about [using modes](/docs/code-with-ai/agents/using-modes) and [auto-approving actions](/docs/getting-started/settings/auto-approving-actions).
|
||||
{% /callout %}
|
||||
|
||||
### Step 5: Iterate
|
||||
|
||||
@@ -46,6 +46,6 @@ If you set the rate limit to 10 seconds, Kilo Code will wait at least 10 seconds
|
||||
- **Use Custom Instructions:** Provide custom instructions to guide Kilo Code's behavior and reduce the need for lengthy explanations in each prompt.
|
||||
- **Choose the Right Model:** Some models are more cost-effective than others. Consider using a smaller, faster model for tasks that don't require the full power of a larger model.
|
||||
- **Use Modes:** Different modes can access different tools, for example `Architect` can't modify code, which makes it a safe choice when analyzing a complex codebase, without worrying about accidentally allowing expensive operations.
|
||||
- **Disable MCP If Not Used:** If you're not using MCP (Model Context Protocol) features, consider [disabling it in Settings > Agent Behaviour > MCP Servers](/automate/mcp/overview) to significantly reduce the size of the system prompt and save tokens.
|
||||
- **Disable MCP If Not Used:** If you're not using MCP (Model Context Protocol) features, consider [disabling it in Settings > Agent Behaviour > MCP Servers](/docs/automate/mcp/overview) to significantly reduce the size of the system prompt and save tokens.
|
||||
|
||||
By understanding and managing your API usage, you can use Kilo Code effectively and efficiently.
|
||||
|
||||
@@ -41,7 +41,7 @@ Every task is automatically classified into one of these categories:
|
||||
|
||||
#### Understanding Task Completion
|
||||
|
||||
A task is considered "completed" when Kilo Code uses the [`attempt_completion`](/automate/tools/attempt-completion) tool to formally mark it as finished. Tasks without this completion marker are classified as incomplete, even if you consider them done. This distinction helps clean up abandoned or experimental tasks more aggressively.
|
||||
A task is considered "completed" when Kilo Code uses the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool to formally mark it as finished. Tasks without this completion marker are classified as incomplete, even if you consider them done. This distinction helps clean up abandoned or experimental tasks more aggressively.
|
||||
|
||||
### Cleanup Process
|
||||
|
||||
@@ -102,7 +102,7 @@ Default: 30 days
|
||||
Minimum: 1 day
|
||||
```
|
||||
|
||||
Tasks successfully completed via the [`attempt_completion`](/automate/tools/attempt-completion) tool are retained for this period. These tasks typically represent finished work that may still be useful for reference.
|
||||
Tasks successfully completed via the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool are retained for this period. These tasks typically represent finished work that may still be useful for reference.
|
||||
|
||||
#### Incomplete Tasks
|
||||
|
||||
@@ -240,9 +240,9 @@ Task data is stored in your VS Code global storage location:
|
||||
|
||||
## Related Features
|
||||
|
||||
- [**Checkpoints**](/code-with-ai/features/checkpoints): Version control for tasks that can be restored
|
||||
- [**Settings Management**](/getting-started/settings): Export/import settings including cleanup configuration
|
||||
- [**Task History**](/code-with-ai/agents/chat-interface): Managing and organizing your task history
|
||||
- [**Checkpoints**](/docs/code-with-ai/features/checkpoints): Version control for tasks that can be restored
|
||||
- [**Settings Management**](/docs/getting-started/settings): Export/import settings including cleanup configuration
|
||||
- [**Task History**](/docs/code-with-ai/agents/chat-interface): Managing and organizing your task history
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ These are just a few examples! Kilo Code supports many more providers including
|
||||
|
||||
### ChatGPT Plus/Pro Subscription
|
||||
|
||||
Already have a ChatGPT subscription? You can use it with Kilo Code through the [OpenAI ChatGPT provider](/docs/providers/openai-chatgpt-plus-pro)—no API key needed.
|
||||
Already have a ChatGPT subscription? You can use it with Kilo Code through the [OpenAI ChatGPT provider](/docs/ai-providers/openai-chatgpt-plus-pro)—no API key needed.
|
||||
|
||||
### OpenRouter
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Kilo-specific i18n translations and overrides",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Telemetry for Kilo CLI - PostHog analytics integration",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "1.0.24",
|
||||
"version": "1.0.25",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -2,4 +2,32 @@
|
||||
.shiki {
|
||||
margin: 0rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--border-weak-base) transparent;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: var(--border-weak-base);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: var(--border-strong-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,8 @@
|
||||
[data-slot="text-part-body"] {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
[data-slot="text-part-copy-wrapper"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: block;
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
@@ -63,7 +64,8 @@ html[data-theme="kilo-vscode"] {
|
||||
font-weight: var(--vscode-font-weight);
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: block;
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"name": "kilo-code",
|
||||
"displayName": "Kilo Code",
|
||||
"description": "Kilo Code AI Agent & Autocomplete",
|
||||
"version": "7.0.24",
|
||||
"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.0.25",
|
||||
"icon": "assets/icons/logo-outline-black.png",
|
||||
"publisher": "kilocode",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -291,6 +292,11 @@
|
||||
"key": "ctrl+shift+a",
|
||||
"mac": "cmd+shift+a"
|
||||
},
|
||||
{
|
||||
"command": "kilo-code.new.agentManagerOpen",
|
||||
"key": "ctrl+shift+m",
|
||||
"mac": "cmd+shift+m"
|
||||
},
|
||||
{
|
||||
"command": "kilo-code.new.addToContext",
|
||||
"key": "ctrl+k ctrl+a",
|
||||
@@ -504,7 +510,8 @@
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "eslint src",
|
||||
"test": "vscode-test"
|
||||
"test": "vscode-test",
|
||||
"test:unit": "bun test tests/unit/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/diff": "^6.0.0",
|
||||
@@ -530,6 +537,7 @@
|
||||
"@kilocode/kilo-ui": "workspace:*",
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@thisbeyond/solid-dnd": "0.7.5",
|
||||
"diff": "^7.0.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"eventsource": "^2.0.2",
|
||||
|
||||
@@ -22,7 +22,8 @@ const packagesDir = join(kiloVscodeDir, "..")
|
||||
const opencodeDir = join(packagesDir, "opencode")
|
||||
|
||||
const targetBinDir = join(kiloVscodeDir, "bin")
|
||||
const targetBinPath = join(targetBinDir, "kilo")
|
||||
const binName = process.platform === "win32" ? "kilo.exe" : "kilo"
|
||||
const targetBinPath = join(targetBinDir, binName)
|
||||
|
||||
function log(msg: string) {
|
||||
console.log(`[local-bin] ${msg}`)
|
||||
@@ -44,7 +45,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
|
||||
|
||||
// Prefer the binary matching the current platform (e.g. cli-darwin-arm64)
|
||||
const tag = platformTag()
|
||||
const preferred = join(distDir, `@kilocode`, tag, "bin", "kilo")
|
||||
const preferred = join(distDir, `@kilocode`, tag, "bin", binName)
|
||||
try {
|
||||
statSync(preferred)
|
||||
return preferred
|
||||
@@ -52,7 +53,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
|
||||
// fall through to generic search
|
||||
}
|
||||
|
||||
// Fallback: find any dist/**/bin/kilo
|
||||
// Fallback: find any dist/**/bin/kilo or kilo.exe
|
||||
const queue = [distDir]
|
||||
while (queue.length) {
|
||||
const dir = queue.pop()
|
||||
@@ -71,7 +72,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
|
||||
queue.push(p)
|
||||
continue
|
||||
}
|
||||
if (e.isFile() && e.name === "kilo" && basename(dirname(p)) === "bin") {
|
||||
if (e.isFile() && (e.name === "kilo" || e.name === "kilo.exe") && basename(dirname(p)) === "bin") {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import * as vscode from "vscode"
|
||||
import { z } from "zod"
|
||||
import { type HttpClient, type SessionInfo, type SSEEvent, type KiloConnectionService } from "./services/cli-backend"
|
||||
import {
|
||||
type HttpClient,
|
||||
type SessionInfo,
|
||||
type SSEEvent,
|
||||
type KiloConnectionService,
|
||||
type KilocodeNotification,
|
||||
} from "./services/cli-backend"
|
||||
import { handleChatCompletionRequest } from "./services/autocomplete/chat-autocomplete/handleChatCompletionRequest"
|
||||
import { handleChatCompletionAccepted } from "./services/autocomplete/chat-autocomplete/handleChatCompletionAccepted"
|
||||
import { buildWebviewHtml } from "./utils"
|
||||
import { TelemetryProxy, type TelemetryPropertiesProvider } from "./services/telemetry"
|
||||
import {
|
||||
sessionToWebview,
|
||||
normalizeProviders,
|
||||
filterVisibleAgents,
|
||||
buildSettingPath,
|
||||
mapSSEEventToWebviewMessage,
|
||||
} from "./kilo-provider-utils"
|
||||
|
||||
export class KiloProvider implements vscode.WebviewViewProvider, TelemetryPropertiesProvider {
|
||||
public static readonly viewType = "kilo-code.new.sidebarView"
|
||||
@@ -22,12 +35,17 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
private cachedAgentsMessage: unknown = null
|
||||
/** Cached configLoaded payload so requestConfig can be served before httpClient is ready */
|
||||
private cachedConfigMessage: unknown = null
|
||||
/** Cached notificationsLoaded payload */
|
||||
private cachedNotificationsMessage: unknown = null
|
||||
|
||||
private trackedSessionIds: Set<string> = new Set()
|
||||
/** Per-session directory overrides (e.g., worktree paths registered by AgentManagerProvider). */
|
||||
private sessionDirectories = new Map<string, string>()
|
||||
/** Abort controller for the current loadMessages request; aborted when a new session is selected. */
|
||||
private loadMessagesAbort: AbortController | null = null
|
||||
private unsubscribeEvent: (() => void) | null = null
|
||||
private unsubscribeState: (() => void) | null = null
|
||||
private unsubscribeNotificationDismiss: (() => void) | null = null
|
||||
private webviewMessageDisposable: vscode.Disposable | null = null
|
||||
|
||||
/** Optional interceptor called before the standard message handler.
|
||||
@@ -37,6 +55,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
private readonly connectionService: KiloConnectionService,
|
||||
private readonly extensionContext?: vscode.ExtensionContext,
|
||||
) {
|
||||
TelemetryProxy.getInstance().setProvider(this)
|
||||
}
|
||||
@@ -267,6 +286,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
message.providerID,
|
||||
message.modelID,
|
||||
message.agent,
|
||||
message.variant,
|
||||
files,
|
||||
)
|
||||
break
|
||||
@@ -285,7 +305,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
this.trackedSessionIds.clear()
|
||||
break
|
||||
case "loadMessages":
|
||||
await this.handleLoadMessages(message.sessionID)
|
||||
// Don't await: allow parallel loads so rapid session switching
|
||||
// isn't blocked by slow responses for earlier sessions.
|
||||
void this.handleLoadMessages(message.sessionID)
|
||||
break
|
||||
case "syncSession":
|
||||
await this.handleSyncSession(message.sessionID)
|
||||
@@ -316,6 +338,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
vscode.env.openExternal(vscode.Uri.parse(message.url))
|
||||
}
|
||||
break
|
||||
case "openFile":
|
||||
if (message.filePath) {
|
||||
this.handleOpenFile(message.filePath, message.line, message.column)
|
||||
}
|
||||
break
|
||||
case "requestProviders":
|
||||
await this.fetchAndSendProviders()
|
||||
break
|
||||
@@ -402,12 +429,29 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
case "requestNotificationSettings":
|
||||
this.sendNotificationSettings()
|
||||
break
|
||||
case "requestNotifications":
|
||||
await this.fetchAndSendNotifications()
|
||||
break
|
||||
case "dismissNotification":
|
||||
await this.handleDismissNotification(message.notificationId)
|
||||
break
|
||||
case "resetAllSettings":
|
||||
await this.handleResetAllSettings()
|
||||
break
|
||||
case "telemetry":
|
||||
TelemetryProxy.capture(message.event, message.properties)
|
||||
break
|
||||
case "persistVariant": {
|
||||
const stored = this.extensionContext?.globalState.get<Record<string, string>>("variantSelections") ?? {}
|
||||
stored[message.key] = message.value
|
||||
await this.extensionContext?.globalState.update("variantSelections", stored)
|
||||
break
|
||||
}
|
||||
case "requestVariants": {
|
||||
const variants = this.extensionContext?.globalState.get<Record<string, string>>("variantSelections") ?? {}
|
||||
this.postMessage({ type: "variantsLoaded", variants })
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -422,6 +466,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
// Clean up any existing subscriptions (e.g., sidebar re-shown)
|
||||
this.unsubscribeEvent?.()
|
||||
this.unsubscribeState?.()
|
||||
this.unsubscribeNotificationDismiss?.()
|
||||
|
||||
try {
|
||||
const workspaceDir = this.getWorkspaceDirectory()
|
||||
@@ -469,6 +514,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
})
|
||||
|
||||
// Subscribe to notification dismiss broadcast from other KiloProvider instances
|
||||
this.unsubscribeNotificationDismiss = this.connectionService.onNotificationDismissed(() => {
|
||||
this.fetchAndSendNotifications()
|
||||
})
|
||||
|
||||
// Get current state and push to webview
|
||||
const serverInfo = this.connectionService.getServerInfo()
|
||||
this.connectionState = this.connectionService.getConnectionState()
|
||||
@@ -491,6 +541,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
await this.fetchAndSendProviders()
|
||||
await this.fetchAndSendAgents()
|
||||
await this.fetchAndSendConfig()
|
||||
await this.fetchAndSendNotifications()
|
||||
this.sendNotificationSettings()
|
||||
|
||||
console.log("[Kilo New] KiloProvider: ✅ initializeConnection completed successfully")
|
||||
@@ -505,16 +556,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert SessionInfo to webview format.
|
||||
*/
|
||||
private sessionToWebview(session: SessionInfo) {
|
||||
return {
|
||||
id: session.id,
|
||||
title: session.title,
|
||||
createdAt: new Date(session.time.created).toISOString(),
|
||||
updatedAt: new Date(session.time.updated).toISOString(),
|
||||
}
|
||||
return sessionToWebview(session)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,25 +603,36 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
this.postMessage({
|
||||
type: "error",
|
||||
message: "Not connected to CLI backend",
|
||||
sessionID,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Abort any previous in-flight loadMessages request so the backend
|
||||
// isn't overwhelmed when the user switches sessions rapidly.
|
||||
this.loadMessagesAbort?.abort()
|
||||
const abort = new AbortController()
|
||||
this.loadMessagesAbort = abort
|
||||
|
||||
try {
|
||||
const workspaceDir = this.getWorkspaceDirectory(sessionID)
|
||||
const messagesData = await this.httpClient.getMessages(sessionID, workspaceDir)
|
||||
const messagesData = await this.httpClient.getMessages(sessionID, workspaceDir, abort.signal)
|
||||
|
||||
// If this request was aborted while awaiting, skip posting stale results
|
||||
if (abort.signal.aborted) return
|
||||
|
||||
// Update currentSession so fallback logic in handleSendMessage/handleAbort
|
||||
// references the correct session after switching to a historical session.
|
||||
// Non-blocking: don't let a failure here prevent messages from loading.
|
||||
// 404s are expected for cross-worktree sessions — use silent to suppress HTTP error logs.
|
||||
this.httpClient
|
||||
.getSession(sessionID, workspaceDir)
|
||||
.getSession(sessionID, workspaceDir, true)
|
||||
.then((session) => {
|
||||
if (!this.currentSession || this.currentSession.id === sessionID) {
|
||||
this.currentSession = session
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error("[Kilo New] KiloProvider: Failed to fetch session for tracking:", err))
|
||||
.catch((err) => console.warn("[Kilo New] KiloProvider: getSession failed (non-critical):", err))
|
||||
|
||||
// Fetch current session status so the webview has the correct busy/idle
|
||||
// state after switching tabs (SSE events may have been missed).
|
||||
@@ -618,10 +672,13 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
messages,
|
||||
})
|
||||
} catch (error) {
|
||||
// Silently ignore aborted requests — the user switched to a different session
|
||||
if (abort.signal.aborted) return
|
||||
console.error("[Kilo New] KiloProvider: Failed to load messages:", error)
|
||||
this.postMessage({
|
||||
type: "error",
|
||||
message: error instanceof Error ? error.message : "Failed to load messages",
|
||||
sessionID,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -786,11 +843,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const workspaceDir = this.getWorkspaceDirectory()
|
||||
const response = await this.httpClient.listProviders(workspaceDir)
|
||||
|
||||
// Re-key providers from numeric indices to provider.id
|
||||
const normalized: typeof response.all = {}
|
||||
for (const provider of Object.values(response.all)) {
|
||||
normalized[provider.id] = provider
|
||||
}
|
||||
const normalized = normalizeProviders(response.all)
|
||||
|
||||
const config = vscode.workspace.getConfiguration("kilo-code.new.model")
|
||||
const providerID = config.get<string>("providerID", "kilo")
|
||||
@@ -825,11 +878,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const workspaceDir = this.getWorkspaceDirectory()
|
||||
const agents = await this.httpClient.listAgents(workspaceDir)
|
||||
|
||||
// Filter to only visible primary/all modes (not subagents, not hidden)
|
||||
const visible = agents.filter((a) => a.mode !== "subagent" && !a.hidden)
|
||||
|
||||
// Find default agent: first one in list (CLI sorts default first)
|
||||
const defaultAgent = visible.length > 0 ? visible[0].name : "code"
|
||||
const { visible, defaultAgent } = filterVisibleAgents(agents)
|
||||
|
||||
const message = {
|
||||
type: "agentsLoaded",
|
||||
@@ -875,6 +924,47 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch Kilo news/notifications and send to webview.
|
||||
* Uses the cached message pattern so the webview gets data immediately on refresh.
|
||||
*/
|
||||
private async fetchAndSendNotifications(): Promise<void> {
|
||||
if (!this.httpClient) {
|
||||
if (this.cachedNotificationsMessage) {
|
||||
this.postMessage(this.cachedNotificationsMessage)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const notifications = await this.httpClient.getNotifications()
|
||||
const existing = this.extensionContext?.globalState.get<string[]>("kilo.dismissedNotificationIds", []) ?? []
|
||||
const active = new Set(notifications.map((n) => n.id))
|
||||
const dismissedIds = existing.filter((id) => active.has(id))
|
||||
if (dismissedIds.length !== existing.length) {
|
||||
await this.extensionContext?.globalState.update("kilo.dismissedNotificationIds", dismissedIds)
|
||||
}
|
||||
const message = { type: "notificationsLoaded", notifications, dismissedIds }
|
||||
this.cachedNotificationsMessage = message
|
||||
this.postMessage(message)
|
||||
} catch (error) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to fetch notifications:", error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist a dismissed notification ID in globalState and push updated lists to webview.
|
||||
*/
|
||||
private async handleDismissNotification(notificationId: string): Promise<void> {
|
||||
if (!this.extensionContext) return
|
||||
const existing = this.extensionContext.globalState.get<string[]>("kilo.dismissedNotificationIds", [])
|
||||
if (!existing.includes(notificationId)) {
|
||||
await this.extensionContext.globalState.update("kilo.dismissedNotificationIds", [...existing, notificationId])
|
||||
}
|
||||
await this.fetchAndSendNotifications()
|
||||
this.connectionService.notifyNotificationDismissed(notificationId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read notification/sound settings from VS Code config and push to webview.
|
||||
*/
|
||||
@@ -932,6 +1022,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
providerID?: string,
|
||||
modelID?: string,
|
||||
agent?: string,
|
||||
variant?: string,
|
||||
files?: Array<{ mime: string; url: string }>,
|
||||
): Promise<void> {
|
||||
if (!this.httpClient) {
|
||||
@@ -987,6 +1078,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
providerID,
|
||||
modelID,
|
||||
agent,
|
||||
variant,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to send message:", error)
|
||||
@@ -1218,6 +1310,28 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle openFile request from the webview — open a file in the VS Code editor.
|
||||
*/
|
||||
private handleOpenFile(filePath: string, line?: number, column?: number): void {
|
||||
const absolute = /^(?:\/|[a-zA-Z]:[\\/])/.test(filePath)
|
||||
const uri = absolute
|
||||
? vscode.Uri.file(filePath)
|
||||
: vscode.Uri.joinPath(vscode.Uri.file(this.getWorkspaceDirectory()), filePath)
|
||||
vscode.workspace.openTextDocument(uri).then(
|
||||
(doc) => {
|
||||
const options: vscode.TextDocumentShowOptions = { preview: true }
|
||||
if (line !== undefined && line > 0) {
|
||||
const col = column !== undefined && column > 0 ? column - 1 : 0
|
||||
const pos = new vscode.Position(line - 1, col)
|
||||
options.selection = new vscode.Range(pos, pos)
|
||||
}
|
||||
vscode.window.showTextDocument(doc, options)
|
||||
},
|
||||
(err) => console.error("[Kilo New] KiloProvider: Failed to open file:", uri.fsPath, err),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle logout request from the webview.
|
||||
*/
|
||||
@@ -1256,9 +1370,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
* The key uses dot notation relative to `kilo-code.new` (e.g. "browserAutomation.enabled").
|
||||
*/
|
||||
private async handleUpdateSetting(key: string, value: unknown): Promise<void> {
|
||||
const parts = key.split(".")
|
||||
const section = parts.slice(0, -1).join(".")
|
||||
const leaf = parts[parts.length - 1]
|
||||
const { section, leaf } = buildSettingPath(key)
|
||||
const config = vscode.workspace.getConfiguration(`kilo-code.new${section ? `.${section}` : ""}`)
|
||||
await config.update(leaf, value, vscode.ConfigurationTarget.Global)
|
||||
}
|
||||
@@ -1342,124 +1454,18 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
|
||||
// Forward relevant events to webview
|
||||
switch (event.type) {
|
||||
case "message.part.updated": {
|
||||
// The part contains the full part data including messageID, delta is optional text delta
|
||||
const part = event.properties.part as { messageID?: string; sessionID?: string }
|
||||
const messageID = part.messageID || ""
|
||||
// Side effects that must happen before the webview message is sent
|
||||
if (event.type === "session.created" && !this.currentSession) {
|
||||
this.currentSession = event.properties.info
|
||||
this.trackedSessionIds.add(event.properties.info.id)
|
||||
}
|
||||
if (event.type === "session.updated" && this.currentSession?.id === event.properties.info.id) {
|
||||
this.currentSession = event.properties.info
|
||||
}
|
||||
|
||||
const resolvedSessionID = sessionID
|
||||
if (!resolvedSessionID) {
|
||||
return
|
||||
}
|
||||
this.postMessage({
|
||||
type: "partUpdated",
|
||||
sessionID: resolvedSessionID,
|
||||
messageID,
|
||||
part: event.properties.part,
|
||||
delta: event.properties.delta ? { type: "text-delta", textDelta: event.properties.delta } : undefined,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case "message.updated":
|
||||
// Message info updated — forward cost/tokens for assistant messages
|
||||
this.postMessage({
|
||||
type: "messageCreated",
|
||||
message: {
|
||||
id: event.properties.info.id,
|
||||
sessionID: event.properties.info.sessionID,
|
||||
role: event.properties.info.role,
|
||||
createdAt: new Date(event.properties.info.time.created).toISOString(),
|
||||
cost: event.properties.info.cost,
|
||||
tokens: event.properties.info.tokens,
|
||||
},
|
||||
})
|
||||
break
|
||||
|
||||
case "session.status": {
|
||||
const info = event.properties.status
|
||||
this.postMessage({
|
||||
type: "sessionStatus",
|
||||
sessionID: event.properties.sessionID,
|
||||
status: info.type,
|
||||
...(info.type === "retry" ? { attempt: info.attempt, message: info.message, next: info.next } : {}),
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case "permission.asked":
|
||||
this.postMessage({
|
||||
type: "permissionRequest",
|
||||
permission: {
|
||||
id: event.properties.id,
|
||||
sessionID: event.properties.sessionID,
|
||||
toolName: event.properties.permission,
|
||||
patterns: event.properties.patterns ?? [],
|
||||
args: event.properties.metadata,
|
||||
message: `Permission required: ${event.properties.permission}`,
|
||||
tool: event.properties.tool,
|
||||
},
|
||||
})
|
||||
break
|
||||
|
||||
case "todo.updated":
|
||||
this.postMessage({
|
||||
type: "todoUpdated",
|
||||
sessionID: event.properties.sessionID,
|
||||
items: event.properties.items,
|
||||
})
|
||||
break
|
||||
|
||||
case "question.asked":
|
||||
this.postMessage({
|
||||
type: "questionRequest",
|
||||
question: {
|
||||
id: event.properties.id,
|
||||
sessionID: event.properties.sessionID,
|
||||
questions: event.properties.questions,
|
||||
tool: event.properties.tool,
|
||||
},
|
||||
})
|
||||
break
|
||||
|
||||
case "question.replied":
|
||||
this.postMessage({
|
||||
type: "questionResolved",
|
||||
requestID: event.properties.requestID,
|
||||
})
|
||||
break
|
||||
|
||||
case "question.rejected":
|
||||
this.postMessage({
|
||||
type: "questionResolved",
|
||||
requestID: event.properties.requestID,
|
||||
})
|
||||
break
|
||||
|
||||
case "session.created":
|
||||
// Store session if we don't have one yet
|
||||
if (!this.currentSession) {
|
||||
this.currentSession = event.properties.info
|
||||
this.trackedSessionIds.add(event.properties.info.id)
|
||||
}
|
||||
// Notify webview
|
||||
this.postMessage({
|
||||
type: "sessionCreated",
|
||||
session: this.sessionToWebview(event.properties.info),
|
||||
})
|
||||
break
|
||||
|
||||
case "session.updated":
|
||||
// Keep local state in sync (e.g. title generation)
|
||||
if (this.currentSession?.id === event.properties.info.id) {
|
||||
this.currentSession = event.properties.info
|
||||
}
|
||||
this.postMessage({
|
||||
type: "sessionUpdated",
|
||||
session: this.sessionToWebview(event.properties.info),
|
||||
})
|
||||
break
|
||||
const msg = mapSSEEventToWebviewMessage(event, sessionID)
|
||||
if (msg) {
|
||||
this.postMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1534,6 +1540,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
dispose(): void {
|
||||
this.unsubscribeEvent?.()
|
||||
this.unsubscribeState?.()
|
||||
this.unsubscribeNotificationDismiss?.()
|
||||
this.webviewMessageDisposable?.dispose()
|
||||
this.trackedSessionIds.clear()
|
||||
this.sessionDirectories.clear()
|
||||
|
||||
@@ -4,7 +4,10 @@ import { KiloProvider } from "../KiloProvider"
|
||||
import { buildWebviewHtml } from "../utils"
|
||||
import { WorktreeManager, type CreateWorktreeResult } from "./WorktreeManager"
|
||||
import { WorktreeStateManager } from "./WorktreeStateManager"
|
||||
import { SetupScriptService } from "./SetupScriptService"
|
||||
import { SetupScriptRunner } from "./SetupScriptRunner"
|
||||
import { SessionTerminalManager } from "./SessionTerminalManager"
|
||||
import { formatKeybinding } from "./format-keybinding"
|
||||
|
||||
/**
|
||||
* AgentManagerProvider opens the Agent Manager panel.
|
||||
@@ -22,7 +25,9 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
private outputChannel: vscode.OutputChannel
|
||||
private worktrees: WorktreeManager | undefined
|
||||
private state: WorktreeStateManager | undefined
|
||||
private setupScript: SetupScriptService | undefined
|
||||
private terminalManager: SessionTerminalManager
|
||||
private stateReady: Promise<void> | undefined
|
||||
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
@@ -70,8 +75,9 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
onBeforeMessage: (msg) => this.onMessage(msg),
|
||||
})
|
||||
|
||||
void this.initializeState()
|
||||
this.stateReady = this.initializeState()
|
||||
void this.sendRepoInfo()
|
||||
this.sendKeybindings()
|
||||
|
||||
this.panel.onDidDispose(() => {
|
||||
this.log("Panel disposed")
|
||||
@@ -88,7 +94,10 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
private async initializeState(): Promise<void> {
|
||||
const manager = this.getWorktreeManager()
|
||||
const state = this.getStateManager()
|
||||
if (!manager || !state) return
|
||||
if (!manager || !state) {
|
||||
this.pushEmptyState()
|
||||
return
|
||||
}
|
||||
|
||||
await state.load()
|
||||
|
||||
@@ -129,6 +138,10 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
return this.onAddSessionToWorktree(msg.worktreeId)
|
||||
if (type === "agentManager.closeSession" && typeof msg.sessionId === "string")
|
||||
return this.onCloseSession(msg.sessionId)
|
||||
if (type === "agentManager.configureSetupScript") {
|
||||
void this.configureSetupScript()
|
||||
return null
|
||||
}
|
||||
if (type === "agentManager.showTerminal" && typeof msg.sessionId === "string") {
|
||||
this.terminalManager.showTerminal(msg.sessionId, this.state)
|
||||
return null
|
||||
@@ -137,6 +150,37 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
void this.sendRepoInfo()
|
||||
return null
|
||||
}
|
||||
if (type === "agentManager.createMultiVersion") {
|
||||
void this.onCreateMultiVersion(msg)
|
||||
return null
|
||||
}
|
||||
if (type === "agentManager.requestState") {
|
||||
void this.stateReady
|
||||
?.then(() => {
|
||||
this.pushState()
|
||||
// Refresh sessions after pushState so the webview's sessionsLoaded
|
||||
// handler is guaranteed to be registered (requestState fires from
|
||||
// onMount). Without this, the initial refreshSessions() in
|
||||
// initializeState() can race ahead of webview mount, causing
|
||||
// sessionsLoaded to never flip to true.
|
||||
if (this.state && this.state.getSessions().length > 0) {
|
||||
this.provider?.refreshSessions()
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
this.log("initializeState failed, pushing partial state:", err)
|
||||
this.pushState()
|
||||
})
|
||||
return null
|
||||
}
|
||||
if (type === "agentManager.setTabOrder" && typeof msg.key === "string" && Array.isArray(msg.order)) {
|
||||
this.state?.setTabOrder(msg.key as string, msg.order as string[])
|
||||
return null
|
||||
}
|
||||
if (type === "agentManager.setSessionsCollapsed" && typeof msg.collapsed === "boolean") {
|
||||
this.state?.setSessionsCollapsed(msg.collapsed as boolean)
|
||||
return null
|
||||
}
|
||||
|
||||
// When switching sessions, show existing terminal if one is open
|
||||
if (type === "loadMessages" && typeof msg.sessionID === "string") {
|
||||
@@ -161,14 +205,18 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Create a git worktree on disk and register it in state. Returns null on failure. */
|
||||
private async createWorktreeOnDisk(): Promise<{
|
||||
private async createWorktreeOnDisk(groupId?: string): Promise<{
|
||||
worktree: ReturnType<WorktreeStateManager["addWorktree"]>
|
||||
result: CreateWorktreeResult
|
||||
} | null> {
|
||||
const manager = this.getWorktreeManager()
|
||||
const state = this.getStateManager()
|
||||
if (!manager || !state) {
|
||||
this.postToWebview({ type: "agentManager.worktreeSetup", status: "error", message: "No workspace folder open" })
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "error",
|
||||
message: "Open a folder that contains a git repository to use worktrees",
|
||||
})
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -178,21 +226,41 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
try {
|
||||
result = await manager.createWorktree({ prompt: "kilo" })
|
||||
} catch (error) {
|
||||
const err = error instanceof Error ? error.message : String(error)
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "error",
|
||||
message: `Failed to create worktree: ${err}`,
|
||||
message: msg,
|
||||
})
|
||||
return null
|
||||
}
|
||||
|
||||
const worktree = state.addWorktree({ branch: result.branch, path: result.path, parentBranch: result.parentBranch })
|
||||
const worktree = state.addWorktree({
|
||||
branch: result.branch,
|
||||
path: result.path,
|
||||
parentBranch: result.parentBranch,
|
||||
groupId,
|
||||
})
|
||||
|
||||
// Push state immediately so the sidebar shows the new worktree with a loading indicator
|
||||
this.pushState()
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "creating",
|
||||
message: "Setting up workspace...",
|
||||
branch: result.branch,
|
||||
worktreeId: worktree.id,
|
||||
})
|
||||
|
||||
return { worktree, result }
|
||||
}
|
||||
|
||||
/** Create a CLI session in a worktree directory. Returns null on failure. */
|
||||
private async createSessionInWorktree(worktreePath: string, branch: string): Promise<SessionInfo | null> {
|
||||
private async createSessionInWorktree(
|
||||
worktreePath: string,
|
||||
branch: string,
|
||||
worktreeId?: string,
|
||||
): Promise<SessionInfo | null> {
|
||||
let client: HttpClient
|
||||
try {
|
||||
client = this.connectionService.getHttpClient()
|
||||
@@ -201,6 +269,7 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "error",
|
||||
message: "Not connected to CLI backend",
|
||||
worktreeId,
|
||||
})
|
||||
return null
|
||||
}
|
||||
@@ -210,6 +279,7 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
status: "starting",
|
||||
message: "Starting session...",
|
||||
branch,
|
||||
worktreeId,
|
||||
})
|
||||
|
||||
try {
|
||||
@@ -220,13 +290,14 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "error",
|
||||
message: `Failed to create session: ${err}`,
|
||||
worktreeId,
|
||||
})
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Send worktreeSetup.ready + sessionMeta + pushState after worktree creation. */
|
||||
private notifyWorktreeReady(sessionId: string, result: CreateWorktreeResult): void {
|
||||
private notifyWorktreeReady(sessionId: string, result: CreateWorktreeResult, worktreeId?: string): void {
|
||||
this.pushState()
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
@@ -234,6 +305,7 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
message: "Worktree ready",
|
||||
sessionId,
|
||||
branch: result.branch,
|
||||
worktreeId,
|
||||
})
|
||||
this.postToWebview({
|
||||
type: "agentManager.sessionMeta",
|
||||
@@ -254,19 +326,23 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
const created = await this.createWorktreeOnDisk()
|
||||
if (!created) return null
|
||||
|
||||
const session = await this.createSessionInWorktree(created.result.path, created.result.branch)
|
||||
// Run setup script for new worktree (blocks until complete, shows in overlay)
|
||||
await this.runSetupScriptForWorktree(created.result.path, created.result.branch, created.worktree.id)
|
||||
|
||||
const session = await this.createSessionInWorktree(created.result.path, created.result.branch, created.worktree.id)
|
||||
if (!session) {
|
||||
const state = this.getStateManager()
|
||||
const manager = this.getWorktreeManager()
|
||||
state?.removeWorktree(created.worktree.id)
|
||||
await manager?.removeWorktree(created.result.path)
|
||||
this.pushState()
|
||||
return null
|
||||
}
|
||||
|
||||
const state = this.getStateManager()!
|
||||
state.addSession(session.id, created.worktree.id)
|
||||
this.registerWorktreeSession(session.id, created.result.path)
|
||||
this.notifyWorktreeReady(session.id, created.result)
|
||||
this.notifyWorktreeReady(session.id, created.result, created.worktree.id)
|
||||
this.log(`Created worktree ${created.worktree.id} with session ${session.id}`)
|
||||
return null
|
||||
}
|
||||
@@ -303,6 +379,9 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
const created = await this.createWorktreeOnDisk()
|
||||
if (!created) return null
|
||||
|
||||
// Run setup script for new worktree (blocks until complete, shows in overlay)
|
||||
await this.runSetupScriptForWorktree(created.result.path, created.result.branch, created.worktree.id)
|
||||
|
||||
const state = this.getStateManager()!
|
||||
if (!state.getSession(sessionId)) {
|
||||
state.addSession(sessionId, created.worktree.id)
|
||||
@@ -311,7 +390,7 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
}
|
||||
|
||||
this.registerWorktreeSession(sessionId, created.result.path)
|
||||
this.notifyWorktreeReady(sessionId, created.result)
|
||||
this.notifyWorktreeReady(sessionId, created.result, created.worktree.id)
|
||||
this.log(`Promoted session ${sessionId} to worktree ${created.worktree.id}`)
|
||||
return null
|
||||
}
|
||||
@@ -372,6 +451,210 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
return null
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Multi-version worktree creation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Create N worktree sessions for the same prompt (multi-version mode). */
|
||||
private async onCreateMultiVersion(msg: Record<string, unknown>): Promise<null> {
|
||||
const text = msg.text as string
|
||||
if (!text) return null
|
||||
|
||||
const versions = Math.min(Math.max(Number(msg.versions) || 1, 1), 4)
|
||||
const providerID = msg.providerID as string | undefined
|
||||
const modelID = msg.modelID as string | undefined
|
||||
const agent = msg.agent as string | undefined
|
||||
const files = msg.files as Array<{ mime: string; url: string }> | undefined
|
||||
|
||||
// Generate a shared group ID for multi-version worktrees
|
||||
const groupId = versions > 1 ? `grp-${Date.now()}` : undefined
|
||||
|
||||
this.log(
|
||||
`Creating ${versions} multi-version worktrees for: ${text.slice(0, 60)}${groupId ? ` (group=${groupId})` : ""}`,
|
||||
)
|
||||
|
||||
// Notify webview that multi-version creation has started
|
||||
this.postToWebview({
|
||||
type: "agentManager.multiVersionProgress",
|
||||
status: "creating",
|
||||
total: versions,
|
||||
completed: 0,
|
||||
groupId,
|
||||
})
|
||||
|
||||
// Phase 1: Create all worktrees + sessions first
|
||||
const created: Array<{
|
||||
worktreeId: string
|
||||
sessionId: string
|
||||
path: string
|
||||
branch: string
|
||||
parentBranch: string
|
||||
}> = []
|
||||
|
||||
for (let i = 0; i < versions; i++) {
|
||||
this.log(`Creating worktree ${i + 1}/${versions}`)
|
||||
|
||||
const wt = await this.createWorktreeOnDisk(groupId)
|
||||
if (!wt) {
|
||||
this.log(`Failed to create worktree for version ${i + 1}`)
|
||||
continue
|
||||
}
|
||||
|
||||
await this.runSetupScriptForWorktree(wt.result.path, wt.result.branch)
|
||||
|
||||
const session = await this.createSessionInWorktree(wt.result.path, wt.result.branch)
|
||||
if (!session) {
|
||||
const state = this.getStateManager()
|
||||
const manager = this.getWorktreeManager()
|
||||
state?.removeWorktree(wt.worktree.id)
|
||||
await manager?.removeWorktree(wt.result.path)
|
||||
this.log(`Failed to create session for version ${i + 1}`)
|
||||
continue
|
||||
}
|
||||
|
||||
const state = this.getStateManager()!
|
||||
state.addSession(session.id, wt.worktree.id)
|
||||
this.registerWorktreeSession(session.id, wt.result.path)
|
||||
this.notifyWorktreeReady(session.id, wt.result)
|
||||
|
||||
created.push({
|
||||
worktreeId: wt.worktree.id,
|
||||
sessionId: session.id,
|
||||
path: wt.result.path,
|
||||
branch: wt.result.branch,
|
||||
parentBranch: wt.result.parentBranch,
|
||||
})
|
||||
|
||||
this.log(`Version ${i + 1} worktree ready: session=${session.id}`)
|
||||
|
||||
// Update progress
|
||||
this.postToWebview({
|
||||
type: "agentManager.multiVersionProgress",
|
||||
status: "creating",
|
||||
total: versions,
|
||||
completed: created.length,
|
||||
groupId,
|
||||
})
|
||||
}
|
||||
|
||||
// Phase 2: Send the initial prompt to all sessions via the KiloProvider's
|
||||
// message handling (same path as typing in the chat). This ensures SSE
|
||||
// subscriptions and session tracking are properly set up before the message
|
||||
// is sent. We route each message through the webview→KiloProvider pipeline.
|
||||
for (let i = 0; i < created.length; i++) {
|
||||
const entry = created[i]!
|
||||
this.log(`Sending initial message to version ${i + 1} (session=${entry.sessionId})`)
|
||||
|
||||
// Tell the webview to send the message through the normal session flow
|
||||
this.postToWebview({
|
||||
type: "agentManager.sendInitialMessage",
|
||||
sessionId: entry.sessionId,
|
||||
worktreeId: entry.worktreeId,
|
||||
text,
|
||||
providerID,
|
||||
modelID,
|
||||
agent,
|
||||
files,
|
||||
})
|
||||
|
||||
// Small delay between sends to avoid overwhelming the backend
|
||||
if (i < created.length - 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300))
|
||||
}
|
||||
}
|
||||
|
||||
// Notify completion
|
||||
this.postToWebview({
|
||||
type: "agentManager.multiVersionProgress",
|
||||
status: "done",
|
||||
total: versions,
|
||||
completed: created.length,
|
||||
groupId,
|
||||
})
|
||||
|
||||
if (created.length === 0) {
|
||||
vscode.window.showErrorMessage(`Failed to create any of the ${versions} multi-version worktrees.`)
|
||||
}
|
||||
|
||||
this.log(`Multi-version creation complete: ${created.length}/${versions} versions`)
|
||||
return null
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Keybindings
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
private sendKeybindings(): void {
|
||||
const ext = vscode.extensions.getExtension("kilocode.kilo-code")
|
||||
const keybindings: Array<{ command: string; key?: string; mac?: string }> =
|
||||
ext?.packageJSON?.contributes?.keybindings ?? []
|
||||
|
||||
const mac = process.platform === "darwin"
|
||||
const prefix = "kilo-code.new.agentManager."
|
||||
const bindings: Record<string, string> = {}
|
||||
|
||||
// Global keybindings exposed to the shortcuts dialog
|
||||
const globals: Record<string, string> = {
|
||||
"kilo-code.new.agentManagerOpen": "agentManagerOpen",
|
||||
}
|
||||
|
||||
for (const kb of keybindings) {
|
||||
const raw = mac ? (kb.mac ?? kb.key) : kb.key
|
||||
if (!raw) continue
|
||||
|
||||
if (kb.command.startsWith(prefix)) {
|
||||
bindings[kb.command.slice(prefix.length)] = formatKeybinding(raw, mac)
|
||||
} else if (globals[kb.command]) {
|
||||
bindings[globals[kb.command]] = formatKeybinding(raw, mac)
|
||||
}
|
||||
}
|
||||
|
||||
this.postToWebview({ type: "agentManager.keybindings", bindings })
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Setup script
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Open the worktree setup script in the editor for user configuration. */
|
||||
private async configureSetupScript(): Promise<void> {
|
||||
const service = this.getSetupScriptService()
|
||||
if (!service) return
|
||||
try {
|
||||
await service.openInEditor()
|
||||
} catch (error) {
|
||||
this.log(`Failed to open setup script: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/** Run the worktree setup script if configured. Blocks until complete. Shows progress in overlay. */
|
||||
private async runSetupScriptForWorktree(worktreePath: string, branch?: string, worktreeId?: string): Promise<void> {
|
||||
const root = this.getWorkspaceRoot()
|
||||
if (!root) return
|
||||
try {
|
||||
const service = this.getSetupScriptService()
|
||||
if (!service || !service.hasScript()) return
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "creating",
|
||||
message: "Running setup script...",
|
||||
branch,
|
||||
worktreeId,
|
||||
})
|
||||
const runner = new SetupScriptRunner(this.outputChannel, service)
|
||||
await runner.runIfConfigured({ worktreePath, repoPath: root })
|
||||
} catch (error) {
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
this.outputChannel.appendLine(`[AgentManager] Setup script error: ${msg}`)
|
||||
this.postToWebview({
|
||||
type: "agentManager.worktreeSetup",
|
||||
status: "error",
|
||||
message: `Setup script failed: ${msg}`,
|
||||
branch,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Repo info
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -404,6 +687,19 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
type: "agentManager.state",
|
||||
worktrees: state.getWorktrees(),
|
||||
sessions: state.getSessions(),
|
||||
tabOrder: state.getTabOrder(),
|
||||
sessionsCollapsed: state.getSessionsCollapsed(),
|
||||
isGitRepo: true,
|
||||
})
|
||||
}
|
||||
|
||||
/** Push empty state when the workspace is not a git repo or has no workspace folder. */
|
||||
private pushEmptyState(): void {
|
||||
this.postToWebview({
|
||||
type: "agentManager.state",
|
||||
worktrees: [],
|
||||
sessions: [],
|
||||
isGitRepo: false,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -439,6 +735,17 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
return this.state
|
||||
}
|
||||
|
||||
private getSetupScriptService(): SetupScriptService | undefined {
|
||||
if (this.setupScript) return this.setupScript
|
||||
const root = this.getWorkspaceRoot()
|
||||
if (!root) {
|
||||
this.log("getSetupScriptService: no workspace folder available")
|
||||
return undefined
|
||||
}
|
||||
this.setupScript = new SetupScriptService(root)
|
||||
return this.setupScript
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -474,6 +781,10 @@ export class AgentManagerProvider implements vscode.Disposable {
|
||||
this.panel.reveal(vscode.ViewColumn.One, false)
|
||||
}
|
||||
|
||||
public isActive(): boolean {
|
||||
return this.panel?.active === true
|
||||
}
|
||||
|
||||
public postMessage(message: unknown): void {
|
||||
this.panel?.webview.postMessage(message)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export class SessionTerminalManager {
|
||||
|
||||
if (!cwd) {
|
||||
this.log(`showTerminal: no cwd resolved for session ${sessionId}`)
|
||||
vscode.window.showWarningMessage("No workspace folder open")
|
||||
vscode.window.showWarningMessage("Open a folder that contains a git repository to use worktrees")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* SetupScriptRunner - Executes worktree setup scripts
|
||||
*
|
||||
* Runs setup scripts in VS Code integrated terminal before agent starts.
|
||||
* Uses VS Code shell integration to track execution and exit code.
|
||||
* Falls back to sendText + onDidCloseTerminal if shell integration is unavailable.
|
||||
* Cross-platform: Unix uses sh, Windows uses cmd.exe.
|
||||
*/
|
||||
|
||||
import * as vscode from "vscode"
|
||||
import { SetupScriptService } from "./SetupScriptService"
|
||||
import { buildSetupCommand } from "./setup-script-command"
|
||||
|
||||
export interface SetupScriptEnvironment {
|
||||
/** Absolute path to the worktree directory */
|
||||
worktreePath: string
|
||||
/** Absolute path to the main repository */
|
||||
repoPath: string
|
||||
}
|
||||
|
||||
export class SetupScriptRunner {
|
||||
constructor(
|
||||
private readonly output: vscode.OutputChannel,
|
||||
private readonly service: SetupScriptService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Execute setup script in a worktree if script exists.
|
||||
* Waits for the script to finish before resolving.
|
||||
*
|
||||
* @returns true if script was executed, false if skipped (no script configured)
|
||||
*/
|
||||
async runIfConfigured(env: SetupScriptEnvironment): Promise<boolean> {
|
||||
if (!this.service.hasScript()) {
|
||||
this.log("No setup script configured, skipping")
|
||||
return false
|
||||
}
|
||||
|
||||
const script = this.service.getScriptPath()
|
||||
this.log(`Running setup script: ${script}`)
|
||||
|
||||
try {
|
||||
await this.executeInTerminal(script, env)
|
||||
this.log("Setup script completed")
|
||||
return true
|
||||
} catch (error) {
|
||||
const msg = error instanceof Error ? error.message : String(error)
|
||||
this.log(`Setup script execution failed: ${msg}`)
|
||||
return true // Script was attempted
|
||||
}
|
||||
}
|
||||
|
||||
/** Execute the setup script in a VS Code terminal and wait for it to finish. */
|
||||
private async executeInTerminal(script: string, env: SetupScriptEnvironment): Promise<void> {
|
||||
const terminal = vscode.window.createTerminal({
|
||||
name: "Worktree Setup",
|
||||
cwd: env.worktreePath,
|
||||
env: {
|
||||
WORKTREE_PATH: env.worktreePath,
|
||||
REPO_PATH: env.repoPath,
|
||||
},
|
||||
iconPath: new vscode.ThemeIcon("gear"),
|
||||
})
|
||||
|
||||
terminal.show(true)
|
||||
|
||||
// Try shell integration first — gives us proper exit code tracking
|
||||
const integration = await this.waitForShellIntegration(terminal, 5000)
|
||||
if (integration) {
|
||||
this.log("Using shell integration for setup script execution")
|
||||
await this.runViaShellIntegration(terminal, integration, script, env)
|
||||
} else {
|
||||
this.log("Shell integration unavailable, falling back to sendText")
|
||||
await this.runViaSendText(terminal, script, env)
|
||||
}
|
||||
}
|
||||
|
||||
/** Wait for shell integration to become available on a terminal, with timeout. */
|
||||
private waitForShellIntegration(
|
||||
terminal: vscode.Terminal,
|
||||
timeout: number,
|
||||
): Promise<vscode.TerminalShellIntegration | undefined> {
|
||||
if (terminal.shellIntegration) return Promise.resolve(terminal.shellIntegration)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(() => {
|
||||
listener.dispose()
|
||||
resolve(undefined)
|
||||
}, timeout)
|
||||
|
||||
const listener = vscode.window.onDidChangeTerminalShellIntegration((e) => {
|
||||
if (e.terminal !== terminal) return
|
||||
clearTimeout(timer)
|
||||
listener.dispose()
|
||||
resolve(e.shellIntegration)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** Run script via shell integration — tracks execution and exit code properly. */
|
||||
private runViaShellIntegration(
|
||||
terminal: vscode.Terminal,
|
||||
integration: vscode.TerminalShellIntegration,
|
||||
script: string,
|
||||
env: SetupScriptEnvironment,
|
||||
): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const command = buildSetupCommand(script, env)
|
||||
const execution = integration.executeCommand(command)
|
||||
|
||||
const cleanup = () => {
|
||||
execListener.dispose()
|
||||
closeListener.dispose()
|
||||
}
|
||||
|
||||
// Primary: shell integration reports execution finished with exit code
|
||||
const execListener = vscode.window.onDidEndTerminalShellExecution((e) => {
|
||||
if (e.execution !== execution) return
|
||||
cleanup()
|
||||
this.log(`Setup script exited with code ${e.exitCode ?? "unknown"}`)
|
||||
resolve()
|
||||
})
|
||||
|
||||
// Fallback: terminal was closed externally (user, VS Code restart, etc.)
|
||||
const closeListener = vscode.window.onDidCloseTerminal((closed) => {
|
||||
if (closed !== terminal) return
|
||||
cleanup()
|
||||
this.log("Setup script terminal closed before execution event fired")
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** Fallback: run via sendText and wait for terminal to close. */
|
||||
private runViaSendText(terminal: vscode.Terminal, script: string, env: SetupScriptEnvironment): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const listener = vscode.window.onDidCloseTerminal((closed) => {
|
||||
if (closed !== terminal) return
|
||||
listener.dispose()
|
||||
resolve()
|
||||
})
|
||||
|
||||
const command = buildSetupCommand(script, env) + (process.platform === "win32" ? "& exit" : "; exit")
|
||||
terminal.sendText(command)
|
||||
this.log("Setup script started in terminal, waiting for completion...")
|
||||
})
|
||||
}
|
||||
|
||||
private log(message: string): void {
|
||||
this.output.appendLine(`[SetupScriptRunner] ${message}`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* SetupScriptService - Manages worktree setup scripts
|
||||
*
|
||||
* Handles reading, creating, and checking for setup scripts stored in .kilocode/setup-script.
|
||||
* Setup scripts run before an agent starts in a worktree (new sessions only).
|
||||
*/
|
||||
|
||||
import * as vscode from "vscode"
|
||||
import * as fs from "node:fs"
|
||||
import * as path from "node:path"
|
||||
import { SETUP_SCRIPT_TEMPLATE } from "./setup-script-template"
|
||||
|
||||
const SETUP_SCRIPT_FILENAME = "setup-script"
|
||||
const KILOCODE_DIR = ".kilocode"
|
||||
|
||||
export class SetupScriptService {
|
||||
private readonly root: string
|
||||
private readonly script: string
|
||||
|
||||
constructor(root: string) {
|
||||
this.root = root
|
||||
this.script = path.join(root, KILOCODE_DIR, SETUP_SCRIPT_FILENAME)
|
||||
}
|
||||
|
||||
/** Get the path to the setup script */
|
||||
getScriptPath(): string {
|
||||
return this.script
|
||||
}
|
||||
|
||||
/** Check if a setup script exists */
|
||||
hasScript(): boolean {
|
||||
return fs.existsSync(this.script)
|
||||
}
|
||||
|
||||
/** Read the setup script content. Returns null if not found or read fails. */
|
||||
async getScript(): Promise<string | null> {
|
||||
if (!this.hasScript()) return null
|
||||
try {
|
||||
return await fs.promises.readFile(this.script, "utf-8")
|
||||
} catch (error) {
|
||||
this.log(`Failed to read setup script: ${error}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a default setup script with helpful comments */
|
||||
async createDefaultScript(): Promise<void> {
|
||||
const dir = path.join(this.root, KILOCODE_DIR)
|
||||
if (!fs.existsSync(dir)) {
|
||||
await fs.promises.mkdir(dir, { recursive: true })
|
||||
}
|
||||
await fs.promises.writeFile(this.script, SETUP_SCRIPT_TEMPLATE, "utf-8")
|
||||
}
|
||||
|
||||
/** Open the setup script in VS Code editor. Creates the default script if it doesn't exist. */
|
||||
async openInEditor(): Promise<void> {
|
||||
if (!this.hasScript()) {
|
||||
await this.createDefaultScript()
|
||||
}
|
||||
const document = await vscode.workspace.openTextDocument(this.script)
|
||||
await vscode.window.showTextDocument(document)
|
||||
}
|
||||
|
||||
private log(message: string): void {
|
||||
// Log to console since we don't have an OutputChannel here
|
||||
console.log(`[SetupScriptService] ${message}`)
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,10 @@ export class WorktreeManager {
|
||||
|
||||
async createWorktree(params: { prompt?: string; existingBranch?: string }): Promise<CreateWorktreeResult> {
|
||||
const repo = await this.git.checkIsRepo()
|
||||
if (!repo) throw new Error("Workspace is not a git repository")
|
||||
if (!repo)
|
||||
throw new Error(
|
||||
"This folder is not a git repository. Initialize a repository or open a git project to use worktrees.",
|
||||
)
|
||||
|
||||
await this.ensureDir()
|
||||
await this.ensureGitExclude()
|
||||
@@ -182,6 +185,7 @@ export class WorktreeManager {
|
||||
const excludePath = path.join(gitDir, "info", "exclude")
|
||||
await this.addExcludeEntry(excludePath, ".kilocode/worktrees/", "Kilo Code agent worktrees")
|
||||
await this.addExcludeEntry(excludePath, ".kilocode/agent-manager.json", "Kilo Agent Manager state")
|
||||
await this.addExcludeEntry(excludePath, ".kilocode/setup-script", "Kilo Code worktree setup script")
|
||||
}
|
||||
|
||||
private async ensureWorktreeExclude(worktreePath: string): Promise<void> {
|
||||
|
||||
@@ -18,6 +18,8 @@ export interface Worktree {
|
||||
path: string
|
||||
parentBranch: string
|
||||
createdAt: string
|
||||
/** Shared identifier for worktrees created together via multi-version mode. */
|
||||
groupId?: string
|
||||
}
|
||||
|
||||
export interface ManagedSession {
|
||||
@@ -29,6 +31,8 @@ export interface ManagedSession {
|
||||
interface StateFile {
|
||||
worktrees: Record<string, Omit<Worktree, "id">>
|
||||
sessions: Record<string, Omit<ManagedSession, "id">>
|
||||
tabOrder?: Record<string, string[]>
|
||||
sessionsCollapsed?: boolean
|
||||
}
|
||||
|
||||
const STATE_FILE = "agent-manager.json"
|
||||
@@ -44,6 +48,8 @@ export class WorktreeStateManager {
|
||||
private readonly file: string
|
||||
private worktrees = new Map<string, Worktree>()
|
||||
private sessions = new Map<string, ManagedSession>()
|
||||
private tabOrder: Record<string, string[]> = {}
|
||||
private collapsed = false
|
||||
private readonly log: (msg: string) => void
|
||||
private saving: Promise<void> | undefined
|
||||
private pendingSave = false
|
||||
@@ -103,11 +109,18 @@ export class WorktreeStateManager {
|
||||
// Mutations
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
addWorktree(params: { branch: string; path: string; parentBranch: string }): Worktree {
|
||||
addWorktree(params: { branch: string; path: string; parentBranch: string; groupId?: string }): Worktree {
|
||||
const id = generateId("wt")
|
||||
const wt: Worktree = { id, ...params, createdAt: new Date().toISOString() }
|
||||
const wt: Worktree = {
|
||||
id,
|
||||
branch: params.branch,
|
||||
path: params.path,
|
||||
parentBranch: params.parentBranch,
|
||||
createdAt: new Date().toISOString(),
|
||||
}
|
||||
if (params.groupId) wt.groupId = params.groupId
|
||||
this.worktrees.set(id, wt)
|
||||
this.log(`Added worktree ${id}: ${params.branch}`)
|
||||
this.log(`Added worktree ${id}: ${params.branch}${params.groupId ? ` (group=${params.groupId})` : ""}`)
|
||||
void this.save()
|
||||
return wt
|
||||
}
|
||||
@@ -125,6 +138,9 @@ export class WorktreeStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up tab order for this worktree
|
||||
delete this.tabOrder[id]
|
||||
|
||||
this.log(`Removed worktree ${id}, orphaned ${orphaned.length} sessions`)
|
||||
void this.save()
|
||||
return orphaned
|
||||
@@ -149,6 +165,47 @@ export class WorktreeStateManager {
|
||||
|
||||
removeSession(id: string): void {
|
||||
this.sessions.delete(id)
|
||||
|
||||
// Remove this session from any tab order arrays
|
||||
for (const [key, order] of Object.entries(this.tabOrder)) {
|
||||
const idx = order.indexOf(id)
|
||||
if (idx !== -1) {
|
||||
order.splice(idx, 1)
|
||||
if (order.length === 0) delete this.tabOrder[key]
|
||||
}
|
||||
}
|
||||
|
||||
void this.save()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tab order
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
getTabOrder(): Record<string, string[]> {
|
||||
return this.tabOrder
|
||||
}
|
||||
|
||||
setTabOrder(key: string, order: string[]): void {
|
||||
this.tabOrder[key] = order
|
||||
void this.save()
|
||||
}
|
||||
|
||||
removeTabOrder(key: string): void {
|
||||
delete this.tabOrder[key]
|
||||
void this.save()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Sessions collapsed
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
getSessionsCollapsed(): boolean {
|
||||
return this.collapsed
|
||||
}
|
||||
|
||||
setSessionsCollapsed(value: boolean): void {
|
||||
this.collapsed = value
|
||||
void this.save()
|
||||
}
|
||||
|
||||
@@ -162,6 +219,7 @@ export class WorktreeStateManager {
|
||||
const data = JSON.parse(content) as StateFile
|
||||
this.worktrees.clear()
|
||||
this.sessions.clear()
|
||||
this.tabOrder = {}
|
||||
|
||||
for (const [id, wt] of Object.entries(data.worktrees ?? {})) {
|
||||
this.worktrees.set(id, { id, ...wt })
|
||||
@@ -169,6 +227,10 @@ export class WorktreeStateManager {
|
||||
for (const [id, s] of Object.entries(data.sessions ?? {})) {
|
||||
this.sessions.set(id, { id, ...s })
|
||||
}
|
||||
if (data.tabOrder) {
|
||||
this.tabOrder = data.tabOrder
|
||||
}
|
||||
this.collapsed = data.sessionsCollapsed ?? false
|
||||
this.log(`Loaded state: ${this.worktrees.size} worktrees, ${this.sessions.size} sessions`)
|
||||
} catch (error) {
|
||||
const code = (error as NodeJS.ErrnoException).code
|
||||
@@ -229,6 +291,12 @@ export class WorktreeStateManager {
|
||||
const { id: _, ...rest } = s
|
||||
data.sessions[id] = rest
|
||||
}
|
||||
if (Object.keys(this.tabOrder).length > 0) {
|
||||
data.tabOrder = this.tabOrder
|
||||
}
|
||||
if (this.collapsed) {
|
||||
data.sessionsCollapsed = true
|
||||
}
|
||||
|
||||
const dir = path.dirname(this.file)
|
||||
if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true })
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { describe, it, expect } from "vitest"
|
||||
import { buildSetupCommand } from "../setup-script-command"
|
||||
|
||||
const env = {
|
||||
worktreePath: "/repos/project/.kilocode/worktrees/wt-1",
|
||||
repoPath: "/repos/project",
|
||||
}
|
||||
|
||||
const script = "/repos/project/.kilocode/setup-script"
|
||||
|
||||
describe("buildSetupCommand", () => {
|
||||
it("builds unix command with inline env vars and sh", () => {
|
||||
const result = buildSetupCommand(script, env, "darwin")
|
||||
expect(result).toBe(
|
||||
`WORKTREE_PATH="/repos/project/.kilocode/worktrees/wt-1" REPO_PATH="/repos/project" sh "/repos/project/.kilocode/setup-script"`,
|
||||
)
|
||||
})
|
||||
|
||||
it("builds linux command same as darwin", () => {
|
||||
const result = buildSetupCommand(script, env, "linux")
|
||||
expect(result).toContain("sh ")
|
||||
expect(result).not.toContain("set ")
|
||||
expect(result).not.toContain("call ")
|
||||
})
|
||||
|
||||
it("builds windows command with set and call", () => {
|
||||
const result = buildSetupCommand(script, env, "win32")
|
||||
expect(result).toBe(
|
||||
`set "WORKTREE_PATH=/repos/project/.kilocode/worktrees/wt-1" && set "REPO_PATH=/repos/project" && call "/repos/project/.kilocode/setup-script"`,
|
||||
)
|
||||
})
|
||||
|
||||
it("includes both env vars in unix command", () => {
|
||||
const result = buildSetupCommand(script, env, "darwin")
|
||||
expect(result).toContain(`WORKTREE_PATH="${env.worktreePath}"`)
|
||||
expect(result).toContain(`REPO_PATH="${env.repoPath}"`)
|
||||
})
|
||||
|
||||
it("includes both env vars in windows command", () => {
|
||||
const result = buildSetupCommand(script, env, "win32")
|
||||
expect(result).toContain(`set "WORKTREE_PATH=${env.worktreePath}"`)
|
||||
expect(result).toContain(`set "REPO_PATH=${env.repoPath}"`)
|
||||
})
|
||||
|
||||
it("handles paths with spaces", () => {
|
||||
const spaced = {
|
||||
worktreePath: "/Users/dev/my project/.kilocode/worktrees/wt-1",
|
||||
repoPath: "/Users/dev/my project",
|
||||
}
|
||||
const spacedScript = "/Users/dev/my project/.kilocode/setup-script"
|
||||
|
||||
const unix = buildSetupCommand(spacedScript, spaced, "darwin")
|
||||
expect(unix).toContain(`sh "/Users/dev/my project/.kilocode/setup-script"`)
|
||||
|
||||
const win = buildSetupCommand(spacedScript, spaced, "win32")
|
||||
expect(win).toContain(`call "/Users/dev/my project/.kilocode/setup-script"`)
|
||||
})
|
||||
|
||||
it("escapes double quotes in unix paths", () => {
|
||||
const dangerous = {
|
||||
worktreePath: '/repos/proj"ect',
|
||||
repoPath: "/repos/safe",
|
||||
}
|
||||
const result = buildSetupCommand(script, dangerous, "darwin")
|
||||
expect(result).toContain(`WORKTREE_PATH="/repos/proj\\"ect"`)
|
||||
})
|
||||
|
||||
it("escapes dollar signs in unix paths", () => {
|
||||
const dangerous = {
|
||||
worktreePath: "/repos/$HOME/project",
|
||||
repoPath: "/repos/safe",
|
||||
}
|
||||
const result = buildSetupCommand(script, dangerous, "darwin")
|
||||
expect(result).toContain(`WORKTREE_PATH="/repos/\\$HOME/project"`)
|
||||
})
|
||||
|
||||
it("escapes backticks in unix paths", () => {
|
||||
const dangerous = {
|
||||
worktreePath: "/repos/`whoami`/project",
|
||||
repoPath: "/repos/safe",
|
||||
}
|
||||
const result = buildSetupCommand(script, dangerous, "darwin")
|
||||
expect(result).toContain('WORKTREE_PATH="/repos/\\`whoami\\`/project"')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
const KEY_SYMBOLS: Record<string, { mac: string; other: string }> = {
|
||||
ctrl: { mac: "⌃", other: "Ctrl" },
|
||||
cmd: { mac: "⌘", other: "Ctrl" },
|
||||
shift: { mac: "⇧", other: "Shift" },
|
||||
alt: { mac: "⌥", other: "Alt" },
|
||||
}
|
||||
|
||||
const SPECIAL_KEYS: Record<string, string> = {
|
||||
left: "←",
|
||||
right: "→",
|
||||
up: "↑",
|
||||
down: "↓",
|
||||
backspace: "⌫",
|
||||
delete: "Del",
|
||||
enter: "↵",
|
||||
escape: "Esc",
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a VS Code keybinding string (e.g. "cmd+shift+w") into
|
||||
* a display string using platform-appropriate symbols.
|
||||
* Mac: "⌘⇧W" Windows/Linux: "Ctrl+Shift+W"
|
||||
*/
|
||||
export function formatKeybinding(raw: string, mac: boolean): string {
|
||||
const symbols = raw
|
||||
.split("+")
|
||||
.map((p) => p.trim().toLowerCase())
|
||||
.map((part) => {
|
||||
const mod = KEY_SYMBOLS[part]
|
||||
if (mod) return mac ? mod.mac : mod.other
|
||||
return SPECIAL_KEYS[part] ?? part.toUpperCase()
|
||||
})
|
||||
return mac ? symbols.join("") : symbols.join("+")
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/** Escape characters that are special inside double-quoted shell strings. */
|
||||
function escapeShell(value: string): string {
|
||||
return value.replace(/["$`\\]/g, "\\$&")
|
||||
}
|
||||
|
||||
/** Build the platform-appropriate command string for running a setup script. */
|
||||
export function buildSetupCommand(
|
||||
script: string,
|
||||
env: { worktreePath: string; repoPath: string },
|
||||
platform: NodeJS.Platform = process.platform,
|
||||
): string {
|
||||
if (platform === "win32") {
|
||||
// Windows cmd.exe: double quotes in set values don't need escaping the same way,
|
||||
// but we escape for the call argument
|
||||
return `set "WORKTREE_PATH=${env.worktreePath}" && set "REPO_PATH=${env.repoPath}" && call "${script}"`
|
||||
}
|
||||
const wt = escapeShell(env.worktreePath)
|
||||
const repo = escapeShell(env.repoPath)
|
||||
const path = escapeShell(script)
|
||||
return `WORKTREE_PATH="${wt}" REPO_PATH="${repo}" sh "${path}"`
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/** Default template for worktree setup scripts. */
|
||||
export const SETUP_SCRIPT_TEMPLATE = `#!/bin/bash
|
||||
# Kilo Code Worktree Setup Script
|
||||
# This script runs before the agent starts in a worktree (new sessions only).
|
||||
#
|
||||
# Available environment variables:
|
||||
# WORKTREE_PATH - Absolute path to the worktree directory
|
||||
# REPO_PATH - Absolute path to the main repository
|
||||
#
|
||||
# Example tasks:
|
||||
# - Copy .env files from main repo
|
||||
# - Install dependencies
|
||||
# - Run database migrations
|
||||
# - Set up local configuration
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
echo "Setting up worktree: $WORKTREE_PATH"
|
||||
|
||||
# Uncomment and modify as needed:
|
||||
|
||||
# Copy environment files
|
||||
# if [ -f "$REPO_PATH/.env" ]; then
|
||||
# cp "$REPO_PATH/.env" "$WORKTREE_PATH/.env"
|
||||
# echo "Copied .env"
|
||||
# fi
|
||||
|
||||
# Install dependencies (Node.js)
|
||||
# if [ -f "$WORKTREE_PATH/package.json" ]; then
|
||||
# cd "$WORKTREE_PATH"
|
||||
# npm install
|
||||
# fi
|
||||
|
||||
# Install dependencies (Python)
|
||||
# if [ -f "$WORKTREE_PATH/requirements.txt" ]; then
|
||||
# cd "$WORKTREE_PATH"
|
||||
# pip install -r requirements.txt
|
||||
# fi
|
||||
|
||||
echo "Setup complete!"
|
||||
`
|
||||
@@ -33,7 +33,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
})
|
||||
|
||||
// Create the provider with shared service
|
||||
const provider = new KiloProvider(context.extensionUri, connectionService)
|
||||
const provider = new KiloProvider(context.extensionUri, connectionService, context)
|
||||
|
||||
// Register the webview view provider for the sidebar.
|
||||
// retainContextWhenHidden keeps the webview alive when switching to other sidebar panels.
|
||||
@@ -109,7 +109,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
registerCommitMessageService(context, connectionService)
|
||||
|
||||
// Register code actions (editor context menus, terminal context menus, keyboard shortcuts)
|
||||
registerCodeActions(context, provider)
|
||||
registerCodeActions(context, provider, agentManagerProvider)
|
||||
registerTerminalActions(context, provider)
|
||||
|
||||
// Register CodeActionProvider (lightbulb quick fixes)
|
||||
@@ -157,7 +157,7 @@ async function openKiloInNewTab(context: vscode.ExtensionContext, connectionServ
|
||||
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "kilo-dark.svg"),
|
||||
}
|
||||
|
||||
const tabProvider = new KiloProvider(context.extensionUri, connectionService)
|
||||
const tabProvider = new KiloProvider(context.extensionUri, connectionService, context)
|
||||
tabProvider.resolveWebviewPanel(panel)
|
||||
|
||||
// Wait for the new panel to become active before locking the editor group.
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import type { SessionInfo, AgentInfo, Provider, SSEEvent } from "./services/cli-backend/types"
|
||||
|
||||
export function sessionToWebview(session: SessionInfo) {
|
||||
return {
|
||||
id: session.id,
|
||||
title: session.title,
|
||||
createdAt: new Date(session.time.created).toISOString(),
|
||||
updatedAt: new Date(session.time.updated).toISOString(),
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeProviders(all: Record<string, Provider>): Record<string, Provider> {
|
||||
const normalized: Record<string, Provider> = {}
|
||||
for (const provider of Object.values(all)) {
|
||||
normalized[provider.id] = provider
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function filterVisibleAgents(agents: AgentInfo[]): { visible: AgentInfo[]; defaultAgent: string } {
|
||||
const visible = agents.filter((a) => a.mode !== "subagent" && !a.hidden)
|
||||
const defaultAgent = visible.length > 0 ? visible[0]!.name : "code"
|
||||
return { visible, defaultAgent }
|
||||
}
|
||||
|
||||
export function buildSettingPath(key: string): { section: string; leaf: string } {
|
||||
const parts = key.split(".")
|
||||
const section = parts.slice(0, -1).join(".")
|
||||
const leaf = parts[parts.length - 1]!
|
||||
return { section, leaf }
|
||||
}
|
||||
|
||||
export type WebviewMessage =
|
||||
| {
|
||||
type: "partUpdated"
|
||||
sessionID: string
|
||||
messageID: string
|
||||
part: unknown
|
||||
delta?: { type: "text-delta"; textDelta: string }
|
||||
}
|
||||
| {
|
||||
type: "messageCreated"
|
||||
message: { id: string; sessionID: string; role: string; createdAt: string; cost?: number; tokens?: unknown }
|
||||
}
|
||||
| { type: "sessionStatus"; sessionID: string; status: string; attempt?: number; message?: string; next?: number }
|
||||
| {
|
||||
type: "permissionRequest"
|
||||
permission: {
|
||||
id: string
|
||||
sessionID: string
|
||||
toolName: string
|
||||
patterns: string[]
|
||||
args: Record<string, unknown>
|
||||
message: string
|
||||
tool?: { messageID: string; callID: string }
|
||||
}
|
||||
}
|
||||
| { type: "todoUpdated"; sessionID: string; items: unknown[] }
|
||||
| { type: "questionRequest"; question: { id: string; sessionID: string; questions: unknown[]; tool?: unknown } }
|
||||
| { type: "questionResolved"; requestID: string }
|
||||
| { type: "sessionCreated"; session: ReturnType<typeof sessionToWebview> }
|
||||
| { type: "sessionUpdated"; session: ReturnType<typeof sessionToWebview> }
|
||||
| null
|
||||
|
||||
export function mapSSEEventToWebviewMessage(event: SSEEvent, sessionID: string | undefined): WebviewMessage {
|
||||
switch (event.type) {
|
||||
case "message.part.updated": {
|
||||
const part = event.properties.part as { messageID?: string; sessionID?: string }
|
||||
if (!sessionID) return null
|
||||
return {
|
||||
type: "partUpdated",
|
||||
sessionID,
|
||||
messageID: part.messageID || "",
|
||||
part: event.properties.part,
|
||||
delta: event.properties.delta ? { type: "text-delta", textDelta: event.properties.delta } : undefined,
|
||||
}
|
||||
}
|
||||
case "message.updated":
|
||||
return {
|
||||
type: "messageCreated",
|
||||
message: {
|
||||
id: event.properties.info.id,
|
||||
sessionID: event.properties.info.sessionID,
|
||||
role: event.properties.info.role,
|
||||
createdAt: new Date(event.properties.info.time.created).toISOString(),
|
||||
cost: event.properties.info.cost,
|
||||
tokens: event.properties.info.tokens,
|
||||
},
|
||||
}
|
||||
case "session.status": {
|
||||
const info = event.properties.status
|
||||
return {
|
||||
type: "sessionStatus",
|
||||
sessionID: event.properties.sessionID,
|
||||
status: info.type,
|
||||
...(info.type === "retry" ? { attempt: info.attempt, message: info.message, next: info.next } : {}),
|
||||
}
|
||||
}
|
||||
case "permission.asked":
|
||||
return {
|
||||
type: "permissionRequest",
|
||||
permission: {
|
||||
id: event.properties.id,
|
||||
sessionID: event.properties.sessionID,
|
||||
toolName: event.properties.permission,
|
||||
patterns: event.properties.patterns ?? [],
|
||||
args: event.properties.metadata,
|
||||
message: `Permission required: ${event.properties.permission}`,
|
||||
tool: event.properties.tool,
|
||||
},
|
||||
}
|
||||
case "todo.updated":
|
||||
return {
|
||||
type: "todoUpdated",
|
||||
sessionID: event.properties.sessionID,
|
||||
items: event.properties.items,
|
||||
}
|
||||
case "question.asked":
|
||||
return {
|
||||
type: "questionRequest",
|
||||
question: {
|
||||
id: event.properties.id,
|
||||
sessionID: event.properties.sessionID,
|
||||
questions: event.properties.questions,
|
||||
tool: event.properties.tool,
|
||||
},
|
||||
}
|
||||
case "question.replied":
|
||||
case "question.rejected":
|
||||
return {
|
||||
type: "questionResolved",
|
||||
requestID: event.properties.requestID,
|
||||
}
|
||||
case "session.created":
|
||||
return {
|
||||
type: "sessionCreated",
|
||||
session: sessionToWebview(event.properties.info),
|
||||
}
|
||||
case "session.updated":
|
||||
return {
|
||||
type: "sessionUpdated",
|
||||
session: sessionToWebview(event.properties.info),
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as vscode from "vscode"
|
||||
import { t } from "./shims/i18n"
|
||||
import type { AutocompleteStatusBarStateProps } from "./types"
|
||||
import { humanFormatSessionCost, formatTime } from "./statusbar-utils"
|
||||
|
||||
const SUPPORTED_PROVIDER_DISPLAY_NAME = "Kilo Gateway"
|
||||
|
||||
@@ -40,14 +41,7 @@ export class AutocompleteStatusBar {
|
||||
}
|
||||
|
||||
private humanFormatSessionCost(): string {
|
||||
const cost = this.props.totalSessionCost
|
||||
if (cost === 0) {
|
||||
return t("kilocode:autocomplete.statusBar.cost.zero")
|
||||
}
|
||||
if (cost > 0 && cost < 0.01) {
|
||||
return t("kilocode:autocomplete.statusBar.cost.lessThanCent")
|
||||
}
|
||||
return `$${cost.toFixed(2)}`
|
||||
return humanFormatSessionCost(this.props.totalSessionCost)
|
||||
}
|
||||
|
||||
public update(params: Partial<AutocompleteStatusBarStateProps>) {
|
||||
@@ -60,8 +54,7 @@ export class AutocompleteStatusBar {
|
||||
}
|
||||
|
||||
private formatTime(timestamp: number): string {
|
||||
const date = new Date(timestamp)
|
||||
return date.toLocaleTimeString()
|
||||
return formatTime(timestamp)
|
||||
}
|
||||
|
||||
private renderDefault() {
|
||||
|
||||
+6
-40
@@ -4,6 +4,7 @@ import { removePrefixOverlap } from "../continuedev/core/autocomplete/postproces
|
||||
import { AutocompleteTelemetry } from "../classic-auto-complete/AutocompleteTelemetry"
|
||||
import { postprocessAutocompleteSuggestion } from "../classic-auto-complete/uselessSuggestionFilter"
|
||||
import type { KiloConnectionService } from "../../cli-backend"
|
||||
import { finalizeChatSuggestion, buildChatPrefix } from "./chat-autocomplete-utils"
|
||||
|
||||
export class ChatTextAreaAutocomplete {
|
||||
private model: AutocompleteModel
|
||||
@@ -134,52 +135,17 @@ TASK: Complete the user's message naturally.
|
||||
}
|
||||
|
||||
private async buildPrefix(userText: string, visibleCodeContext?: VisibleCodeContext): Promise<string> {
|
||||
const contextParts: string[] = []
|
||||
|
||||
// Add visible code context (replaces cursor-based prefix/suffix)
|
||||
if (visibleCodeContext && visibleCodeContext.editors.length > 0) {
|
||||
contextParts.push("// Code visible in editor:")
|
||||
|
||||
for (const editor of visibleCodeContext.editors) {
|
||||
const fileName = editor.filePath.split("/").pop() || editor.filePath
|
||||
contextParts.push(`\n// File: ${fileName} (${editor.languageId})`)
|
||||
|
||||
for (const range of editor.visibleRanges) {
|
||||
contextParts.push(range.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contextParts.push("\n// User's message:")
|
||||
contextParts.push(userText)
|
||||
|
||||
return contextParts.join("\n")
|
||||
return buildChatPrefix(userText, visibleCodeContext?.editors)
|
||||
}
|
||||
|
||||
public cleanSuggestion(suggestion: string, userText: string): string {
|
||||
let cleaned = postprocessAutocompleteSuggestion({
|
||||
const cleaned = postprocessAutocompleteSuggestion({
|
||||
suggestion: removePrefixOverlap(suggestion, userText),
|
||||
prefix: userText,
|
||||
suffix: "", // Chat textarea has no suffix
|
||||
suffix: "",
|
||||
model: this.model.getModelName() ?? "unknown",
|
||||
})
|
||||
|
||||
if (cleaned === undefined) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Filter suggestions that look like code rather than natural language
|
||||
if (cleaned.match(/^(\/\/|\/\*|\*|#)/)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Chat-specific: truncate at first newline for single-line suggestions
|
||||
const firstNewline = cleaned.indexOf("\n")
|
||||
if (firstNewline !== -1) {
|
||||
cleaned = cleaned.substring(0, firstNewline)
|
||||
}
|
||||
cleaned = cleaned.trimEnd()
|
||||
|
||||
return cleaned
|
||||
if (cleaned === undefined) return ""
|
||||
return finalizeChatSuggestion(cleaned)
|
||||
}
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Apply chat-specific post-processing to a suggestion:
|
||||
* - Filter suggestions that look like code comments
|
||||
* - Truncate at first newline (chat is single-line)
|
||||
* - Trim trailing whitespace
|
||||
* Returns empty string when the suggestion should be discarded.
|
||||
*/
|
||||
export function finalizeChatSuggestion(cleaned: string): string {
|
||||
if (!cleaned) return ""
|
||||
|
||||
if (cleaned.match(/^(\/\/|\/\*|\*|#)/)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const firstNewline = cleaned.indexOf("\n")
|
||||
const truncated = firstNewline !== -1 ? cleaned.substring(0, firstNewline) : cleaned
|
||||
return truncated.trimEnd()
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the prefix string for a chat completion request from user text and visible code context.
|
||||
*/
|
||||
export function buildChatPrefix(
|
||||
userText: string,
|
||||
editors?: Array<{
|
||||
filePath: string
|
||||
languageId: string
|
||||
visibleRanges: Array<{ content: string }>
|
||||
}>,
|
||||
): string {
|
||||
const parts: string[] = []
|
||||
if (editors && editors.length > 0) {
|
||||
parts.push("// Code visible in editor:")
|
||||
for (const editor of editors) {
|
||||
const fileName = editor.filePath.split("/").pop() || editor.filePath
|
||||
parts.push(`\n// File: ${fileName} (${editor.languageId})`)
|
||||
for (const range of editor.visibleRanges) {
|
||||
parts.push(range.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
parts.push("\n// User's message:")
|
||||
parts.push(userText)
|
||||
return parts.join("\n")
|
||||
}
|
||||
+16
-156
@@ -13,6 +13,15 @@ import {
|
||||
AutocompleteContext,
|
||||
LastSuggestionInfo,
|
||||
} from "../types"
|
||||
import {
|
||||
findMatchingSuggestion as _findMatchingSuggestion,
|
||||
applyFirstLineOnly as _applyFirstLineOnly,
|
||||
countLines as _countLines,
|
||||
shouldShowOnlyFirstLine as _shouldShowOnlyFirstLine,
|
||||
getFirstLine as _getFirstLine,
|
||||
calcDebounceDelay,
|
||||
MatchingSuggestionWithFillIn as _MatchingSuggestionWithFillIn,
|
||||
} from "./inline-utils"
|
||||
import { HoleFiller } from "./HoleFiller"
|
||||
import { FimPromptBuilder } from "./FillInTheMiddle"
|
||||
import { AutocompleteModel } from "../AutocompleteModel"
|
||||
@@ -59,101 +68,21 @@ const LATENCY_SAMPLE_SIZE = 10
|
||||
|
||||
export type { CostTrackingCallback, AutocompletePrompt, MatchingSuggestionResult, LLMRetrievalResult }
|
||||
|
||||
/**
|
||||
* Result from findMatchingSuggestion including the original suggestion for telemetry tracking
|
||||
*/
|
||||
export interface MatchingSuggestionWithFillIn extends MatchingSuggestionResult {
|
||||
/** The original FillInAtCursorSuggestion for telemetry tracking */
|
||||
fillInAtCursor: FillInAtCursorSuggestion
|
||||
}
|
||||
export type MatchingSuggestionWithFillIn = _MatchingSuggestionWithFillIn
|
||||
|
||||
/**
|
||||
* Find a matching suggestion from the history based on current prefix and suffix.
|
||||
*
|
||||
* @param prefix - The text before the cursor position
|
||||
* @param suffix - The text after the cursor position
|
||||
* @param suggestionsHistory - Array of previous suggestions (most recent last)
|
||||
* @returns The matching suggestion with match type and the original FillInAtCursorSuggestion, or null if no match found
|
||||
*/
|
||||
export function findMatchingSuggestion(
|
||||
prefix: string,
|
||||
suffix: string,
|
||||
suggestionsHistory: FillInAtCursorSuggestion[],
|
||||
): MatchingSuggestionWithFillIn | null {
|
||||
// Search from most recent to least recent
|
||||
for (let i = suggestionsHistory.length - 1; i >= 0; i--) {
|
||||
const fillInAtCursor = suggestionsHistory[i]
|
||||
|
||||
// First, try exact prefix/suffix match
|
||||
if (prefix === fillInAtCursor.prefix && suffix === fillInAtCursor.suffix) {
|
||||
return {
|
||||
text: fillInAtCursor.text,
|
||||
matchType: "exact",
|
||||
fillInAtCursor,
|
||||
}
|
||||
}
|
||||
|
||||
// If no exact match, but suggestion is available, check for partial typing
|
||||
// The user may have started typing the suggested text
|
||||
if (fillInAtCursor.text !== "" && prefix.startsWith(fillInAtCursor.prefix) && suffix === fillInAtCursor.suffix) {
|
||||
// Extract what the user has typed between the original prefix and current position
|
||||
const typedContent = prefix.substring(fillInAtCursor.prefix.length)
|
||||
|
||||
// Check if the typed content matches the beginning of the suggestion
|
||||
if (fillInAtCursor.text.startsWith(typedContent)) {
|
||||
// Return the remaining part of the suggestion (with already-typed portion removed)
|
||||
return {
|
||||
text: fillInAtCursor.text.substring(typedContent.length),
|
||||
matchType: "partial_typing",
|
||||
fillInAtCursor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for backward deletion: user deleted characters from the end of the prefix
|
||||
// The stored prefix should start with the current prefix (current is shorter)
|
||||
// Only use this logic if the original suggestion is non-empty
|
||||
if (fillInAtCursor.text !== "" && fillInAtCursor.prefix.startsWith(prefix) && suffix === fillInAtCursor.suffix) {
|
||||
// Extract the deleted portion of the prefix
|
||||
const deletedContent = fillInAtCursor.prefix.substring(prefix.length)
|
||||
|
||||
// Return the deleted portion plus the original suggestion text
|
||||
return {
|
||||
text: deletedContent + fillInAtCursor.text,
|
||||
matchType: "backward_deletion",
|
||||
fillInAtCursor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
return _findMatchingSuggestion(prefix, suffix, suggestionsHistory)
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a matching suggestion result by applying first-line-only logic if needed.
|
||||
* Use this at call sites where you want to show only the first line of multi-line completions
|
||||
* when the cursor is in the middle of a line.
|
||||
*
|
||||
* @param result - The result from findMatchingSuggestion
|
||||
* @param prefix - The text before the cursor position
|
||||
* @returns A new result with potentially truncated text, or null if input was null
|
||||
*/
|
||||
export function applyFirstLineOnly(
|
||||
result: MatchingSuggestionWithFillIn | null,
|
||||
prefix: string,
|
||||
): MatchingSuggestionWithFillIn | null {
|
||||
if (result === null || result.text === "") {
|
||||
return result
|
||||
}
|
||||
if (shouldShowOnlyFirstLine(prefix, result.text)) {
|
||||
const firstLineText = getFirstLine(result.text)
|
||||
return {
|
||||
text: firstLineText,
|
||||
matchType: result.matchType,
|
||||
fillInAtCursor: result.fillInAtCursor,
|
||||
}
|
||||
}
|
||||
return result
|
||||
return _applyFirstLineOnly(result, prefix)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,76 +91,16 @@ export function applyFirstLineOnly(
|
||||
*/
|
||||
export const INLINE_COMPLETION_ACCEPTED_COMMAND = "kilocode.autocomplete.inline-completion.accepted"
|
||||
|
||||
/**
|
||||
* Counts the number of lines in a text string.
|
||||
*
|
||||
* Notes:
|
||||
* - Returns 0 for an empty string
|
||||
* - A single trailing newline (or CRLF) does not count as an additional line
|
||||
*
|
||||
* @param text - The text to count lines in
|
||||
* @returns The number of lines
|
||||
*/
|
||||
export function countLines(text: string): number {
|
||||
if (text === "") {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Count line breaks and add 1 for the first line.
|
||||
// If the text ends with a line break, don't count the implicit trailing empty line.
|
||||
const lineBreakCount = (text.match(/\r?\n/g) || []).length
|
||||
const endsWithLineBreak = text.endsWith("\n")
|
||||
|
||||
return lineBreakCount + 1 - (endsWithLineBreak ? 1 : 0)
|
||||
return _countLines(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if only the first line of a completion should be shown.
|
||||
*
|
||||
* The logic is:
|
||||
* - If the suggestion starts with a newline → show the whole block
|
||||
* - If the prefix's last line has non-whitespace text → show only the first line
|
||||
* - If at start of line and suggestion is 3+ lines → show only the first line
|
||||
* - Otherwise → show the whole block
|
||||
*
|
||||
* @param prefix - The text before the cursor position
|
||||
* @param suggestion - The completion text being suggested
|
||||
* @returns true if only the first line should be shown
|
||||
*/
|
||||
export function shouldShowOnlyFirstLine(prefix: string, suggestion: string): boolean {
|
||||
// If the suggestion starts with a newline, show the whole block
|
||||
if (suggestion.startsWith("\n") || suggestion.startsWith("\r\n")) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the current line (before cursor) has non-whitespace text
|
||||
const lastNewlineIndex = prefix.lastIndexOf("\n")
|
||||
const currentLinePrefix = prefix.slice(lastNewlineIndex + 1)
|
||||
|
||||
// if the first line contains no word characters, show the whole block
|
||||
if (!currentLinePrefix.match(/\w/)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the current line prefix contains non-whitespace, only show the first line
|
||||
if (currentLinePrefix.trim().length > 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
// At start of line (only whitespace before cursor on this line)
|
||||
// Show only first line if suggestion is 3 or more lines
|
||||
const lineCount = countLines(suggestion)
|
||||
return lineCount >= 3
|
||||
return _shouldShowOnlyFirstLine(prefix, suggestion)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first line from a completion text.
|
||||
*
|
||||
* @param text - The full completion text
|
||||
* @returns The first line of the completion (without the newline)
|
||||
*/
|
||||
export function getFirstLine(text: string): string {
|
||||
return text.split(/\r?\n/, 1)[0]
|
||||
return _getFirstLine(text)
|
||||
}
|
||||
|
||||
export function stringToInlineCompletions(text: string, position: vscode.Position): vscode.InlineCompletionItem[] {
|
||||
@@ -398,19 +267,10 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple
|
||||
* @param latencyMs - The latency of the most recent request in milliseconds
|
||||
*/
|
||||
public recordLatency(latencyMs: number): void {
|
||||
// Add the new latency to the history
|
||||
this.latencyHistory.push(latencyMs)
|
||||
|
||||
// Remove oldest if we exceed the sample size
|
||||
if (this.latencyHistory.length > LATENCY_SAMPLE_SIZE) {
|
||||
this.latencyHistory.shift()
|
||||
|
||||
// Once we have enough samples, update the debounce delay to the average
|
||||
const sum = this.latencyHistory.reduce((acc, val) => acc + val, 0)
|
||||
const averageLatency = Math.round(sum / this.latencyHistory.length)
|
||||
|
||||
// Clamp the debounce delay between MIN and MAX
|
||||
this.debounceDelayMs = Math.max(MIN_DEBOUNCE_DELAY_MS, Math.min(averageLatency, MAX_DEBOUNCE_DELAY_MS))
|
||||
this.debounceDelayMs = calcDebounceDelay(this.latencyHistory)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-13
@@ -1,14 +1,11 @@
|
||||
import { TelemetryProxy, TelemetryEventName } from "../../telemetry"
|
||||
import type { AutocompleteContext, CacheMatchType, FillInAtCursorSuggestion } from "../types"
|
||||
import { getSuggestionKey as _getSuggestionKey, insertWithLRUEviction } from "./telemetry-utils"
|
||||
|
||||
export type { AutocompleteContext, CacheMatchType, FillInAtCursorSuggestion }
|
||||
|
||||
/**
|
||||
* Generate a unique key for a suggestion based on its content and context.
|
||||
* This key is used to track whether the same suggestion is still being displayed.
|
||||
*/
|
||||
export function getSuggestionKey(suggestion: FillInAtCursorSuggestion): string {
|
||||
return `${suggestion.prefix}|${suggestion.suffix}|${suggestion.text}`
|
||||
return _getSuggestionKey(suggestion)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,14 +61,7 @@ export class AutocompleteTelemetry {
|
||||
private firedUniqueTelemetryKeys: Map<string, true> = new Map()
|
||||
|
||||
private markSuggestionKeyAsFired(suggestionKey: string): void {
|
||||
this.firedUniqueTelemetryKeys.set(suggestionKey, true)
|
||||
|
||||
if (this.firedUniqueTelemetryKeys.size > MAX_FIRED_UNIQUE_TELEMETRY_KEYS) {
|
||||
const oldestKey = this.firedUniqueTelemetryKeys.keys().next().value as string | undefined
|
||||
if (oldestKey) {
|
||||
this.firedUniqueTelemetryKeys.delete(oldestKey)
|
||||
}
|
||||
}
|
||||
insertWithLRUEviction(this.firedUniqueTelemetryKeys, suggestionKey, MAX_FIRED_UNIQUE_TELEMETRY_KEYS)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user