mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge branch 'main' into disco-trapezoid
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep Agent Manager state hidden from Git before creating local sessions.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Auto-approve Task subagent tool permissions when running `kilo run --auto`.
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"@kilocode/kilo-docs": patch
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Remove `--dangerously-skip-permissions` CLI flag which did nothing
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep VS Code session timeline, token, context, and cost stats in sync after restoring a checkpoint.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Show ChatGPT sign-in again when Codex authentication expires.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Prevent subagents from spawning nested subagents.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Fix TUI diff rendering when header-like content lines appear inside a unified diff hunk.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Reduce delays in long sessions by compacting older tool outputs when the model request becomes too large.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Use the VS Code-native placeholder color for input fields so placeholder text is consistently distinct from values you have typed (Settings, Agent Manager, prompt input, model search, etc.).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Reset the To-dos tab when reverting a session snapshot.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Clarify that semantic search returns matching code snippets with paths, line ranges, and relevance scores.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Fix Mermaid diagrams rendering with empty text inside every shape by restoring the `foreignObject` HTML integration point that DOMPurify dropped in 3.1.7.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
"@kilocode/kilo-gateway": patch
|
||||
---
|
||||
|
||||
Prevent Kilo Gateway Responses requests from replaying transient provider item IDs when request storage is disabled.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Keep configured mode models in sync when switching modes in VS Code.
|
||||
+100
-22
@@ -1,35 +1,113 @@
|
||||
name: Trigger webhook for feat PRs
|
||||
name: Auto-docs dry-run intake
|
||||
|
||||
# Trigger on merged feature PRs, or manually with a specific PR number.
|
||||
# IMPORTANT: This workflow intentionally does NOT check out PR code and does NOT
|
||||
# execute any code from the PR branch. It only reads PR metadata and forwards it
|
||||
# to a webhook. This is required for safe use of pull_request_target on a public repo.
|
||||
on:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: "PR number to test"
|
||||
required: true
|
||||
|
||||
# Minimal permissions: read repo contents and PR metadata only.
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# One run per PR at a time. Does not cancel in progress — let the current run
|
||||
# finish so we don't drop events when a PR is quickly closed/reopened/closed.
|
||||
concurrency:
|
||||
group: auto-docs-${{ github.event.pull_request.number || inputs.pr_number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
call-webhook:
|
||||
call-valtown:
|
||||
if: >
|
||||
github.event.pull_request.merged == true &&
|
||||
(startsWith(github.event.pull_request.title, 'feat:') ||
|
||||
startsWith(github.event.pull_request.title, 'feat('))
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(
|
||||
github.event.pull_request.merged == true &&
|
||||
(
|
||||
startsWith(github.event.pull_request.title, 'feat:') ||
|
||||
startsWith(github.event.pull_request.title, 'feat(')
|
||||
)
|
||||
)
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- name: Send webhook safely
|
||||
- name: Build webhook payload
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER_FROM_EVENT: ${{ github.event.pull_request.number }}
|
||||
PR_NUMBER_FROM_INPUT: ${{ inputs.pr_number }}
|
||||
run: |
|
||||
payload=$(jq -n \
|
||||
--arg repo "${GITHUB_REPOSITORY}" \
|
||||
--arg pr_number "${{ github.event.pull_request.number }}" \
|
||||
--arg title "${{ github.event.pull_request.title }}" \
|
||||
--arg body "${{ github.event.pull_request.body }}" \
|
||||
--arg author "${{ github.event.pull_request.user.login }}" \
|
||||
--arg merged_at "${{ github.event.pull_request.merged_at }}" \
|
||||
set -euo pipefail
|
||||
|
||||
PR_NUMBER="${PR_NUMBER_FROM_EVENT:-$PR_NUMBER_FROM_INPUT}"
|
||||
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
echo "Missing PR number"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gh api "repos/$REPO/pulls/$PR_NUMBER" > pr.json
|
||||
|
||||
jq -n \
|
||||
--arg event_name "$EVENT_NAME" \
|
||||
--arg repo "$REPO" \
|
||||
--arg pr_number "$PR_NUMBER" \
|
||||
--slurpfile pr pr.json \
|
||||
'{
|
||||
event_name: $event_name,
|
||||
repo: $repo,
|
||||
pr_number: $pr_number,
|
||||
title: $title,
|
||||
description: $body,
|
||||
author: $author,
|
||||
merged_at: $merged_at
|
||||
}'
|
||||
)
|
||||
curl --fail-with-body -X POST "${{ secrets.DOC_WEBHOOK_URL }}" \
|
||||
title: $pr[0].title,
|
||||
description: ($pr[0].body // ""),
|
||||
author: $pr[0].user.login,
|
||||
merged_at: ($pr[0].merged_at // ""),
|
||||
pr_url: $pr[0].html_url,
|
||||
base_branch: $pr[0].base.ref,
|
||||
head_branch: $pr[0].head.ref
|
||||
}' > payload.json
|
||||
|
||||
echo "Payload created:"
|
||||
jq '{
|
||||
event_name,
|
||||
repo,
|
||||
pr_number,
|
||||
title,
|
||||
author,
|
||||
merged_at,
|
||||
pr_url,
|
||||
base_branch,
|
||||
head_branch
|
||||
}' payload.json
|
||||
|
||||
- name: Send webhook to Val Town
|
||||
env:
|
||||
DOC_WEBHOOK_URL: ${{ secrets.DOC_WEBHOOK_URL }}
|
||||
DOC_WEBHOOK_SECRET: ${{ secrets.DOC_WEBHOOK_SECRET }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ -z "${DOC_WEBHOOK_URL:-}" ]; then
|
||||
echo "DOC_WEBHOOK_URL secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${DOC_WEBHOOK_SECRET:-}" ]; then
|
||||
echo "DOC_WEBHOOK_SECRET secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl --fail-with-body -sS -X POST "$DOC_WEBHOOK_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data-raw "$payload"
|
||||
-H "X-Docs-Webhook-Secret: $DOC_WEBHOOK_SECRET" \
|
||||
--data-binary @payload.json
|
||||
|
||||
+4
-15
@@ -136,29 +136,18 @@ There are also optional overrides for other services:
|
||||
|
||||
If you open an issue through the GitHub web UI, GitHub will guide you through the correct template automatically.
|
||||
|
||||
If you open an issue through `gh issue create`, the API, or another tool that bypasses the web UI, include the equivalent required fields yourself so the issue still matches the template.
|
||||
If you open an issue through `gh issue create`, the API, or another tool that bypasses the web UI, include the equivalent required fields yourself so the issue still matches the template. Issues that skip required fields may be auto-closed by the compliance bot.
|
||||
|
||||
Current required fields by issue type:
|
||||
|
||||
- **Bug report:** include a `Description`.
|
||||
- **Feature request:** prefix the title with `[FEATURE]:`, include confirmation that the feature has not already been suggested, and add a description of the enhancement.
|
||||
- **Question:** include the `Question`.
|
||||
|
||||
Recommended fields for bug reports, even when not strictly required by the template:
|
||||
|
||||
- Plugins
|
||||
- Kilo version
|
||||
- Steps to reproduce
|
||||
- Screenshot and/or share link
|
||||
- Operating System
|
||||
- Terminal
|
||||
- **Bug report:** include a `Description`. When you can, also add Plugins, Kilo version, Steps to reproduce, Screenshot and/or share link, Operating System, and Terminal so the report matches the full bug template.
|
||||
- **Feature request:** use a title prefixed with `[FEATURE]:`, complete the required checkbox confirming you have searched for duplicates, and fill in `Describe the enhancement you want to request`.
|
||||
- **Question:** include the `Question` field.
|
||||
|
||||
## Pull Request Expectations
|
||||
|
||||
- **Issue First Policy:** All PRs must reference an existing issue.
|
||||
- **UI Changes:** Include screenshots or videos (before/after).
|
||||
- **Logic Changes:** Explain how you verified it works.
|
||||
- **PR Titles:** Follow conventional commit standards (`feat:`, `fix:`, `docs:`, etc.).
|
||||
|
||||
## Issue First Policy
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@opencode-ai/core",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"packages/kilo-docs": {
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@docsearch/css": "^4",
|
||||
"@docsearch/js": "^4",
|
||||
@@ -98,7 +98,7 @@
|
||||
},
|
||||
"packages/kilo-gateway": {
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@ai-sdk/alibaba": "1.0.17",
|
||||
"@ai-sdk/anthropic": "3.0.71",
|
||||
@@ -134,7 +134,7 @@
|
||||
},
|
||||
"packages/kilo-i18n": {
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/bun": "catalog:",
|
||||
@@ -144,7 +144,7 @@
|
||||
},
|
||||
"packages/kilo-indexing": {
|
||||
"name": "@kilocode/kilo-indexing",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1005.0",
|
||||
"@aws-sdk/credential-provider-ini": "3.972.31",
|
||||
@@ -178,7 +178,7 @@
|
||||
},
|
||||
"packages/kilo-telemetry": {
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
"posthog-node": "4.4.0",
|
||||
@@ -192,7 +192,7 @@
|
||||
},
|
||||
"packages/kilo-ui": {
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "0.13.11",
|
||||
@@ -229,7 +229,7 @@
|
||||
},
|
||||
"packages/kilo-vscode": {
|
||||
"name": "kilo-code",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.39.0",
|
||||
"@kilocode/kilo-gateway": "workspace:*",
|
||||
@@ -292,7 +292,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "@kilocode/cli",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"bin": {
|
||||
"kilo": "./bin/kilo",
|
||||
"kilocode": "./bin/kilo",
|
||||
@@ -450,7 +450,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@kilocode/plugin",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"effect": "catalog:",
|
||||
@@ -475,7 +475,7 @@
|
||||
},
|
||||
"packages/script": {
|
||||
"name": "@opencode-ai/script",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"semver": "^7.6.3",
|
||||
},
|
||||
@@ -486,7 +486,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@kilocode/sdk",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"cross-spawn": "catalog:",
|
||||
},
|
||||
@@ -501,7 +501,7 @@
|
||||
},
|
||||
"packages/storybook": {
|
||||
"name": "@opencode-ai/storybook",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"devDependencies": {
|
||||
"@opencode-ai/ui": "workspace:*",
|
||||
"@solidjs/meta": "catalog:",
|
||||
@@ -524,7 +524,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"dependencies": {
|
||||
"@kilocode/sdk": "workspace:*",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -574,13 +574,6 @@
|
||||
},
|
||||
},
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"esbuild",
|
||||
"tree-sitter-powershell",
|
||||
"protobufjs",
|
||||
"web-tree-sitter",
|
||||
"tree-sitter-bash",
|
||||
],
|
||||
"patchedDependencies": {
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"@npmcli/agent@4.0.0": "patches/@npmcli%2Fagent@4.0.0.patch",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[install]
|
||||
exact = true
|
||||
minimumReleaseAge = 410520 # seconds (~4.75 days / ~114 hours)
|
||||
|
||||
[test]
|
||||
root = "./do-not-run-tests-from-root"
|
||||
|
||||
+1
-11
@@ -114,16 +114,6 @@
|
||||
"semi": false,
|
||||
"printWidth": 120
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"esbuild",
|
||||
"node-pty",
|
||||
"protobufjs",
|
||||
"tree-sitter",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-powershell",
|
||||
"web-tree-sitter",
|
||||
"electron"
|
||||
],
|
||||
"overrides": {
|
||||
"@types/bun": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
@@ -145,6 +135,6 @@
|
||||
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
|
||||
"solid-js@1.9.10": "patches/solid-js@1.9.10.patch"
|
||||
},
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"name": "@opencode-ai/core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -7,6 +7,28 @@ import { Effect, FileSystem, Layer, Schema, Context } from "effect"
|
||||
import type { PlatformError } from "effect/PlatformError"
|
||||
import { Glob } from "./util/glob"
|
||||
|
||||
// kilocode_change start - Windows-resilient mkdir -p.
|
||||
// fs.mkdir(dir, { recursive: true }) should be idempotent, but on Windows
|
||||
// with NTFS reparse points (OneDrive), directory junctions, or WSL-served
|
||||
// paths, libuv can still throw EEXIST. This wrapper catches that specific
|
||||
// error so callers get the promised directory-exists semantics.
|
||||
//
|
||||
// https://github.com/Kilo-Org/kilocode/issues/9618
|
||||
// https://github.com/Kilo-Org/kilocode/issues/9755
|
||||
function isEexist(err: unknown): boolean {
|
||||
return typeof err === "object" && err !== null && "code" in err && (err as NodeJS.ErrnoException).code === "EEXIST"
|
||||
}
|
||||
|
||||
async function mkdirSafe(dir: string): Promise<void> {
|
||||
try {
|
||||
await NFS.mkdir(dir, { recursive: true })
|
||||
} catch (err: unknown) {
|
||||
if (isEexist(err)) return
|
||||
throw err
|
||||
}
|
||||
}
|
||||
// kilocode_change end
|
||||
|
||||
export namespace AppFileSystem {
|
||||
export class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", {
|
||||
method: Schema.String,
|
||||
@@ -84,7 +106,12 @@ export namespace AppFileSystem {
|
||||
})
|
||||
|
||||
const ensureDir = Effect.fn("FileSystem.ensureDir")(function* (path: string) {
|
||||
yield* fs.makeDirectory(path, { recursive: true })
|
||||
// kilocode_change start - use mkdirSafe to tolerate Windows EEXIST
|
||||
yield* Effect.tryPromise({
|
||||
try: () => mkdirSafe(path),
|
||||
catch: (cause) => new FileSystemError({ method: "ensureDir", cause }),
|
||||
})
|
||||
// kilocode_change end
|
||||
})
|
||||
|
||||
const writeWithDirs = Effect.fn("FileSystem.writeWithDirs")(function* (
|
||||
@@ -99,7 +126,12 @@ export namespace AppFileSystem {
|
||||
(e) => e.reason._tag === "NotFound",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
yield* fs.makeDirectory(dirname(path), { recursive: true })
|
||||
// kilocode_change start - use mkdirSafe to tolerate Windows EEXIST
|
||||
yield* Effect.tryPromise({
|
||||
try: () => mkdirSafe(dirname(path)),
|
||||
catch: (cause) => new FileSystemError({ method: "writeWithDirs:mkdir", cause }),
|
||||
})
|
||||
// kilocode_change end
|
||||
yield* write
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id = "kilo"
|
||||
name = "Kilo"
|
||||
description = "The open source coding agent."
|
||||
version = "7.2.50"
|
||||
version = "7.2.52"
|
||||
schema_version = 1
|
||||
authors = ["Anomaly"]
|
||||
repository = "https://github.com/Kilo-Org/kilocode"
|
||||
@@ -11,26 +11,26 @@ name = "Kilo"
|
||||
icon = "./icons/opencode.svg"
|
||||
|
||||
[agent_servers.opencode.targets.darwin-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.50/opencode-darwin-arm64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.52/opencode-darwin-arm64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.darwin-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.50/opencode-darwin-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.52/opencode-darwin-x64.zip"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-aarch64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.50/opencode-linux-arm64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.52/opencode-linux-arm64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.linux-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.50/opencode-linux-x64.tar.gz"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.52/opencode-linux-x64.tar.gz"
|
||||
cmd = "./opencode"
|
||||
args = ["acp"]
|
||||
|
||||
[agent_servers.opencode.targets.windows-x86_64]
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.50/opencode-windows-x64.zip"
|
||||
archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.2.52/opencode-windows-x64.zip"
|
||||
cmd = "./opencode.exe"
|
||||
args = ["acp"]
|
||||
|
||||
@@ -19,9 +19,17 @@ export const CodeWithAiNav: NavSection[] = [
|
||||
children: "CLI",
|
||||
subLinks: [{ href: "/code-with-ai/platforms/cli-reference", children: "Command Reference" }],
|
||||
},
|
||||
{
|
||||
href: "/code-with-ai/platforms/kilo-connect",
|
||||
children: "Kilo Connect",
|
||||
subLinks: [
|
||||
{ href: "/code-with-ai/platforms/slack", children: "Slack" },
|
||||
{ href: "/code-with-ai/platforms/github", children: "GitHub" },
|
||||
{ href: "/code-with-ai/platforms/linear", children: "Linear" },
|
||||
],
|
||||
},
|
||||
{ href: "/code-with-ai/platforms/cloud-agent", children: "Cloud Agent" },
|
||||
{ href: "/code-with-ai/platforms/mobile", children: "Mobile Apps" },
|
||||
{ href: "/code-with-ai/platforms/slack", children: "Slack" },
|
||||
{ href: "/code-with-ai/app-builder", children: "App Builder" },
|
||||
{
|
||||
href: "/code-with-ai/gastown",
|
||||
|
||||
@@ -43,6 +43,8 @@ exclude = [
|
||||
# Consistently times out in CI
|
||||
'^https?://opncd\.ai',
|
||||
'^https?://zod\.dev/v4/changelog',
|
||||
# Example punycode domain used in homograph attack documentation — does not exist
|
||||
'^https?://xn--pitest',
|
||||
# OpenAI docs return 404 to plain GET link checks but resolve in browsers
|
||||
'^https?://platform\.openai\.com/docs/api-reference/responses/create',
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-docs",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --webpack --port 3002",
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Access MCP Resource Tool | Kilo Code Docs
|
||||
description: Learn how the access_mcp_resource tool retrieves data from Model Context Protocol servers to provide additional context for Kilo Code tasks.
|
||||
---
|
||||
|
||||
# access_mcp_resource
|
||||
|
||||
The `access_mcp_resource` tool retrieves data from resources exposed by connected Model Context Protocol (MCP) servers. It allows Kilo Code to access files, API responses, documentation, or system information that provides additional context for tasks.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Apply Diff Tool | Kilo Code Docs
|
||||
description: Learn how the apply_diff tool makes precise, surgical changes to files using search/replace blocks with intelligent matching algorithms.
|
||||
---
|
||||
|
||||
# apply_diff
|
||||
|
||||
The `apply_diff` tool makes precise, surgical changes to files by specifying exactly what content to replace. It uses multiple sophisticated strategies for finding and applying changes while maintaining proper code formatting and structure.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Ask Followup Question Tool | Kilo Code Docs
|
||||
description: Learn how the ask_followup_question tool enables Kilo Code to gather additional information needed to complete tasks through interactive communication.
|
||||
---
|
||||
|
||||
# ask_followup_question
|
||||
|
||||
The `ask_followup_question` tool enables interactive communication by asking specific questions to gather additional information needed to complete tasks effectively.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Attempt Completion Tool | Kilo Code Docs
|
||||
description: Learn how the attempt_completion tool signals task completion, presents results to the user, and supports continued refinement through feedback.
|
||||
---
|
||||
|
||||
# attempt_completion
|
||||
|
||||
The `attempt_completion` tool signals that Kilo Code believes a task is complete and presents results to the user. It provides a summary of what was accomplished, optionally includes a command to demonstrate the result, and supports continued refinement through user feedback.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Browser Action Tool | Kilo Code Docs
|
||||
description: Learn how the browser_action tool enables web automation via a Puppeteer-controlled browser to navigate sites, click elements, and capture screenshots.
|
||||
---
|
||||
|
||||
# browser_action
|
||||
|
||||
The `browser_action` tool enables web automation and interaction via a Puppeteer-controlled browser. It allows Kilo Code to launch browsers, navigate to websites, click elements, type text, and scroll pages with visual feedback through screenshots.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Delete File Tool | Kilo Code Docs
|
||||
description: Learn how the delete_file tool safely removes files and directories from the workspace across all platforms as an alternative to rm commands.
|
||||
---
|
||||
|
||||
# delete_file
|
||||
|
||||
Delete a file or directory from the workspace. This tool provides a safe alternative to rm commands and works across all platforms.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Execute Command Tool | Kilo Code Docs
|
||||
description: Learn how the execute_command tool runs CLI commands on your system to install dependencies, build projects, start servers, and run terminal operations.
|
||||
---
|
||||
|
||||
# execute_command
|
||||
|
||||
The `execute_command` tool runs CLI commands on the user's system. It allows Kilo Code to perform system operations, install dependencies, build projects, start servers, and execute other terminal-based tasks needed to accomplish user objectives.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: List Code Definition Names Tool | Kilo Code Docs
|
||||
description: Learn how the list_code_definition_names tool provides a structural overview of your codebase by listing functions, classes, and definitions with line numbers.
|
||||
---
|
||||
|
||||
# list_code_definition_names
|
||||
|
||||
The `list_code_definition_names` tool provides a structural overview of your codebase by listing code definitions from source files at the top level of a specified directory. It helps Kilo Code understand code architecture by displaying line numbers and definition snippets.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: List Files Tool | Kilo Code Docs
|
||||
description: Learn how the list_files tool displays files and directories within a specified location to help Kilo Code understand your project structure.
|
||||
---
|
||||
|
||||
# list_files
|
||||
|
||||
The `list_files` tool displays the files and directories within a specified location. It helps Kilo Code understand your project structure and navigate your codebase effectively.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: New Task Tool | Kilo Code Docs
|
||||
description: Learn how the new_task tool creates subtasks with specialized modes to break down complex projects into manageable pieces with parent-child relationships.
|
||||
---
|
||||
|
||||
# new_task
|
||||
|
||||
The `new_task` tool creates subtasks with specialized modes while maintaining a parent-child relationship. It breaks down complex projects into manageable pieces, each operating in the mode best suited for specific work.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Read File Tool | Kilo Code Docs
|
||||
description: Learn how the read_file tool examines file contents with line number support to help Kilo Code understand code, configuration, and documentation.
|
||||
---
|
||||
|
||||
# read_file
|
||||
|
||||
The `read_file` tool examines the contents of files in a project. It allows Kilo Code to understand code, configuration files, and documentation to provide better assistance.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Search Files Tool | Kilo Code Docs
|
||||
description: Learn how the search_files tool performs regex searches across multiple files in your project to locate specific code patterns, text, and content with context.
|
||||
---
|
||||
|
||||
# search_files
|
||||
|
||||
The `search_files` tool performs regex searches across multiple files in your project. It helps Kilo Code locate specific code patterns, text, or other content throughout your codebase with contextual results.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Semantic Search Tool | Kilo Code Docs
|
||||
description: Learn how the semantic_search tool uses AI embeddings and vector search to find semantically relevant code across your indexed codebase.
|
||||
---
|
||||
|
||||
# semantic_search
|
||||
|
||||
{% callout type="info" title="Setup Required" %}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Switch Mode Tool | Kilo Code Docs
|
||||
description: Learn how the switch_mode tool enables Kilo Code to transition between operational modes like Code, Architect, Ask, and Debug for specialized task handling.
|
||||
---
|
||||
|
||||
# switch_mode
|
||||
|
||||
The `switch_mode` tool enables Kilo Code to change between different operational modes, each with specialized capabilities for specific types of tasks. This allows seamless transitions between modes like Code, Architect, Ask, or Debug when the current task requires different expertise.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Update Todo List Tool | Kilo Code Docs
|
||||
description: Learn how the update_todo_list tool tracks step-by-step task progress, replacing the entire TODO list to reflect current completion state during complex tasks.
|
||||
---
|
||||
|
||||
# update_todo_list
|
||||
|
||||
The `update_todo_list` tool replaces the entire TODO list with an updated checklist reflecting the current state. It provides step-by-step task tracking, allowing confirmation of completion before updating and dynamic addition of new todos discovered during complex tasks.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Use MCP Tool | Kilo Code Docs
|
||||
description: Learn how the use_mcp_tool tool enables Kilo Code to interact with external tools provided by Model Context Protocol servers for extended capabilities.
|
||||
---
|
||||
|
||||
# use_mcp_tool
|
||||
|
||||
The `use_mcp_tool` tool enables interaction with external tools provided by connected Model Context Protocol (MCP) servers. It extends Kilo Code's capabilities with domain-specific functionality through a standardized protocol.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
title: Write to File Tool | Kilo Code Docs
|
||||
description: Learn how the write_to_file tool creates new files or replaces existing file content with an interactive diff-based approval process.
|
||||
---
|
||||
|
||||
# write_to_file
|
||||
|
||||
The `write_to_file` tool creates new files or completely replaces existing file content with an interactive approval process. It provides a diff view for reviewing changes before they're applied.
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
title: "GitHub"
|
||||
description: "Using Kilo Code in GitHub issues, pull requests, and review comments"
|
||||
---
|
||||
|
||||
# Kilo for GitHub
|
||||
|
||||
**Kilo for GitHub** lets you interact with Kilo directly from your GitHub issues, pull requests, and review comments. Mention the bot and it will:
|
||||
|
||||
- Read the surrounding context
|
||||
- Access the repository
|
||||
- Respond with answers, code reviews, or full implementations
|
||||
|
||||
---
|
||||
|
||||
## What You Can Do
|
||||
|
||||
### Ask questions on review comments
|
||||
|
||||
When you're reviewing a pull request and want a second opinion on a piece of code:
|
||||
|
||||
```
|
||||
@kilocode-bot is this true?
|
||||
```
|
||||
|
||||
The bot reads the review comment, the surrounding diff, and the relevant code in the repository to give you an informed answer.
|
||||
|
||||
### Fix issues directly from GitHub
|
||||
|
||||
Tag the bot on any issue and ask it to handle the fix:
|
||||
|
||||
```
|
||||
@kilocode-bot please fix
|
||||
```
|
||||
|
||||
The bot will:
|
||||
|
||||
- Read the issue description
|
||||
- Analyze the relevant code
|
||||
- Create a branch with the implementation
|
||||
- Open a pull request
|
||||
|
||||
### Diagnose bug reports
|
||||
|
||||
When a bug report comes in and you want to understand what's going on before diving in:
|
||||
|
||||
```
|
||||
@kilocode-bot what could be the cause of this issue?
|
||||
```
|
||||
|
||||
The bot examines the bug report, searches the codebase for related code paths, and shares its analysis directly in the issue thread.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Mention `@kilocode-bot`** on an issue, pull request, or review comment
|
||||
2. **Kilo reads the context** — the issue description, PR diff, review thread, and connected repository code
|
||||
3. **A Cloud Agent spins up** to process the request
|
||||
4. **Kilo responds** with an answer, analysis, or a pull request containing the implementation
|
||||
|
||||
For implementation requests, the bot creates a new branch, commits the changes, and opens a PR back to the repository. You'll see the PR linked directly in the thread.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kilo Code account with available credits
|
||||
- Your GitHub integration configured via the Integrations tab at [app.kilo.ai](https://app.kilo.ai)
|
||||
- The Kilo Code Bot GitHub App installed on the relevant repositories
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
1. Go to [app.kilo.ai](https://app.kilo.ai) and navigate to the **Integrations** tab
|
||||
2. Connect your GitHub account through the **KiloConnect** GitHub App if you haven't already
|
||||
3. Install the **Kilo Code Bot** GitHub App on your repositories at [github.com/apps/kilo-code-bot](https://github.com/apps/kilo-code-bot/)
|
||||
|
||||
Once installed, `@kilocode-bot` is available on any issue or PR in the repositories you've authorized.
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Code Review Assistance
|
||||
|
||||
During a PR review, mention the bot on any comment or line of code to get a quick analysis. The bot can:
|
||||
|
||||
- Verify logic
|
||||
- Suggest improvements
|
||||
- Explain unfamiliar patterns
|
||||
|
||||
### Issue Triage and Fixes
|
||||
|
||||
When new issues come in, the bot can diagnose probable causes and, if you ask, implement a fix directly. This works best for straightforward bugs where the issue description gives enough context to act.
|
||||
|
||||
### Bulk or Cross-Repo Changes
|
||||
|
||||
Need to bump a dependency or apply a config change across your org? Mention the repos in a single comment and the bot handles each one.
|
||||
|
||||
---
|
||||
|
||||
## Cost
|
||||
|
||||
Kilo Code credits are consumed the same way as any other Kilo interface. Credit usage depends on the model selected and the complexity of the task.
|
||||
|
||||
---
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
- **Be specific about what you want.** "Please fix" works best on well-described issues. For vague issues, ask the bot to diagnose first.
|
||||
- **Mention specific repositories** if the fix spans multiple repos.
|
||||
- **Use on review comments** for quick, contextual questions during code review.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**The bot isn't responding to mentions.**
|
||||
Make sure the Kilo Code Bot GitHub App is installed on the repository and that you're mentioning `@kilocode-bot` (not `@kilo`).
|
||||
|
||||
**The bot can't access the repository.**
|
||||
Verify that both the KiloConnect App and the Kilo Code Bot App are installed and have access to the repository in question.
|
||||
|
||||
**The implementation doesn't match what I expected.**
|
||||
Try providing more context in the issue description or comment. The bot works best when the problem and desired outcome are clearly described.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: "Kilo Connect"
|
||||
description: "Use Kilo Code directly from Slack, GitHub, and Linear"
|
||||
---
|
||||
|
||||
# Kilo Connect
|
||||
|
||||
**Kilo Connect** brings Kilo Code into the tools your team already uses. Instead of switching to a separate interface, you can trigger implementations, ask questions, and get pull requests opened directly from your chat, issue tracker, or code review workflow.
|
||||
|
||||
---
|
||||
|
||||
## Supported Integrations
|
||||
|
||||
| Integration | Trigger | What It Can Do |
|
||||
|---|---|---|
|
||||
| [Slack](/docs/code-with-ai/platforms/slack) | `@Kilo` in any channel or DM | Ask questions, implement fixes, debug issues |
|
||||
| [GitHub](/docs/code-with-ai/platforms/github) | `@kilocode-bot` on issues and PRs | Fix issues, review code, cross-repo changes |
|
||||
| [Linear](/docs/code-with-ai/platforms/linear) | `@kilo` on any issue | Implement fixes, investigate bugs, cross-repo changes |
|
||||
|
||||
---
|
||||
|
||||
## How to Set Up
|
||||
|
||||
All integrations are configured from the **Integrations** tab at [app.kilo.ai](https://app.kilo.ai). Each integration requires:
|
||||
|
||||
- A Kilo Code account with available credits
|
||||
- A connected Git provider (GitHub or GitLab) so Kilo can access your repositories
|
||||
- The specific integration installed and authorized for your workspace
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: "Linear"
|
||||
description: "Using Kilo Code in Linear"
|
||||
---
|
||||
|
||||
# Kilo for Linear
|
||||
|
||||
**Kilo for Linear** connects Kilo Code to your Linear workspace, so you can trigger implementations, debug issues, and investigate bugs directly from your project management tool. Mention `@kilo` on any issue and the bot gets to work.
|
||||
|
||||
---
|
||||
|
||||
## What You Can Do
|
||||
|
||||
### Fix issues from Linear
|
||||
|
||||
Tag the bot on any Linear issue and tell it to implement the fix:
|
||||
|
||||
```
|
||||
@kilo please fix
|
||||
```
|
||||
|
||||
The bot will:
|
||||
|
||||
- Read the issue title, description, and comments
|
||||
- Spin up a Cloud Agent to implement the solution
|
||||
- Show a thinking/processing animation in Linear while it works
|
||||
- Link the resulting pull request back to the issue
|
||||
|
||||
### Apply changes across multiple repositories
|
||||
|
||||
If a fix or upgrade needs to land in several repos at once:
|
||||
|
||||
```
|
||||
@kilo please fix this in the cloud, landing, and handbook repos
|
||||
```
|
||||
|
||||
The bot handles each repository independently, creating separate branches and pull requests for each.
|
||||
|
||||
### Get help understanding an issue
|
||||
|
||||
Before jumping into a fix, ask the bot to analyze the problem:
|
||||
|
||||
```
|
||||
@kilo what could be the cause of this issue?
|
||||
```
|
||||
|
||||
The bot examines the issue context and searches the connected codebase to surface likely causes.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Mention `@kilo`** in a comment on a Linear issue
|
||||
2. **Kilo reads the issue context** — title, description, labels, and comment thread
|
||||
3. **A Cloud Agent spins up** to process the request (you'll see a thinking animation in Linear while this happens)
|
||||
4. **Kilo responds** with an answer or opens a pull request with the implementation
|
||||
|
||||
When Kilo creates a pull request, it links back to the Linear issue so everything stays connected.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Kilo Code account with available credits
|
||||
- Your GitHub or GitLab integration configured via the Integrations tab at [app.kilo.ai](https://app.kilo.ai)
|
||||
- Access to a Linear workspace where you can install integrations
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
1. Go to [app.kilo.ai](https://app.kilo.ai) and navigate to the **Integrations** tab
|
||||
2. Set up the **Linear** integration
|
||||
3. Authorize Kilo to access your Linear workspace
|
||||
|
||||
Once connected, `@kilo` is available as a mention in any issue across your Linear workspace.
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Sprint Cleanup
|
||||
|
||||
Have a backlog of well-described bugs? Tag the bot on each one and let it work through them while you focus on higher-priority work.
|
||||
|
||||
### Cross-Repo Upgrades
|
||||
|
||||
Need to upgrade a framework version or apply a config change across several services? Create a single Linear issue describing the change, then tell the bot which repos to update.
|
||||
|
||||
### Issue Investigation
|
||||
|
||||
When a bug report is unclear or the root cause isn't obvious, ask the bot to analyze the issue before committing to a fix. It can search the codebase and surface likely problem areas.
|
||||
|
||||
---
|
||||
|
||||
## Cost
|
||||
|
||||
Kilo Code credits are consumed the same way as any other Kilo interface. Credit usage depends on the model selected and the complexity of the task.
|
||||
|
||||
---
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
- **Write clear issue descriptions.** The bot works best when the issue title and description give enough context to understand the problem and the expected outcome.
|
||||
- **Mention specific repositories** if the change needs to land in more than one.
|
||||
- **Start with diagnosis for ambiguous issues.** Ask the bot to analyze the issue before asking it to fix.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**The bot isn't responding to mentions.**
|
||||
Confirm that the Linear integration is set up in the Integrations tab at [app.kilo.ai](https://app.kilo.ai) and that the bot has access to your workspace.
|
||||
|
||||
**The bot can't access the repository.**
|
||||
Make sure your GitHub or GitLab integration is configured and that the relevant repositories are authorized.
|
||||
|
||||
**The pull request doesn't match what I expected.**
|
||||
Provide more detail in the issue description, or comment with additional context before asking the bot to fix.
|
||||
@@ -5,50 +5,71 @@ description: "Using Kilo Code in Slack"
|
||||
|
||||
# Kilo for Slack
|
||||
|
||||
Kilo for Slack brings the power of Kilo Code directly into your Slack workspace. Ask questions about your repositories, request code implementations, or get help with issues—all without leaving Slack.
|
||||
**Kilo for Slack** brings Kilo Code directly into your Slack workspace. Ask questions about your repositories, request code implementations, debug issues, and collaborate with your team — all without leaving Slack.
|
||||
|
||||
When you mention `@Kilo` in a thread, the bot:
|
||||
|
||||
- Reads the full conversation
|
||||
- Accesses your connected repositories
|
||||
- Answers your question or spins up a Cloud Agent to implement the change
|
||||
- Creates branches, pushes commits, and opens pull requests on your behalf
|
||||
|
||||
---
|
||||
|
||||
## What You Can Do With Kilo for Slack
|
||||
## What You Can Do
|
||||
|
||||
- **Ask questions about your repositories** — Get explanations about code, architecture, or implementation details
|
||||
- **Request code implementations** — Tell the bot to implement fixes or features suggested in Slack threads
|
||||
- **Get help with debugging** — Share error messages or issues and get AI-powered assistance
|
||||
- **Collaborate with your team** — Mention the bot in any channel to get help in context
|
||||
### Ask questions about your codebase
|
||||
|
||||
```
|
||||
@Kilo what does the UserService class do in our main backend repo?
|
||||
```
|
||||
|
||||
```
|
||||
@Kilo how is error handling implemented in the payment processing module?
|
||||
```
|
||||
|
||||
### Implement fixes and features from Slack discussions
|
||||
|
||||
When your team identifies a bug or improvement in a thread, ask the bot to handle it:
|
||||
|
||||
```
|
||||
@Kilo based on this thread, can you implement the fix for the null pointer exception in the order processing service?
|
||||
```
|
||||
|
||||
The bot will:
|
||||
|
||||
- Read the thread context
|
||||
- Understand the proposed solution
|
||||
- Create a branch with the implementation
|
||||
- Push a pull request to your repository
|
||||
|
||||
### Implement changes across multiple repositories
|
||||
|
||||
If the same change needs to land in several repos, just tell the bot:
|
||||
|
||||
```
|
||||
@Kilo please fix this in the cloud, landing, and handbook repos
|
||||
```
|
||||
|
||||
### Debug issues
|
||||
|
||||
Paste an error message or stack trace and ask for help:
|
||||
|
||||
```
|
||||
@Kilo I'm seeing this error in production:
|
||||
[paste error message]
|
||||
Can you help me understand what's causing it?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Integration Type | Details |
|
||||
|---|---|---|
|
||||
| GitHub | GitHub App | [GitHub Setup Guide](/docs/automate/integrations#connecting-github) |
|
||||
| GitLab | OAuth or PAT | [GitLab Setup Guide](/docs/automate/integrations#connecting-gitlab) |
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before using Kilo for Slack:
|
||||
|
||||
- You must have a **Kilo Code account** with available credits
|
||||
- Your **Git provider integration must be configured** via the [Integrations tab](https://app.kilo.ai/integrations) so Kilo can access your repositories
|
||||
|
||||
To install Kilo for Slack, simply go to the integrations menu in the sidebar on https://app.kilo.ai and set up the Slack integration.
|
||||
|
||||
---
|
||||
|
||||
## How to Interact with Kilo
|
||||
## How to Interact
|
||||
|
||||
### Direct Messages
|
||||
|
||||
You can message Kilo directly through Slack DMs for private conversations:
|
||||
You can DM Kilo directly for private conversations. Find Kilo in your workspace's app list and start a direct message.
|
||||
|
||||
1. Find **Kilo** in your Slack workspace's app list
|
||||
2. Start a direct message conversation
|
||||
3. Ask your question or describe what you need
|
||||
|
||||
This is ideal for:
|
||||
Good for:
|
||||
|
||||
- Private questions about your code
|
||||
- Sensitive debugging sessions
|
||||
@@ -62,114 +83,80 @@ Mention the bot in any channel where it's been added:
|
||||
@Kilo can you explain how the authentication flow works in our backend?
|
||||
```
|
||||
|
||||
This is great for:
|
||||
Good for:
|
||||
|
||||
- Team discussions where AI assistance would help
|
||||
- Collaborative debugging sessions
|
||||
- Collaborative debugging
|
||||
- Getting quick answers during code reviews
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
## Prerequisites
|
||||
|
||||
### Ask Questions About Your Repositories
|
||||
Before using Kilo for Slack:
|
||||
|
||||
Get instant answers about your codebase without switching contexts:
|
||||
- You need a Kilo Code account with available credits
|
||||
- Your Git provider integration (GitHub or GitLab) must be configured via the Integrations tab at [app.kilo.ai](https://app.kilo.ai) so Kilo can access your repositories
|
||||
|
||||
```
|
||||
@Kilo what does the UserService class do in our main backend repo?
|
||||
```
|
||||
---
|
||||
|
||||
```
|
||||
@Kilo how is error handling implemented in the payment processing module?
|
||||
```
|
||||
## Setup
|
||||
|
||||
### Implement Fixes from Slack Discussions
|
||||
To install Kilo for Slack, go to the Integrations menu in the sidebar at [app.kilo.ai](https://app.kilo.ai) and set up the Slack integration.
|
||||
|
||||
When your team identifies an issue or improvement in a Slack thread, ask the bot to implement it:
|
||||
|
||||
```
|
||||
@Kilo based on this thread, can you implement the fix for the null pointer exception in the order processing service?
|
||||
```
|
||||
|
||||
The bot can:
|
||||
|
||||
- Read the context from the thread
|
||||
- Understand the proposed solution
|
||||
- Create a branch with the implementation
|
||||
- Push the changes to your repository
|
||||
|
||||
### Debug Issues
|
||||
|
||||
Share error messages or stack traces and get help:
|
||||
|
||||
```
|
||||
@Kilo I'm seeing this error in production:
|
||||
[paste error message]
|
||||
Can you help me understand what's causing it?
|
||||
```
|
||||
| Platform | Integration Type | Details |
|
||||
|---|---|---|
|
||||
| GitHub | GitHub App | [GitHub Setup Guide](/docs/automate/integrations#connecting-github) |
|
||||
| GitLab | OAuth or PAT | [GitLab Setup Guide](/docs/automate/integrations#connecting-gitlab) |
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Message Kilo** — Either through DMs or by mentioning it in a channel
|
||||
2. **Kilo processes your request** — Kilo uses your connected repositories to understand context
|
||||
3. **AI generates a response** — Kilo Code's AI analyzes your request and provides helpful responses
|
||||
4. **Code changes (if requested)** — For implementation requests, Kilo can create pull or merge requests
|
||||
|
||||
---
|
||||
|
||||
## Cost
|
||||
|
||||
- **Kilo Code credits are used** when Kilo performs work (model usage, operations, etc.)
|
||||
- Credit usage is similar to using Kilo Code through other interfaces
|
||||
|
||||
---
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
- **Be specific** — The more context you provide, the better the response
|
||||
- **Reference specific files or functions** — Help the bot understand exactly what you're asking about
|
||||
- **Use threads** — Keep related conversations in threads for better context
|
||||
- **Specify the repository** — If you have multiple repos connected, mention which one you're asking about
|
||||
|
||||
---
|
||||
|
||||
## Limitations
|
||||
|
||||
- Kilo can only access repositories you've connected through the [Integrations](https://app.kilo.ai/integrations) page
|
||||
- Complex multi-step implementations may require follow-up messages
|
||||
- Response times may vary based on the complexity of your request
|
||||
1. **Message Kilo** through a DM or channel mention
|
||||
2. **Kilo processes your request** using your connected repositories for context
|
||||
3. **AI generates a response** analyzing your request and providing an answer
|
||||
4. **Code changes (if requested)** — Kilo creates a branch, commits the changes, and opens a pull or merge request
|
||||
|
||||
---
|
||||
|
||||
## Changing the Model
|
||||
|
||||
You can customize which AI model Kilo uses for generating responses. The model affects the quality, speed, and capabilities of Kilo's responses.
|
||||
You can customize which AI model Kilo uses for generating responses.
|
||||
|
||||
1. Go to your [Kilo Workspace](https://app.kilo.ai/)
|
||||
2. Navigate to **Integrations** > **Slack**
|
||||
3. Select your preferred model for Kilo for Slack
|
||||
1. Go to your Kilo Workspace at [app.kilo.ai](https://app.kilo.ai)
|
||||
2. Navigate to **Integrations > Slack**
|
||||
3. Select your preferred model
|
||||
|
||||
Kilo will start using the new model immediately for subsequent requests.
|
||||
Kilo for Slack supports 400+ models across different providers. The new model applies immediately to subsequent requests.
|
||||
|
||||
### Available Models
|
||||
---
|
||||
|
||||
Kilo for Slack supports over 400+ models across different providers.
|
||||
## Cost
|
||||
|
||||
Kilo Code credits are used when Kilo performs work (model usage, operations, etc.). Credit usage is the same as using Kilo through any other interface.
|
||||
|
||||
---
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
- **Be specific.** The more context you provide, the better the response.
|
||||
- **Reference specific files or functions.** Help the bot understand exactly what you're asking about.
|
||||
- **Use threads.** Keep related conversations in threads for better context.
|
||||
- **Specify the repository.** If you have multiple repos connected, mention which one you're asking about.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Kilo isn't responding."**
|
||||
Ensure Kilo for Slack is installed in your workspace and has been added to the channel you're using.
|
||||
**Kilo isn't responding.**
|
||||
Make sure Kilo for Slack is installed in your workspace and has been added to the channel you're using.
|
||||
|
||||
**"Kilo can't access my repository."**
|
||||
Verify your Git provider integration is configured correctly in the [Integrations tab](https://app.kilo.ai/integrations).
|
||||
**Kilo can't access my repository.**
|
||||
Verify your Git provider integration is configured correctly in the Integrations tab.
|
||||
|
||||
**"I'm getting incomplete responses."**
|
||||
**I'm getting incomplete responses.**
|
||||
Try breaking your request into smaller, more specific questions.
|
||||
|
||||
**"Kilo doesn't understand my codebase."**
|
||||
Make sure the repository you're asking about is connected and accessible through your Git provider integration.
|
||||
**Kilo doesn't understand my codebase.**
|
||||
Confirm that the repository you're asking about is connected and accessible through your Git provider integration.
|
||||
|
||||
@@ -96,10 +96,9 @@ Auto: Small does not appear in the model picker. It is filtered out by the UI (s
|
||||
|
||||
### Defaults
|
||||
|
||||
- **Authenticated users**: Default to `kilo-auto/balanced` (defined in `packages/kilo-gateway/src/api/constants.ts`)
|
||||
- **Unauthenticated users**: Default to `kilo-auto/free`
|
||||
- **All new users**: Default to `kilo-auto/free` (defined in `packages/kilo-gateway/src/api/constants.ts`)
|
||||
|
||||
This means a brand-new user who hasn't signed in gets a working experience immediately — no model selection required.
|
||||
This means a brand-new user gets a working experience immediately — no model selection or credits required.
|
||||
|
||||
### What users see
|
||||
|
||||
@@ -167,7 +166,7 @@ The client-side chain works as follows:
|
||||
| Free model disappears mid-session | User's next message fails | Fallback chain: primary → secondary → tertiary free model. Graceful error only if all options exhausted. |
|
||||
| Model quality variance across free/balanced tiers | Inconsistent experience compared to Frontier | Set clear expectations in UI. Curate model lists, don't just pick the cheapest. |
|
||||
| Cross-family model switching breaks context | Thinking blocks from Model A incompatible with Model B | Strip thinking blocks when the underlying model family changes between turns. Frontier stays within one family so this primarily affects Free tier (which may switch models). |
|
||||
| Users don't understand the tier differences | Wrong tier selected, poor experience | Clear descriptions in the model picker. Good defaults (Balanced for paid, Free for unpaid) so most users never need to actively choose. |
|
||||
| Users don't understand the tier differences | Wrong tier selected, poor experience | Clear descriptions in the model picker. Good defaults (Free for all new users) so most users never need to actively choose. |
|
||||
|
||||
## Data and compliance
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Use your provider API key to route matching models through your account:
|
||||
|
||||
- Anthropic
|
||||
- AWS Bedrock
|
||||
- DeepSeek
|
||||
- Fireworks
|
||||
- Google AI Studio
|
||||
- Inception
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d34153690f8aa4ef7e06e12385a184c151843f3ae75a9955619a6d7e88dc8c8b
|
||||
size 7981
|
||||
oid sha256:22cfec1cfdfe2deb4299f62bd677eeee34b522c581504297fd356efbf26e9b44
|
||||
size 6351
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Source Code Links
|
||||
|
||||
<!-- Auto-generated by script/extract-source-links.ts — DO NOT EDIT -->
|
||||
<!-- 81 unique URLs extracted from extension and CLI source -->
|
||||
<!-- 86 unique URLs extracted from extension and CLI source -->
|
||||
|
||||
- <https://api.apertis.ai/v1>
|
||||
<!-- packages/opencode/src/provider/model-cache.ts -->
|
||||
@@ -62,6 +62,10 @@
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/settings/AboutKiloCodeTab.tsx -->
|
||||
- <https://github.com/Kilo-Org/kilocode/issues/6986>
|
||||
<!-- packages/kilo-vscode/src/agent-manager/constants.ts -->
|
||||
- <https://github.com/Kilo-Org/kilocode/issues/9618>
|
||||
<!-- packages/opencode/src/kilocode/encoding.ts -->
|
||||
- <https://github.com/Kilo-Org/kilocode/issues/9755>
|
||||
<!-- packages/opencode/src/kilocode/encoding.ts -->
|
||||
- <https://github.com/Kilo-Org/kilocode/issues/new?template=bug-report.yml>
|
||||
<!-- packages/opencode/src/cli/cmd/tui/app.tsx -->
|
||||
- <https://github.com/Kilo-Org/kilocode/issues/new/choose>
|
||||
@@ -87,10 +91,10 @@
|
||||
- <https://kilo.ai/docs>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/hooks/useSlashCommand.ts -->
|
||||
<!-- packages/opencode/src/kilocode/cli/cmd/tui/app.tsx -->
|
||||
- <https://kilo.ai/docs/ai-providers#custom-provider>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx -->
|
||||
- <https://kilo.ai/docs/code-with-ai/platforms/vscode/whats-new>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx -->
|
||||
- <https://kilo.ai/docs/providers/#custom-provider>
|
||||
<!-- packages/kilo-vscode/webview-ui/src/components/settings/CustomProviderDialog.tsx -->
|
||||
- <https://kilo.ai/gateway>
|
||||
<!-- packages/opencode/src/kilocode/cli/cmd/tui/component/dialog-provider.tsx -->
|
||||
- <https://kilo.ai/install>
|
||||
@@ -177,3 +181,9 @@
|
||||
<!-- packages/opencode/src/tool/warpgrep.ts -->
|
||||
- <https://www.rfc-editor.org/rfc/rfc8628#section-3.5>
|
||||
<!-- packages/opencode/src/plugin/github-copilot/copilot.ts -->
|
||||
- <https://x.com>
|
||||
<!-- packages/opencode/src/kilocode/util/url.ts -->
|
||||
- <https://xn--pitest-2nf.com/status>
|
||||
<!-- packages/opencode/src/kilocode/util/url.ts -->
|
||||
- <https://аpitest.com/status>
|
||||
<!-- packages/opencode/src/kilocode/util/url.ts -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-gateway",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration",
|
||||
|
||||
@@ -37,7 +37,7 @@ export const KILO_OPENROUTER_BASE = `${KILO_API_BASE}/api/openrouter`
|
||||
export const POLL_INTERVAL_MS = 3000
|
||||
|
||||
/** Default model for authenticated users */
|
||||
export const DEFAULT_MODEL = "kilo-auto/balanced"
|
||||
export const DEFAULT_MODEL = "kilo-auto/free"
|
||||
|
||||
/** Default model for anonymous/free usage */
|
||||
export const DEFAULT_FREE_MODEL = "kilo-auto/free"
|
||||
|
||||
@@ -8,6 +8,7 @@ import { getApiKey } from "./auth/token.js"
|
||||
import { buildKiloHeaders, getDefaultHeaders } from "./headers.js"
|
||||
import { ANONYMOUS_API_KEY } from "./api/constants.js"
|
||||
import { resolveKiloOpenRouterBaseUrl } from "./api/url.js"
|
||||
import { sanitizeResponsesBody } from "./responses.js"
|
||||
|
||||
/**
|
||||
* Create a KiloCode provider instance
|
||||
@@ -45,6 +46,7 @@ export function createKilo(options: KiloProviderOptions = {}): KiloProvider {
|
||||
const originalFetch = options.fetch ?? fetch
|
||||
const wrappedFetch = async (input: string | URL | Request, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers)
|
||||
const body = sanitizeResponsesBody(input, init?.body)
|
||||
|
||||
// Add custom headers
|
||||
Object.entries(customHeaders).forEach(([key, value]) => {
|
||||
@@ -59,6 +61,7 @@ export function createKilo(options: KiloProviderOptions = {}): KiloProvider {
|
||||
return originalFetch(input, {
|
||||
...init,
|
||||
headers,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
function record(input: unknown): input is Record<string, unknown> {
|
||||
return typeof input === "object" && input !== null && !Array.isArray(input)
|
||||
}
|
||||
|
||||
function endpoint(input: string | URL | Request) {
|
||||
const raw = input instanceof Request ? input.url : input.toString()
|
||||
const path = (() => {
|
||||
try {
|
||||
return new URL(raw).pathname
|
||||
} catch {
|
||||
return raw.split(/[?#]/, 1)[0]
|
||||
}
|
||||
})()
|
||||
return path.endsWith("/responses")
|
||||
}
|
||||
|
||||
function strip(input: unknown[]) {
|
||||
const kept = input.flatMap((item) => {
|
||||
if (!record(item)) return [item]
|
||||
if (item.type === "item_reference") return []
|
||||
if (!("id" in item)) return [item]
|
||||
|
||||
const next = { ...item }
|
||||
delete next.id
|
||||
return [next]
|
||||
})
|
||||
const changed = kept.length !== input.length || kept.some((item, index) => item !== input[index])
|
||||
return { kept, changed }
|
||||
}
|
||||
|
||||
export function sanitizeResponsesBody(input: string | URL | Request, body: BodyInit | null | undefined) {
|
||||
if (!endpoint(input)) return body
|
||||
if (typeof body !== "string") return body
|
||||
|
||||
const data = (() => {
|
||||
try {
|
||||
return JSON.parse(body) as unknown
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
if (!record(data)) return body
|
||||
if (data.store === true) return body
|
||||
if (!Array.isArray(data.input)) return body
|
||||
|
||||
const result = strip(data.input)
|
||||
if (!result.changed) return body
|
||||
return JSON.stringify({ ...data, input: result.kept })
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { sanitizeResponsesBody } from "../src/responses"
|
||||
|
||||
describe("Responses request sanitization", () => {
|
||||
test("strips item ids when storage is disabled", () => {
|
||||
const body = JSON.stringify({
|
||||
store: false,
|
||||
input: [
|
||||
{
|
||||
type: "reasoning",
|
||||
id: "rs_tmp_123",
|
||||
encrypted_content: "encrypted",
|
||||
summary: [{ type: "summary_text", text: "thinking" }],
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
id: "msg_tmp_123",
|
||||
content: [{ type: "output_text", text: "Hello" }],
|
||||
},
|
||||
{
|
||||
type: "item_reference",
|
||||
id: "rs_tmp_456",
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [{ type: "input_text", text: "Continue" }],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const result = sanitizeResponsesBody("https://api.kilo.ai/api/openrouter/responses", body)
|
||||
const data = JSON.parse(result as string)
|
||||
|
||||
expect(data.input).toHaveLength(3)
|
||||
expect(data.input[0].id).toBeUndefined()
|
||||
expect(data.input[0].encrypted_content).toBe("encrypted")
|
||||
expect(data.input[0].summary[0].text).toBe("thinking")
|
||||
expect(data.input[1].id).toBeUndefined()
|
||||
expect(data.input[1].content[0].text).toBe("Hello")
|
||||
expect(data.input.some((item: { type?: string }) => item.type === "item_reference")).toBe(false)
|
||||
expect(data.input[2].content[0].text).toBe("Continue")
|
||||
})
|
||||
|
||||
test("keeps item ids when storage is enabled", () => {
|
||||
const body = JSON.stringify({
|
||||
store: true,
|
||||
input: [
|
||||
{
|
||||
type: "reasoning",
|
||||
id: "rs_123",
|
||||
encrypted_content: "encrypted",
|
||||
summary: [],
|
||||
},
|
||||
{
|
||||
type: "item_reference",
|
||||
id: "rs_456",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(sanitizeResponsesBody("https://api.kilo.ai/api/openrouter/responses", body)).toBe(body)
|
||||
})
|
||||
|
||||
test("leaves non-responses requests unchanged", () => {
|
||||
const body = "not json"
|
||||
|
||||
expect(sanitizeResponsesBody("https://api.kilo.ai/api/openrouter/chat/completions", body)).toBe(body)
|
||||
})
|
||||
|
||||
test("leaves invalid responses JSON unchanged", () => {
|
||||
const body = "not json"
|
||||
|
||||
expect(sanitizeResponsesBody("https://api.kilo.ai/api/openrouter/responses", body)).toBe(body)
|
||||
})
|
||||
|
||||
test("matches relative responses paths without a placeholder host", () => {
|
||||
const body = JSON.stringify({
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
id: "msg_tmp_123",
|
||||
content: [{ type: "output_text", text: "Hello" }],
|
||||
},
|
||||
],
|
||||
})
|
||||
const result = sanitizeResponsesBody("/api/openrouter/responses?stream=true", body)
|
||||
const data = JSON.parse(result as string)
|
||||
|
||||
expect(data.input[0].id).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-i18n",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"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-indexing",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Standalone indexing engine and host helpers for Kilo Code",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@kilocode/kilo-telemetry",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"description": "Telemetry for Kilo CLI - PostHog analytics integration",
|
||||
|
||||
@@ -156,7 +156,7 @@ export namespace Telemetry {
|
||||
taskId?: string
|
||||
mode?: "review"
|
||||
feature?: "code_reviews"
|
||||
command?: "local-review" | "local-review-uncommitted"
|
||||
command?: "review" | "local-review" | "local-review-uncommitted"
|
||||
apiProvider: string
|
||||
modelId: string
|
||||
inputTokens?: number
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
color: var(--text-base);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--icon-weak-base);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# kilo-code
|
||||
|
||||
## 7.2.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#10143](https://github.com/Kilo-Org/kilocode/pull/10143) [`ea023b0`](https://github.com/Kilo-Org/kilocode/commit/ea023b06dd269445eaf0c433fb42f4c9de2605b9) - Reduce delays in long sessions by compacting older tool outputs when the model request becomes too large.
|
||||
|
||||
## 7.2.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "kilo-code",
|
||||
"displayName": "Kilo Code: AI Coding Agent, Copilot, and Autocomplete",
|
||||
"description": "Open Source AI coding agent that generates code from natural language, automates tasks, and runs terminal commands. Features inline autocomplete, browser automation, automated refactoring, and custom modes for planning, coding, and debugging. Supports 500+ AI models including Claude (Anthropic), Gemini, Grok, GPT, Codex and GLM.",
|
||||
"version": "7.2.50",
|
||||
"version": "7.2.52",
|
||||
"icon": "assets/icons/logo-outline-black.png",
|
||||
"galleryBanner": {
|
||||
"color": "#FFFFFF",
|
||||
|
||||
@@ -670,7 +670,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
await this.handleAbort(message.sessionID)
|
||||
break
|
||||
case "revertSession":
|
||||
this.handleRevertSession(message.sessionID, message.messageID).catch((e) =>
|
||||
this.handleRevertSession(message.sessionID, message.messageID, message.partID).catch((e) =>
|
||||
console.error("[Kilo New] handleRevertSession failed:", e),
|
||||
)
|
||||
break
|
||||
@@ -2356,6 +2356,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
partial.provider !== undefined ||
|
||||
partial.disabled_providers !== undefined ||
|
||||
partial.enabled_providers !== undefined
|
||||
const refreshAgents =
|
||||
partial.default_agent !== undefined ||
|
||||
partial.agent !== undefined ||
|
||||
project.default_agent !== undefined ||
|
||||
project.agent !== undefined
|
||||
const hasGlobal = Object.keys(partial).length > 0
|
||||
const hasProject = Object.keys(project).length > 0
|
||||
|
||||
@@ -2388,7 +2393,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
globalConfig: global,
|
||||
features: configFeatures(merged),
|
||||
})
|
||||
if (refreshProviders) await this.fetchAndSendProviders()
|
||||
await Promise.all([
|
||||
refreshProviders ? this.fetchAndSendProviders() : Promise.resolve(),
|
||||
refreshAgents ? this.fetchAndSendAgents() : Promise.resolve(),
|
||||
])
|
||||
} catch (error) {
|
||||
console.error("[Kilo New] KiloProvider: Config write succeeded but post-write refresh failed:", error)
|
||||
const patch =
|
||||
@@ -2696,10 +2704,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
}
|
||||
|
||||
private async handleRevertSession(sessionID: string, messageID: string): Promise<void> {
|
||||
private async handleRevertSession(sessionID: string, messageID: string, partID?: string): Promise<void> {
|
||||
if (!this.client) return
|
||||
const dir = this.getWorkspaceDirectory(sessionID)
|
||||
const { data, error } = await this.client.session.revert({ sessionID, messageID, directory: dir })
|
||||
const { data, error } = await this.client.session.revert({ sessionID, messageID, partID, directory: dir })
|
||||
if (error) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to revert session:", error)
|
||||
this.postMessage({ type: "error", message: "Failed to revert session", sessionID })
|
||||
@@ -3091,9 +3099,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
|
||||
// Config was updated without a full dispose (e.g. permission-only save).
|
||||
// Fetch and push the updated config so the Settings panel reflects the change.
|
||||
// Fetch and push the updated config + refresh agents and providers so the
|
||||
// Settings panel and mode/model pickers reflect the change.
|
||||
if (event.type === "global.config.updated") {
|
||||
void this.fetchAndSendConfigUpdated()
|
||||
void Promise.all([this.fetchAndSendConfigUpdated(), this.fetchAndSendAgents(), this.fetchAndSendProviders()])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,7 @@ export class AgentManagerProvider implements Disposable {
|
||||
return
|
||||
}
|
||||
|
||||
await this.ensureGitExclude(manager)
|
||||
const loaded = await state.load()
|
||||
manager.cleanupOrphanedTempDirs()
|
||||
|
||||
@@ -291,6 +292,12 @@ export class AgentManagerProvider implements Disposable {
|
||||
this.panel?.sessions.recoverPendingPrompts()
|
||||
}
|
||||
|
||||
private async ensureGitExclude(manager: WorktreeManager): Promise<void> {
|
||||
await manager.ensureGitExclude().catch((err) => {
|
||||
this.log("Failed to update git exclude:", err)
|
||||
})
|
||||
}
|
||||
|
||||
private async recoverWorktrees(manager: WorktreeManager, state: WorktreeStateManager): Promise<void> {
|
||||
const infos = await manager.discoverWorktrees().catch((err) => {
|
||||
this.log("Failed to discover worktrees during state recovery:", err)
|
||||
|
||||
@@ -183,6 +183,16 @@ describe("Agent Manager Provider Messages", () => {
|
||||
expect(getMethodBody("onMessage")).toContain("if (this.shouldWaitForState(m)) await this.waitForStateReady(m.type)")
|
||||
})
|
||||
|
||||
it("initializeState updates local git exclude before loading persisted state", () => {
|
||||
const body = getMethodBody("initializeState")
|
||||
const exclude = body.indexOf("await this.ensureGitExclude(manager)")
|
||||
const load = body.indexOf("const loaded = await state.load()")
|
||||
|
||||
expect(exclude).toBeGreaterThanOrEqual(0)
|
||||
expect(load).toBeGreaterThanOrEqual(0)
|
||||
expect(exclude).toBeLessThan(load)
|
||||
})
|
||||
|
||||
it("async shutdown waits for terminal router cleanup", () => {
|
||||
const body = getMethodBody("disposeAsync")
|
||||
expect(body).toContain("await this.terminalRouter.dispose()")
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { AssistantMessage } from "@kilocode/sdk/v2"
|
||||
import {
|
||||
unwrapError,
|
||||
parseAssistantError,
|
||||
parseProviderAuthError,
|
||||
isUnauthorizedPaidModelError,
|
||||
isUnauthorizedPromotionLimitError,
|
||||
} from "../../webview-ui/src/utils/errorUtils"
|
||||
@@ -97,6 +98,26 @@ describe("parseAssistantError", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("parseProviderAuthError", () => {
|
||||
it("extracts provider auth errors", () => {
|
||||
const error: AssistantError = {
|
||||
name: "ProviderAuthError",
|
||||
data: { providerID: "openai", message: "Sign in again" },
|
||||
}
|
||||
|
||||
expect(parseProviderAuthError(error)).toEqual({ providerID: "openai", message: "Sign in again" })
|
||||
})
|
||||
|
||||
it("returns null for non-provider-auth errors", () => {
|
||||
const error: AssistantError = {
|
||||
name: "APIError",
|
||||
data: { statusCode: 401, message: "Unauthorized", isRetryable: false },
|
||||
}
|
||||
|
||||
expect(parseProviderAuthError(error)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe("isUnauthorizedPaidModelError", () => {
|
||||
it("returns true for 401 + PAID_MODEL_AUTH_REQUIRED", () => {
|
||||
expect(isUnauthorizedPaidModelError({ statusCode: 401, code: "PAID_MODEL_AUTH_REQUIRED" })).toBe(true)
|
||||
|
||||
@@ -105,6 +105,67 @@ describe("resolveSelectedQuestionMode", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("plan follow-up Continue here option", () => {
|
||||
it("resolves to code mode when option carries mode: code matching the Continue here label", () => {
|
||||
const questions = [
|
||||
{
|
||||
options: [
|
||||
{
|
||||
label: "Start new session",
|
||||
description: "Implement in a fresh session",
|
||||
labelKey: "plan.followup.answer.newSession",
|
||||
descriptionKey: "plan.followup.answer.newSession.description",
|
||||
},
|
||||
{
|
||||
label: "Continue here",
|
||||
description: "Implement the plan in this session",
|
||||
labelKey: "plan.followup.answer.continue",
|
||||
descriptionKey: "plan.followup.answer.continue.description",
|
||||
mode: "code",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
expect(resolveSelectedQuestionMode(questions, [["Continue here"]])).toBe("code")
|
||||
})
|
||||
|
||||
it("does not resolve a mode for Start new session (it carries no mode)", () => {
|
||||
const questions = [
|
||||
{
|
||||
options: [
|
||||
{
|
||||
label: "Start new session",
|
||||
description: "Implement in a fresh session",
|
||||
labelKey: "plan.followup.answer.newSession",
|
||||
descriptionKey: "plan.followup.answer.newSession.description",
|
||||
},
|
||||
{
|
||||
label: "Continue here",
|
||||
description: "Implement the plan in this session",
|
||||
labelKey: "plan.followup.answer.continue",
|
||||
descriptionKey: "plan.followup.answer.continue.description",
|
||||
mode: "code",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
expect(resolveSelectedQuestionMode(questions, [["Start new session"]])).toBeUndefined()
|
||||
})
|
||||
|
||||
it("resolves optimistic agent to code when Continue here is picked while in plan mode", () => {
|
||||
const mode = resolveSelectedQuestionMode(
|
||||
[
|
||||
{
|
||||
options: [{ label: "Continue here", description: "Implement here", mode: "code" }],
|
||||
},
|
||||
],
|
||||
[["Continue here"]],
|
||||
)
|
||||
const result = resolveOptimisticQuestionAgent(undefined, "plan", mode)
|
||||
expect(result).toEqual({ base: "plan", agent: "code" })
|
||||
})
|
||||
})
|
||||
|
||||
describe("resolveOptimisticQuestionAgent", () => {
|
||||
it("stores the previous agent when applying an optimistic mode", () => {
|
||||
const result = resolveOptimisticQuestionAgent(undefined, "ask", "code")
|
||||
|
||||
@@ -216,4 +216,76 @@ describe("per-mode model memory", () => {
|
||||
expect(result.modelSelections["code"]).toEqual(claude)
|
||||
expect(Object.keys(result.sessionOverrides)).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("clearing both session override and per-mode selection falls back to config default", () => {
|
||||
let store = emptyStore()
|
||||
// Simulate mode model set in config (getModeModel returns claude).
|
||||
const configured: ResolveEnv = {
|
||||
...env(),
|
||||
getModeModel: (name) => (name === "code" ? claude : null),
|
||||
}
|
||||
|
||||
// User picked gpt globally for "code"
|
||||
let result = applyModel(store, "code", gpt, undefined)
|
||||
store = { ...store, ...result }
|
||||
|
||||
// User then overrode the session with claude
|
||||
result = applyModel(store, "code", claude, "session-a")
|
||||
store = { ...store, ...result }
|
||||
|
||||
// Simulate clearModelOverride: clear both session override and per-mode selection
|
||||
const reset: ModelStore = {
|
||||
...store,
|
||||
sessionOverrides: {},
|
||||
modelSelections: { ...store.modelSelections, code: null },
|
||||
}
|
||||
|
||||
// Should fall through to the configured per-mode model (claude from config)
|
||||
expect(getSelected(reset, configured, "session-a", "code")).toEqual(claude)
|
||||
})
|
||||
|
||||
it("clearing only session override but not per-mode selection leaves persisted pick visible", () => {
|
||||
let store = emptyStore()
|
||||
const e = env()
|
||||
|
||||
// User picked claude globally for "code"
|
||||
const result = applyModel(store, "code", claude, undefined)
|
||||
store = { ...store, ...result }
|
||||
|
||||
// User then overrode the session with gpt
|
||||
const r2 = applyModel(store, "code", gpt, "session-a")
|
||||
store = { ...store, ...r2 }
|
||||
|
||||
// Simulate OLD behaviour: only clear session override, leave modelSelections intact
|
||||
const partial: ModelStore = { ...store, sessionOverrides: {} }
|
||||
|
||||
// The persisted per-mode selection (claude) is still returned — this is
|
||||
// why the reset appeared to "do nothing" when config also resolved to claude.
|
||||
expect(getSelected(partial, e, "session-a", "code")).toEqual(claude)
|
||||
})
|
||||
|
||||
it("switching from plan to implementation uses implementation config after clearing stale memory", () => {
|
||||
let store = emptyStore()
|
||||
const configured: ResolveEnv = {
|
||||
...env(),
|
||||
getModeModel: (name) => (name === "code" ? gpt : name === "plan" ? claude : null),
|
||||
}
|
||||
|
||||
// Old manual memory says implementation/code should use claude.
|
||||
let result = applyModel(store, "code", claude, undefined)
|
||||
store = { ...store, ...result }
|
||||
|
||||
// Current plan session is using its own model.
|
||||
result = applyModel(store, "plan", claude, "session-a")
|
||||
store = { ...store, ...result, agentSelections: { "session-a": "plan" } }
|
||||
|
||||
const switched: ModelStore = {
|
||||
...store,
|
||||
agentSelections: { "session-a": "code" },
|
||||
sessionOverrides: {},
|
||||
modelSelections: { ...store.modelSelections, code: null },
|
||||
}
|
||||
|
||||
expect(getSelected(switched, configured, "session-a", "code")).toEqual(gpt)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
messageTurns,
|
||||
queuedUserMessageIDs,
|
||||
stableMessageTurns,
|
||||
visibleMessages,
|
||||
} from "../../webview-ui/src/context/session-queue"
|
||||
import type { Message } from "../../webview-ui/src/types/messages"
|
||||
|
||||
@@ -107,6 +108,36 @@ describe("messageTurns", () => {
|
||||
{ id: "message_6", partial: undefined, assistant: [] },
|
||||
])
|
||||
})
|
||||
|
||||
it("stops at the revert boundary user turn", () => {
|
||||
const messages = [
|
||||
user("message_1"),
|
||||
assistant("message_2", "message_1"),
|
||||
user("message_3"),
|
||||
assistant("message_4", "message_3"),
|
||||
]
|
||||
|
||||
expect(messageTurns(messages, "message_3").map((turn) => turn.user.id)).toEqual(["message_1"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("visibleMessages", () => {
|
||||
it("flattens only turns before the revert boundary", () => {
|
||||
const messages = [
|
||||
user("message_1"),
|
||||
assistant("message_2", "message_1"),
|
||||
user("message_3"),
|
||||
assistant("message_4", "message_3"),
|
||||
]
|
||||
|
||||
expect(visibleMessages(messages, "message_3").map((msg) => msg.id)).toEqual(["message_1", "message_2"])
|
||||
})
|
||||
|
||||
it("keeps leading partial assistant output", () => {
|
||||
const messages = [assistant("message_2", "message_1"), user("message_3")]
|
||||
|
||||
expect(visibleMessages(messages).map((msg) => msg.id)).toEqual(["message_2", "message_3"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("stableMessageTurns", () => {
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import { state, target } from "../../webview-ui/src/context/todo-revert"
|
||||
import type { Message, Part, TodoItem } from "../../webview-ui/src/types/messages"
|
||||
|
||||
const base = {
|
||||
sessionID: "session",
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
time: { created: 1 },
|
||||
}
|
||||
|
||||
const user = (id: string): Message => ({ ...base, id, role: "user" })
|
||||
|
||||
const assistant = (id: string, parentID: string): Message => ({ ...base, id, parentID, role: "assistant" })
|
||||
|
||||
const todos = (...status: TodoItem["status"][]): TodoItem[] =>
|
||||
status.map((status, index) => ({ id: String(index + 1), content: `todo ${index + 1}`, status }))
|
||||
|
||||
const part = (id: string, messageID: string, list: TodoItem[]): Part => ({
|
||||
id,
|
||||
messageID,
|
||||
sessionID: "session",
|
||||
type: "tool",
|
||||
tool: "todowrite",
|
||||
state: {
|
||||
status: "completed",
|
||||
input: { todos: list },
|
||||
output: JSON.stringify(list),
|
||||
title: `${list.length} todos`,
|
||||
metadata: { todos: list },
|
||||
},
|
||||
})
|
||||
|
||||
describe("todo revert helpers", () => {
|
||||
const messages = [user("message_1"), assistant("message_2", "message_1")]
|
||||
const parts = {
|
||||
message_2: [
|
||||
part("part_1", "message_2", todos("pending", "pending", "pending")),
|
||||
part("part_2", "message_2", todos("completed", "pending", "pending")),
|
||||
part("part_3", "message_2", todos("completed", "completed", "pending")),
|
||||
],
|
||||
}
|
||||
|
||||
it("restores the todo state before a reverted todowrite part", () => {
|
||||
expect(state({ messages, parts, revert: { messageID: "message_2", partID: "part_3" } })).toEqual(
|
||||
todos("completed", "pending", "pending"),
|
||||
)
|
||||
})
|
||||
|
||||
it("restores the latest todo state on redo", () => {
|
||||
expect(state({ messages, parts })).toEqual(todos("completed", "completed", "pending"))
|
||||
})
|
||||
|
||||
it("targets the todowrite part that first completed the clicked todo", () => {
|
||||
expect(target({ messages, parts }, 0)?.id).toBe("part_2")
|
||||
expect(target({ messages, parts }, 1)?.id).toBe("part_3")
|
||||
expect(target({ messages, parts }, 2)).toBeUndefined()
|
||||
})
|
||||
|
||||
it("uses normal part ordering inside the revert boundary message", () => {
|
||||
expect(state({ messages, parts, revert: { messageID: "message_2", partID: "part_2" } })).toEqual(
|
||||
todos("pending", "pending", "pending"),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -680,7 +680,7 @@ describe("WorktreeManager.discoverWorktrees", () => {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("WorktreeManager.ensureGitExclude", () => {
|
||||
it("adds .kilo/worktrees/ to .git/info/exclude", async () => {
|
||||
it("adds Agent Manager state and worktrees to .git/info/exclude", async () => {
|
||||
const root = await createTempRepo()
|
||||
const mgr = createManager(root)
|
||||
|
||||
@@ -688,6 +688,7 @@ describe("WorktreeManager.ensureGitExclude", () => {
|
||||
|
||||
const content = await fs.readFile(path.join(root, ".git", "info", "exclude"), "utf-8")
|
||||
expect(content).toContain(".kilo/worktrees/")
|
||||
expect(content).toContain(".kilo/agent-manager.json")
|
||||
})
|
||||
|
||||
it("adds only specific legacy Agent Manager paths", async () => {
|
||||
|
||||
@@ -1403,7 +1403,7 @@ body.am-wt-dragging-active * {
|
||||
}
|
||||
|
||||
.am-tabs-menu-search-input::placeholder {
|
||||
color: var(--text-weaker);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
|
||||
.am-tabs-menu-list {
|
||||
@@ -2482,7 +2482,7 @@ body.am-wt-dragging-active * {
|
||||
}
|
||||
|
||||
.am-nv-name-input::placeholder {
|
||||
color: var(--text-weaker);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
|
||||
/* Dialog overrides for prompt-input-container — resizable from bottom edge */
|
||||
@@ -2665,7 +2665,7 @@ body.am-wt-dragging-active * {
|
||||
}
|
||||
|
||||
.am-mm-search-input::placeholder {
|
||||
color: var(--text-weaker);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
|
||||
.am-mm-list {
|
||||
@@ -2808,7 +2808,7 @@ body.am-wt-dragging-active * {
|
||||
}
|
||||
|
||||
.am-advanced-input::placeholder {
|
||||
color: var(--text-weaker);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
|
||||
/* Branch selector */
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
}
|
||||
|
||||
.kiloclaw-input::placeholder {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
|
||||
}
|
||||
|
||||
/* Status sidebar */
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { Component, createMemo, Switch, Match } from "solid-js"
|
||||
import { Card } from "@kilocode/kilo-ui/card"
|
||||
import { Collapsible } from "@kilocode/kilo-ui/collapsible"
|
||||
import { useDialog } from "@kilocode/kilo-ui/context/dialog"
|
||||
import { ErrorDetails } from "@kilocode/kilo-ui/error-details"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import type { AssistantMessage } from "@kilocode/sdk/v2"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import { useProvider } from "../../context/provider"
|
||||
import {
|
||||
unwrapError,
|
||||
parseAssistantError,
|
||||
parseProviderAuthError,
|
||||
isUnauthorizedPaidModelError,
|
||||
isUnauthorizedPromotionLimitError,
|
||||
} from "../../utils/errorUtils"
|
||||
import ProviderConnectDialog from "../settings/ProviderConnectDialog"
|
||||
|
||||
export interface ErrorDisplayProps {
|
||||
error: NonNullable<AssistantMessage["error"]>
|
||||
@@ -19,7 +23,28 @@ export interface ErrorDisplayProps {
|
||||
|
||||
export const ErrorDisplay: Component<ErrorDisplayProps> = (props) => {
|
||||
const { t } = useLanguage()
|
||||
const dialog = useDialog()
|
||||
const provider = useProvider()
|
||||
const parsed = createMemo(() => parseAssistantError(props.error))
|
||||
const auth = createMemo(() => parseProviderAuthError(props.error))
|
||||
const authProvider = createMemo(() => {
|
||||
const err = auth()
|
||||
if (!err) return
|
||||
return provider.providers()[err.providerID]
|
||||
})
|
||||
const canAuth = createMemo(() => {
|
||||
const err = auth()
|
||||
if (!err || !authProvider()) return false
|
||||
return (provider.authMethods()[err.providerID] ?? []).length > 0
|
||||
})
|
||||
const oauth = createMemo(() => {
|
||||
const err = auth()
|
||||
if (!err) return false
|
||||
return (
|
||||
err.providerID === "openai" &&
|
||||
(provider.authMethods()[err.providerID] ?? []).some((method) => method.type === "oauth")
|
||||
)
|
||||
})
|
||||
|
||||
const errorText = createMemo(() => {
|
||||
const msg = props.error.data?.message
|
||||
@@ -28,6 +53,12 @@ export const ErrorDisplay: Component<ErrorDisplayProps> = (props) => {
|
||||
return unwrapError(String(msg))
|
||||
})
|
||||
|
||||
function connectProvider() {
|
||||
const err = auth()
|
||||
if (!err) return
|
||||
dialog.show(() => <ProviderConnectDialog providerID={err.providerID} oauthOnly={oauth()} />)
|
||||
}
|
||||
|
||||
return (
|
||||
<Switch
|
||||
fallback={
|
||||
@@ -69,6 +100,28 @@ export const ErrorDisplay: Component<ErrorDisplayProps> = (props) => {
|
||||
</Button>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={canAuth()}>
|
||||
<div data-component="auth-prompt">
|
||||
<div data-slot="auth-prompt-header">
|
||||
<span data-slot="auth-prompt-icon">↻</span>
|
||||
<span data-slot="auth-prompt-title">
|
||||
{oauth()
|
||||
? t("error.providerAuth.chatgpt.title")
|
||||
: t("error.providerAuth.title", { provider: authProvider()?.name ?? auth()?.providerID ?? "provider" })}
|
||||
</span>
|
||||
</div>
|
||||
<p data-slot="auth-prompt-description">
|
||||
{oauth()
|
||||
? t("error.providerAuth.chatgpt.description")
|
||||
: t("error.providerAuth.description", {
|
||||
provider: authProvider()?.name ?? auth()?.providerID ?? "provider",
|
||||
})}
|
||||
</p>
|
||||
<Button variant="primary" onClick={connectProvider}>
|
||||
{oauth() ? t("settings.providers.action.signInChatGPT") : t("common.connect")}
|
||||
</Button>
|
||||
</div>
|
||||
</Match>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { describePatterns, resolveLabel, savedRuleStates, type RuleDecision } fr
|
||||
import { PermissionCommand } from "./PermissionCommand"
|
||||
import { PermissionDiff } from "./PermissionDiff"
|
||||
import { permissionDiffs } from "./permission-diff-utils"
|
||||
import { normalizeUrls } from "../../../../../opencode/src/kilocode/util/url"
|
||||
import type { PermissionRequest } from "../../types/messages"
|
||||
|
||||
let rulesExpandedPreference = false
|
||||
@@ -42,7 +43,9 @@ export const PermissionDock: Component<{
|
||||
const label = (rule: string) => (rule === "*" ? "" : rule.replace(/ \*$/, ""))
|
||||
const command = () => {
|
||||
const cmd = props.request.args?.command
|
||||
return typeof cmd === "string" ? cmd : undefined
|
||||
if (typeof cmd !== "string") return undefined
|
||||
// Normalize IDN/Unicode hostnames to punycode ASCII to prevent homograph attacks.
|
||||
return normalizeUrls(cmd)
|
||||
}
|
||||
const description = createMemo(() =>
|
||||
command() ? null : describePatterns(props.request.toolName, props.request.patterns, language.t),
|
||||
|
||||
@@ -19,7 +19,8 @@ import { useLanguage } from "../../context/language"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { TaskTimeline } from "./TaskTimeline"
|
||||
import { ContextProgress } from "./ContextProgress"
|
||||
import type { TodoItem, ExtensionMessage } from "../../types/messages"
|
||||
import { target as todoTarget } from "../../context/todo-revert"
|
||||
import type { Part, TodoItem, ExtensionMessage } from "../../types/messages"
|
||||
|
||||
interface TaskHeaderProps {
|
||||
readonly?: boolean
|
||||
@@ -32,7 +33,7 @@ export const TaskHeader: Component<TaskHeaderProps> = (props) => {
|
||||
const title = createMemo(() => session.currentSession()?.title ?? language.t("command.session.new"))
|
||||
const hasMessages = createMemo(() => session.messages().length > 0)
|
||||
const busy = createMemo(() => session.status() === "busy")
|
||||
const canCompact = createMemo(() => !busy() && hasMessages() && !!session.selected())
|
||||
const canCompact = createMemo(() => !busy() && session.visibleMessages().length > 0 && !!session.selected())
|
||||
|
||||
const fmt = (n: number) => new Intl.NumberFormat(language.locale(), { style: "currency", currency: "USD" }).format(n)
|
||||
|
||||
@@ -67,7 +68,7 @@ export const TaskHeader: Component<TaskHeaderProps> = (props) => {
|
||||
|
||||
// Token breakdown from the last assistant message — only return if at least one value is > 0
|
||||
const tokens = createMemo(() => {
|
||||
const msgs = session.messages()
|
||||
const msgs = session.visibleMessages()
|
||||
for (let i = msgs.length - 1; i >= 0; i--) {
|
||||
const m = msgs[i]
|
||||
if (m.role !== "assistant" || !m.tokens) continue
|
||||
@@ -79,7 +80,7 @@ export const TaskHeader: Component<TaskHeaderProps> = (props) => {
|
||||
})
|
||||
|
||||
const hasTimeline = createMemo(() => {
|
||||
for (const m of session.messages()) {
|
||||
for (const m of session.visibleMessages()) {
|
||||
if (m.role !== "assistant") continue
|
||||
if (session.getParts(m.id).some((p) => p.type !== "step-start")) return true
|
||||
}
|
||||
@@ -125,6 +126,16 @@ export const TaskHeader: Component<TaskHeaderProps> = (props) => {
|
||||
|
||||
const [todosOpen, setTodosOpen] = createSignal(false)
|
||||
|
||||
const donePart = (idx: number): Part | undefined =>
|
||||
todoTarget({ messages: session.messages(), parts: session.allParts() }, idx)
|
||||
|
||||
const revertTodo = (part: Part | undefined) => {
|
||||
if (session.status() !== "idle") return
|
||||
if (part?.type !== "tool") return
|
||||
if (!part.messageID) return
|
||||
session.revertSession(part.messageID, part.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={hasMessages()}>
|
||||
<div data-component="task-header">
|
||||
@@ -234,16 +245,21 @@ export const TaskHeader: Component<TaskHeaderProps> = (props) => {
|
||||
<Show when={todosOpen()}>
|
||||
<div data-slot="task-header-todos-list">
|
||||
<For each={todos()}>
|
||||
{(todo: TodoItem) => (
|
||||
<Checkbox readOnly checked={todo.status === "completed"}>
|
||||
<span
|
||||
data-slot="task-header-todo-content"
|
||||
data-completed={todo.status === "completed" ? "" : undefined}
|
||||
>
|
||||
{todo.content}
|
||||
</span>
|
||||
</Checkbox>
|
||||
)}
|
||||
{(todo: TodoItem, idx) => {
|
||||
const part = createMemo(() => (todo.status === "completed" ? donePart(idx()) : undefined))
|
||||
return (
|
||||
<Tooltip value={part() ? language.t("settings.checkpoints.title") : undefined} placement="bottom">
|
||||
<Checkbox readOnly checked={todo.status === "completed"} onClick={() => revertTodo(part())}>
|
||||
<span
|
||||
data-slot="task-header-todo-content"
|
||||
data-completed={todo.status === "completed" ? "" : undefined}
|
||||
>
|
||||
{todo.content}
|
||||
</span>
|
||||
</Checkbox>
|
||||
</Tooltip>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
@@ -57,7 +57,7 @@ export const TaskTimeline: Component = () => {
|
||||
let startX = 0
|
||||
let startScroll = 0
|
||||
|
||||
const messages = () => session.messages()
|
||||
const messages = () => session.visibleMessages()
|
||||
const allParts = () => {
|
||||
const msgs = messages()
|
||||
const result: Record<string, Part[]> = {}
|
||||
|
||||
@@ -449,12 +449,12 @@ const CustomProviderDialog = (props: CustomProviderDialogProps) => {
|
||||
<div style={{ "font-size": "var(--kilo-font-size-14)", color: "var(--text-base)" }}>
|
||||
{language.t("provider.custom.description.prefix")}
|
||||
<a
|
||||
href="https://kilo.ai/docs/providers/#custom-provider"
|
||||
href="https://kilo.ai/docs/ai-providers#custom-provider"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
vscode.postMessage({
|
||||
type: "openExternal",
|
||||
url: "https://kilo.ai/docs/providers/#custom-provider",
|
||||
url: "https://kilo.ai/docs/ai-providers#custom-provider",
|
||||
})
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -74,6 +74,12 @@ export function messageTurns(messages: Message[], boundary?: string): MessageTur
|
||||
return [...partials(lead), ...result]
|
||||
}
|
||||
|
||||
export function visibleMessages(messages: Message[], boundary?: string): Message[] {
|
||||
return messageTurns(messages, boundary).flatMap((turn) =>
|
||||
turn.partial ? turn.assistant : [turn.user, ...turn.assistant],
|
||||
)
|
||||
}
|
||||
|
||||
function sameMessages(a: Message[], b: Message[]) {
|
||||
if (a.length !== b.length) return false
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
|
||||
@@ -49,8 +49,10 @@ import { resolveModelSelection } from "./model-selection"
|
||||
import { resolveMessagePrefs } from "./session-preferences"
|
||||
import { errorIDs } from "./session-errors"
|
||||
import { PartStash } from "./part-stash"
|
||||
import { state as todoState } from "./todo-revert"
|
||||
import { getVariant, sessionVariantKeys, transferVariants, variantKey } from "./session-variant-store"
|
||||
import { KILO_AUTO, parseModelString } from "../../../src/shared/provider-model"
|
||||
import { visibleMessages as filterVisibleMessages } from "./session-queue"
|
||||
|
||||
const RECENT_LIMIT = 5
|
||||
const MESSAGE_PAGE_LIMIT = 80
|
||||
@@ -109,6 +111,9 @@ interface SessionContextValue {
|
||||
// Messages for current session
|
||||
messages: Accessor<Message[]>
|
||||
|
||||
// Messages for current session with soft-reverted turns hidden
|
||||
visibleMessages: Accessor<Message[]>
|
||||
|
||||
// User messages for current session (role === "user")
|
||||
userMessages: Accessor<Message[]>
|
||||
|
||||
@@ -205,7 +210,7 @@ interface SessionContextValue {
|
||||
worktreeStats: Accessor<{ files: number; additions: number; deletions: number } | undefined>
|
||||
|
||||
// Actions
|
||||
revertSession: (messageID: string) => void
|
||||
revertSession: (messageID: string, partID?: string) => void
|
||||
unrevertSession: () => void
|
||||
sendMessage: (
|
||||
text: string,
|
||||
@@ -517,6 +522,25 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
function clearModeModelSelection(agentName: string, persist = false) {
|
||||
setUserSetAgents((prev) => {
|
||||
const next = { ...prev }
|
||||
delete next[agentName]
|
||||
return next
|
||||
})
|
||||
setStore(
|
||||
"modelSelections",
|
||||
produce((selections) => {
|
||||
delete selections[agentName]
|
||||
}),
|
||||
)
|
||||
if (persist) vscode.postMessage({ type: "clearModelSelection", agent: agentName })
|
||||
}
|
||||
|
||||
function shouldClearModeModelSelection(agentName: string) {
|
||||
return getModeModel(agentName) !== null && userSetAgents()[agentName] === true
|
||||
}
|
||||
|
||||
function clearHiddenErrors(ids: string[]) {
|
||||
if (ids.length === 0) return
|
||||
setHiddenErrors((prev) => {
|
||||
@@ -543,6 +567,10 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
/** Clear the per-mode model override, falling back to config default. */
|
||||
function clearModelOverride(sessionID?: string) {
|
||||
const sid = sessionID ?? currentSessionID()
|
||||
const agentName = sid ? agentForScope(sid) : selectedAgentName()
|
||||
// Always clear the persisted per-mode model selection so the user's
|
||||
// configured (or fallback) model becomes effective, not the last manual pick.
|
||||
clearModeModelSelection(agentName, true)
|
||||
if (sid) {
|
||||
setStore(
|
||||
"sessionOverrides",
|
||||
@@ -551,22 +579,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
}),
|
||||
)
|
||||
hideErrors(sid)
|
||||
return
|
||||
}
|
||||
const agentName = selectedAgentName()
|
||||
setUserSetAgents((prev) => {
|
||||
const next = { ...prev }
|
||||
delete next[agentName]
|
||||
return next
|
||||
})
|
||||
setStore(
|
||||
"modelSelections",
|
||||
produce((selections) => {
|
||||
delete selections[agentName]
|
||||
}),
|
||||
)
|
||||
// Clear from model.json via extension host
|
||||
vscode.postMessage({ type: "clearModelSelection", agent: agentName })
|
||||
}
|
||||
|
||||
// Handle agentsLoaded immediately (not in onMount) so we never miss
|
||||
@@ -840,7 +853,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
break
|
||||
|
||||
case "sessionUpdated":
|
||||
setStore("sessions", message.session.id, message.session)
|
||||
handleSessionUpdated(message.session)
|
||||
break
|
||||
|
||||
case "sessionDeleted":
|
||||
@@ -1103,6 +1116,8 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
const revert = store.sessions[sessionID]?.revert ?? undefined
|
||||
if (revert) resetTodos(sessionID, revert)
|
||||
recoverPrefs(sessionID, merged)
|
||||
})
|
||||
if (reset) requestAnimationFrame(() => patchPage(sessionID, { lastMutation: undefined }))
|
||||
@@ -1401,13 +1416,12 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
* family tree (self + subagents + sub-subagents). Reads directly from the
|
||||
* store so it's reactive — automatically updates when new parts arrive.
|
||||
*/
|
||||
function sessionFamily(rootID: string): Set<string> {
|
||||
const family = new Set<string>([rootID])
|
||||
function sessionIDs(rootID: string, source: (sessionID: string) => Message[]): Set<string> {
|
||||
const ids = new Set<string>([rootID])
|
||||
const queue = [rootID]
|
||||
while (queue.length > 0) {
|
||||
const sid = queue.pop()!
|
||||
const msgs = store.messages[sid]
|
||||
if (!msgs) continue
|
||||
const msgs = source(sid)
|
||||
for (const msg of msgs) {
|
||||
const parts = store.parts[msg.id]
|
||||
if (!parts) continue
|
||||
@@ -1422,14 +1436,22 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
state?: { metadata?: { sessionId?: string } }
|
||||
},
|
||||
)
|
||||
if (child && !family.has(child)) {
|
||||
family.add(child)
|
||||
if (child && !ids.has(child)) {
|
||||
ids.add(child)
|
||||
queue.push(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return family
|
||||
return ids
|
||||
}
|
||||
|
||||
function sessionFamily(rootID: string): Set<string> {
|
||||
return sessionIDs(rootID, (sid) => store.messages[sid] ?? [])
|
||||
}
|
||||
|
||||
function visibleFamily(rootID: string): Set<string> {
|
||||
return sessionIDs(rootID, visible)
|
||||
}
|
||||
|
||||
/** Return permissions scoped to the given session's family (self + subagents). */
|
||||
@@ -1456,6 +1478,23 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
setStore("todos", sessionID, items)
|
||||
}
|
||||
|
||||
function resetTodos(sessionID: string, revert?: NonNullable<SessionInfo["revert"]>) {
|
||||
const items = todoState({
|
||||
messages: store.messages[sessionID] ?? [],
|
||||
parts: (messageID) => store.parts[messageID] ?? stash.peek(messageID),
|
||||
revert,
|
||||
})
|
||||
setStore("todos", sessionID, items)
|
||||
}
|
||||
|
||||
function handleSessionUpdated(session: SessionInfo) {
|
||||
const prev = store.sessions[session.id]?.revert
|
||||
const next = session.revert ?? undefined
|
||||
setStore("sessions", session.id, session)
|
||||
if (prev?.messageID === next?.messageID && prev?.partID === next?.partID) return
|
||||
resetTodos(session.id, next)
|
||||
}
|
||||
|
||||
function handleSessionsLoaded(loaded: SessionInfo[], preserve?: string[]) {
|
||||
const kept = preserve?.length ? new Set(preserve) : undefined
|
||||
batch(() => {
|
||||
@@ -1698,8 +1737,15 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
delete overrides[id]
|
||||
}),
|
||||
)
|
||||
if (shouldClearModeModelSelection(name)) {
|
||||
clearModeModelSelection(name)
|
||||
}
|
||||
} else {
|
||||
setPendingAgentSelection(name)
|
||||
if (shouldClearModeModelSelection(name)) {
|
||||
clearModeModelSelection(name)
|
||||
return
|
||||
}
|
||||
// When switching mode, initialize model for the new mode if the user
|
||||
// hasn't explicitly set one for it
|
||||
if (!userSetAgents()[name] && !store.modelSelections[name]) {
|
||||
@@ -2138,12 +2184,21 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
|
||||
const userMessages = createMemo(() => messages().filter((m) => m.role === "user"))
|
||||
|
||||
function visible(sessionID: string) {
|
||||
return filterVisibleMessages(store.messages[sessionID] ?? [], store.sessions[sessionID]?.revert?.messageID)
|
||||
}
|
||||
|
||||
const revert = createMemo(() => {
|
||||
const id = currentSessionID()
|
||||
// revert can be null (cleared by unrevert) or undefined (never set) — treat both as "no revert"
|
||||
return id ? (store.sessions[id]?.revert ?? undefined) : undefined
|
||||
})
|
||||
|
||||
const visibleMessages = createMemo(() => {
|
||||
const id = currentSessionID()
|
||||
return id ? visible(id) : []
|
||||
})
|
||||
|
||||
const revertedCount = createMemo(() => {
|
||||
const boundary = revert()?.messageID
|
||||
if (!boundary) return 0
|
||||
@@ -2155,7 +2210,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
return id ? (store.sessions[id]?.summary ?? undefined) : undefined
|
||||
})
|
||||
|
||||
function revertSession(messageID: string) {
|
||||
function revertSession(messageID: string, partID?: string) {
|
||||
const id = currentSessionID()
|
||||
if (!id) return
|
||||
// Restore the reverted user message's prompt text into the input.
|
||||
@@ -2168,7 +2223,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
.join("")
|
||||
if (text) window.postMessage({ type: "setChatBoxMessage", text }, "*")
|
||||
}
|
||||
vscode.postMessage({ type: "revertSession", sessionID: id, messageID })
|
||||
vscode.postMessage({ type: "revertSession", sessionID: id, messageID, partID })
|
||||
}
|
||||
|
||||
function unrevertSession() {
|
||||
@@ -2203,16 +2258,21 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
const familyCosts = createMemo<Map<string, number>>(() => {
|
||||
const id = currentSessionID()
|
||||
if (!id) return new Map()
|
||||
const family = sessionFamily(id)
|
||||
const parents = buildFamilyParents(family, store.messages as any, store.parts as any)
|
||||
return buildFamilyCosts(family, store.messages, store.sessions, parents)
|
||||
const family = visibleFamily(id)
|
||||
const msgs: Record<string, Message[]> = {}
|
||||
for (const sid of family) msgs[sid] = visible(sid)
|
||||
const parents = buildFamilyParents(family, msgs, store.parts)
|
||||
return buildFamilyCosts(family, msgs, store.sessions, parents)
|
||||
})
|
||||
|
||||
/** Child session labels — only reads store.parts (not message costs). */
|
||||
const familyLabels = createMemo<Map<string, string>>(() => {
|
||||
const id = currentSessionID()
|
||||
if (!id) return new Map()
|
||||
return buildFamilyLabels(sessionFamily(id), store.messages as any, store.parts as any)
|
||||
const family = visibleFamily(id)
|
||||
const msgs: Record<string, Message[]> = {}
|
||||
for (const sid of family) msgs[sid] = visible(sid)
|
||||
return buildFamilyLabels(family, msgs, store.parts)
|
||||
})
|
||||
|
||||
/** Combined cost breakdown with labels. */
|
||||
@@ -2249,7 +2309,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
})
|
||||
|
||||
const contextUsage = createMemo<ContextUsage | undefined>(() => {
|
||||
const msgs = messages()
|
||||
const msgs = visibleMessages()
|
||||
for (let i = msgs.length - 1; i >= 0; i--) {
|
||||
const m = msgs[i]
|
||||
if (m.role !== "assistant" || !m.tokens) continue
|
||||
@@ -2277,6 +2337,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
hasOlderMessages,
|
||||
messageMutation,
|
||||
messages,
|
||||
visibleMessages,
|
||||
userMessages,
|
||||
getParts,
|
||||
isErrorHidden: (messageID: string) => hiddenErrors().has(messageID),
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { Message, Part, SessionInfo, TodoItem, ToolPart } from "../types/messages"
|
||||
|
||||
type Revert = NonNullable<SessionInfo["revert"]>
|
||||
type Source = Record<string, Part[]> | ((messageID: string) => Part[] | undefined)
|
||||
type TodoPart = ToolPart & { state: { status: "completed"; metadata?: Record<string, unknown> } }
|
||||
|
||||
interface Input {
|
||||
messages: Message[]
|
||||
parts: Source
|
||||
revert?: Revert
|
||||
}
|
||||
|
||||
interface Write {
|
||||
part: TodoPart
|
||||
todos: TodoItem[]
|
||||
}
|
||||
|
||||
function list(source: Source, messageID: string) {
|
||||
if (typeof source === "function") return source(messageID) ?? []
|
||||
return source[messageID] ?? []
|
||||
}
|
||||
|
||||
export function isTodo(part: Part): part is TodoPart {
|
||||
if (part.type !== "tool") return false
|
||||
if (part.tool !== "todowrite") return false
|
||||
if (part.state.status !== "completed") return false
|
||||
return true
|
||||
}
|
||||
|
||||
export function items(part: Part): TodoItem[] | undefined {
|
||||
if (!isTodo(part)) return undefined
|
||||
const todos = part.state.metadata?.todos
|
||||
if (!Array.isArray(todos)) return undefined
|
||||
return todos as TodoItem[]
|
||||
}
|
||||
|
||||
function active(input: Input, msg: Message) {
|
||||
const parts = list(input.parts, msg.id)
|
||||
const revert = input.revert
|
||||
if (!revert) return parts
|
||||
if (msg.id < revert.messageID) return parts
|
||||
if (msg.id > revert.messageID) return []
|
||||
if (!revert.partID) return []
|
||||
const partID = revert.partID
|
||||
return parts.filter((part) => part.id < partID)
|
||||
}
|
||||
|
||||
export function writes(input: Input): Write[] {
|
||||
return input.messages.flatMap((msg) =>
|
||||
active(input, msg).flatMap((part) => {
|
||||
const todos = items(part)
|
||||
return todos ? [{ part: part as TodoPart, todos }] : []
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
export function state(input: Input): TodoItem[] {
|
||||
return writes(input).at(-1)?.todos ?? []
|
||||
}
|
||||
|
||||
export function target(input: Omit<Input, "revert">, index: number): Part | undefined {
|
||||
const all = writes(input)
|
||||
const done = (item: Write) => item.todos[index]?.status === "completed"
|
||||
const fallback = [...all].reverse().find(done)
|
||||
const entry = all
|
||||
.map((item, idx) => ({ item, idx }))
|
||||
.reverse()
|
||||
.find(({ item, idx }) => {
|
||||
if (!done(item)) return false
|
||||
return all[idx - 1]?.todos[index]?.status !== "completed"
|
||||
})
|
||||
|
||||
return entry?.item.part ?? fallback?.part
|
||||
}
|
||||
+5
@@ -462,6 +462,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"سجّل مجانًا للمتابعة واستكشاف أكثر من 500 نموذج. يستغرق دقيقتين، بدون بطاقة ائتمان. أو عُد لاحقًا.",
|
||||
"error.promotionLimit.action": "التسجيل",
|
||||
"error.providerAuth.title": "تم تسجيل خروجك من {{provider}}",
|
||||
"error.providerAuth.description": "أعد الاتصال بـ {{provider}}، ثم أرسل رسالتك مرة أخرى.",
|
||||
"error.providerAuth.chatgpt.title": "تسجيل الدخول باستخدام ChatGPT مرة أخرى",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"سجل الدخول باستخدام ChatGPT مرة أخرى، ثم أرسل رسالتك مرة أخرى لمواصلة استخدام نماذج Codex.",
|
||||
|
||||
"error.chain.unknown": "خطأ غير معروف",
|
||||
"error.chain.causedBy": "بسبب:",
|
||||
|
||||
+5
@@ -465,6 +465,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Cadastre-se gratuitamente para continuar e explorar mais de 500 modelos. Leva 2 minutos, sem cartão de crédito. Ou volte mais tarde.",
|
||||
"error.promotionLimit.action": "Cadastrar-se",
|
||||
"error.providerAuth.title": "{{provider}} desconectou você",
|
||||
"error.providerAuth.description": "Reconecte o {{provider}} e envie sua mensagem novamente.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI desconectou você",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Faça login no ChatGPT novamente e envie sua mensagem de novo para continuar usando os modelos Codex.",
|
||||
|
||||
"error.chain.unknown": "Erro desconhecido",
|
||||
"error.chain.causedBy": "Causado por:",
|
||||
|
||||
+5
@@ -469,6 +469,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Registrujte se besplatno da nastavite i istražite preko 500 modela. Traje 2 minute, bez kreditne kartice. Ili se vratite kasnije.",
|
||||
"error.promotionLimit.action": "Registracija",
|
||||
"error.providerAuth.title": "{{provider}} vas je odjavio",
|
||||
"error.providerAuth.description": "Ponovo se povežite sa {{provider}}, a zatim ponovo pošaljite poruku.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI vas je odjavio",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Ponovo se prijavite na ChatGPT, a zatim ponovo pošaljite poruku da nastavite koristiti Codex modele.",
|
||||
|
||||
"error.chain.unknown": "Nepoznata greška",
|
||||
"error.chain.causedBy": "Uzrok:",
|
||||
|
||||
+5
@@ -466,6 +466,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Tilmeld dig gratis for at fortsætte og udforske over 500 modeller. Tager 2 minutter, intet kreditkort nødvendigt. Eller kom tilbage senere.",
|
||||
"error.promotionLimit.action": "Tilmeld dig",
|
||||
"error.providerAuth.title": "{{provider}} har logget dig af",
|
||||
"error.providerAuth.description": "Forbind til {{provider}} igen, og send din besked på ny.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI har logget dig af",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Log ind med ChatGPT igen, og send din besked på ny for at fortsætte med at bruge Codex-modeller.",
|
||||
|
||||
"error.chain.unknown": "Ukendt fejl",
|
||||
"error.chain.causedBy": "Forårsaget af:",
|
||||
|
||||
+5
@@ -471,6 +471,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Registriere dich kostenlos, um weiterzumachen und über 500 Modelle zu entdecken. Dauert 2 Minuten, keine Kreditkarte nötig. Oder komm später wieder.",
|
||||
"error.promotionLimit.action": "Registrieren",
|
||||
"error.providerAuth.title": "{{provider}} hat Sie abgemeldet",
|
||||
"error.providerAuth.description": "Verbinden Sie {{provider}} erneut und senden Sie Ihre Nachricht noch einmal.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI hat Sie abgemeldet",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Melden Sie sich erneut bei ChatGPT an und senden Sie Ihre Nachricht noch einmal, um weiterhin Codex-Modelle zu verwenden.",
|
||||
|
||||
"error.chain.unknown": "Unbekannter Fehler",
|
||||
"error.chain.causedBy": "Verursacht durch:",
|
||||
|
||||
@@ -467,6 +467,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Sign up for free to continue and explore 500 other models. Takes 2 minutes, no credit card required. Or come back later.",
|
||||
"error.promotionLimit.action": "Sign Up",
|
||||
"error.providerAuth.title": "{{provider}} signed you out",
|
||||
"error.providerAuth.description": "Reconnect {{provider}}, then send your message again.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI signed you out",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Sign in with ChatGPT again, then send your message again to keep using Codex models.",
|
||||
|
||||
"error.chain.unknown": "Unknown error",
|
||||
"error.chain.causedBy": "Caused by:",
|
||||
|
||||
+5
@@ -469,6 +469,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Regístrate gratis para continuar y explorar más de 500 modelos. Solo 2 minutos, sin tarjeta de crédito. O vuelve más tarde.",
|
||||
"error.promotionLimit.action": "Registrarse",
|
||||
"error.providerAuth.title": "{{provider}} cerró tu sesión",
|
||||
"error.providerAuth.description": "Vuelve a conectar {{provider}} y envía tu mensaje de nuevo.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI cerró tu sesión",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Vuelve a iniciar sesión con ChatGPT y envía tu mensaje de nuevo para seguir usando los modelos Codex.",
|
||||
|
||||
"error.chain.unknown": "Error desconocido",
|
||||
"error.chain.causedBy": "Causado por:",
|
||||
|
||||
+5
@@ -473,6 +473,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Inscrivez-vous gratuitement pour continuer et explorer plus de 500 modèles. 2 minutes, sans carte bancaire. Ou revenez plus tard.",
|
||||
"error.promotionLimit.action": "S'inscrire",
|
||||
"error.providerAuth.title": "{{provider}} vous a déconnecté",
|
||||
"error.providerAuth.description": "Reconnectez {{provider}}, puis renvoyez votre message.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI vous a déconnecté",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Reconnectez-vous à ChatGPT, puis renvoyez votre message pour continuer à utiliser les modèles Codex.",
|
||||
|
||||
"error.chain.unknown": "Erreur inconnue",
|
||||
"error.chain.causedBy": "Causé par :",
|
||||
|
||||
+5
@@ -463,6 +463,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"無料でサインアップして、500以上のモデルを探索しましょう。2分で完了、クレジットカード不要。または後でお戻りください。",
|
||||
"error.promotionLimit.action": "サインアップ",
|
||||
"error.providerAuth.title": "{{provider}} からログアウトしました",
|
||||
"error.providerAuth.description": "{{provider}} に再接続してから、メッセージを再送信してください。",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI からログアウトしました",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Codex モデルを引き続き使用するには、ChatGPT に再度ログインしてから、メッセージを再送信してください。",
|
||||
|
||||
"error.chain.unknown": "不明なエラー",
|
||||
"error.chain.causedBy": "原因:",
|
||||
|
||||
+5
@@ -465,6 +465,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"무료로 가입하여 500개 이상의 모델을 탐색하세요. 2분이면 완료, 신용카드 불필요. 또는 나중에 다시 오세요.",
|
||||
"error.promotionLimit.action": "가입하기",
|
||||
"error.providerAuth.title": "{{provider}}에서 로그아웃되었습니다",
|
||||
"error.providerAuth.description": "{{provider}}에 다시 연결한 후 메시지를 다시 보내주세요.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI에서 로그아웃되었습니다",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"ChatGPT에 다시 로그인한 후 메시지를 다시 보내 Codex 모델을 계속 사용하세요.",
|
||||
|
||||
"error.chain.unknown": "알 수 없는 오류",
|
||||
"error.chain.causedBy": "원인:",
|
||||
|
||||
+5
@@ -469,6 +469,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Registreer je gratis om door te gaan en 500 andere modellen te ontdekken. Duurt 2 minuten, geen creditcard vereist. Of kom later terug.",
|
||||
"error.promotionLimit.action": "Registreren",
|
||||
"error.providerAuth.title": "{{provider}} heeft je afgemeld",
|
||||
"error.providerAuth.description": "Verbind opnieuw met {{provider}} en stuur je bericht nog een keer.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI heeft je afgemeld",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Meld je opnieuw aan bij ChatGPT en stuur je bericht nog een keer om Codex-modellen te blijven gebruiken.",
|
||||
|
||||
"error.chain.unknown": "Onbekende fout",
|
||||
"error.chain.causedBy": "Veroorzaakt door:",
|
||||
|
||||
+5
@@ -470,6 +470,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Registrer deg gratis for å fortsette og utforske over 500 modeller. Tar 2 minutter, ingen kredittkort nødvendig. Eller kom tilbake senere.",
|
||||
"error.promotionLimit.action": "Registrer deg",
|
||||
"error.providerAuth.title": "{{provider}} logget deg ut",
|
||||
"error.providerAuth.description": "Koble til {{provider}} på nytt, og send meldingen din igjen.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI logget deg ut",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Logg på ChatGPT igjen, og send meldingen din på nytt for å fortsette å bruke Codex-modeller.",
|
||||
|
||||
"error.chain.unknown": "Ukjent feil",
|
||||
"error.chain.causedBy": "Forårsaket av:",
|
||||
|
||||
+5
@@ -467,6 +467,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Zarejestruj się za darmo, aby kontynuować i odkryć ponad 500 modeli. Zajmie to 2 minuty, bez karty kredytowej. Lub wróć później.",
|
||||
"error.promotionLimit.action": "Zarejestruj się",
|
||||
"error.providerAuth.title": "{{provider}} wylogował Cię",
|
||||
"error.providerAuth.description": "Połącz się ponownie z {{provider}}, a następnie wyślij wiadomość jeszcze raz.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI wylogowało Cię",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Zaloguj się ponownie do ChatGPT, a następnie wyślij wiadomość jeszcze raz, aby kontynuować korzystanie z modeli Codex.",
|
||||
|
||||
"error.chain.unknown": "Nieznany błąd",
|
||||
"error.chain.causedBy": "Spowodowany przez:",
|
||||
|
||||
+5
@@ -466,6 +466,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Зарегистрируйтесь бесплатно, чтобы продолжить и исследовать более 500 моделей. Займёт 2 минуты, кредитная карта не нужна. Или вернитесь позже.",
|
||||
"error.promotionLimit.action": "Зарегистрироваться",
|
||||
"error.providerAuth.title": "Сеанс {{provider}} завершен",
|
||||
"error.providerAuth.description": "Подключитесь к {{provider}} снова, затем отправьте сообщение еще раз.",
|
||||
"error.providerAuth.chatgpt.title": "Сеанс OpenAI завершен",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Войдите в ChatGPT снова, затем отправьте сообщение еще раз, чтобы продолжить использование моделей Codex.",
|
||||
|
||||
"error.chain.unknown": "Неизвестная ошибка",
|
||||
"error.chain.causedBy": "Причина:",
|
||||
|
||||
+5
@@ -464,6 +464,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"สมัครฟรีเพื่อดำเนินการต่อและสำรวจโมเดลกว่า 500 รายการ ใช้เวลา 2 นาที ไม่ต้องใช้บัตรเครดิต หรือกลับมาทีหลัง",
|
||||
"error.promotionLimit.action": "สมัครสมาชิก",
|
||||
"error.providerAuth.title": "{{provider}} ออกจากระบบของคุณแล้ว",
|
||||
"error.providerAuth.description": "เชื่อมต่อ {{provider}} อีกครั้ง จากนั้นส่งข้อความของคุณใหม่",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI ออกจากระบบของคุณแล้ว",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"เข้าสู่ระบบ ChatGPT อีกครั้ง จากนั้นส่งข้อความของคุณใหม่เพื่อใช้งานโมเดล Codex ต่อไป",
|
||||
|
||||
"error.chain.unknown": "ข้อผิดพลาดที่ไม่รู้จัก",
|
||||
"error.chain.causedBy": "สาเหตุ:",
|
||||
|
||||
+5
@@ -466,6 +466,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Devam etmek ve 500'den fazla modeli keşfetmek için ücretsiz kayıt olun. 2 dakika sürer, kredi kartı gerekmez. Ya da daha sonra gelin.",
|
||||
"error.promotionLimit.action": "Kayıt Ol",
|
||||
"error.providerAuth.title": "{{provider}} oturumunuzu kapattı",
|
||||
"error.providerAuth.description": "{{provider}} bağlantısını yeniden kurun ve mesajınızı tekrar gönderin.",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI oturumunuzu kapattı",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Codex modellerini kullanmaya devam etmek için ChatGPT ile tekrar giriş yapın ve mesajınızı yeniden gönderin.",
|
||||
|
||||
"error.chain.unknown": "Bilinmeyen hata",
|
||||
"error.chain.causedBy": "Nedeni:",
|
||||
|
||||
+5
@@ -470,6 +470,11 @@ export const dict = {
|
||||
"error.promotionLimit.description":
|
||||
"Зареєструйтеся безкоштовно для продовження та доступу до 500+ моделей. Займе 2 хвилини, кредитна картка не потрібна. Або поверніться пізніше.",
|
||||
"error.promotionLimit.action": "Зареєструватися",
|
||||
"error.providerAuth.title": "Сеанс {{provider}} завершено",
|
||||
"error.providerAuth.description": "Підключіться до {{provider}} знову, а потім надішліть повідомлення ще раз.",
|
||||
"error.providerAuth.chatgpt.title": "Сеанс OpenAI завершено",
|
||||
"error.providerAuth.chatgpt.description":
|
||||
"Увійдіть у ChatGPT знову, а потім надішліть повідомлення ще раз, щоб продовжити використання моделей Codex.",
|
||||
|
||||
"error.chain.unknown": "Невідома помилка",
|
||||
"error.chain.causedBy": "Спричинено:",
|
||||
|
||||
+4
@@ -459,6 +459,10 @@ export const dict = {
|
||||
"error.promotionLimit.title": "您需要注册才能继续",
|
||||
"error.promotionLimit.description": "免费注册以继续探索500多个模型。只需2分钟,无需信用卡。或稍后再来。",
|
||||
"error.promotionLimit.action": "注册",
|
||||
"error.providerAuth.title": "{{provider}} 已将您登出",
|
||||
"error.providerAuth.description": "请重新连接 {{provider}},然后再次发送消息。",
|
||||
"error.providerAuth.chatgpt.title": "OpenAI 已将您登出",
|
||||
"error.providerAuth.chatgpt.description": "请再次登录 ChatGPT,然后重新发送消息以继续使用 Codex 模型。",
|
||||
|
||||
"error.chain.unknown": "未知错误",
|
||||
"error.chain.causedBy": "原因:",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user