From 207fc8b02244ac2d61c27a65e1e86a60e272ca77 Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:06:10 +0000 Subject: [PATCH 01/18] test(vscode): add CI check for missing translation keys Add i18n-keys.test.ts that validates all string-literal t() keys used in the webview, cli-backend, and autocomplete code exist in the corresponding English dictionaries. Runs as part of bun run test:unit in CI. Also adds missing 'session.status.retry' key to the sidebar English dictionary that was caught by the new test. --- .../kilo-vscode/tests/unit/i18n-keys.test.ts | 189 ++++++++++++++++++ .../kilo-vscode/webview-ui/src/i18n/en.ts | 1 + 2 files changed, 190 insertions(+) create mode 100644 packages/kilo-vscode/tests/unit/i18n-keys.test.ts diff --git a/packages/kilo-vscode/tests/unit/i18n-keys.test.ts b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts new file mode 100644 index 00000000000..e4ea2dab5e3 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts @@ -0,0 +1,189 @@ +/** + * Translation key validation + * + * Ensures every string-literal translation key passed to a t() function + * actually exists in the corresponding English dictionary. + * + * Three independent key pools are checked: + * 1. Webview (sidebar + agent manager): merged from app, ui, kilo-i18n, agent-manager dicts + * 2. CLI backend (extension-side server-manager): cli-backend/i18n dict + * 3. Autocomplete (extension-side): autocomplete/i18n dict + * + * Dynamic keys (template literals, variables) are intentionally skipped — + * only string literals are validated. + */ + +import { describe, it, expect } from "bun:test" +import { Glob } from "bun" +import path from "node:path" + +// ── Dictionaries ──────────────────────────────────────────────────────────── + +// Webview layer 1: app-local (sidebar) +import { dict as appEn } from "../../webview-ui/src/i18n/en" +// Webview layer 2: upstream UI (@opencode-ai/ui re-exported via @kilocode/kilo-ui) +import { dict as uiEn } from "../../../ui/src/i18n/en" +// Webview layer 3: kilo-i18n overrides +import { dict as kiloEn } from "../../../kilo-i18n/src/en" +// Webview layer 4: agent manager +import { dict as amEn } from "../../webview-ui/agent-manager/i18n/en" + +// Extension-side: CLI backend +import { dict as cliEn } from "../../src/services/cli-backend/i18n/en" +// Extension-side: autocomplete +import { dict as acEn } from "../../src/services/autocomplete/i18n/en" + +const ROOT = path.resolve(import.meta.dir, "../..") + +// Merge webview dictionaries in the same priority order as language.tsx +const webviewKeys = new Set(Object.keys({ ...appEn, ...uiEn, ...kiloEn, ...amEn })) +const cliKeys = new Set(Object.keys(cliEn)) +const acKeys = new Set(Object.keys(acEn)) + +// ── File scanning ─────────────────────────────────────────────────────────── + +interface Missing { + file: string + line: number + key: string +} + +/** + * Regex to match t("key") / t('key') calls. + * + * Captures the string literal argument to any of these patterns: + * t("key") language.t("key") i18n.t("key") + * + * Skips template literals (backticks) and variable arguments. + */ +const T_CALL = /(?:^|[^a-zA-Z_$])t\(\s*(?:["'])([^"']+)["']/g + +function extractKeys(content: string): Array<{ line: number; key: string }> { + const results: Array<{ line: number; key: string }> = [] + const lines = content.split("\n") + for (let i = 0; i < lines.length; i++) { + const text = lines[i] + let match: RegExpExecArray | null + T_CALL.lastIndex = 0 + while ((match = T_CALL.exec(text)) !== null) { + const key = match[1] + if (key) results.push({ line: i + 1, key }) + } + } + return results +} + +async function collectFiles(glob: Glob, dir: string): Promise { + const files: string[] = [] + for await (const entry of glob.scan({ cwd: dir, absolute: true })) { + files.push(entry) + } + return files +} + +// ── Webview files ─────────────────────────────────────────────────────────── + +async function findWebviewMissing(): Promise { + const glob = new Glob("**/*.{ts,tsx}") + const dirs = [path.join(ROOT, "webview-ui/src"), path.join(ROOT, "webview-ui/agent-manager")] + + const files: string[] = [] + for (const dir of dirs) { + files.push(...(await collectFiles(glob, dir))) + } + + // Exclude i18n dictionary files themselves and storybook files + const filtered = files.filter((f) => !f.includes("/i18n/") && !f.includes(".stories.") && !f.includes("/stories/")) + + const missing: Missing[] = [] + for (const file of filtered) { + const content = await Bun.file(file).text() + for (const { line, key } of extractKeys(content)) { + if (!webviewKeys.has(key)) { + missing.push({ file: path.relative(ROOT, file), line, key }) + } + } + } + return missing +} + +// ── CLI backend files ─────────────────────────────────────────────────────── + +async function findCliBackendMissing(): Promise { + const glob = new Glob("**/*.ts") + const dir = path.join(ROOT, "src/services/cli-backend") + + const files = (await collectFiles(glob, dir)).filter((f) => !f.includes("/i18n/")) + + const missing: Missing[] = [] + for (const file of files) { + const content = await Bun.file(file).text() + for (const { line, key } of extractKeys(content)) { + if (!cliKeys.has(key)) { + missing.push({ file: path.relative(ROOT, file), line, key }) + } + } + } + return missing +} + +// ── Autocomplete files ────────────────────────────────────────────────────── + +async function findAutocompleteMissing(): Promise { + const glob = new Glob("**/*.ts") + const dir = path.join(ROOT, "src/services/autocomplete") + + const files = (await collectFiles(glob, dir)).filter((f) => !f.includes("/i18n/") && !f.includes("/shims/")) + + const missing: Missing[] = [] + for (const file of files) { + const content = await Bun.file(file).text() + for (const { line, key } of extractKeys(content)) { + if (!acKeys.has(key)) { + missing.push({ file: path.relative(ROOT, file), line, key }) + } + } + } + return missing +} + +// ── Tests ─────────────────────────────────────────────────────────────────── + +function formatReport(missing: Missing[]): string { + return missing.map((m) => ` ${m.file}:${m.line} — "${m.key}"`).join("\n") +} + +describe("i18n key validation — no missing translation keys", () => { + it("webview: all t() string literal keys exist in merged dictionaries", async () => { + const missing = await findWebviewMissing() + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} translation key(s) not present in any dictionary:\n${formatReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) + + it("cli-backend: all t() string literal keys exist in cli-backend dictionary", async () => { + const missing = await findCliBackendMissing() + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} translation key(s) not present in cli-backend dictionary:\n${formatReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) + + it("autocomplete: all t() string literal keys exist in autocomplete dictionary", async () => { + const missing = await findAutocompleteMissing() + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} translation key(s) not present in autocomplete dictionary:\n${formatReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) +}) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 23eef2801c6..72872fb9ae2 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -838,6 +838,7 @@ export const dict = { "Kilo Code is an AI coding assistant. Ask it to build features, fix bugs, or explain your codebase.", "session.messages.scrollToBottom": "Scroll to bottom", "session.status.writingResponse": "Writing response...", + "session.status.retry": "Retrying…", "session.status.retrying": "Retrying (attempt {{ attempt }})… {{ message }}", "session.status.working": "Working...", From b2a59fe5f677ef84da8d6388ee49b0598fb9d8ae Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:34:20 +0000 Subject: [PATCH 02/18] fix(vscode): reload autocomplete when CLI backend connection state changes AutocompleteServiceManager only called model.reload() once at startup, before the CLI backend had finished connecting. Since it never subscribed to connection state changes, hasValidCredentials() permanently returned false, causing the 'No autocomplete model configured' error even when the user was logged into Kilo Gateway with credits. Subscribe to connectionService.onStateChange() so the autocomplete model and status bar re-evaluate whenever the backend connects or disconnects. --- .../autocomplete/AutocompleteServiceManager.ts | 11 +++++++++++ .../__tests__/AutocompleteServiceManager.spec.ts | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts index 4aaad29e7c6..6fb130edcdd 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts @@ -59,6 +59,7 @@ export class AutocompleteServiceManager { public readonly codeActionProvider: AutocompleteCodeActionProvider public readonly inlineCompletionProvider: AutocompleteInlineCompletionProvider private inlineCompletionProviderDisposable: vscode.Disposable | null = null + private unsubscribeState: (() => void) | null = null constructor(context: vscode.ExtensionContext, connectionService: KiloConnectionService) { if (AutocompleteServiceManager._instance) { @@ -86,6 +87,12 @@ export class AutocompleteServiceManager { new AutocompleteTelemetry(), ) + // Reload when CLI backend connection state changes so autocomplete + // picks up the connected state even if it wasn't ready at startup. + this.unsubscribeState = connectionService.onStateChange(() => { + void this.load() + }) + void this.load() } @@ -360,6 +367,10 @@ export class AutocompleteServiceManager { this.snoozeTimer = null } + // Unsubscribe from connection state changes + this.unsubscribeState?.() + this.unsubscribeState = null + // Dispose inline completion provider registration if (this.inlineCompletionProviderDisposable) { this.inlineCompletionProviderDisposable.dispose() diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts index 456eaa5fbcd..11fb9ff0042 100644 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts @@ -169,7 +169,9 @@ async function createManager(): Promise { postStateToWebview: vi.fn().mockResolvedValue(undefined), } - const manager = new AutocompleteServiceManager(context, cline as any) + const connection = { onStateChange: vi.fn().mockReturnValue(() => {}), ...cline } + + const manager = new AutocompleteServiceManager(context, connection as any) await manager.load() From b74fe9baffe7795e16bc479e3fdfb651df5c5a3a Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:36:56 +0000 Subject: [PATCH 03/18] test(vscode): add locale completeness checks and fix missing translations Extend i18n-keys.test.ts with locale completeness validation that ensures every English key has a corresponding translation in all locale files. Covers sidebar app, kilo-i18n, and cli-backend dictionaries. Add missing keys to all 15 non-English locale files: - session.status.retry - prompt.placeholder.error - settings.providers.modeModels - settings.providers.modeModels.description - error.details.show (Norwegian only) --- .../kilo-vscode/tests/unit/i18n-keys.test.ts | 192 ++++++++++++++++-- .../kilo-vscode/webview-ui/src/i18n/ar.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/br.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/bs.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/da.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/de.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/es.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/fr.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/ja.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/ko.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/no.ts | 6 + .../kilo-vscode/webview-ui/src/i18n/pl.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/ru.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/th.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/zh.ts | 5 + .../kilo-vscode/webview-ui/src/i18n/zht.ts | 5 + 16 files changed, 256 insertions(+), 12 deletions(-) diff --git a/packages/kilo-vscode/tests/unit/i18n-keys.test.ts b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts index e4ea2dab5e3..fb40b104d9c 100644 --- a/packages/kilo-vscode/tests/unit/i18n-keys.test.ts +++ b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts @@ -1,13 +1,14 @@ /** * Translation key validation * - * Ensures every string-literal translation key passed to a t() function - * actually exists in the corresponding English dictionary. + * 1. Ensures every string-literal translation key passed to a t() function + * actually exists in the corresponding English dictionary. + * 2. Ensures every English key has a translation in all other locale files. * * Three independent key pools are checked: - * 1. Webview (sidebar + agent manager): merged from app, ui, kilo-i18n, agent-manager dicts - * 2. CLI backend (extension-side server-manager): cli-backend/i18n dict - * 3. Autocomplete (extension-side): autocomplete/i18n dict + * - Webview (sidebar + agent manager): merged from app, ui, kilo-i18n, agent-manager dicts + * - CLI backend (extension-side server-manager): cli-backend/i18n dict + * - Autocomplete (extension-side): autocomplete/i18n dict * * Dynamic keys (template literals, variables) are intentionally skipped — * only string literals are validated. @@ -17,24 +18,132 @@ import { describe, it, expect } from "bun:test" import { Glob } from "bun" import path from "node:path" -// ── Dictionaries ──────────────────────────────────────────────────────────── +// ── Webview dictionaries ──────────────────────────────────────────────────── -// Webview layer 1: app-local (sidebar) +// Layer 1: app-local (sidebar) import { dict as appEn } from "../../webview-ui/src/i18n/en" -// Webview layer 2: upstream UI (@opencode-ai/ui re-exported via @kilocode/kilo-ui) +import { dict as appZh } from "../../webview-ui/src/i18n/zh" +import { dict as appZht } from "../../webview-ui/src/i18n/zht" +import { dict as appKo } from "../../webview-ui/src/i18n/ko" +import { dict as appDe } from "../../webview-ui/src/i18n/de" +import { dict as appEs } from "../../webview-ui/src/i18n/es" +import { dict as appFr } from "../../webview-ui/src/i18n/fr" +import { dict as appDa } from "../../webview-ui/src/i18n/da" +import { dict as appJa } from "../../webview-ui/src/i18n/ja" +import { dict as appPl } from "../../webview-ui/src/i18n/pl" +import { dict as appRu } from "../../webview-ui/src/i18n/ru" +import { dict as appAr } from "../../webview-ui/src/i18n/ar" +import { dict as appNo } from "../../webview-ui/src/i18n/no" +import { dict as appBr } from "../../webview-ui/src/i18n/br" +import { dict as appTh } from "../../webview-ui/src/i18n/th" +import { dict as appBs } from "../../webview-ui/src/i18n/bs" + +// Layer 2: upstream UI (@opencode-ai/ui re-exported via @kilocode/kilo-ui) import { dict as uiEn } from "../../../ui/src/i18n/en" -// Webview layer 3: kilo-i18n overrides + +// Layer 3: kilo-i18n overrides import { dict as kiloEn } from "../../../kilo-i18n/src/en" -// Webview layer 4: agent manager +import { dict as kiloZh } from "../../../kilo-i18n/src/zh" +import { dict as kiloZht } from "../../../kilo-i18n/src/zht" +import { dict as kiloKo } from "../../../kilo-i18n/src/ko" +import { dict as kiloDe } from "../../../kilo-i18n/src/de" +import { dict as kiloEs } from "../../../kilo-i18n/src/es" +import { dict as kiloFr } from "../../../kilo-i18n/src/fr" +import { dict as kiloDa } from "../../../kilo-i18n/src/da" +import { dict as kiloJa } from "../../../kilo-i18n/src/ja" +import { dict as kiloPl } from "../../../kilo-i18n/src/pl" +import { dict as kiloRu } from "../../../kilo-i18n/src/ru" +import { dict as kiloAr } from "../../../kilo-i18n/src/ar" +import { dict as kiloNo } from "../../../kilo-i18n/src/no" +import { dict as kiloBr } from "../../../kilo-i18n/src/br" +import { dict as kiloTh } from "../../../kilo-i18n/src/th" +import { dict as kiloBs } from "../../../kilo-i18n/src/bs" + +// Layer 4: agent manager (locale alignment already tested in agent-manager-i18n-split.test.ts) import { dict as amEn } from "../../webview-ui/agent-manager/i18n/en" -// Extension-side: CLI backend +// ── Extension-side dictionaries ───────────────────────────────────────────── + import { dict as cliEn } from "../../src/services/cli-backend/i18n/en" -// Extension-side: autocomplete +import { dict as cliZh } from "../../src/services/cli-backend/i18n/zh" +import { dict as cliZht } from "../../src/services/cli-backend/i18n/zht" +import { dict as cliDe } from "../../src/services/cli-backend/i18n/de" +import { dict as cliEs } from "../../src/services/cli-backend/i18n/es" +import { dict as cliFr } from "../../src/services/cli-backend/i18n/fr" +import { dict as cliDa } from "../../src/services/cli-backend/i18n/da" +import { dict as cliJa } from "../../src/services/cli-backend/i18n/ja" +import { dict as cliKo } from "../../src/services/cli-backend/i18n/ko" +import { dict as cliPl } from "../../src/services/cli-backend/i18n/pl" +import { dict as cliRu } from "../../src/services/cli-backend/i18n/ru" +import { dict as cliAr } from "../../src/services/cli-backend/i18n/ar" +import { dict as cliNo } from "../../src/services/cli-backend/i18n/no" +import { dict as cliBr } from "../../src/services/cli-backend/i18n/br" +import { dict as cliTh } from "../../src/services/cli-backend/i18n/th" +import { dict as cliBs } from "../../src/services/cli-backend/i18n/bs" + import { dict as acEn } from "../../src/services/autocomplete/i18n/en" +// ── Locale maps ───────────────────────────────────────────────────────────── + const ROOT = path.resolve(import.meta.dir, "../..") +const appLocales: Record> = { + en: appEn, + zh: appZh, + zht: appZht, + ko: appKo, + de: appDe, + es: appEs, + fr: appFr, + da: appDa, + ja: appJa, + pl: appPl, + ru: appRu, + ar: appAr, + no: appNo, + br: appBr, + th: appTh, + bs: appBs, +} + +const kiloLocales: Record> = { + en: kiloEn, + zh: kiloZh, + zht: kiloZht, + ko: kiloKo, + de: kiloDe, + es: kiloEs, + fr: kiloFr, + da: kiloDa, + ja: kiloJa, + pl: kiloPl, + ru: kiloRu, + ar: kiloAr, + no: kiloNo, + br: kiloBr, + th: kiloTh, + bs: kiloBs, +} + +const cliLocales: Record> = { + en: cliEn, + zh: cliZh, + zht: cliZht, + de: cliDe, + es: cliEs, + fr: cliFr, + da: cliDa, + ja: cliJa, + ko: cliKo, + pl: cliPl, + ru: cliRu, + ar: cliAr, + no: cliNo, + br: cliBr, + th: cliTh, + bs: cliBs, +} + // Merge webview dictionaries in the same priority order as language.tsx const webviewKeys = new Set(Object.keys({ ...appEn, ...uiEn, ...kiloEn, ...amEn })) const cliKeys = new Set(Object.keys(cliEn)) @@ -147,6 +256,30 @@ async function findAutocompleteMissing(): Promise { return missing } +// ── Locale completeness helpers ───────────────────────────────────────────── + +function findMissingLocaleKeys( + en: Record, + locales: Record>, +): Array<{ locale: string; key: string }> { + const base = Object.keys(en) + const results: Array<{ locale: string; key: string }> = [] + for (const [locale, dict] of Object.entries(locales)) { + if (locale === "en") continue + const keys = new Set(Object.keys(dict)) + for (const key of base) { + if (!keys.has(key)) { + results.push({ locale, key }) + } + } + } + return results +} + +function formatLocaleReport(items: Array<{ locale: string; key: string }>): string { + return items.map((m) => ` [${m.locale}] "${m.key}"`).join("\n") +} + // ── Tests ─────────────────────────────────────────────────────────────────── function formatReport(missing: Missing[]): string { @@ -187,3 +320,38 @@ describe("i18n key validation — no missing translation keys", () => { expect(missing).toEqual([]) }) }) + +describe("i18n locale completeness — every English key exists in all locales", () => { + it("sidebar app: every English key has a translation in all locales", () => { + const missing = findMissingLocaleKeys(appEn, appLocales) + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} missing sidebar translation(s):\n${formatLocaleReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) + + it("kilo-i18n: every English key has a translation in all locales", () => { + const missing = findMissingLocaleKeys(kiloEn, kiloLocales) + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} missing kilo-i18n translation(s):\n${formatLocaleReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) + + it("cli-backend: every English key has a translation in all locales", () => { + const missing = findMissingLocaleKeys(cliEn, cliLocales) + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} missing cli-backend translation(s):\n${formatLocaleReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) +}) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index c4fa3f25acb..f0decff554e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -680,6 +680,9 @@ export const dict = { "settings.providers.tag.config": "التكوين", "settings.providers.tag.custom": "مخصص", "settings.providers.tag.other": "أخرى", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "النماذج", "settings.models.description": "ستكون إعدادات النموذج قابلة للتكوين هنا.", "settings.agents.title": "الوكلاء", @@ -827,12 +830,14 @@ export const dict = { "Kilo Code هو مساعد ترميز بالذكاء الاصطناعي. اطلب منه بناء ميزات أو إصلاح أخطاء أو شرح قاعدة الشيفرة.", "session.messages.scrollToBottom": "التمرير إلى الأسفل", "session.status.writingResponse": "...جارٍ كتابة الرد", + "session.status.retry": "Retrying…", "session.status.retrying": "...إعادة المحاولة (المحاولة {{ attempt }})… {{ message }}", "session.status.working": "...جارٍ العمل", "dialog.model.noProviders": "لا يوجد موفرون", "prompt.placeholder.connecting": "جارٍ الاتصال بالخادم...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "اكتب رسالة... (Enter للإرسال، Shift+Enter لسطر جديد)", "context.usage.sessionCost": "تكلفة الجلسة", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index e8a16504af0..79a171678e8 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -687,6 +687,9 @@ export const dict = { "settings.providers.tag.config": "Configuração", "settings.providers.tag.custom": "Personalizado", "settings.providers.tag.other": "Outro", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modelos", "settings.models.description": "Configurações de modelos estarão disponíveis aqui.", "settings.agents.title": "Agentes", @@ -835,12 +838,14 @@ export const dict = { "Kilo Code é um assistente de programação com IA. Peça para criar funcionalidades, corrigir bugs ou explicar sua base de código.", "session.messages.scrollToBottom": "Rolar para o final", "session.status.writingResponse": "Escrevendo resposta…", + "session.status.retry": "Retrying…", "session.status.retrying": "Tentando novamente (tentativa {{ attempt }})… {{ message }}", "session.status.working": "Trabalhando…", "dialog.model.noProviders": "Nenhum provedor", "prompt.placeholder.connecting": "Conectando ao servidor...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Digite uma mensagem... (Enter para enviar, Shift+Enter para nova linha)", "context.usage.sessionCost": "Custo da sessão", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 5097fd6a307..9c1bef45bac 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -691,6 +691,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguracija", "settings.providers.tag.custom": "Prilagođeno", "settings.providers.tag.other": "Ostalo", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modeli", "settings.models.description": "Postavke modela će se ovdje moći podešavati.", "settings.agents.title": "Agenti", @@ -838,12 +841,14 @@ export const dict = { "Kilo Code je AI asistent za programiranje. Zatražite da gradi funkcionalnosti, ispravlja greške ili objasni vašu bazu koda.", "session.messages.scrollToBottom": "Pomakni se na dno", "session.status.writingResponse": "Pisanje odgovora…", + "session.status.retry": "Retrying…", "session.status.retrying": "Ponovni pokušaj (pokušaj {{ attempt }})… {{ message }}", "session.status.working": "Radim…", "dialog.model.noProviders": "Nema pružatelja", "prompt.placeholder.connecting": "Povezivanje na server...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Unesite poruku... (Enter za slanje, Shift+Enter za novi red)", "context.usage.sessionCost": "Cijena sesije", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 1e979d37779..e7de1399ffc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -686,6 +686,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguration", "settings.providers.tag.custom": "Brugerdefineret", "settings.providers.tag.other": "Andet", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modeller", "settings.models.description": "Modelindstillinger vil kunne konfigureres her.", "settings.agents.title": "Agenter", @@ -833,12 +836,14 @@ export const dict = { "Kilo Code er en AI-kodningsassistent. Bed den om at bygge funktioner, rette fejl eller forklare din kodebase.", "session.messages.scrollToBottom": "Rul til bunden", "session.status.writingResponse": "Skriver svar…", + "session.status.retry": "Retrying…", "session.status.retrying": "Prøver igen (forsøg {{ attempt }})… {{ message }}", "session.status.working": "Arbejder…", "dialog.model.noProviders": "Ingen udbydere", "prompt.placeholder.connecting": "Opretter forbindelse til server...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Skriv en besked... (Enter for at sende, Shift+Enter for ny linje)", "context.usage.sessionCost": "Sessionsomkostning", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 99f0f585e0a..c9b2a01c7a1 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -696,6 +696,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguration", "settings.providers.tag.custom": "Benutzerdefiniert", "settings.providers.tag.other": "Andere", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modelle", "settings.models.description": "Modelleinstellungen können hier konfiguriert werden.", "settings.agents.title": "Agenten", @@ -843,12 +846,14 @@ export const dict = { "Kilo Code ist ein KI-Programmierassistent. Bitten Sie ihn, Funktionen zu erstellen, Fehler zu beheben oder Ihre Codebasis zu erklären.", "session.messages.scrollToBottom": "Nach unten scrollen", "session.status.writingResponse": "Antwort wird geschrieben…", + "session.status.retry": "Retrying…", "session.status.retrying": "Erneuter Versuch ({{ attempt }})… {{ message }}", "session.status.working": "Wird bearbeitet…", "dialog.model.noProviders": "Keine Anbieter", "prompt.placeholder.connecting": "Verbindung zum Server wird hergestellt...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Nachricht eingeben... (Enter zum Senden, Shift+Enter für neue Zeile)", "context.usage.sessionCost": "Sitzungskosten", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 47d663824f3..d49ca0d1e04 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -692,6 +692,9 @@ export const dict = { "settings.providers.tag.config": "Configuración", "settings.providers.tag.custom": "Personalizado", "settings.providers.tag.other": "Otro", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modelos", "settings.models.description": "La configuración de modelos estará disponible aquí.", "settings.agents.title": "Agentes", @@ -840,12 +843,14 @@ export const dict = { "Kilo Code es un asistente de programación con IA. Pídele que cree funcionalidades, corrija errores o explique tu código.", "session.messages.scrollToBottom": "Desplazar al final", "session.status.writingResponse": "Escribiendo respuesta…", + "session.status.retry": "Retrying…", "session.status.retrying": "Reintentando (intento {{ attempt }})… {{ message }}", "session.status.working": "Trabajando…", "dialog.model.noProviders": "Sin proveedores", "prompt.placeholder.connecting": "Conectando al servidor...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Escribe un mensaje... (Enter para enviar, Shift+Enter para nueva línea)", "context.usage.sessionCost": "Coste de la sesión", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index da0135db55d..35f02b3a486 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -696,6 +696,9 @@ export const dict = { "settings.providers.tag.config": "Configuration", "settings.providers.tag.custom": "Personnalisé", "settings.providers.tag.other": "Autre", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modèles", "settings.models.description": "Les paramètres des modèles seront configurables ici.", "settings.agents.title": "Agents", @@ -845,12 +848,14 @@ export const dict = { "Kilo Code est un assistant de programmation IA. Demandez-lui de créer des fonctionnalités, corriger des bugs ou expliquer votre code.", "session.messages.scrollToBottom": "Défiler vers le bas", "session.status.writingResponse": "Rédaction de la réponse…", + "session.status.retry": "Retrying…", "session.status.retrying": "Nouvelle tentative (essai {{ attempt }})… {{ message }}", "session.status.working": "En cours…", "dialog.model.noProviders": "Aucun fournisseur", "prompt.placeholder.connecting": "Connexion au serveur...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Tapez un message... (Entrée pour envoyer, Maj+Entrée pour un saut de ligne)", "context.usage.sessionCost": "Coût de la session", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 7c7e68c0ced..5d91287959f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -685,6 +685,9 @@ export const dict = { "settings.providers.tag.config": "設定", "settings.providers.tag.custom": "カスタム", "settings.providers.tag.other": "その他", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "モデル", "settings.models.description": "モデル設定はここで構成できます。", "settings.agents.title": "エージェント", @@ -832,12 +835,14 @@ export const dict = { "Kilo CodeはAIコーディングアシスタントです。機能の構築、バグの修正、コードベースの説明を依頼できます。", "session.messages.scrollToBottom": "下にスクロール", "session.status.writingResponse": "応答を作成中…", + "session.status.retry": "Retrying…", "session.status.retrying": "再試行中({{ attempt }}回目)… {{ message }}", "session.status.working": "作業中…", "dialog.model.noProviders": "プロバイダーなし", "prompt.placeholder.connecting": "サーバーに接続中...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "メッセージを入力... (Enterで送信、Shift+Enterで改行)", "context.usage.sessionCost": "セッションコスト", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index db088d27173..a8464a71f20 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -686,6 +686,9 @@ export const dict = { "settings.providers.tag.config": "구성", "settings.providers.tag.custom": "사용자 지정", "settings.providers.tag.other": "기타", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "모델", "settings.models.description": "모델 설정은 여기서 구성할 수 있습니다.", "settings.agents.title": "에이전트", @@ -832,12 +835,14 @@ export const dict = { "Kilo Code는 AI 코딩 어시스턴트입니다. 기능 구축, 버그 수정 또는 코드베이스 설명을 요청하세요.", "session.messages.scrollToBottom": "하단으로 스크롤", "session.status.writingResponse": "응답 작성 중...", + "session.status.retry": "Retrying…", "session.status.retrying": "재시도 중 ({{ attempt }}번째 시도)… {{ message }}", "session.status.working": "작업 중...", "dialog.model.noProviders": "공급자 없음", "prompt.placeholder.connecting": "서버에 연결 중...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "메시지를 입력하세요... (Enter로 전송, Shift+Enter로 줄 바꿈)", "context.usage.sessionCost": "세션 비용", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 5a5205d4532..e5c707a83ae 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -398,6 +398,7 @@ export const dict = { "error.page.title": "Noe gikk galt", "error.page.description": "Det oppstod en feil under lasting av applikasjonen.", "error.page.details.label": "Feildetaljer", + "error.details.show": "Details", "error.page.action.restart": "Start på nytt", "error.page.action.checking": "Sjekker...", "error.page.action.checkUpdates": "Se etter oppdateringer", @@ -689,6 +690,9 @@ export const dict = { "settings.providers.tag.config": "Konfigurasjon", "settings.providers.tag.custom": "Tilpasset", "settings.providers.tag.other": "Annet", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modeller", "settings.models.description": "Modellinnstillinger vil kunne konfigureres her.", "settings.agents.title": "Agenter", @@ -836,12 +840,14 @@ export const dict = { "Kilo Code er en AI-kodingsassistent. Be den om å bygge funksjoner, fikse feil eller forklare kodebasen din.", "session.messages.scrollToBottom": "Rull til bunnen", "session.status.writingResponse": "Skriver svar…", + "session.status.retry": "Retrying…", "session.status.retrying": "Prøver på nytt (forsøk {{ attempt }})… {{ message }}", "session.status.working": "Arbeider…", "dialog.model.noProviders": "Ingen leverandører", "prompt.placeholder.connecting": "Kobler til server...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Skriv en melding... (Enter for å sende, Shift+Enter for ny linje)", "context.usage.sessionCost": "Sesjonskostnad", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 97923dc9774..0d6dba9c3dc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -689,6 +689,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguracja", "settings.providers.tag.custom": "Niestandardowe", "settings.providers.tag.other": "Inne", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Modele", "settings.models.description": "Ustawienia modeli będą tutaj konfigurowalne.", "settings.agents.title": "Agenci", @@ -835,12 +838,14 @@ export const dict = { "Kilo Code to asystent programowania AI. Poproś go o tworzenie funkcji, naprawę błędów lub wyjaśnienie bazy kodu.", "session.messages.scrollToBottom": "Przewiń na dół", "session.status.writingResponse": "Pisanie odpowiedzi…", + "session.status.retry": "Retrying…", "session.status.retrying": "Ponawiam próbę ({{ attempt }})… {{ message }}", "session.status.working": "Pracuję…", "dialog.model.noProviders": "Brak dostawców", "prompt.placeholder.connecting": "Łączenie z serwerem...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Wpisz wiadomość... (Enter, aby wysłać, Shift+Enter dla nowej linii)", "context.usage.sessionCost": "Koszt sesji", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 08100091c9e..5192306a677 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -692,6 +692,9 @@ export const dict = { "settings.providers.tag.config": "Конфигурация", "settings.providers.tag.custom": "Пользовательский", "settings.providers.tag.other": "Другое", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "Модели", "settings.models.description": "Настройки моделей будут доступны здесь.", "settings.agents.title": "Агенты", @@ -839,12 +842,14 @@ export const dict = { "Kilo Code — это AI-помощник для программирования. Попросите его создать функции, исправить ошибки или объяснить вашу кодовую базу.", "session.messages.scrollToBottom": "Прокрутить вниз", "session.status.writingResponse": "Пишу ответ…", + "session.status.retry": "Retrying…", "session.status.retrying": "Повторная попытка ({{ attempt }})… {{ message }}", "session.status.working": "Работаю…", "dialog.model.noProviders": "Нет провайдеров", "prompt.placeholder.connecting": "Подключение к серверу...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "Введите сообщение... (Enter для отправки, Shift+Enter для новой строки)", "context.usage.sessionCost": "Стоимость сессии", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index cdfd4b6bf06..0241f742947 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -683,6 +683,9 @@ export const dict = { "settings.providers.tag.config": "กำหนดค่า", "settings.providers.tag.custom": "กำหนดเอง", "settings.providers.tag.other": "อื่น ๆ", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "โมเดล", "settings.models.description": "การตั้งค่าโมเดลจะสามารถกำหนดค่าได้ที่นี่", "settings.agents.title": "เอเจนต์", @@ -828,12 +831,14 @@ export const dict = { "session.messages.welcome": "Kilo Code เป็นผู้ช่วยเขียนโค้ด AI ขอให้สร้างฟีเจอร์ แก้ไขบัก หรืออธิบายโค้ดเบสของคุณ", "session.messages.scrollToBottom": "เลื่อนไปด้านล่าง", "session.status.writingResponse": "กำลังเขียนคำตอบ...", + "session.status.retry": "Retrying…", "session.status.retrying": "กำลังลองใหม่ (ครั้งที่ {{ attempt }})… {{ message }}", "session.status.working": "กำลังทำงาน...", "dialog.model.noProviders": "ไม่มีผู้ให้บริการ", "prompt.placeholder.connecting": "กำลังเชื่อมต่อกับเซิร์ฟเวอร์...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "พิมพ์ข้อความ... (Enter เพื่อส่ง, Shift+Enter เพื่อขึ้นบรรทัดใหม่)", "context.usage.sessionCost": "ค่าใช้จ่ายเซสชัน", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index ab749eb7c67..03ed924a7de 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -676,6 +676,9 @@ export const dict = { "settings.providers.tag.config": "配置", "settings.providers.tag.custom": "自定义", "settings.providers.tag.other": "其他", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "模型", "settings.models.description": "模型设置将在此处可配置。", "settings.agents.title": "智能体", @@ -821,12 +824,14 @@ export const dict = { "session.messages.welcome": "Kilo Code 是一个 AI 编程助手。让它帮你构建功能、修复 bug 或解释代码库。", "session.messages.scrollToBottom": "滚动到底部", "session.status.writingResponse": "正在撰写回复…", + "session.status.retry": "Retrying…", "session.status.retrying": "正在重试(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "处理中…", "dialog.model.noProviders": "无供应商", "prompt.placeholder.connecting": "正在连接服务器...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "输入消息... (Enter 发送,Shift+Enter 换行)", "context.usage.sessionCost": "会话费用", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 07ae7f89231..54aa5214ba6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -678,6 +678,9 @@ export const dict = { "settings.providers.tag.config": "設定", "settings.providers.tag.custom": "自訂", "settings.providers.tag.other": "其他", + "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels.description": + "Override the default model for specific modes. If not set, the global default model is used.", "settings.models.title": "模型", "settings.models.description": "可在此調整模型設定。", "settings.agents.title": "Agents", @@ -823,12 +826,14 @@ export const dict = { "session.messages.welcome": "Kilo Code 是一個 AI 程式設計助手。讓它幫你建構功能、修復 bug 或解釋程式碼庫。", "session.messages.scrollToBottom": "捲動至底部", "session.status.writingResponse": "正在撰寫回覆…", + "session.status.retry": "Retrying…", "session.status.retrying": "正在重試(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "處理中…", "dialog.model.noProviders": "沒有供應商", "prompt.placeholder.connecting": "正在連線至伺服器...", + "prompt.placeholder.error": "", "prompt.placeholder.default": "輸入訊息... (Enter 送出,Shift+Enter 換行)", "context.usage.sessionCost": "工作階段費用", From ee3a6d61431b8692333816be9777c6e5f86b7c0a Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:50:14 +0000 Subject: [PATCH 04/18] fix(vscode): address i18n test review feedback - Fix multiline t() detection: run regex on full file content with dotAll flag instead of line-by-line, so t(\n "key"\n) calls are captured - Add shared UI (packages/ui/src/i18n) locale completeness validation to close the coverage gap for the merged webview dictionaries --- .../kilo-vscode/tests/unit/i18n-keys.test.ts | 80 +++++++++++++++---- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/packages/kilo-vscode/tests/unit/i18n-keys.test.ts b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts index fb40b104d9c..3410f5a2ad3 100644 --- a/packages/kilo-vscode/tests/unit/i18n-keys.test.ts +++ b/packages/kilo-vscode/tests/unit/i18n-keys.test.ts @@ -40,6 +40,21 @@ import { dict as appBs } from "../../webview-ui/src/i18n/bs" // Layer 2: upstream UI (@opencode-ai/ui re-exported via @kilocode/kilo-ui) import { dict as uiEn } from "../../../ui/src/i18n/en" +import { dict as uiZh } from "../../../ui/src/i18n/zh" +import { dict as uiZht } from "../../../ui/src/i18n/zht" +import { dict as uiKo } from "../../../ui/src/i18n/ko" +import { dict as uiDe } from "../../../ui/src/i18n/de" +import { dict as uiEs } from "../../../ui/src/i18n/es" +import { dict as uiFr } from "../../../ui/src/i18n/fr" +import { dict as uiDa } from "../../../ui/src/i18n/da" +import { dict as uiJa } from "../../../ui/src/i18n/ja" +import { dict as uiPl } from "../../../ui/src/i18n/pl" +import { dict as uiRu } from "../../../ui/src/i18n/ru" +import { dict as uiAr } from "../../../ui/src/i18n/ar" +import { dict as uiNo } from "../../../ui/src/i18n/no" +import { dict as uiBr } from "../../../ui/src/i18n/br" +import { dict as uiTh } from "../../../ui/src/i18n/th" +import { dict as uiBs } from "../../../ui/src/i18n/bs" // Layer 3: kilo-i18n overrides import { dict as kiloEn } from "../../../kilo-i18n/src/en" @@ -125,6 +140,25 @@ const kiloLocales: Record> = { bs: kiloBs, } +const uiLocales: Record> = { + en: uiEn, + zh: uiZh, + zht: uiZht, + ko: uiKo, + de: uiDe, + es: uiEs, + fr: uiFr, + da: uiDa, + ja: uiJa, + pl: uiPl, + ru: uiRu, + ar: uiAr, + no: uiNo, + br: uiBr, + th: uiTh, + bs: uiBs, +} + const cliLocales: Record> = { en: cliEn, zh: cliZh, @@ -158,26 +192,31 @@ interface Missing { } /** - * Regex to match t("key") / t('key') calls. + * Regex to match t("key") / t('key') calls, including multiline. * - * Captures the string literal argument to any of these patterns: - * t("key") language.t("key") i18n.t("key") - * - * Skips template literals (backticks) and variable arguments. + * The `s` (dotAll) flag lets `\s*` span newlines so that calls like: + * t( + * "key" + * ) + * are captured. Runs against the entire file content, not line-by-line. */ -const T_CALL = /(?:^|[^a-zA-Z_$])t\(\s*(?:["'])([^"']+)["']/g +const T_CALL = /(?:^|[^a-zA-Z_$])t\(\s*(?:["'])([^"']+)["']/gs + +function offsetToLine(content: string, offset: number): number { + let line = 1 + for (let i = 0; i < offset && i < content.length; i++) { + if (content[i] === "\n") line++ + } + return line +} function extractKeys(content: string): Array<{ line: number; key: string }> { const results: Array<{ line: number; key: string }> = [] - const lines = content.split("\n") - for (let i = 0; i < lines.length; i++) { - const text = lines[i] - let match: RegExpExecArray | null - T_CALL.lastIndex = 0 - while ((match = T_CALL.exec(text)) !== null) { - const key = match[1] - if (key) results.push({ line: i + 1, key }) - } + let match: RegExpExecArray | null + T_CALL.lastIndex = 0 + while ((match = T_CALL.exec(content)) !== null) { + const key = match[1] + if (key) results.push({ line: offsetToLine(content, match.index), key }) } return results } @@ -322,6 +361,17 @@ describe("i18n key validation — no missing translation keys", () => { }) describe("i18n locale completeness — every English key exists in all locales", () => { + it("shared UI: every English key has a translation in all locales", () => { + const missing = findMissingLocaleKeys(uiEn, uiLocales) + if (missing.length > 0) { + expect( + missing, + `Found ${missing.length} missing shared UI translation(s):\n${formatLocaleReport(missing)}`, + ).toEqual([]) + } + expect(missing).toEqual([]) + }) + it("sidebar app: every English key has a translation in all locales", () => { const missing = findMissingLocaleKeys(appEn, appLocales) if (missing.length > 0) { From 2dcbc7fb1d6a0fe6064044c1eda19ae928c6788f Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 12:24:59 +0100 Subject: [PATCH 05/18] refactor(vscode): remove dead hasKilocodeProfileWithNoBalance code and stale tests The hasKilocodeProfileWithNoBalance property was never set to true in the current CLI-backend architecture, making the no-credits status bar state unreachable. Also removes AutocompleteModel.spec.ts which tested an old profile-based architecture that no longer exists. --- .../autocomplete/AutocompleteModel.ts | 1 - .../AutocompleteServiceManager.ts | 4 +- .../autocomplete/AutocompleteStatusBar.ts | 10 - .../__tests__/AutocompleteModel.spec.ts | 732 ------------------ .../src/services/autocomplete/i18n/ar.ts | 2 - .../src/services/autocomplete/i18n/ca.ts | 2 - .../src/services/autocomplete/i18n/cs.ts | 2 - .../src/services/autocomplete/i18n/de.ts | 2 - .../src/services/autocomplete/i18n/en.ts | 2 - .../src/services/autocomplete/i18n/es.ts | 2 - .../src/services/autocomplete/i18n/fr.ts | 2 - .../src/services/autocomplete/i18n/hi.ts | 2 - .../src/services/autocomplete/i18n/id.ts | 2 - .../src/services/autocomplete/i18n/it.ts | 2 - .../src/services/autocomplete/i18n/ja.ts | 2 - .../src/services/autocomplete/i18n/ko.ts | 2 - .../src/services/autocomplete/i18n/nl.ts | 2 - .../src/services/autocomplete/i18n/pl.ts | 2 - .../src/services/autocomplete/i18n/pt-BR.ts | 2 - .../src/services/autocomplete/i18n/ru.ts | 2 - .../src/services/autocomplete/i18n/sk.ts | 2 - .../src/services/autocomplete/i18n/th.ts | 2 - .../src/services/autocomplete/i18n/tr.ts | 2 - .../src/services/autocomplete/i18n/uk.ts | 2 - .../src/services/autocomplete/i18n/vi.ts | 2 - .../src/services/autocomplete/i18n/zh-CN.ts | 2 - .../src/services/autocomplete/i18n/zh-TW.ts | 2 - .../src/services/autocomplete/types.ts | 1 - .../components/settings/AgentBehaviourTab.tsx | 2 + packages/sdk/js/openapi.json | 0 30 files changed, 3 insertions(+), 793 deletions(-) delete mode 100644 packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts create mode 100644 packages/sdk/js/openapi.json diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts index 71adb447a9b..58c60988650 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts @@ -21,7 +21,6 @@ export class AutocompleteModel { public profileName: string | null = null public profileType: string | null = null public loaded = false - public hasKilocodeProfileWithNoBalance = false constructor(connectionService?: KiloConnectionService) { if (connectionService) { diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts index 6fb130edcdd..eaad9936311 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts @@ -18,7 +18,6 @@ export interface AutocompleteServiceSettings { provider?: string model?: string snoozeUntil?: number - hasKilocodeProfileWithNoBalance?: boolean } function readSettings(): AutocompleteServiceSettings { @@ -315,7 +314,7 @@ export class AutocompleteServiceManager { } private hasNoUsableProvider(): boolean { - return this.model.loaded && !this.model.hasValidCredentials() && !this.model.hasKilocodeProfileWithNoBalance + return this.model.loaded && !this.model.hasValidCredentials() } private updateCostTracking(cost: number, _inputTokens: number, _outputTokens: number): void { @@ -335,7 +334,6 @@ export class AutocompleteServiceManager { model: this.getCurrentModelName(), provider: this.getCurrentProviderName(), profileName: this.model.profileName, - hasKilocodeProfileWithNoBalance: this.model.hasKilocodeProfileWithNoBalance, hasNoUsableProvider: this.hasNoUsableProvider(), totalSessionCost: this.sessionCost, completionCount: this.completionCount, diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteStatusBar.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteStatusBar.ts index 2719d8d96ea..867a2f67717 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteStatusBar.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteStatusBar.ts @@ -86,22 +86,12 @@ export class AutocompleteStatusBar { } public render() { - if (this.props.hasKilocodeProfileWithNoBalance) { - return this.renderNoCreditsError() - } if (this.props.hasNoUsableProvider) { return this.renderNoUsableProviderError() } return this.renderDefault() } - private renderNoCreditsError() { - this.statusBar.text = t("kilocode:autocomplete.statusBar.warning") - this.statusBar.tooltip = this.createMarkdownTooltip( - t("kilocode:autocomplete.statusBar.tooltip.noCredits", { command: SETTINGS_COMMAND }), - ) - } - private renderNoUsableProviderError() { this.statusBar.text = t("kilocode:autocomplete.statusBar.warning") this.statusBar.tooltip = this.createMarkdownTooltip( diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts deleted file mode 100644 index 20f91a1c2c2..00000000000 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts +++ /dev/null @@ -1,732 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" -import { AutocompleteModel } from "../AutocompleteModel" -import { ProviderSettingsManager } from "../../../core/config/ProviderSettingsManager" -import { AUTOCOMPLETE_PROVIDER_MODELS } from "../utils/kilocode-utils" -import * as apiIndex from "../../../api" -import { TelemetryService } from "../../../../packages/telemetry/src/TelemetryService" - -describe("AutocompleteModel", () => { - let mockProviderSettingsManager: ProviderSettingsManager - - beforeEach(() => { - mockProviderSettingsManager = { - listConfig: vi.fn(), - getProfile: vi.fn(), - } as any - }) - - describe("reload", () => { - it("sorts profiles by supportedProviders index order", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { id: "3", name: "profile3", apiProvider: supportedProviders[2] }, - { id: "1", name: "profile1", apiProvider: supportedProviders[0] }, - { id: "2", name: "profile2", apiProvider: supportedProviders[1] }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "profile1", - apiProvider: supportedProviders[0], - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(mockProviderSettingsManager.getProfile).toHaveBeenCalledWith({ id: "1" }) - }) - - it("filters out profiles without apiProvider", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { id: "1", name: "profile1", apiProvider: undefined }, - { id: "2", name: "profile2", apiProvider: supportedProviders[0] }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "2", - name: "profile2", - apiProvider: supportedProviders[0], - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(mockProviderSettingsManager.getProfile).toHaveBeenCalledWith({ id: "2" }) - }) - - it("filters out profiles with unsupported apiProvider", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { id: "1", name: "profile1", apiProvider: "unsupported" }, - { id: "2", name: "profile2", apiProvider: supportedProviders[0] }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "2", - name: "profile2", - apiProvider: supportedProviders[0], - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(mockProviderSettingsManager.getProfile).toHaveBeenCalledWith({ id: "2" }) - }) - - it("handles empty profile list", async () => { - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue([]) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - expect(mockProviderSettingsManager.getProfile).not.toHaveBeenCalled() - expect(model.hasValidCredentials()).toBe(false) - expect(result).toBe(false) - }) - - it("returns true when profile found", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [{ id: "1", name: "mistral-profile", apiProvider: "mistral" }] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "mistral-profile", - apiProvider: "mistral", - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - expect(result).toBe(true) - expect(model.loaded).toBe(true) - }) - }) - - describe("provider usability", () => { - beforeEach(() => { - // Mock fetch globally for these tests - vi.stubGlobal("fetch", vi.fn()) - - // Mock TelemetryService - const mockTelemetryService = { - captureEvent: vi.fn(), - captureException: vi.fn(), - isTelemetryEnabled: vi.fn().mockReturnValue(false), - shutdown: vi.fn(), - } - vi.spyOn(TelemetryService, "hasInstance").mockReturnValue(true) - vi.spyOn(TelemetryService, "instance", "get").mockReturnValue(mockTelemetryService as any) - }) - - afterEach(() => { - // Restore fetch - vi.unstubAllGlobals() - - // Restore TelemetryService mocks - vi.restoreAllMocks() - }) - - it("should skip kilocode provider when balance is zero and use openrouter instead", async () => { - const profiles = [ - { id: "1", name: "kilocode-profile", apiProvider: "kilocode" }, - { id: "2", name: "openrouter-profile", apiProvider: "openrouter" }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profiles with tokens - vi.mocked(mockProviderSettingsManager.getProfile).mockImplementation(async (args: any) => { - if (args.id === "1") { - return { - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "test-token", - } as any - } else if (args.id === "2") { - return { - id: "2", - name: "openrouter-profile", - apiProvider: "openrouter", - openRouterApiKey: "test-key", - } as any - } - return null as any - }) - - // Mock fetch to return zero balance for kilocode - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ data: { balance: 0 } }), - } as any - } - // For OpenRouter models endpoint - if (url.includes("/models")) { - return { - ok: true, - json: async () => ({ data: [] }), - } as any - } - // For other URLs, return a basic response - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - // Should have tried both providers but used openrouter (since kilocode balance is 0) - expect(result).toBe(true) - expect(model.loaded).toBe(true) - }) - - it("should use kilocode provider when balance is greater than zero", async () => { - const profiles = [ - { id: "1", name: "kilocode-profile", apiProvider: "kilocode" }, - { id: "2", name: "openrouter-profile", apiProvider: "openrouter" }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profiles with tokens - vi.mocked(mockProviderSettingsManager.getProfile).mockImplementation(async (args: any) => { - if (args.id === "1") { - return { - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "test-token", - } as any - } else if (args.id === "2") { - return { - id: "2", - name: "openrouter-profile", - apiProvider: "openrouter", - openRouterApiKey: "test-key", - } as any - } - return null as any - }) - - // Mock fetch to return positive balance for kilocode - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ data: { balance: 10.5 } }), - } as any - } - // For OpenRouter models endpoint - if (url.includes("/models")) { - return { - ok: true, - json: async () => ({ data: [] }), - } as any - } - // For other URLs, return a basic response - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - // Should have used kilocode provider (first one with positive balance) - expect(result).toBe(true) - expect(model.loaded).toBe(true) - }) - - it("should handle kilocode provider with no token", async () => { - const profiles = [ - { id: "1", name: "kilocode-profile", apiProvider: "kilocode" }, - { id: "2", name: "openrouter-profile", apiProvider: "openrouter" }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profiles - kilocode without token - vi.mocked(mockProviderSettingsManager.getProfile).mockImplementation(async (args: any) => { - if (args.id === "1") { - return { - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "", // No token - } as any - } else if (args.id === "2") { - return { - id: "2", - name: "openrouter-profile", - apiProvider: "openrouter", - openRouterApiKey: "test-key", - } as any - } - return null as any - }) - - // Mock fetch to handle the no-token case - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - // This should not be called since there's no token - return { - ok: false, - status: 401, - } as any - } - // For OpenRouter models endpoint - if (url.includes("/models")) { - return { - ok: true, - json: async () => ({ data: [] }), - } as any - } - // For other URLs, return a basic response - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - // Should skip kilocode (no token) and use openrouter - expect(result).toBe(true) - expect(model.loaded).toBe(true) - }) - - it("should set hasKilocodeProfileWithNoBalance when kilocode profile exists but has no balance", async () => { - const profiles = [{ id: "1", name: "kilocode-profile", apiProvider: "kilocode" }] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profile with token - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "test-token", - } as any) - - // Mock fetch to return zero balance for kilocode - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ balance: 0 }), - } as any - } - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - // Should not find a usable provider - expect(result).toBe(false) - expect(model.loaded).toBe(true) - // Should have set the flag indicating kilocode profile exists but has no balance - expect(model.hasKilocodeProfileWithNoBalance).toBe(true) - }) - - it("should not set hasKilocodeProfileWithNoBalance when kilocode profile has balance", async () => { - const profiles = [{ id: "1", name: "kilocode-profile", apiProvider: "kilocode" }] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profile with token - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "test-token", - } as any) - - // Mock fetch to return positive balance for kilocode and valid models response - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ balance: 10.5 }), - } as any - } - // For OpenRouter/Kilocode models endpoint - if (url.includes("/models")) { - return { - ok: true, - json: async () => ({ - data: [ - { - id: "mistralai/codestral-2508", - name: "Codestral", - context_length: 32000, - pricing: { prompt: "0.0001", completion: "0.0003" }, - }, - ], - }), - } as any - } - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - const result = await model.reload(mockProviderSettingsManager) - - // Should find a usable provider - expect(result).toBe(true) - expect(model.loaded).toBe(true) - // Should not have set the flag - expect(model.hasKilocodeProfileWithNoBalance).toBe(false) - }) - - it("should clear hasKilocodeProfileWithNoBalance on reload", async () => { - const profiles = [{ id: "1", name: "kilocode-profile", apiProvider: "kilocode" }] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - - // Mock profile with token - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "kilocode-profile", - apiProvider: "kilocode", - kilocodeToken: "test-token", - } as any) - - // First reload: zero balance - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ balance: 0 }), - } as any - } - return { - ok: true, - json: async () => ({}), - } as any - }) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - expect(model.hasKilocodeProfileWithNoBalance).toBe(true) - - // Second reload: positive balance with valid models response - ;(global.fetch as any).mockImplementation(async (url: string) => { - if (url.includes("/api/profile/balance")) { - return { - ok: true, - json: async () => ({ balance: 10.5 }), - } as any - } - // For OpenRouter/Kilocode models endpoint - if (url.includes("/models")) { - return { - ok: true, - json: async () => ({ - data: [ - { - id: "mistralai/codestral-2508", - name: "Codestral", - context_length: 32000, - pricing: { prompt: "0.0001", completion: "0.0003" }, - }, - ], - }), - } as any - } - return { - ok: true, - json: async () => ({}), - } as any - }) - - await model.reload(mockProviderSettingsManager) - // Flag should be cleared after reload with positive balance - expect(model.hasKilocodeProfileWithNoBalance).toBe(false) - }) - }) - - describe("getProviderDisplayName", () => { - it("returns undefined when no provider is loaded", () => { - const model = new AutocompleteModel() - expect(model.getProviderDisplayName()).toBeUndefined() - }) - - it("returns provider name from API handler when provider is loaded", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [{ id: "1", name: "profile1", apiProvider: supportedProviders[0] }] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "profile1", - apiProvider: supportedProviders[0], - mistralApiKey: "test-key", - } as any) - - // Mock buildApiHandler to return a handler with providerName - const mockApiHandler = { - providerName: "Mistral", - getModel: vi.fn().mockReturnValue({ id: "mistral-model", info: {} }), - createMessage: vi.fn(), - countTokens: vi.fn(), - } - vi.spyOn(apiIndex, "buildApiHandler").mockReturnValue(mockApiHandler as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - const providerName = model.getProviderDisplayName() - expect(providerName).toBeTruthy() - expect(typeof providerName).toBe("string") - expect(providerName).toBe("Mistral") - - // Restore the spy - vi.restoreAllMocks() - }) - - describe("profile information", () => { - it("returns null for profile name when no profile is loaded", () => { - const model = new AutocompleteModel() - expect(model.profileName).toBeNull() - }) - - it("returns null for profile type when no profile is loaded", () => { - const model = new AutocompleteModel() - expect(model.profileType).toBeNull() - }) - - it("stores and returns profile name after loading", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { - id: "1", - name: "My Autocomplete Profile", - apiProvider: supportedProviders[0], - profileType: "autocomplete", - }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Autocomplete Profile", - apiProvider: supportedProviders[0], - profileType: "autocomplete", - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(model.profileName).toBe("My Autocomplete Profile") - }) - - it("stores and returns profile type after loading", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "autocomplete" }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Profile", - apiProvider: supportedProviders[0], - profileType: "autocomplete", - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(model.profileType).toBe("autocomplete") - }) - - it("clears profile information on cleanup", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const profiles = [ - { id: "1", name: "My Profile", apiProvider: supportedProviders[0], profileType: "autocomplete" }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Profile", - apiProvider: supportedProviders[0], - profileType: "autocomplete", - mistralApiKey: "test-key", - } as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - expect(model.profileName).toBe("My Profile") - expect(model.profileType).toBe("autocomplete") - - // Reload with empty profiles to trigger cleanup - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue([]) - await model.reload(mockProviderSettingsManager) - - expect(model.profileName).toBeNull() - expect(model.profileType).toBeNull() - }) - }) - }) - - describe("reload model override behavior", () => { - beforeEach(() => { - // Mock buildApiHandler to return a handler with getModel - const mockApiHandler = { - getModel: vi.fn().mockReturnValue({ id: "test-model", info: {} }), - createMessage: vi.fn(), - countTokens: vi.fn(), - } - vi.spyOn(apiIndex, "buildApiHandler").mockReturnValue(mockApiHandler as any) - }) - - afterEach(() => { - vi.restoreAllMocks() - }) - - it("should use custom model for explicit autocomplete profiles", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const provider = supportedProviders[0] - const customModelId = "custom-autocomplete-model" - - const profiles = [ - { - id: "1", - name: "My Autocomplete Profile", - apiProvider: provider, - profileType: "autocomplete", - }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Autocomplete Profile", - apiProvider: provider, - profileType: "autocomplete", - mistralApiKey: "test-key", - apiModelId: customModelId, // Custom model set by user - } as any) - - // Mock buildApiHandler to return the custom model - const mockApiHandler = { - getModel: vi.fn().mockReturnValue({ id: customModelId, info: {} }), - createMessage: vi.fn(), - countTokens: vi.fn(), - } - vi.spyOn(apiIndex, "buildApiHandler").mockReturnValue(mockApiHandler as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - // The model should use the custom model from the profile - const modelName = model.getModelName() - expect(modelName).toBe(customModelId) - }) - - it("should override model for non-autocomplete profiles", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const provider = supportedProviders[0] - const defaultAutocompleteModel = AUTOCOMPLETE_PROVIDER_MODELS.get(provider) - - const profiles = [ - { - id: "1", - name: "My Chat Profile", - apiProvider: provider, - profileType: "chat", // Not an autocomplete profile - }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Chat Profile", - apiProvider: provider, - profileType: "chat", - mistralApiKey: "test-key", - apiModelId: "custom-chat-model", // This should be overridden - } as any) - - // Mock buildApiHandler to return the overridden model - const mockApiHandler = { - getModel: vi.fn().mockReturnValue({ id: defaultAutocompleteModel, info: {} }), - createMessage: vi.fn(), - countTokens: vi.fn(), - } - vi.spyOn(apiIndex, "buildApiHandler").mockReturnValue(mockApiHandler as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - // The model should be overridden with the default autocomplete model - const modelName = model.getModelName() - expect(modelName).toBe(defaultAutocompleteModel) - }) - - it("should override model for profiles without profileType", async () => { - const supportedProviders = [...AUTOCOMPLETE_PROVIDER_MODELS.keys()] - const provider = supportedProviders[0] - const defaultAutocompleteModel = AUTOCOMPLETE_PROVIDER_MODELS.get(provider) - - const profiles = [ - { - id: "1", - name: "My Generic Profile", - apiProvider: provider, - // No profileType specified - }, - ] as any - - vi.mocked(mockProviderSettingsManager.listConfig).mockResolvedValue(profiles) - vi.mocked(mockProviderSettingsManager.getProfile).mockResolvedValue({ - id: "1", - name: "My Generic Profile", - apiProvider: provider, - mistralApiKey: "test-key", - apiModelId: "custom-model", // This should be overridden - } as any) - - // Mock buildApiHandler to return the overridden model - const mockApiHandler = { - getModel: vi.fn().mockReturnValue({ id: defaultAutocompleteModel, info: {} }), - createMessage: vi.fn(), - countTokens: vi.fn(), - } - vi.spyOn(apiIndex, "buildApiHandler").mockReturnValue(mockApiHandler as any) - - const model = new AutocompleteModel() - await model.reload(mockProviderSettingsManager) - - // The model should be overridden with the default autocomplete model - const modelName = model.getModelName() - expect(modelName).toBe(defaultAutocompleteModel) - }) - }) -}) diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/ar.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/ar.ts index c85054d374d..c2df6d81c72 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/ar.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/ar.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (معطل)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**لا يوجد رصيد في حسابك**\n\nحساب Kilo Code الخاص بك لا يحتوي على رصيد. لاستخدام الإكمال التلقائي، يرجى إضافة رصيد إلى حسابك.\n\n[فتح الإعدادات]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**لم يتم تكوين نموذج الإكمال التلقائي**\n\nلتمكين الإكمال التلقائي، أضف ملفًا شخصيًا مع أحد هذه المزودين المدعومين: {{providers}}.\n\n[فتح الإعدادات]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "إجمالي تكلفة الجلسة:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/ca.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/ca.ts index df4b70cff80..92a7802c492 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/ca.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/ca.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (desactivat)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**No tens crèdits al teu compte**\n\nEl teu compte de Kilo Code no té crèdits. Per utilitzar l'autocompletat, si us plau afegeix crèdits al teu compte.\n\n[Obrir Configuració]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**No s'ha configurat cap model d'autocompletat**\n\nPer habilitar l'autocompletat, afegeix un perfil amb un d'aquests proveïdors compatibles: {{providers}}.\n\n[Obrir Configuració]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Cost total de la sessió:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/cs.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/cs.ts index 7b22314cd5f..a12a46c8a0c 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/cs.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/cs.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (zakázáno)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Na tvém účtu nejsou žádné kredity**\n\nTvůj účet Kilo Code nemá žádné kredity. Pro použití automatického doplňování prosím přidej kredity na svůj účet.\n\n[Otevřít Nastavení]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Není nakonfigurován žádný model automatického doplňování**\n\nPro povolení automatického doplňování přidej profil s jedním z těchto podporovaných poskytovatelů: {{providers}}.\n\n[Otevřít Nastavení]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Celkové náklady relace:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/de.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/de.ts index 507187a4e50..2525a491c04 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/de.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/de.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (deaktiviert)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Kein Guthaben auf deinem Konto**\n\nDein Kilo Code Konto hat kein Guthaben. Um Autocomplete zu nutzen, füge bitte Guthaben zu deinem Konto hinzu.\n\n[Einstellungen öffnen]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Kein Autocomplete-Modell konfiguriert**\n\nUm Autocomplete zu aktivieren, füge ein Profil mit einem dieser unterstützten Anbieter hinzu: {{providers}}.\n\n[Einstellungen öffnen]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Sitzungsgesamtkosten:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/en.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/en.ts index a0d5d2f02fe..bd536d23c07 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/en.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/en.ts @@ -7,8 +7,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (disabled)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**No credits in your account**\n\nYour Kilo Code account has no credits. To use autocomplete, please add credits to your account.\n\n[Open Settings]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**No autocomplete model configured**\n\nTo enable autocomplete, add a profile with one of these supported providers: {{providers}}.\n\n[Open Settings]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Session total cost:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/es.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/es.ts index adf5e07a993..2348ca32e9a 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/es.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/es.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (deshabilitado)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**No hay créditos en tu cuenta**\n\nTu cuenta de Kilo Code no tiene créditos. Para usar el autocompletado, por favor añade créditos a tu cuenta.\n\n[Abrir Configuración]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**No hay modelo de autocompletado configurado**\n\nPara habilitar el autocompletado, añade un perfil con uno de estos proveedores compatibles: {{providers}}.\n\n[Abrir Configuración]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Costo total de la sesión:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/fr.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/fr.ts index 65f9d13a86f..56dd0f139aa 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/fr.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/fr.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (désactivé)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Pas de crédits sur ton compte**\n\nTon compte Kilo Code n'a pas de crédits. Pour utiliser l'autocomplétion, ajoute des crédits à ton compte.\n\n[Ouvrir les Paramètres]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Aucun modèle d'autocomplétion configuré**\n\nPour activer l'autocomplétion, ajoute un profil avec l'un de ces fournisseurs pris en charge : {{providers}}.\n\n[Ouvrir les Paramètres]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Coût total de la session :", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/hi.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/hi.ts index 7cb24ae396c..b23e34b5bb4 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/hi.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/hi.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (अक्षम)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**आपके खाते में कोई क्रेडिट नहीं है**\n\nआपके Kilo Code खाते में कोई क्रेडिट नहीं है। ऑटोकम्प्लीट का उपयोग करने के लिए, कृपया अपने खाते में क्रेडिट जोड़ें।\n\n[सेटिंग्स खोलें]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**कोई ऑटोकम्प्लीट मॉडल कॉन्फ़िगर नहीं किया गया**\n\nऑटोकम्प्लीट सक्षम करने के लिए, इन समर्थित प्रदाताओं में से एक के साथ एक प्रोफ़ाइल जोड़ें: {{providers}}।\n\n[सेटिंग्स खोलें]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "सत्र की कुल लागत:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/id.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/id.ts index 062ebf6f835..4f7384d404d 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/id.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/id.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (dinonaktifkan)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Tidak ada kredit di akun kamu**\n\nAkun Kilo Code kamu tidak memiliki kredit. Untuk menggunakan autocomplete, silakan tambahkan kredit ke akun kamu.\n\n[Buka Pengaturan]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Tidak ada model autocomplete yang dikonfigurasi**\n\nUntuk mengaktifkan autocomplete, tambahkan profil dengan salah satu penyedia yang didukung ini: {{providers}}.\n\n[Buka Pengaturan]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Total biaya sesi:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/it.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/it.ts index bdc75654b60..5bd075d981b 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/it.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/it.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (disabilitato)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Nessun credito nel tuo account**\n\nIl tuo account Kilo Code non ha crediti. Per usare l'autocompletamento, aggiungi crediti al tuo account.\n\n[Apri Impostazioni]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Nessun modello di autocompletamento configurato**\n\nPer abilitare l'autocompletamento, aggiungi un profilo con uno di questi provider supportati: {{providers}}.\n\n[Apri Impostazioni]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Costo totale della sessione:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/ja.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/ja.ts index b4d3a9f2772..ad59af271d7 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/ja.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/ja.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete(無効)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**アカウントにクレジットがありません**\n\nKilo Code アカウントにクレジットがありません。オートコンプリートを使用するには、アカウントにクレジットを追加してください。\n\n[設定を開く]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**オートコンプリートモデルが設定されていません**\n\nオートコンプリートを有効にするには、これらのサポートされているプロバイダーのいずれかでプロファイルを追加してください: {{providers}}。\n\n[設定を開く]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "セッション合計コスト:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/ko.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/ko.ts index cc55702d80b..cc4eab6dfb8 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/ko.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/ko.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (비활성화됨)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**계정에 크레딧이 없습니다**\n\nKilo Code 계정에 크레딧이 없습니다. 자동완성을 사용하려면 계정에 크레딧을 추가해 주세요.\n\n[설정 열기]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**자동완성 모델이 구성되지 않았습니다**\n\n자동완성을 활성화하려면 다음 지원되는 제공업체 중 하나로 프로필을 추가하세요: {{providers}}.\n\n[설정 열기]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "세션 총 비용:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts index 8ca573dab41..b30b2d2834d 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (uitgeschakeld)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Geen tegoed op je account**\n\nJe Kilo Code account heeft geen tegoed. Om autocomplete te gebruiken, voeg tegoed toe aan je account.\n\n[Instellingen openen]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Geen autocomplete model geconfigureerd**\n\nOm autocomplete in te schakelen, voeg een profiel toe met een van deze ondersteunde providers: {{providers}}.\n\n[Instellingen openen]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Totale sessiekosten:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/pl.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/pl.ts index 7bb800c8d6c..64251cd2df7 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/pl.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/pl.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (wyłączone)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Brak środków na koncie**\n\nTwoje konto Kilo Code nie ma środków. Aby korzystać z autouzupełniania, dodaj środki do swojego konta.\n\n[Otwórz Ustawienia]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Nie skonfigurowano modelu autouzupełniania**\n\nAby włączyć autouzupełnianie, dodaj profil z jednym z tych obsługiwanych dostawców: {{providers}}.\n\n[Otwórz Ustawienia]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Całkowity koszt sesji:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/pt-BR.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/pt-BR.ts index a4794f2cf73..8c879217de2 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/pt-BR.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/pt-BR.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (desabilitado)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Sem créditos na sua conta**\n\nSua conta Kilo Code não tem créditos. Para usar o autocompletar, adicione créditos à sua conta.\n\n[Abrir Configurações]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Nenhum modelo de autocompletar configurado**\n\nPara habilitar o autocompletar, adicione um perfil com um destes provedores suportados: {{providers}}.\n\n[Abrir Configurações]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Custo total da sessão:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/ru.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/ru.ts index 4e1afb0d3f0..bb572c5f3e4 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/ru.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/ru.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (отключено)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**На вашем счёте нет кредитов**\n\nНа вашем счёте Kilo Code нет кредитов. Чтобы использовать автодополнение, пожалуйста, пополните счёт.\n\n[Открыть Настройки]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Модель автодополнения не настроена**\n\nЧтобы включить автодополнение, добавьте профиль с одним из поддерживаемых провайдеров: {{providers}}.\n\n[Открыть Настройки]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Общая стоимость сессии:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/sk.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/sk.ts index 4e2959c3b98..8ff2f3c8e15 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/sk.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/sk.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (zakázané)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Na tvojom účte nie sú žiadne kredity**\n\nTvoj účet Kilo Code nemá žiadne kredity. Pre použitie automatického doplňovania prosím pridaj kredity na svoj účet.\n\n[Otvoriť Nastavenia]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Nie je nakonfigurovaný žiadny model automatického doplňovania**\n\nPre povolenie automatického doplňovania pridaj profil s jedným z týchto podporovaných poskytovateľov: {{providers}}.\n\n[Otvoriť Nastavenia]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Celkové náklady relácie:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/th.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/th.ts index 3f3b18aa595..3ceeca319f3 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/th.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/th.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (ปิดใช้งาน)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**ไม่มีเครดิตในบัญชีของคุณ**\n\nบัญชี Kilo Code ของคุณไม่มีเครดิต หากต้องการใช้การเติมข้อความอัตโนมัติ กรุณาเพิ่มเครดิตในบัญชีของคุณ\n\n[เปิดการตั้งค่า]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**ไม่ได้กำหนดค่าโมเดลการเติมข้อความอัตโนมัติ**\n\nหากต้องการเปิดใช้งานการเติมข้อความอัตโนมัติ ให้เพิ่มโปรไฟล์กับผู้ให้บริการที่รองรับเหล่านี้: {{providers}}\n\n[เปิดการตั้งค่า]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "ค่าใช้จ่ายรวมของเซสชัน:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/tr.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/tr.ts index d7c9586926b..417ba03ee1c 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/tr.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/tr.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (devre dışı)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Hesabınızda kredi yok**\n\nKilo Code hesabınızda kredi bulunmuyor. Otomatik tamamlamayı kullanmak için lütfen hesabınıza kredi ekleyin.\n\n[Ayarları Aç]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Otomatik tamamlama modeli yapılandırılmadı**\n\nOtomatik tamamlamayı etkinleştirmek için desteklenen sağlayıcılardan biriyle bir profil ekleyin: {{providers}}.\n\n[Ayarları Aç]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Oturum toplam maliyeti:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/uk.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/uk.ts index 57d742b661b..3dc1b1b32a4 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/uk.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/uk.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (вимкнено)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**На вашому рахунку немає кредитів**\n\nНа вашому рахунку Kilo Code немає кредитів. Щоб використовувати автодоповнення, будь ласка, поповніть рахунок.\n\n[Відкрити Налаштування]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Модель автодоповнення не налаштована**\n\nЩоб увімкнути автодоповнення, додайте профіль з одним із підтримуваних провайдерів: {{providers}}.\n\n[Відкрити Налаштування]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Загальна вартість сесії:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/vi.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/vi.ts index c1f9f90775a..f645e3e2fe0 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/vi.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/vi.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (đã tắt)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**Không có tín dụng trong tài khoản của bạn**\n\nTài khoản Kilo Code của bạn không có tín dụng. Để sử dụng tự động hoàn thành, vui lòng thêm tín dụng vào tài khoản của bạn.\n\n[Mở Cài đặt]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**Chưa cấu hình mô hình tự động hoàn thành**\n\nĐể bật tự động hoàn thành, hãy thêm hồ sơ với một trong các nhà cung cấp được hỗ trợ sau: {{providers}}.\n\n[Mở Cài đặt]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Tổng chi phí phiên:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/zh-CN.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/zh-CN.ts index 4efa687064d..da8cf67adbf 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/zh-CN.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/zh-CN.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete(已禁用)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**账户余额不足**\n\n你的 Kilo Code 账户没有余额。要使用自动补全功能,请为账户充值。\n\n[打开设置]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**未配置自动补全模型**\n\n要启用自动补全,请添加一个使用以下支持的提供商的配置文件:{{providers}}。\n\n[打开设置]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "会话总费用:", diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/zh-TW.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/zh-TW.ts index a6bb2fd388b..7bce63c2476 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/zh-TW.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/zh-TW.ts @@ -6,8 +6,6 @@ export const dict = { "kilocode:autocomplete.statusBar.warning": "$(warning) Autocomplete", "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete(已停用)", - "kilocode:autocomplete.statusBar.tooltip.noCredits": - "**帳戶中沒有額度**\n\nKilo Code 帳戶沒有額度。若要使用 Autocomplete,請為帳戶儲值。\n\n[開啟設定]({{command}})", "kilocode:autocomplete.statusBar.tooltip.noUsableProvider": "**未設定 Autocomplete 模型**\n\n若要啟用 Autocomplete,請新增一個使用以下支援供應商的設定檔:{{providers}}。\n\n[開啟設定]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "工作階段總費用:", diff --git a/packages/kilo-vscode/src/services/autocomplete/types.ts b/packages/kilo-vscode/src/services/autocomplete/types.ts index d32531f55f7..cce2f84cdc7 100644 --- a/packages/kilo-vscode/src/services/autocomplete/types.ts +++ b/packages/kilo-vscode/src/services/autocomplete/types.ts @@ -137,7 +137,6 @@ export interface AutocompleteStatusBarStateProps { model?: string provider?: string profileName?: string | null - hasKilocodeProfileWithNoBalance?: boolean hasNoUsableProvider?: boolean totalSessionCost: number completionCount: number diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index ada39f81c6e..16f3c8cd273 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -358,6 +358,8 @@ const AgentBehaviourTab: Component = () => { /> +
Date: Tue, 17 Mar 2026 12:33:02 +0100 Subject: [PATCH 06/18] fix(vscode): revert stray test div and empty openapi.json from previous commit --- .../webview-ui/src/components/settings/AgentBehaviourTab.tsx | 2 -- packages/sdk/js/openapi.json | 0 2 files changed, 2 deletions(-) delete mode 100644 packages/sdk/js/openapi.json diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 16f3c8cd273..ada39f81c6e 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -358,8 +358,6 @@ const AgentBehaviourTab: Component = () => { /> -
Date: Tue, 17 Mar 2026 12:35:14 +0100 Subject: [PATCH 07/18] test(vscode): rewrite AutocompleteModel tests for current CLI-backend architecture --- .../__tests__/AutocompleteModel.spec.ts | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts new file mode 100644 index 00000000000..dd17da63618 --- /dev/null +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts @@ -0,0 +1,206 @@ +import { describe, it, expect, vi } from "vitest" +import { AutocompleteModel } from "../AutocompleteModel" +import type { KiloConnectionService } from "../../cli-backend" + +function createMockConnectionService(state: "connecting" | "connected" | "disconnected" | "error" = "connected") { + return { + getConnectionState: vi.fn().mockReturnValue(state), + getClient: vi.fn().mockReturnValue({ + kilo: { + fim: vi.fn(), + }, + }), + onStateChange: vi.fn().mockReturnValue(() => {}), + } as unknown as KiloConnectionService +} + +describe("AutocompleteModel", () => { + describe("constructor", () => { + it("sets loaded to true when connection service is provided", () => { + const connection = createMockConnectionService() + const model = new AutocompleteModel(connection) + expect(model.loaded).toBe(true) + }) + + it("defaults loaded to false without connection service", () => { + const model = new AutocompleteModel() + expect(model.loaded).toBe(false) + }) + + it("defaults profileName and profileType to null", () => { + const model = new AutocompleteModel() + expect(model.profileName).toBeNull() + expect(model.profileType).toBeNull() + }) + }) + + describe("setConnectionService", () => { + it("sets the connection service after construction", () => { + const model = new AutocompleteModel() + expect(model.hasValidCredentials()).toBe(false) + + const connection = createMockConnectionService("connected") + model.setConnectionService(connection) + expect(model.hasValidCredentials()).toBe(true) + }) + }) + + describe("reload", () => { + it("sets loaded to true", async () => { + const model = new AutocompleteModel() + expect(model.loaded).toBe(false) + await model.reload() + expect(model.loaded).toBe(true) + }) + + it("returns true when connected", async () => { + const connection = createMockConnectionService("connected") + const model = new AutocompleteModel(connection) + expect(await model.reload()).toBe(true) + }) + + it("returns false when disconnected", async () => { + const connection = createMockConnectionService("disconnected") + const model = new AutocompleteModel(connection) + expect(await model.reload()).toBe(false) + }) + + it("returns false when connecting", async () => { + const connection = createMockConnectionService("connecting") + const model = new AutocompleteModel(connection) + expect(await model.reload()).toBe(false) + }) + + it("returns false when in error state", async () => { + const connection = createMockConnectionService("error") + const model = new AutocompleteModel(connection) + expect(await model.reload()).toBe(false) + }) + + it("returns false without connection service", async () => { + const model = new AutocompleteModel() + expect(await model.reload()).toBe(false) + }) + }) + + describe("hasValidCredentials", () => { + it("returns true when connected", () => { + const connection = createMockConnectionService("connected") + const model = new AutocompleteModel(connection) + expect(model.hasValidCredentials()).toBe(true) + }) + + it("returns false when disconnected", () => { + const connection = createMockConnectionService("disconnected") + const model = new AutocompleteModel(connection) + expect(model.hasValidCredentials()).toBe(false) + }) + + it("returns false without connection service", () => { + const model = new AutocompleteModel() + expect(model.hasValidCredentials()).toBe(false) + }) + }) + + describe("supportsFim", () => { + it("always returns true", () => { + const model = new AutocompleteModel() + expect(model.supportsFim()).toBe(true) + }) + }) + + describe("getModelName", () => { + it("returns the default model", () => { + const model = new AutocompleteModel() + expect(model.getModelName()).toBe("mistralai/codestral-2508") + }) + }) + + describe("getProviderDisplayName", () => { + it("returns Kilo Gateway", () => { + const model = new AutocompleteModel() + expect(model.getProviderDisplayName()).toBe("Kilo Gateway") + }) + }) + + describe("generateFimResponse", () => { + it("throws when connection service is not available", async () => { + const model = new AutocompleteModel() + await expect(model.generateFimResponse("prefix", "suffix", vi.fn())).rejects.toThrow( + "Connection service is not available", + ) + }) + + it("throws when not connected", async () => { + const connection = createMockConnectionService("disconnected") + const model = new AutocompleteModel(connection) + await expect(model.generateFimResponse("prefix", "suffix", vi.fn())).rejects.toThrow( + "CLI backend is not connected (state: disconnected)", + ) + }) + + it("streams chunks and returns metadata", async () => { + const chunks = [ + { choices: [{ delta: { content: "hello" } }] }, + { + choices: [{ delta: { content: " world" } }], + usage: { prompt_tokens: 10, completion_tokens: 5 }, + cost: 0.001, + }, + ] + + const connection = createMockConnectionService("connected") + const client = (connection as any).getClient() + client.kilo.fim.mockResolvedValue({ + stream: (async function* () { + for (const chunk of chunks) yield chunk + })(), + }) + + const model = new AutocompleteModel(connection) + const received: string[] = [] + const result = await model.generateFimResponse("prefix", "suffix", (text) => received.push(text)) + + expect(received).toEqual(["hello", " world"]) + expect(result).toEqual({ + cost: 0.001, + inputTokens: 10, + outputTokens: 5, + cacheWriteTokens: 0, + cacheReadTokens: 0, + }) + }) + + it("passes model parameters to fim call", async () => { + const connection = createMockConnectionService("connected") + const client = (connection as any).getClient() + client.kilo.fim.mockResolvedValue({ + stream: (async function* () {})(), + }) + + const model = new AutocompleteModel(connection) + const signal = new AbortController().signal + await model.generateFimResponse("pre", "suf", vi.fn(), signal) + + expect(client.kilo.fim).toHaveBeenCalledWith( + { + prefix: "pre", + suffix: "suf", + model: "mistralai/codestral-2508", + maxTokens: 256, + temperature: 0.2, + }, + { signal }, + ) + }) + }) + + describe("generateResponse", () => { + it("throws because FIM is the primary strategy", async () => { + const model = new AutocompleteModel() + await expect(model.generateResponse("system", "user", vi.fn())).rejects.toThrow( + "Chat-based completions are not supported via CLI backend", + ) + }) + }) +}) From 1043d9dd52ad2cb51eca41ef9af95cb583d9d7b9 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 13:02:05 +0100 Subject: [PATCH 08/18] refactor(vscode): remove unused loaded/reload from AutocompleteModel The loaded flag was always true after construction (set unconditionally) and reload() did nothing beyond that. Connection state is already checked live via hasValidCredentials(). Removes the dead indirection from AutocompleteModel, AutocompleteServiceManager, and ChatTextAreaAutocomplete. --- .../autocomplete/AutocompleteModel.ts | 17 ------ .../AutocompleteServiceManager.ts | 18 +----- .../__tests__/AutocompleteModel.spec.ts | 61 ++++--------------- .../AutocompleteServiceManager.spec.ts | 5 -- .../ChatTextAreaAutocomplete.ts | 11 ---- .../ChatTextAreaAutocomplete.spec.ts | 1 - 6 files changed, 15 insertions(+), 98 deletions(-) diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts index 58c60988650..bfadd50204b 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteModel.ts @@ -20,12 +20,10 @@ export class AutocompleteModel { private connectionService: KiloConnectionService | null = null public profileName: string | null = null public profileType: string | null = null - public loaded = false constructor(connectionService?: KiloConnectionService) { if (connectionService) { this.connectionService = connectionService - this.loaded = true } } @@ -36,21 +34,6 @@ export class AutocompleteModel { this.connectionService = service } - /** - * Load model configuration. - * Returns true if the connection service is available. - */ - public async reload(): Promise { - this.loaded = true - - if (this.connectionService) { - const state = this.connectionService.getConnectionState() - return state === "connected" - } - - return false - } - public supportsFim(): boolean { return true } diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts index eaad9936311..09dd95e0c66 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts @@ -103,7 +103,6 @@ export class AutocompleteServiceManager { } public async load() { - await this.model.reload() this.settings = readSettings() await this.updateGlobalContext() @@ -243,11 +242,6 @@ export class AutocompleteServiceManager { const document = editor.document - // Ensure model is loaded - if (!this.model.loaded) { - await this.load() - } - // Call the inline completion provider directly with manual trigger context const position = editor.selection.active const context: vscode.InlineCompletionContext = { @@ -299,22 +293,16 @@ export class AutocompleteServiceManager { }) } - private getCurrentModelName(): string | undefined { - if (!this.model.loaded) { - return - } + private getCurrentModelName(): string { return this.model.getModelName() } - private getCurrentProviderName(): string | undefined { - if (!this.model.loaded) { - return - } + private getCurrentProviderName(): string { return this.model.getProviderDisplayName() } private hasNoUsableProvider(): boolean { - return this.model.loaded && !this.model.hasValidCredentials() + return !this.model.hasValidCredentials() } private updateCostTracking(cost: number, _inputTokens: number, _outputTokens: number): void { diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts index dd17da63618..d94bcd0612e 100644 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteModel.spec.ts @@ -16,17 +16,6 @@ function createMockConnectionService(state: "connecting" | "connected" | "discon describe("AutocompleteModel", () => { describe("constructor", () => { - it("sets loaded to true when connection service is provided", () => { - const connection = createMockConnectionService() - const model = new AutocompleteModel(connection) - expect(model.loaded).toBe(true) - }) - - it("defaults loaded to false without connection service", () => { - const model = new AutocompleteModel() - expect(model.loaded).toBe(false) - }) - it("defaults profileName and profileType to null", () => { const model = new AutocompleteModel() expect(model.profileName).toBeNull() @@ -45,44 +34,6 @@ describe("AutocompleteModel", () => { }) }) - describe("reload", () => { - it("sets loaded to true", async () => { - const model = new AutocompleteModel() - expect(model.loaded).toBe(false) - await model.reload() - expect(model.loaded).toBe(true) - }) - - it("returns true when connected", async () => { - const connection = createMockConnectionService("connected") - const model = new AutocompleteModel(connection) - expect(await model.reload()).toBe(true) - }) - - it("returns false when disconnected", async () => { - const connection = createMockConnectionService("disconnected") - const model = new AutocompleteModel(connection) - expect(await model.reload()).toBe(false) - }) - - it("returns false when connecting", async () => { - const connection = createMockConnectionService("connecting") - const model = new AutocompleteModel(connection) - expect(await model.reload()).toBe(false) - }) - - it("returns false when in error state", async () => { - const connection = createMockConnectionService("error") - const model = new AutocompleteModel(connection) - expect(await model.reload()).toBe(false) - }) - - it("returns false without connection service", async () => { - const model = new AutocompleteModel() - expect(await model.reload()).toBe(false) - }) - }) - describe("hasValidCredentials", () => { it("returns true when connected", () => { const connection = createMockConnectionService("connected") @@ -96,6 +47,18 @@ describe("AutocompleteModel", () => { expect(model.hasValidCredentials()).toBe(false) }) + it("returns false when connecting", () => { + const connection = createMockConnectionService("connecting") + const model = new AutocompleteModel(connection) + expect(model.hasValidCredentials()).toBe(false) + }) + + it("returns false when in error state", () => { + const connection = createMockConnectionService("error") + const model = new AutocompleteModel(connection) + expect(model.hasValidCredentials()).toBe(false) + }) + it("returns false without connection service", () => { const model = new AutocompleteModel() expect(model.hasValidCredentials()).toBe(false) diff --git a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts index 11fb9ff0042..5d4c68a34cf 100644 --- a/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/__tests__/AutocompleteServiceManager.spec.ts @@ -63,13 +63,8 @@ vi.mock("vscode", () => { vi.mock("../AutocompleteModel", () => { class AutocompleteModel { - public loaded = false public profileName = "test-profile" - public async reload(): Promise { - this.loaded = true - } - public getModelName(): string { return "test-model" } diff --git a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts index 113247c89e7..6dc2bb97c9b 100644 --- a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts +++ b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts @@ -15,10 +15,6 @@ export class ChatTextAreaAutocomplete { this.telemetry = new AutocompleteTelemetry("chat-textarea") } - async initialize(): Promise { - return this.model.reload() - } - async getCompletion(userText: string, visibleCodeContext?: VisibleCodeContext): Promise<{ suggestion: string }> { const startTime = Date.now() @@ -29,13 +25,6 @@ export class ChatTextAreaAutocomplete { provider: this.model.getProviderDisplayName(), } - if (!this.model.loaded) { - const loaded = await this.initialize() - if (!loaded) { - return { suggestion: "" } - } - } - // Check if model has valid credentials (but don't require FIM) if (!this.model.hasValidCredentials()) { return { suggestion: "" } diff --git a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts index dc43ff1b076..6fb284743d5 100644 --- a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts +++ b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/__tests__/ChatTextAreaAutocomplete.spec.ts @@ -16,7 +16,6 @@ describe("ChatTextAreaAutocomplete", () => { it("should work with non-FIM models using chat-based completion", async () => { // Setup: Model without FIM support (like Mistral) const mockModel = new AutocompleteModel() - mockModel.loaded = true vi.spyOn(mockModel, "hasValidCredentials").mockReturnValue(true) vi.spyOn(mockModel, "supportsFim").mockReturnValue(false) From 8df8fc85205f1d753ea3fd69a52a56e971a0e02a Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 13:32:59 +0100 Subject: [PATCH 09/18] fix(i18n): add prompt.placeholder.error translations for all 16 locales --- packages/kilo-vscode/webview-ui/src/i18n/ar.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/br.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/bs.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/da.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/de.ts | 3 ++- packages/kilo-vscode/webview-ui/src/i18n/en.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/es.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/fr.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/ja.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/ko.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/no.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/pl.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/ru.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/th.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/zh.ts | 2 +- packages/kilo-vscode/webview-ui/src/i18n/zht.ts | 2 +- 16 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index f0decff554e..da05e2cb574 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -837,7 +837,7 @@ export const dict = { "dialog.model.noProviders": "لا يوجد موفرون", "prompt.placeholder.connecting": "جارٍ الاتصال بالخادم...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "فشل الاتصال. تحقق من لوحة الإخراج أو أعد تشغيل الإضافة.", "prompt.placeholder.default": "اكتب رسالة... (Enter للإرسال، Shift+Enter لسطر جديد)", "context.usage.sessionCost": "تكلفة الجلسة", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 79a171678e8..8e1d0266692 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -845,7 +845,7 @@ export const dict = { "dialog.model.noProviders": "Nenhum provedor", "prompt.placeholder.connecting": "Conectando ao servidor...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Conexão falhou. Verifique o painel de saída ou reinicie a extensão.", "prompt.placeholder.default": "Digite uma mensagem... (Enter para enviar, Shift+Enter para nova linha)", "context.usage.sessionCost": "Custo da sessão", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 9c1bef45bac..8d7d00617bd 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -848,7 +848,7 @@ export const dict = { "dialog.model.noProviders": "Nema pružatelja", "prompt.placeholder.connecting": "Povezivanje na server...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Povezivanje nije uspjelo. Provjerite panel za izlaz ili ponovo pokrenite ekstenziju.", "prompt.placeholder.default": "Unesite poruku... (Enter za slanje, Shift+Enter za novi red)", "context.usage.sessionCost": "Cijena sesije", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index e7de1399ffc..b23ed88ff3f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -843,7 +843,7 @@ export const dict = { "dialog.model.noProviders": "Ingen udbydere", "prompt.placeholder.connecting": "Opretter forbindelse til server...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Forbindelse mislykkedes. Tjek outputpanelet eller genstart udvidelsen.", "prompt.placeholder.default": "Skriv en besked... (Enter for at sende, Shift+Enter for ny linje)", "context.usage.sessionCost": "Sessionsomkostning", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index c9b2a01c7a1..2464ba322f4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -853,7 +853,8 @@ export const dict = { "dialog.model.noProviders": "Keine Anbieter", "prompt.placeholder.connecting": "Verbindung zum Server wird hergestellt...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": + "Verbindung fehlgeschlagen. Überprüfen Sie das Ausgabepanel oder starten Sie die Erweiterung neu.", "prompt.placeholder.default": "Nachricht eingeben... (Enter zum Senden, Shift+Enter für neue Zeile)", "context.usage.sessionCost": "Sitzungskosten", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 72872fb9ae2..57ecac511c5 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -846,7 +846,7 @@ export const dict = { "prompt.placeholder.connecting": "Connecting to server...", "prompt.placeholder.default": "Type a message... (Enter to send, Shift+Enter for new line)", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Connection failed. Check the output panel or restart the extension.", "context.usage.sessionCost": "Session cost", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index d49ca0d1e04..858f0e4ae06 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -850,7 +850,7 @@ export const dict = { "dialog.model.noProviders": "Sin proveedores", "prompt.placeholder.connecting": "Conectando al servidor...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Conexión fallida. Revisa el panel de salida o reinicia la extensión.", "prompt.placeholder.default": "Escribe un mensaje... (Enter para enviar, Shift+Enter para nueva línea)", "context.usage.sessionCost": "Coste de la sesión", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 35f02b3a486..f221576c3b4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -855,7 +855,7 @@ export const dict = { "dialog.model.noProviders": "Aucun fournisseur", "prompt.placeholder.connecting": "Connexion au serveur...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Échec de la connexion. Vérifiez le panneau de sortie ou redémarrez l'extension.", "prompt.placeholder.default": "Tapez un message... (Entrée pour envoyer, Maj+Entrée pour un saut de ligne)", "context.usage.sessionCost": "Coût de la session", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 5d91287959f..37683e27b74 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -842,7 +842,7 @@ export const dict = { "dialog.model.noProviders": "プロバイダーなし", "prompt.placeholder.connecting": "サーバーに接続中...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "接続に失敗しました。出力パネルを確認するか、拡張機能を再起動してください。", "prompt.placeholder.default": "メッセージを入力... (Enterで送信、Shift+Enterで改行)", "context.usage.sessionCost": "セッションコスト", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index a8464a71f20..42e58e00f14 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -842,7 +842,7 @@ export const dict = { "dialog.model.noProviders": "공급자 없음", "prompt.placeholder.connecting": "서버에 연결 중...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "연결에 실패했습니다. 출력 패널을 확인하거나 확장 프로그램을 다시 시작하세요.", "prompt.placeholder.default": "메시지를 입력하세요... (Enter로 전송, Shift+Enter로 줄 바꿈)", "context.usage.sessionCost": "세션 비용", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index e5c707a83ae..86c1ed107a6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -847,7 +847,7 @@ export const dict = { "dialog.model.noProviders": "Ingen leverandører", "prompt.placeholder.connecting": "Kobler til server...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Tilkobling mislyktes. Sjekk utdatapanelet eller start utvidelsen på nytt.", "prompt.placeholder.default": "Skriv en melding... (Enter for å sende, Shift+Enter for ny linje)", "context.usage.sessionCost": "Sesjonskostnad", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 0d6dba9c3dc..f2eb77a7b83 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -845,7 +845,7 @@ export const dict = { "dialog.model.noProviders": "Brak dostawców", "prompt.placeholder.connecting": "Łączenie z serwerem...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Połączenie nie powiodło się. Sprawdź panel wyjściowy lub uruchom ponownie rozszerzenie.", "prompt.placeholder.default": "Wpisz wiadomość... (Enter, aby wysłać, Shift+Enter dla nowej linii)", "context.usage.sessionCost": "Koszt sesji", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 5192306a677..8ecee17b951 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -849,7 +849,7 @@ export const dict = { "dialog.model.noProviders": "Нет провайдеров", "prompt.placeholder.connecting": "Подключение к серверу...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "Не удалось подключиться. Проверьте панель вывода или перезапустите расширение.", "prompt.placeholder.default": "Введите сообщение... (Enter для отправки, Shift+Enter для новой строки)", "context.usage.sessionCost": "Стоимость сессии", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 0241f742947..8441da2a53c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -838,7 +838,7 @@ export const dict = { "dialog.model.noProviders": "ไม่มีผู้ให้บริการ", "prompt.placeholder.connecting": "กำลังเชื่อมต่อกับเซิร์ฟเวอร์...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "การเชื่อมต่อล้มเหลว ตรวจสอบแผงเอาต์พุตหรือรีสตาร์ทส่วนขยาย", "prompt.placeholder.default": "พิมพ์ข้อความ... (Enter เพื่อส่ง, Shift+Enter เพื่อขึ้นบรรทัดใหม่)", "context.usage.sessionCost": "ค่าใช้จ่ายเซสชัน", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 03ed924a7de..5c415474e2a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -831,7 +831,7 @@ export const dict = { "dialog.model.noProviders": "无供应商", "prompt.placeholder.connecting": "正在连接服务器...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "连接失败。请检查输出面板或重启扩展。", "prompt.placeholder.default": "输入消息... (Enter 发送,Shift+Enter 换行)", "context.usage.sessionCost": "会话费用", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 54aa5214ba6..1950c444017 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -833,7 +833,7 @@ export const dict = { "dialog.model.noProviders": "沒有供應商", "prompt.placeholder.connecting": "正在連線至伺服器...", - "prompt.placeholder.error": "", + "prompt.placeholder.error": "連線失敗。請檢查輸出面板或重新啟動擴充功能。", "prompt.placeholder.default": "輸入訊息... (Enter 送出,Shift+Enter 換行)", "context.usage.sessionCost": "工作階段費用", From b70ebd76c1304adc92dc09ddecd09e10eae7ca91 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 13:41:24 +0100 Subject: [PATCH 10/18] fix(i18n): translate error.details.show to Norwegian --- packages/kilo-vscode/webview-ui/src/i18n/no.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 86c1ed107a6..31a443719f7 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -398,7 +398,7 @@ export const dict = { "error.page.title": "Noe gikk galt", "error.page.description": "Det oppstod en feil under lasting av applikasjonen.", "error.page.details.label": "Feildetaljer", - "error.details.show": "Details", + "error.details.show": "Detaljer", "error.page.action.restart": "Start på nytt", "error.page.action.checking": "Sjekker...", "error.page.action.checkUpdates": "Se etter oppdateringer", From 201a62b505eefaaad463fd44c07143d32f29179d Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 13:54:07 +0100 Subject: [PATCH 11/18] fix(vscode): stop pushing provider disposable into context.subscriptions on reconnect The inline completion provider registration was pushed into context.subscriptions on every reconnect, accumulating dead disposables. Track it only via the instance field which is properly disposed and replaced on re-registration. --- .../src/services/autocomplete/AutocompleteServiceManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts index 09dd95e0c66..b69bbaa158a 100644 --- a/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts +++ b/packages/kilo-vscode/src/services/autocomplete/AutocompleteServiceManager.ts @@ -124,12 +124,12 @@ export class AutocompleteServiceManager { return } - // Register classic provider + // Register classic provider (tracked via this.inlineCompletionProviderDisposable, + // not context.subscriptions, so re-registration on reconnect doesn't leak) this.inlineCompletionProviderDisposable = vscode.languages.registerInlineCompletionItemProvider( { scheme: "file" }, this.inlineCompletionProvider, ) - this.context.subscriptions.push(this.inlineCompletionProviderDisposable) } public async disable() { From d744762d5ebb2a38eca8821b34150fc9b6b5c3de Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 14:06:53 +0100 Subject: [PATCH 12/18] fix(i18n): translate remaining English keys (modeModels, retry) for all locales --- packages/kilo-vscode/webview-ui/src/i18n/ar.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/br.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/bs.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/da.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/de.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/es.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/fr.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/ja.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/ko.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/no.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/pl.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/ru.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/th.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/zh.ts | 5 ++--- packages/kilo-vscode/webview-ui/src/i18n/zht.ts | 5 ++--- 15 files changed, 38 insertions(+), 40 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index da05e2cb574..1e07ba7075f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -680,9 +680,9 @@ export const dict = { "settings.providers.tag.config": "التكوين", "settings.providers.tag.custom": "مخصص", "settings.providers.tag.other": "أخرى", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "نموذج لكل وضع", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "تجاوز النموذج الافتراضي لأوضاع محددة. إذا لم يتم التعيين، يتم استخدام النموذج الافتراضي العام.", "settings.models.title": "النماذج", "settings.models.description": "ستكون إعدادات النموذج قابلة للتكوين هنا.", "settings.agents.title": "الوكلاء", @@ -830,7 +830,7 @@ export const dict = { "Kilo Code هو مساعد ترميز بالذكاء الاصطناعي. اطلب منه بناء ميزات أو إصلاح أخطاء أو شرح قاعدة الشيفرة.", "session.messages.scrollToBottom": "التمرير إلى الأسفل", "session.status.writingResponse": "...جارٍ كتابة الرد", - "session.status.retry": "Retrying…", + "session.status.retry": "جارٍ إعادة المحاولة…", "session.status.retrying": "...إعادة المحاولة (المحاولة {{ attempt }})… {{ message }}", "session.status.working": "...جارٍ العمل", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 8e1d0266692..4620236d32b 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -687,9 +687,9 @@ export const dict = { "settings.providers.tag.config": "Configuração", "settings.providers.tag.custom": "Personalizado", "settings.providers.tag.other": "Outro", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Modelo por Modo", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Substitua o modelo padrão para modos específicos. Se não definido, o modelo padrão global é usado.", "settings.models.title": "Modelos", "settings.models.description": "Configurações de modelos estarão disponíveis aqui.", "settings.agents.title": "Agentes", @@ -838,7 +838,7 @@ export const dict = { "Kilo Code é um assistente de programação com IA. Peça para criar funcionalidades, corrigir bugs ou explicar sua base de código.", "session.messages.scrollToBottom": "Rolar para o final", "session.status.writingResponse": "Escrevendo resposta…", - "session.status.retry": "Retrying…", + "session.status.retry": "Tentando novamente…", "session.status.retrying": "Tentando novamente (tentativa {{ attempt }})… {{ message }}", "session.status.working": "Trabalhando…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 8d7d00617bd..0fa2ac754fd 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -691,9 +691,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguracija", "settings.providers.tag.custom": "Prilagođeno", "settings.providers.tag.other": "Ostalo", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Model po režimu", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Zamijenite podrazumijevani model za određene režime. Ako nije postavljeno, koristi se globalni podrazumijevani model.", "settings.models.title": "Modeli", "settings.models.description": "Postavke modela će se ovdje moći podešavati.", "settings.agents.title": "Agenti", @@ -841,7 +841,7 @@ export const dict = { "Kilo Code je AI asistent za programiranje. Zatražite da gradi funkcionalnosti, ispravlja greške ili objasni vašu bazu koda.", "session.messages.scrollToBottom": "Pomakni se na dno", "session.status.writingResponse": "Pisanje odgovora…", - "session.status.retry": "Retrying…", + "session.status.retry": "Ponovni pokušaj…", "session.status.retrying": "Ponovni pokušaj (pokušaj {{ attempt }})… {{ message }}", "session.status.working": "Radim…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index b23ed88ff3f..70aaa315c00 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -686,9 +686,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguration", "settings.providers.tag.custom": "Brugerdefineret", "settings.providers.tag.other": "Andet", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Model pr. tilstand", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Tilsidesæt standardmodellen for bestemte tilstande. Hvis ikke angivet, bruges den globale standardmodel.", "settings.models.title": "Modeller", "settings.models.description": "Modelindstillinger vil kunne konfigureres her.", "settings.agents.title": "Agenter", @@ -836,7 +836,7 @@ export const dict = { "Kilo Code er en AI-kodningsassistent. Bed den om at bygge funktioner, rette fejl eller forklare din kodebase.", "session.messages.scrollToBottom": "Rul til bunden", "session.status.writingResponse": "Skriver svar…", - "session.status.retry": "Retrying…", + "session.status.retry": "Prøver igen…", "session.status.retrying": "Prøver igen (forsøg {{ attempt }})… {{ message }}", "session.status.working": "Arbejder…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 2464ba322f4..ade7ea97d77 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -696,9 +696,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguration", "settings.providers.tag.custom": "Benutzerdefiniert", "settings.providers.tag.other": "Andere", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Modell pro Modus", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Überschreiben Sie das Standardmodell für bestimmte Modi. Wenn nicht festgelegt, wird das globale Standardmodell verwendet.", "settings.models.title": "Modelle", "settings.models.description": "Modelleinstellungen können hier konfiguriert werden.", "settings.agents.title": "Agenten", @@ -846,7 +846,7 @@ export const dict = { "Kilo Code ist ein KI-Programmierassistent. Bitten Sie ihn, Funktionen zu erstellen, Fehler zu beheben oder Ihre Codebasis zu erklären.", "session.messages.scrollToBottom": "Nach unten scrollen", "session.status.writingResponse": "Antwort wird geschrieben…", - "session.status.retry": "Retrying…", + "session.status.retry": "Erneuter Versuch…", "session.status.retrying": "Erneuter Versuch ({{ attempt }})… {{ message }}", "session.status.working": "Wird bearbeitet…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 858f0e4ae06..eb14645a5d3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -692,9 +692,9 @@ export const dict = { "settings.providers.tag.config": "Configuración", "settings.providers.tag.custom": "Personalizado", "settings.providers.tag.other": "Otro", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Modelo por modo", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Anula el modelo predeterminado para modos específicos. Si no se establece, se usa el modelo predeterminado global.", "settings.models.title": "Modelos", "settings.models.description": "La configuración de modelos estará disponible aquí.", "settings.agents.title": "Agentes", @@ -843,7 +843,7 @@ export const dict = { "Kilo Code es un asistente de programación con IA. Pídele que cree funcionalidades, corrija errores o explique tu código.", "session.messages.scrollToBottom": "Desplazar al final", "session.status.writingResponse": "Escribiendo respuesta…", - "session.status.retry": "Retrying…", + "session.status.retry": "Reintentando…", "session.status.retrying": "Reintentando (intento {{ attempt }})… {{ message }}", "session.status.working": "Trabajando…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index f221576c3b4..80650e504a6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -696,9 +696,9 @@ export const dict = { "settings.providers.tag.config": "Configuration", "settings.providers.tag.custom": "Personnalisé", "settings.providers.tag.other": "Autre", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Modèle par mode", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Remplacez le modèle par défaut pour des modes spécifiques. Si non défini, le modèle par défaut global est utilisé.", "settings.models.title": "Modèles", "settings.models.description": "Les paramètres des modèles seront configurables ici.", "settings.agents.title": "Agents", @@ -848,7 +848,7 @@ export const dict = { "Kilo Code est un assistant de programmation IA. Demandez-lui de créer des fonctionnalités, corriger des bugs ou expliquer votre code.", "session.messages.scrollToBottom": "Défiler vers le bas", "session.status.writingResponse": "Rédaction de la réponse…", - "session.status.retry": "Retrying…", + "session.status.retry": "Nouvelle tentative…", "session.status.retrying": "Nouvelle tentative (essai {{ attempt }})… {{ message }}", "session.status.working": "En cours…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 37683e27b74..94441ab90de 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -685,9 +685,9 @@ export const dict = { "settings.providers.tag.config": "設定", "settings.providers.tag.custom": "カスタム", "settings.providers.tag.other": "その他", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "モードごとのモデル", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "特定のモードのデフォルトモデルを上書きします。設定されていない場合、グローバルデフォルトモデルが使用されます。", "settings.models.title": "モデル", "settings.models.description": "モデル設定はここで構成できます。", "settings.agents.title": "エージェント", @@ -835,7 +835,7 @@ export const dict = { "Kilo CodeはAIコーディングアシスタントです。機能の構築、バグの修正、コードベースの説明を依頼できます。", "session.messages.scrollToBottom": "下にスクロール", "session.status.writingResponse": "応答を作成中…", - "session.status.retry": "Retrying…", + "session.status.retry": "再試行中…", "session.status.retrying": "再試行中({{ attempt }}回目)… {{ message }}", "session.status.working": "作業中…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 42e58e00f14..8e25b72f687 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -686,9 +686,9 @@ export const dict = { "settings.providers.tag.config": "구성", "settings.providers.tag.custom": "사용자 지정", "settings.providers.tag.other": "기타", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "모드별 모델", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "특정 모드의 기본 모델을 재정의합니다. 설정하지 않으면 전역 기본 모델이 사용됩니다.", "settings.models.title": "모델", "settings.models.description": "모델 설정은 여기서 구성할 수 있습니다.", "settings.agents.title": "에이전트", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 31a443719f7..c498c64b351 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -690,9 +690,9 @@ export const dict = { "settings.providers.tag.config": "Konfigurasjon", "settings.providers.tag.custom": "Tilpasset", "settings.providers.tag.other": "Annet", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Modell per modus", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Overstyr standardmodellen for bestemte moduser. Hvis ikke angitt, brukes den globale standardmodellen.", "settings.models.title": "Modeller", "settings.models.description": "Modellinnstillinger vil kunne konfigureres her.", "settings.agents.title": "Agenter", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index f2eb77a7b83..1c2f2ef0b26 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -689,9 +689,9 @@ export const dict = { "settings.providers.tag.config": "Konfiguracja", "settings.providers.tag.custom": "Niestandardowe", "settings.providers.tag.other": "Inne", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Model na tryb", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Zastąp domyślny model dla określonych trybów. Jeśli nie ustawiono, używany jest globalny domyślny model.", "settings.models.title": "Modele", "settings.models.description": "Ustawienia modeli będą tutaj konfigurowalne.", "settings.agents.title": "Agenci", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 8ecee17b951..8879bb7cda8 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -692,9 +692,9 @@ export const dict = { "settings.providers.tag.config": "Конфигурация", "settings.providers.tag.custom": "Пользовательский", "settings.providers.tag.other": "Другое", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "Модель для режима", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "Переопределите модель по умолчанию для определённых режимов. Если не задано, используется глобальная модель по умолчанию.", "settings.models.title": "Модели", "settings.models.description": "Настройки моделей будут доступны здесь.", "settings.agents.title": "Агенты", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 8441da2a53c..485dd0cbe04 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -683,9 +683,9 @@ export const dict = { "settings.providers.tag.config": "กำหนดค่า", "settings.providers.tag.custom": "กำหนดเอง", "settings.providers.tag.other": "อื่น ๆ", - "settings.providers.modeModels": "Model per Mode", + "settings.providers.modeModels": "โมเดลต่อโหมด", "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "แทนที่โมเดลเริ่มต้นสำหรับโหมดที่กำหนด หากไม่ได้ตั้งค่า จะใช้โมเดลเริ่มต้นทั่วไป", "settings.models.title": "โมเดล", "settings.models.description": "การตั้งค่าโมเดลจะสามารถกำหนดค่าได้ที่นี่", "settings.agents.title": "เอเจนต์", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 5c415474e2a..1fe39bff6d3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -676,9 +676,8 @@ export const dict = { "settings.providers.tag.config": "配置", "settings.providers.tag.custom": "自定义", "settings.providers.tag.other": "其他", - "settings.providers.modeModels": "Model per Mode", - "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "settings.providers.modeModels": "按模式选择模型", + "settings.providers.modeModels.description": "为特定模式覆盖默认模型。如果未设置,将使用全局默认模型。", "settings.models.title": "模型", "settings.models.description": "模型设置将在此处可配置。", "settings.agents.title": "智能体", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 1950c444017..dc90c91951f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -678,9 +678,8 @@ export const dict = { "settings.providers.tag.config": "設定", "settings.providers.tag.custom": "自訂", "settings.providers.tag.other": "其他", - "settings.providers.modeModels": "Model per Mode", - "settings.providers.modeModels.description": - "Override the default model for specific modes. If not set, the global default model is used.", + "settings.providers.modeModels": "按模式選擇模型", + "settings.providers.modeModels.description": "為特定模式覆寫預設模型。如果未設定,將使用全域預設模型。", "settings.models.title": "模型", "settings.models.description": "可在此調整模型設定。", "settings.agents.title": "Agents", From f91b3c55c2015ced58d8fc5d8c28e5ef3581a32c Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Tue, 17 Mar 2026 14:10:37 +0100 Subject: [PATCH 13/18] fix(i18n): translate remaining English keys (retry, unseen session) for all locales --- packages/kilo-vscode/webview-ui/src/i18n/ar.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/br.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/da.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/de.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/es.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/fr.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/ja.ts | 4 ++-- packages/kilo-vscode/webview-ui/src/i18n/ko.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/no.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/pl.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/ru.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/th.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/zh.ts | 6 +++--- packages/kilo-vscode/webview-ui/src/i18n/zht.ts | 2 +- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 1e07ba7075f..ae1331da7c4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "فتح الإعدادات", "command.session.previous": "الجلسة السابقة", "command.session.next": "الجلسة التالية", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "الجلسة غير المقروءة السابقة", + "command.session.next.unseen": "الجلسة غير المقروءة التالية", "command.session.archive": "أرشفة الجلسة", "command.palette": "لوحة الأوامر", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 4620236d32b..18b78e86894 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Abrir configurações", "command.session.previous": "Sessão anterior", "command.session.next": "Próxima sessão", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Sessão não lida anterior", + "command.session.next.unseen": "Próxima sessão não lida", "command.session.archive": "Arquivar sessão", "command.palette": "Paleta de comandos", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 70aaa315c00..e1bbb6db85e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Åbn indstillinger", "command.session.previous": "Forrige session", "command.session.next": "Næste session", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Forrige ulæste session", + "command.session.next.unseen": "Næste ulæste session", "command.session.archive": "Arkivér session", "command.palette": "Kommandopalette", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index ade7ea97d77..dcc2d4a0647 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -32,8 +32,8 @@ export const dict = { "command.settings.open": "Einstellungen öffnen", "command.session.previous": "Vorherige Sitzung", "command.session.next": "Nächste Sitzung", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Vorherige ungelesene Sitzung", + "command.session.next.unseen": "Nächste ungelesene Sitzung", "command.session.archive": "Sitzung archivieren", "command.palette": "Befehlspalette", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index eb14645a5d3..6efb8e724b5 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Abrir ajustes", "command.session.previous": "Sesión anterior", "command.session.next": "Siguiente sesión", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Sesión no leída anterior", + "command.session.next.unseen": "Siguiente sesión no leída", "command.session.archive": "Archivar sesión", "command.palette": "Paleta de comandos", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 80650e504a6..106bfd293b6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Ouvrir les paramètres", "command.session.previous": "Session précédente", "command.session.next": "Session suivante", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Session non lue précédente", + "command.session.next.unseen": "Session non lue suivante", "command.session.archive": "Archiver la session", "command.palette": "Palette de commandes", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 94441ab90de..cdea158c527 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "設定を開く", "command.session.previous": "前のセッション", "command.session.next": "次のセッション", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "前の未読セッション", + "command.session.next.unseen": "次の未読セッション", "command.session.archive": "セッションをアーカイブ", "command.palette": "コマンドパレット", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 8e25b72f687..7ccb5048ec3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -32,8 +32,8 @@ export const dict = { "command.settings.open": "설정 열기", "command.session.previous": "이전 세션", "command.session.next": "다음 세션", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "이전 읽지 않은 세션", + "command.session.next.unseen": "다음 읽지 않은 세션", "command.session.archive": "세션 보관", "command.palette": "명령 팔레트", @@ -835,7 +835,7 @@ export const dict = { "Kilo Code는 AI 코딩 어시스턴트입니다. 기능 구축, 버그 수정 또는 코드베이스 설명을 요청하세요.", "session.messages.scrollToBottom": "하단으로 스크롤", "session.status.writingResponse": "응답 작성 중...", - "session.status.retry": "Retrying…", + "session.status.retry": "재시도 중…", "session.status.retrying": "재시도 중 ({{ attempt }}번째 시도)… {{ message }}", "session.status.working": "작업 중...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index c498c64b351..d40e28c181a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -31,8 +31,8 @@ export const dict = { "command.settings.open": "Åpne innstillinger", "command.session.previous": "Forrige sesjon", "command.session.next": "Neste sesjon", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Forrige uleste økt", + "command.session.next.unseen": "Neste uleste økt", "command.session.archive": "Arkiver sesjon", "command.palette": "Kommandopalett", @@ -840,7 +840,7 @@ export const dict = { "Kilo Code er en AI-kodingsassistent. Be den om å bygge funksjoner, fikse feil eller forklare kodebasen din.", "session.messages.scrollToBottom": "Rull til bunnen", "session.status.writingResponse": "Skriver svar…", - "session.status.retry": "Retrying…", + "session.status.retry": "Prøver på nytt…", "session.status.retrying": "Prøver på nytt (forsøk {{ attempt }})… {{ message }}", "session.status.working": "Arbeider…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 1c2f2ef0b26..ea2b87c1569 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Otwórz ustawienia", "command.session.previous": "Poprzednia sesja", "command.session.next": "Następna sesja", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Poprzednia nieprzeczytana sesja", + "command.session.next.unseen": "Następna nieprzeczytana sesja", "command.session.archive": "Zarchiwizuj sesję", "command.palette": "Paleta poleceń", @@ -838,7 +838,7 @@ export const dict = { "Kilo Code to asystent programowania AI. Poproś go o tworzenie funkcji, naprawę błędów lub wyjaśnienie bazy kodu.", "session.messages.scrollToBottom": "Przewiń na dół", "session.status.writingResponse": "Pisanie odpowiedzi…", - "session.status.retry": "Retrying…", + "session.status.retry": "Ponawianie…", "session.status.retrying": "Ponawiam próbę ({{ attempt }})… {{ message }}", "session.status.working": "Pracuję…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 8879bb7cda8..9636b2caf17 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "Открыть настройки", "command.session.previous": "Предыдущая сессия", "command.session.next": "Следующая сессия", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "Предыдущая непрочитанная сессия", + "command.session.next.unseen": "Следующая непрочитанная сессия", "command.session.archive": "Архивировать сессию", "command.palette": "Палитра команд", @@ -842,7 +842,7 @@ export const dict = { "Kilo Code — это AI-помощник для программирования. Попросите его создать функции, исправить ошибки или объяснить вашу кодовую базу.", "session.messages.scrollToBottom": "Прокрутить вниз", "session.status.writingResponse": "Пишу ответ…", - "session.status.retry": "Retrying…", + "session.status.retry": "Повторная попытка…", "session.status.retrying": "Повторная попытка ({{ attempt }})… {{ message }}", "session.status.working": "Работаю…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 485dd0cbe04..492a3b78cab 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -28,8 +28,8 @@ export const dict = { "command.settings.open": "เปิดการตั้งค่า", "command.session.previous": "เซสชันก่อนหน้า", "command.session.next": "เซสชันถัดไป", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "เซสชันที่ยังไม่ได้อ่านก่อนหน้า", + "command.session.next.unseen": "เซสชันที่ยังไม่ได้อ่านถัดไป", "command.session.archive": "จัดเก็บเซสชัน", "command.palette": "คำสั่งค้นหา", @@ -831,7 +831,7 @@ export const dict = { "session.messages.welcome": "Kilo Code เป็นผู้ช่วยเขียนโค้ด AI ขอให้สร้างฟีเจอร์ แก้ไขบัก หรืออธิบายโค้ดเบสของคุณ", "session.messages.scrollToBottom": "เลื่อนไปด้านล่าง", "session.status.writingResponse": "กำลังเขียนคำตอบ...", - "session.status.retry": "Retrying…", + "session.status.retry": "กำลังลองใหม่…", "session.status.retrying": "กำลังลองใหม่ (ครั้งที่ {{ attempt }})… {{ message }}", "session.status.working": "กำลังทำงาน...", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 1fe39bff6d3..eeb6304366e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -32,8 +32,8 @@ export const dict = { "command.settings.open": "打开设置", "command.session.previous": "上一个会话", "command.session.next": "下一个会话", - "command.session.previous.unseen": "Previous unread session", - "command.session.next.unseen": "Next unread session", + "command.session.previous.unseen": "上一个未读会话", + "command.session.next.unseen": "下一个未读会话", "command.session.archive": "归档会话", "command.palette": "命令面板", @@ -823,7 +823,7 @@ export const dict = { "session.messages.welcome": "Kilo Code 是一个 AI 编程助手。让它帮你构建功能、修复 bug 或解释代码库。", "session.messages.scrollToBottom": "滚动到底部", "session.status.writingResponse": "正在撰写回复…", - "session.status.retry": "Retrying…", + "session.status.retry": "正在重试…", "session.status.retrying": "正在重试(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "处理中…", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index dc90c91951f..449bde5c80a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -825,7 +825,7 @@ export const dict = { "session.messages.welcome": "Kilo Code 是一個 AI 程式設計助手。讓它幫你建構功能、修復 bug 或解釋程式碼庫。", "session.messages.scrollToBottom": "捲動至底部", "session.status.writingResponse": "正在撰寫回覆…", - "session.status.retry": "Retrying…", + "session.status.retry": "正在重試…", "session.status.retrying": "正在重試(第 {{ attempt }} 次)… {{ message }}", "session.status.working": "處理中…", From 8f9852c08ae2dfbcb6deb330d630263aa942cc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Catriel=20M=C3=BCller?= Date: Tue, 17 Mar 2026 11:39:53 -0300 Subject: [PATCH 14/18] fix: vscode publish --- script/publish.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/script/publish.ts b/script/publish.ts index e27ad59f784..8b99c918412 100755 --- a/script/publish.ts +++ b/script/publish.ts @@ -84,5 +84,10 @@ await import(`../packages/sdk/js/script/publish.ts`) console.log("\n=== plugin ===\n") await import(`../packages/plugin/script/publish.ts`) +// kilocode_change start +console.log("\n=== vscode ===\n") +await import(`../packages/kilo-vscode/script/publish.ts`) +// kilocode_change end + const dir = fileURLToPath(new URL("..", import.meta.url)) process.chdir(dir) From bea9eb6bf4ab80f9f28da2fca0d6f8d4b6726c7a Mon Sep 17 00:00:00 2001 From: "kilo-maintainer[bot]" Date: Tue, 17 Mar 2026 14:54:34 +0000 Subject: [PATCH 15/18] release: v7.0.49 --- bun.lock | 32 +++++++++++++------------- package.json | 2 +- packages/app/package.json | 2 +- packages/desktop-electron/package.json | 2 +- packages/desktop/package.json | 2 +- packages/extensions/zed/extension.toml | 12 +++++----- packages/kilo-docs/package.json | 2 +- packages/kilo-gateway/package.json | 2 +- packages/kilo-i18n/package.json | 2 +- packages/kilo-telemetry/package.json | 2 +- packages/kilo-ui/package.json | 2 +- packages/kilo-vscode/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 2 +- packages/script/package.json | 2 +- packages/sdk/js/package.json | 2 +- packages/storybook/package.json | 2 +- packages/ui/package.json | 2 +- packages/util/package.json | 2 +- script/upstream/package.json | 2 +- sdks/vscode/package.json | 2 +- 21 files changed, 41 insertions(+), 41 deletions(-) diff --git a/bun.lock b/bun.lock index 41e02d1047a..07dd4b75099 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -79,7 +79,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -112,7 +112,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -142,7 +142,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -171,7 +171,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@clack/prompts": "1.0.0-alpha.1", "@kilocode/plugin": "workspace:*", @@ -203,7 +203,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.0.48", + "version": "7.0.49", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -213,7 +213,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -233,7 +233,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", @@ -262,7 +262,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -314,7 +314,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.0.48", + "version": "7.0.49", "bin": { "opencode": "./bin/opencode", }, @@ -434,7 +434,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@kilocode/sdk": "workspace:*", "zod": "catalog:", @@ -448,14 +448,14 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.0.48", + "version": "7.0.49", "devDependencies": { "@types/bun": "catalog:", }, }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.0.48", + "version": "7.0.49", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -466,7 +466,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.0.48", + "version": "7.0.49", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -489,7 +489,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -536,7 +536,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.0.48", + "version": "7.0.49", "dependencies": { "zod": "catalog:", }, diff --git a/package.json b/package.json index 5bea7213568..517a395fb24 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,6 @@ "@openrouter/ai-sdk-provider@1.5.4": "patches/@openrouter%2Fai-sdk-provider@1.5.4.patch", "ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch" }, - "version": "7.0.48", + "version": "7.0.49", "peerDependencies": {} } diff --git a/packages/app/package.json b/packages/app/package.json index fd5448f6ebd..8437ca211c6 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.0.48", + "version": "7.0.49", "description": "", "type": "module", "exports": { diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index b2ab498bef6..a1bd829df8b 100644 --- a/packages/desktop-electron/package.json +++ b/packages/desktop-electron/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop-electron", "private": true, - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index b5963b83fa7..dcdd9e87cf0 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index a6b63c5e35b..d6f807d1294 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "7.0.48" +version = "7.0.49" 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.0.48/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.49/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.0.48/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.49/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.48/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.49/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.0.48/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.49/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.0.48/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.0.49/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index 56aca25365d..ee4bd54463a 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.0.48", + "version": "7.0.49", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index 2acf10f9f6d..7cc37d52c04 100644 --- a/packages/kilo-gateway/package.json +++ b/packages/kilo-gateway/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-gateway", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration", diff --git a/packages/kilo-i18n/package.json b/packages/kilo-i18n/package.json index 47633b39c95..53f1d0e1e72 100644 --- a/packages/kilo-i18n/package.json +++ b/packages/kilo-i18n/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-i18n", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index 4cc1584fa7e..dc03bf9fe16 100644 --- a/packages/kilo-telemetry/package.json +++ b/packages/kilo-telemetry/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/kilo-telemetry", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "description": "Telemetry for Kilo CLI - PostHog analytics integration", diff --git a/packages/kilo-ui/package.json b/packages/kilo-ui/package.json index 2166c64a22d..2b8c5c79295 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 0ccf0bd27db..807c9b1e40b 100644 --- a/packages/kilo-vscode/package.json +++ b/packages/kilo-vscode/package.json @@ -2,7 +2,7 @@ "name": "kilo-code", "displayName": "Kilo Code: AI Coding Agent, Copilot, and Autocomplete", "description": "Open Source AI coding agent that generates code from natural language, automates tasks, and runs terminal commands. Features inline autocomplete, browser automation, automated refactoring, and custom modes for planning, coding, and debugging. Supports 500+ AI models including Claude (Anthropic), Gemini, Grok, GPT, Codex and GLM.", - "version": "7.0.48", + "version": "7.0.49", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ca75fee7923..961b27df1df 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.0.48", + "version": "7.0.49", "name": "@kilocode/cli", "type": "module", "license": "MIT", diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 76b1e2a58d2..95e9d47ac36 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/plugin", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/script/package.json b/packages/script/package.json index 4de96455e64..be4c7b7bc4f 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -8,7 +8,7 @@ "exports": { ".": "./src/index.ts" }, - "version": "7.0.48", + "version": "7.0.49", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 0f8cc0ce759..44a6c1ae150 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/sdk", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "repository": { diff --git a/packages/storybook/package.json b/packages/storybook/package.json index ea8e4f3245a..123a9a185ed 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -26,7 +26,7 @@ "typescript": "catalog:", "vite": "catalog:" }, - "version": "7.0.48", + "version": "7.0.49", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/ui/package.json b/packages/ui/package.json index a340e7f6db7..5107c311f66 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "7.0.48", + "version": "7.0.49", "type": "module", "license": "MIT", "exports": { diff --git a/packages/util/package.json b/packages/util/package.json index a7bd318b887..9e6743d2c9b 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "7.0.48", + "version": "7.0.49", "private": true, "type": "module", "license": "MIT", diff --git a/script/upstream/package.json b/script/upstream/package.json index 1b4f06241fe..8d6d1013f4a 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.0.48", + "version": "7.0.49", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 50a5ac1b771..e709acfcadc 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "7.0.48", + "version": "7.0.49", "publisher": "sst-dev", "repository": { "type": "git", From 28330ea765414c7bf8026ab1e8814eb5a261590e Mon Sep 17 00:00:00 2001 From: Imanol Maiztegui Date: Tue, 17 Mar 2026 15:59:52 +0100 Subject: [PATCH 16/18] Save permission rules to config (#7143) * feat: save permissions to config * fix: preserve wildcard default in jsonc scalar promotion and skip dispose for permission saves * fix: update CLI permission hint to reflect permanent persistence * fix: avoid mutating input in mergeConfig permission normalization * chore: update kilo-vscode visual regression baselines * chore: update kilo-vscode visual regression baselines * fix: scope patchJsonc scalar promotion to permission keys only * fix: toConfig always uses object format to preserve existing granular rules * fix: preserve metadata.rules order in saveAlwaysRules for correct precedence * fix: remove unnecessary dispose con config global update --------- Co-authored-by: github-actions[bot] --- .../bash-expanded-pending-chromium-linux.png | 4 +- .../bash-rule-approved-chromium-linux.png | 4 +- .../bash-rule-denied-chromium-linux.png | 4 +- .../bash-rules-mixed-chromium-linux.png | 4 +- .../edit-expanded-pending-chromium-linux.png | 4 +- ...al-dir-expanded-pending-chromium-linux.png | 4 +- .../glob-expanded-pending-chromium-linux.png | 4 +- .../glob-rule-approved-chromium-linux.png | 4 +- ...-rules-expanded-pending-chromium-linux.png | 4 +- .../many-rules-mixed-chromium-linux.png | 4 +- .../subagent-expanded-chromium-linux.png | 4 +- ...search-expanded-pending-chromium-linux.png | 4 +- .../write-expanded-pending-chromium-linux.png | 4 +- .../write-rules-mixed-chromium-linux.png | 4 +- .../bash-with-permission-chromium-linux.png | 4 +- .../glob-with-permission-chromium-linux.png | 4 +- ...on-dock-bash-many-rules-chromium-linux.png | 4 +- .../permission-dock-edit-chromium-linux.png | 4 +- ...ssion-dock-external-dir-chromium-linux.png | 4 +- ...ermission-dock-subagent-chromium-linux.png | 4 +- .../permission-dock-todo-chromium-linux.png | 4 +- ...rmission-dock-websearch-chromium-linux.png | 4 +- .../permission-dock-write-chromium-linux.png | 4 +- ...o-write-with-permission-chromium-linux.png | 4 +- .../src/components/chat/PermissionDock.tsx | 1 - .../webview-ui/src/styles/chat.css | 8 -- .../cli/cmd/tui/routes/session/permission.tsx | 4 +- packages/opencode/src/config/config.ts | 45 ++++-- packages/opencode/src/permission/next.ts | 48 ++++++- .../test/permission/next.always-rules.test.ts | 128 ++++++++++++++++++ .../test/permission/next.toConfig.test.ts | 62 +++++++++ packages/ui/src/i18n/ar.ts | 1 - packages/ui/src/i18n/br.ts | 2 - packages/ui/src/i18n/bs.ts | 2 - packages/ui/src/i18n/da.ts | 2 - packages/ui/src/i18n/de.ts | 2 - packages/ui/src/i18n/en.ts | 1 - packages/ui/src/i18n/es.ts | 2 - packages/ui/src/i18n/fr.ts | 2 - packages/ui/src/i18n/ja.ts | 2 - packages/ui/src/i18n/ko.ts | 1 - packages/ui/src/i18n/no.ts | 2 - packages/ui/src/i18n/pl.ts | 2 - packages/ui/src/i18n/ru.ts | 2 - packages/ui/src/i18n/th.ts | 1 - packages/ui/src/i18n/zh.ts | 1 - packages/ui/src/i18n/zht.ts | 1 - 47 files changed, 320 insertions(+), 98 deletions(-) create mode 100644 packages/opencode/test/permission/next.toConfig.test.ts diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png index f760f80b321..af11cb0cb01 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ba76e2d5b993e999914fd0538650728adf78f7ad70978d8ee9982525f6ab5e8 -size 17626 +oid sha256:321afc41e5908e73656b1a8d5e3c32f23f54d10dee12655506b4b58348230305 +size 13718 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png index 25eae19771e..52e193cde72 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-approved-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29872fa36a6a6ba9e20765f92380b86f9a91beb9702b3cdb95914ea46a2cf40c -size 17833 +oid sha256:666d73c69b19e8c79815129b9d17747dbf755c316f3e6da0cba6977966b9cccc +size 13906 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png index 7840f5c9b49..feb82c22613 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rule-denied-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce915e449cdec411c00df613ffc1017f95dba69737e0474fc8c483ea9f284026 -size 17872 +oid sha256:b0608142ccb5bab0468ae44060bed17c5ba98b8ee2d5a477627644d1c91e760a +size 13952 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png index d0b71517797..25ef6e6eaf8 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/bash-rules-mixed-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b39675360da34fc6cb9c1ff4e51afeff79417ca4baa88816967d2b0a4ece858f -size 18043 +oid sha256:7dd67617fdfc9ea6c4b0f54895d930d76c5c712b158e4be93967a3a3239a53b2 +size 14143 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png index 5deb79c5feb..77f21c5d8f3 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/edit-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3b7d96f123e880b1395d160d17a48f385ef59344326c44d7cd13b342d2ca49e -size 24193 +oid sha256:43b16bc81164f310ae40f7ebe6459281f374be323dfc07e3bef6b2d1608b6637 +size 20835 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png index fc41dfc1e64..aec5cceeb88 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/external-dir-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:739b8eb94e5cde39e4127a6ed3c499392174a380812e2e3497965643cac3dee9 -size 22265 +oid sha256:ee48a78cd2fe43c34d0014262ac794e48e5405d2116140d08219fc8e1621be0c +size 18516 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png index 8e6f8a9a320..3c52ab82d73 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62ef30b05bf2ec47a7ddd02a03f5f1cded5ced9cf9332dd3bd50d6809bcce96d -size 18447 +oid sha256:f69b6545bd98003edf8c7208eb655066a24847e055cf0a5492c99ff67bbbab38 +size 14621 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png index da8a959b81f..967ec871497 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/glob-rule-approved-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f9864861136b578c4e46ece7dae5a139ada7e7be3d219462ef3a549b94239ec -size 18648 +oid sha256:5a7db3c77ca7dee3a74fe3fd08b45e8d32a00193d1fb13ec7b4e2b1671dac7a3 +size 14831 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png index 90aa5cfaa2e..63a4706a710 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:514803fa46f43ff58d8d403e630afc5c01a8841ac420d406755515bceb38beae -size 23132 +oid sha256:c4aa38c3ade48132b3f0083438ef71c0e34f180db3bbd4d70455d6bb34a1225c +size 19202 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png index 840e6dcdbc4..0dcdc9c789f 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/many-rules-mixed-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:578f6daa54a25fba38b049d623e2b12069b0cbe1c5e094031d8a0b0af0a56f52 -size 23966 +oid sha256:e46b79adada26121c948ce33b78ba78c8b0b13dc153708b60a56f1cfc6034503 +size 20095 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png index 949e7d47de5..e923dbb3d9a 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/subagent-expanded-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91ba11c0a81ced5dfe824a4c9e8fdcbaebaaddc660ef2b245df56903e180e4b7 -size 18949 +oid sha256:699b49cbb768c3a9cea64878a01b5507a1f304a14f12363f2329ad07c8cc35cb +size 15082 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png index e1016e91f6c..2cec9298269 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/websearch-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6f8bc26191620881314eff9ac921abba4e201c5af7ec8d222e405fdee9ddae9a -size 17909 +oid sha256:60e6d4b1d0e860195c26752e50a97e6d22d7911d029e7d08d24f46b327b21a01 +size 14075 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png index feff311b196..396d36f5be6 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-expanded-pending-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce112e9762168271fd8b7b4316b740008269e9d248a668887adce3dde13478f0 -size 18362 +oid sha256:4ff80ac6cd76dbb278e6483c2e5c352095fc893ae5f5d5cb2eb70ded640bfc0e +size 16913 diff --git a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-rules-mixed-chromium-linux.png b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-rules-mixed-chromium-linux.png index 83a6fd71b75..029873cc53b 100644 --- a/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-rules-mixed-chromium-linux.png +++ b/packages/kilo-vscode/tests/permission-dock-dropdown.spec.ts-snapshots/permission-dock-dropdown/write-rules-mixed-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d499d73467c37052d1277deefdd419e370a8239d7e117806d8442b2b9cc851a7 -size 18886 +oid sha256:6531e4d0e975a29d538bc7b609a987071afc0997b396fd06e52cbbf2b7ef2e26 +size 17467 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png index 9a067ead3ed..af129f66347 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/bash-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3656d23c630a2d7f412d2fc3eee231f45cbe47e6d1e4e7ca44ae4cca3c3160b -size 15323 +oid sha256:cb8dd7f0ecbbeed00e1321c050964b54f832a571c8acbc37269de205bd64a483 +size 13788 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png index 9d67d03d5db..c5082b9c68c 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/glob-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c95ebadbd707aab03b0b14858cd9e25c4e7b06e8976abf76e377b9eaa5bd2144 -size 16900 +oid sha256:484ec50824ececf29d8b1464fb94ef48637d4f97b9a3c68dcf3ae5d8f157dcf6 +size 15502 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png index 0fc73f39049..d5d265c84f4 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-bash-many-rules-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1c43a0a2f6a351d53da542aba6b68113e8231c1ee9cf7276bf6a16263b65d811 -size 18775 +oid sha256:ab9edfc18d0d7094f7c5410d7b08e0012c2128f1638b7090aad9301f127473ed +size 17425 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png index 7c9631bb33b..62b3ec797fc 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-edit-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d23b2a1621e33e92e65c7ead23b42f05decd443b370ef7122b840e6f5cf043e1 -size 21177 +oid sha256:05783f1a5b4c8631dee2582b243a724eb4fb811cde894f86ce3575e2da1a997e +size 17416 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png index 4002998e5ab..ee860618172 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-external-dir-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:63b8651967a042ef6e79f721fc4bf99eae875296dbd991566d3c3b7e90f04669 -size 18542 +oid sha256:24364efcbb54ed842a9af0c630e6b2a4f5df37d8cabb651e18dcbebda37a26c5 +size 17221 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png index cf8c0e73185..25a57754eb3 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-subagent-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94ef29b3eca3b0e9e407daf9c17388dcf5735c134a74bc13500559bcf9707c9b -size 16338 +oid sha256:e8e117613ac4378e82739c266c2e2f818e9ed79bc0e84e0ebe7b8f61c02b88c0 +size 14836 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png index ec79a3cc440..917da74bfa0 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-todo-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:168eacdc6523223587bad5f72f3828e03211733b4dc1fa39f152409089e03ff3 -size 16468 +oid sha256:2259e821d911a5455a4bdd72716d5ae1de1a5fd5b6aaad666d41846edac716cc +size 15079 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png index 4667f970ab5..4a53b71a419 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-websearch-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c2402fb61b05c355cedea5a26c39f4a5b4d4a1e04c0fb8ac1ac50edbdc746b3 -size 16426 +oid sha256:3fc2414e502c0f064fc8d15e5f14ccdc5c250ded619b8362472d2a41fb522de9 +size 15023 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png index 542c4451ee0..4b625140e92 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/permission-dock-write-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38712f08584902b1ccb267fed0271c6c1a9b5f549b47bd743ca344604df2095a -size 17433 +oid sha256:acb0efba94927a8ada6a16a66bd82160a1f41d320a2f512114da54aaa2cc1574 +size 16143 diff --git a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png index 2c82c3e045e..65b61ec3305 100644 --- a/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png +++ b/packages/kilo-vscode/tests/visual-regression.spec.ts-snapshots/composite-webview/todo-write-with-permission-chromium-linux.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84e3f1c43bd36828f6548f3a3a85827693b370f6f3fc319408829eb742146bb5 -size 19287 +oid sha256:c21917a9f4f80354ac18a7c4ced1f204a1b28bed4ac5fb0cf34e339dbdc7d5da +size 15929 diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx index fd041287bbb..9c959b4f6da 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PermissionDock.tsx @@ -179,7 +179,6 @@ export const PermissionDock: Component<{
{toolDescription()}
-

{language.t("ui.permission.sessionHint")}

- +
diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx index 0a8332605d5..a9759a6c575 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -41,7 +41,11 @@ function mergeReviewComments(current: ReviewComment[], incoming: ReviewComment[] return [...map.values()] } -export const PromptInput: Component = () => { +interface PromptInputProps { + blocked?: () => boolean +} + +export const PromptInput: Component = (props) => { const session = useSession() const server = useServer() const language = useLanguage() @@ -172,7 +176,7 @@ export const PromptInput: Component = () => { const isBusy = () => session.status() === "busy" const isDisabled = () => !server.isConnected() const hasInput = () => text().trim().length > 0 || imageAttach.images().length > 0 || reviewComments().length > 0 - const canSend = () => hasInput() && !isDisabled() + const canSend = () => hasInput() && !isDisabled() && !props.blocked?.() const showStop = () => isBusy() && !hasInput() const placeholder = () => { switch (server.connectionState()) { @@ -450,7 +454,7 @@ export const PromptInput: Component = () => { const pending = reviewComments() const review = pending.length > 0 ? formatReviewCommentsMarkdown(pending) : "" const message = draft && review ? `${review}\n\n${draft}` : draft || review - if ((!message && imgs.length === 0) || isDisabled()) return + if ((!message && imgs.length === 0) || isDisabled() || props.blocked?.()) return const mentionFiles = mention.parseFileAttachments(draft) const imgFiles = imgs.map((img) => ({ mime: img.mime, url: img.dataUrl, filename: img.filename })) @@ -639,7 +643,10 @@ export const PromptInput: Component = () => { +
diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/RevertBanner.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/RevertBanner.tsx new file mode 100644 index 00000000000..fe23f966b0b --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/chat/RevertBanner.tsx @@ -0,0 +1,74 @@ +/** + * RevertBanner component + * Shows when the session is in a reverted state, displaying the number of + * reverted messages, per-file diff stats, and Redo / Redo All actions. + */ + +import { Component, For, Show } from "solid-js" +import { Button } from "@kilocode/kilo-ui/button" +import { Icon } from "@kilocode/kilo-ui/icon" +import { DiffChanges } from "@kilocode/kilo-ui/diff-changes" +import { useSession } from "../../context/session" +import { useLanguage } from "../../context/language" + +export const RevertBanner: Component = () => { + const session = useSession() + const language = useLanguage() + + const info = () => session.revert() + const count = () => session.revertedCount() + const diffs = () => session.summary()?.diffs + + const users = () => session.userMessages() + + const handleRedo = () => { + const boundary = info()?.messageID + if (!boundary) return + const next = users().find((m) => m.id > boundary) + if (!next) { + session.unrevertSession() + return + } + session.revertSession(next.id) + } + + return ( + +
+
+
+ + + {count() === 1 + ? language.t("revert.banner.count_one", { count: count() }) + : language.t("revert.banner.count_other", { count: count() })} + +
+
+ + 1}> + + +
+
+ +
+ + {(file) => ( +
+ {file.file} + +
+ )} +
+
+
+
{language.t("revert.banner.hint")}
+
+
+ ) +} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx index e109f4791d8..c1092f1eaf5 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx @@ -29,6 +29,7 @@ import type { } from "@kilocode/sdk/v2" import { ErrorDisplay } from "./ErrorDisplay" import { useServer } from "../../context/server" +import { useSession } from "../../context/session" function getDirectory(path: string): string { const sep = path.includes("/") ? "/" : "\\" @@ -53,6 +54,7 @@ export const VscodeSessionTurn: Component = (props) => { const i18n = useI18n() const diffComponent = useDiffComponent() const server = useServer() + const session = useSession() const emptyMessages: SDKMessage[] = [] const emptyParts: SDKPart[] = [] @@ -168,6 +170,11 @@ export const VscodeSessionTurn: Component = (props) => { parts={parts() as unknown as Parameters[0]["parts"]} interrupted={interrupted()} queued={props.queued} + onRevert={ + assistantMessages().length > 0 && session.status() === "idle" && !session.revert() + ? () => session.revertSession(props.messageID) + : undefined + } /> diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index 091272f4b50..700d31cc41b 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -135,7 +135,14 @@ interface SessionContextValue { currentVariant: () => string | undefined selectVariant: (value: string) => void + // Revert/undo state for the current session + revert: Accessor + revertedCount: Accessor + summary: Accessor + // Actions + revertSession: (messageID: string) => void + unrevertSession: () => void sendMessage: (text: string, providerID?: string, modelID?: string, files?: FileAttachment[]) => void abort: () => void compact: () => void @@ -493,6 +500,10 @@ export const SessionProvider: ParentComponent = (props) => { handleSessionDeleted(message.sessionID) break + case "messageRemoved": + handleMessageRemoved(message.sessionID, message.messageID) + break + case "error": // Only clear loading if the error is for the current session // (or has no sessionID for backwards compatibility) @@ -903,6 +914,18 @@ export const SessionProvider: ParentComponent = (props) => { }) } + // Matches desktop app's event-reducer.ts: message.removed handler. + // Splices the message from the store and deletes its parts. + function handleMessageRemoved(sessionID: string, messageID: string) { + setStore("messages", sessionID, (msgs = []) => msgs.filter((m) => m.id !== messageID)) + setStore( + "parts", + produce((parts) => { + delete parts[messageID] + }), + ) + } + function handleCloudSessionDataLoaded(cloudSessionId: string, title: string, messages: Message[]) { if (cloudPreviewId() !== cloudSessionId) return const key = `cloud:${cloudSessionId}` @@ -1262,6 +1285,47 @@ export const SessionProvider: ParentComponent = (props) => { const userMessages = createMemo(() => messages().filter((m) => m.role === "user")) + 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 revertedCount = createMemo(() => { + const boundary = revert()?.messageID + if (!boundary) return 0 + return userMessages().filter((m) => m.id >= boundary).length + }) + + const summary = createMemo(() => { + const id = currentSessionID() + return id ? (store.sessions[id]?.summary ?? undefined) : undefined + }) + + function revertSession(messageID: string) { + const id = currentSessionID() + if (!id) return + // Restore the reverted user message's prompt text into the input. + // Dispatch as a window message so PromptInput picks it up via onMessage. + const parts = store.parts[messageID] + if (parts) { + const text = parts + .filter((p) => p.type === "text" && !(p as { synthetic?: boolean }).synthetic) + .map((p) => (p as { text: string }).text ?? "") + .join("") + if (text) window.postMessage({ type: "setChatBoxMessage", text }, "*") + } + vscode.postMessage({ type: "revertSession", sessionID: id, messageID }) + } + + function unrevertSession() { + const id = currentSessionID() + if (!id) return + // Clear the prompt input on full redo (matching TUI/desktop behavior) + window.postMessage({ type: "setChatBoxMessage", text: "" }, "*") + vscode.postMessage({ type: "unrevertSession", sessionID: id }) + } + function syncSession(sessionID: string) { vscode.postMessage({ type: "syncSession", sessionID }) } @@ -1360,6 +1424,11 @@ export const SessionProvider: ParentComponent = (props) => { variantList, currentVariant, selectVariant, + revert, + revertedCount, + summary, + revertSession, + unrevertSession, sendMessage, abort, compact, diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index b63df90802a..b064704bcac 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "تراجع عن الرسالة الأخيرة", "command.session.redo": "إعادة", "command.session.redo.description": "إعادة الرسالة التي تم التراجع عنها", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "ضغط الجلسة", "command.session.compact.description": "تلخيص الجلسة لتقليل حجم السياق", "command.session.fork": "تشعب من الرسالة", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 5a1681d09d8..fcb2bd1b2d1 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Desfazer a última mensagem", "command.session.redo": "Refazer", "command.session.redo.description": "Refazer a última mensagem desfeita", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Compactar sessão", "command.session.compact.description": "Resumir a sessão para reduzir o tamanho do contexto", "command.session.fork": "Bifurcar da mensagem", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 1ca43e55e50..b2ff6c5f3b8 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Poništi posljednju poruku", "command.session.redo": "Vrati", "command.session.redo.description": "Vrati posljednju poništenu poruku", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Sažmi sesiju", "command.session.compact.description": "Sažmi sesiju kako bi se smanjio kontekst", "command.session.fork": "Fork iz poruke", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 4fe53e1b592..7ebdbb2fac0 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Fortryd den sidste besked", "command.session.redo": "Omgør", "command.session.redo.description": "Omgør den sidste fortrudte besked", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Komprimér session", "command.session.compact.description": "Opsummer sessionen for at reducere kontekststørrelsen", "command.session.fork": "Forgren fra besked", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 3eb052d0a77..29469221cd8 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -82,6 +82,14 @@ export const dict = { "command.session.undo.description": "Letzte Nachricht rückgängig machen", "command.session.redo": "Wiederherstellen", "command.session.redo.description": "Letzte rückgängig gemachte Nachricht wiederherstellen", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Sitzung komprimieren", "command.session.compact.description": "Sitzung zusammenfassen, um die Kontextgröße zu reduzieren", "command.session.fork": "Von Nachricht abzweigen", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index eb40f32b141..ae2b5a4340f 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Undo the last message", "command.session.redo": "Redo", "command.session.redo.description": "Redo the last undone message", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Compact session", "command.session.compact.description": "Summarize the session to reduce context size", "command.session.fork": "Fork from message", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 9f34b9094ea..4a67c75c9d6 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Deshacer el último mensaje", "command.session.redo": "Rehacer", "command.session.redo.description": "Rehacer el último mensaje deshecho", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Compactar sesión", "command.session.compact.description": "Resumir la sesión para reducir el tamaño del contexto", "command.session.fork": "Bifurcar desde mensaje", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index dabceedd183..b343cb3876a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -79,6 +79,14 @@ export const dict = { "command.session.undo.description": "Annuler le dernier message", "command.session.redo": "Rétablir", "command.session.redo.description": "Rétablir le dernier message annulé", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Compacter la session", "command.session.compact.description": "Résumer la session pour réduire la taille du contexte", "command.session.fork": "Bifurquer à partir du message", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 2dea7cfde2f..7fdb68e8de9 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "最後のメッセージを元に戻す", "command.session.redo": "やり直す", "command.session.redo.description": "元に戻したメッセージをやり直す", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "セッションを圧縮", "command.session.compact.description": "セッションを要約してコンテキストサイズを削減", "command.session.fork": "メッセージからフォーク", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 8c3b8ce5db2..1389d5121ae 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -82,6 +82,14 @@ export const dict = { "command.session.undo.description": "마지막 메시지 실행 취소", "command.session.redo": "다시 실행", "command.session.redo.description": "마지막 실행 취소된 메시지 다시 실행", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "세션 압축", "command.session.compact.description": "컨텍스트 크기를 줄이기 위해 세션 요약", "command.session.fork": "메시지에서 분기", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index bd1981ca990..073781cdac7 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -81,6 +81,14 @@ export const dict = { "command.session.undo.description": "Angre siste melding", "command.session.redo": "Gjør om", "command.session.redo.description": "Gjør om siste angrede melding", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Komprimer sesjon", "command.session.compact.description": "Oppsummer sesjonen for å redusere kontekststørrelsen", "command.session.fork": "Forgren fra melding", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index be0542a5e45..5af63b6d036 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Cofnij ostatnią wiadomość", "command.session.redo": "Ponów", "command.session.redo.description": "Ponów ostatnią cofniętą wiadomość", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Kompaktuj sesję", "command.session.compact.description": "Podsumuj sesję, aby zmniejszyć rozmiar kontekstu", "command.session.fork": "Rozwidlij od wiadomości", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index e68ca6e9f6a..4f112c73096 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "Отменить последнее сообщение", "command.session.redo": "Повторить", "command.session.redo.description": "Повторить отменённое сообщение", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "Сжать сессию", "command.session.compact.description": "Сократить сессию для уменьшения размера контекста", "command.session.fork": "Создать ответвление", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 8112e4e2be6..7e974c6bc3c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -78,6 +78,14 @@ export const dict = { "command.session.undo.description": "ยกเลิกข้อความล่าสุด", "command.session.redo": "ทำซ้ำ", "command.session.redo.description": "ทำซ้ำข้อความที่ถูกยกเลิกล่าสุด", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "บีบอัดเซสชัน", "command.session.compact.description": "สรุปเซสชันเพื่อลดขนาดบริบท", "command.session.fork": "แตกแขนงจากข้อความ", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 2d24ab47542..d7c856ae4ee 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -82,6 +82,14 @@ export const dict = { "command.session.undo.description": "撤销上一条消息", "command.session.redo": "重做", "command.session.redo.description": "重做上一条撤销的消息", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "精简会话", "command.session.compact.description": "总结会话以减少上下文大小", "command.session.fork": "从消息分叉", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index eababfc302b..6746fe6c6cf 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -82,6 +82,14 @@ export const dict = { "command.session.undo.description": "復原上一則訊息", "command.session.redo": "重做", "command.session.redo.description": "重做上一則復原的訊息", + "revert.banner.count_one": "{{count}} message reverted", + "revert.banner.count_other": "{{count}} messages reverted", + "revert.banner.redo": "Redo", + "revert.banner.redo.all": "Redo All", + "revert.banner.hint": "Send a new message to make this permanent", + "revert.turn.revert": "Revert to here", + "revert.turn.copy": "Copy message", + "revert.bottom.undo": "Undo Changes", "command.session.compact": "精簡工作階段", "command.session.compact.description": "總結工作階段以減少上下文大小", "command.session.fork": "從訊息分支", diff --git a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx index cdfc06c47ce..3cdf84c201a 100644 --- a/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx +++ b/packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx @@ -152,6 +152,11 @@ export function mockSessionValue(overrides?: { getSessionModel: () => ({ providerID: "kilo", modelID: "anthropic/claude-sonnet-4-6" }), setSessionModel: noop, setSessionAgent: noop, + revert: () => undefined, + revertedCount: () => 0, + summary: () => undefined, + revertSession: noop, + unrevertSession: noop, variantList: () => [], currentVariant: () => undefined, selectVariant: noop, diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat.css b/packages/kilo-vscode/webview-ui/src/styles/chat.css index ccf6db1df4c..604d54edc2e 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat.css @@ -446,6 +446,75 @@ background: var(--vscode-button-hoverBackground); } +/* ============================================ + Revert Banner + ============================================ */ + +.revert-banner { + margin: 8px 12px; + padding: 8px 12px; + border-radius: 4px; + background: var(--surface-secondary, var(--vscode-editorWidget-background, #252526)); + border: 1px solid var(--border-base, var(--vscode-editorWidget-border, #454545)); + font-size: 12px; +} + +.revert-banner-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.revert-banner-info { + display: flex; + align-items: center; + gap: 6px; + color: var(--text-muted, var(--vscode-descriptionForeground)); +} + +.revert-banner-count { + font-weight: 500; +} + +.revert-banner-actions { + display: flex; + gap: 4px; + flex-shrink: 0; +} + +.revert-banner-files { + margin-top: 6px; + display: flex; + flex-direction: column; + gap: 2px; +} + +.revert-banner-file { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 1px 0; + color: var(--text-base, var(--vscode-foreground)); +} + +.revert-banner-filename { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + min-width: 0; + direction: rtl; + text-align: left; +} + +.revert-banner-hint { + margin-top: 6px; + color: var(--text-muted, var(--vscode-descriptionForeground)); + font-style: italic; + font-size: 11px; +} + /* ============================================ Prompt Input ============================================ */ diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 61ffec879d7..27600116722 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -113,12 +113,34 @@ export interface Message { tokens?: TokenUsage } +// File diff info (matches Snapshot.FileDiff from CLI backend) +export interface SessionFileDiff { + file: string + before: string + after: string + additions: number + deletions: number + status?: "added" | "deleted" | "modified" +} + // Session info (simplified for webview) export interface SessionInfo { id: string title?: string createdAt: string updatedAt: string + revert?: { + messageID: string + partID?: string + snapshot?: string + diff?: string + } | null + summary?: { + additions: number + deletions: number + files: number + diffs?: SessionFileDiff[] + } | null } // Cloud session info (from Kilo cloud API) @@ -448,6 +470,12 @@ export interface SessionDeletedMessage { sessionID: string } +export interface MessageRemovedMessage { + type: "messageRemoved" + sessionID: string + messageID: string +} + export interface MessagesLoadedMessage { type: "messagesLoaded" sessionID: string @@ -1102,6 +1130,7 @@ export type ExtensionMessage = | SessionCreatedMessage | SessionUpdatedMessage | SessionDeletedMessage + | MessageRemovedMessage | MessagesLoadedMessage | MessageCreatedMessage | SessionsLoadedMessage @@ -1198,6 +1227,17 @@ export interface AbortRequest { sessionID: string } +export interface RevertSessionRequest { + type: "revertSession" + sessionID: string + messageID: string +} + +export interface UnrevertSessionRequest { + type: "unrevertSession" + sessionID: string +} + export interface PermissionResponseRequest { type: "permissionResponse" permissionId: string @@ -1679,6 +1719,8 @@ export interface SetDefaultBaseBranchRequest { export type WebviewMessage = | SendMessageRequest | AbortRequest + | RevertSessionRequest + | UnrevertSessionRequest | PermissionResponseRequest | CreateSessionRequest | ClearSessionRequest diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 961b27df1df..7b4b30d6dbf 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -81,14 +81,16 @@ "@gitlab/opencode-gitlab-auth": "1.3.3", "@hono/standard-validator": "0.1.5", "@hono/zod-validator": "catalog:", + "@kilocode/kilo-gateway": "workspace:*", + "@kilocode/kilo-telemetry": "workspace:*", + "@kilocode/plugin": "workspace:*", + "@kilocode/sdk": "workspace:*", "@modelcontextprotocol/sdk": "1.25.2", "@morphllm/morphsdk": "0.2.148", "@octokit/graphql": "9.0.2", "@octokit/rest": "catalog:", "@openauthjs/openauth": "catalog:", - "@kilocode/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", - "@kilocode/sdk": "workspace:*", "@opencode-ai/util": "workspace:*", "@openrouter/ai-sdk-provider": "1.5.4", "@opentui/core": "0.1.86", @@ -122,6 +124,7 @@ "opentui-spinner": "0.0.6", "partial-json": "0.1.7", "remeda": "catalog:", + "simple-git": "3.31.1", "solid-js": "catalog:", "strip-ansi": "7.1.2", "tree-sitter-bash": "0.25.0", @@ -133,10 +136,7 @@ "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", - "zod-to-json-schema": "3.24.5", - "@kilocode/kilo-gateway": "workspace:*", - "@kilocode/kilo-telemetry": "workspace:*", - "simple-git": "3.31.1" + "zod-to-json-schema": "3.24.5" }, "overrides": { "drizzle-orm": "1.0.0-beta.12-a5629fb" diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 1a384237554..aead588d809 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -880,6 +880,7 @@ export function UserMessageDisplay(props: { parts: PartType[] interrupted?: boolean queued?: boolean + onRevert?: () => void }) { const data = useData() const dialog = useDialog() @@ -1018,6 +1019,21 @@ export function UserMessageDisplay(props: { + + + e.preventDefault()} + onClick={(event) => { + event.stopPropagation() + props.onRevert?.() + }} + aria-label={i18n.t("ui.message.revert")} + /> + + = { "ui.message.copyMessage": "Copy message", "ui.message.copyResponse": "Copy response", "ui.message.copied": "Copied", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrupted", "ui.message.queued": "Queued", "ui.message.attachment.alt": "attachment", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index 9ee95d82459..5df36d5d92b 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -127,6 +127,7 @@ export const dict = { "ui.message.copyMessage": "Copiar mensaje", "ui.message.copyResponse": "Copiar respuesta", "ui.message.copied": "¡Copiado!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrumpido", "ui.message.queued": "En cola", "ui.message.attachment.alt": "adjunto", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index 431abe56830..df53d9c5584 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -127,6 +127,7 @@ export const dict = { "ui.message.copyMessage": "Copier le message", "ui.message.copyResponse": "Copier la réponse", "ui.message.copied": "Copié !", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrompu", "ui.message.queued": "En file", "ui.message.attachment.alt": "pièce jointe", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index c6cb2ac401e..90448a8562b 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -126,6 +126,7 @@ export const dict = { "ui.message.copyMessage": "メッセージをコピー", "ui.message.copyResponse": "応答をコピー", "ui.message.copied": "コピーしました!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "中断", "ui.message.queued": "待機中", "ui.message.attachment.alt": "添付ファイル", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index cd306e879e5..2eb297f860e 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -127,6 +127,7 @@ export const dict = { "ui.message.copyMessage": "메시지 복사", "ui.message.copyResponse": "응답 복사", "ui.message.copied": "복사됨!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "중단됨", "ui.message.queued": "대기 중", "ui.message.attachment.alt": "첨부 파일", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index ddfe0946188..dc56d918cc9 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -130,6 +130,7 @@ export const dict: Record = { "ui.message.copyMessage": "Kopier melding", "ui.message.copyResponse": "Kopier svar", "ui.message.copied": "Kopiert!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Avbrutt", "ui.message.queued": "I kø", "ui.message.attachment.alt": "vedlegg", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index 73fa96afae3..9e34769bfa7 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -126,6 +126,7 @@ export const dict = { "ui.message.copyMessage": "Kopiuj wiadomość", "ui.message.copyResponse": "Kopiuj odpowiedź", "ui.message.copied": "Skopiowano!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Przerwano", "ui.message.queued": "W kolejce", "ui.message.attachment.alt": "załącznik", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 085be28436f..0a747a24319 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -126,6 +126,7 @@ export const dict = { "ui.message.copyMessage": "Копировать сообщение", "ui.message.copyResponse": "Копировать ответ", "ui.message.copied": "Скопировано!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Прервано", "ui.message.queued": "В очереди", "ui.message.attachment.alt": "вложение", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index 705f68d1b4f..5d480880648 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -128,6 +128,7 @@ export const dict = { "ui.message.copyMessage": "คัดลอกข้อความ", "ui.message.copyResponse": "คัดลอกคำตอบ", "ui.message.copied": "คัดลอกแล้ว!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "ถูกขัดจังหวะ", "ui.message.queued": "อยู่ในคิว", "ui.message.attachment.alt": "ไฟล์แนบ", diff --git a/packages/ui/src/i18n/tr.ts b/packages/ui/src/i18n/tr.ts index 8e536c51768..8db027784ad 100644 --- a/packages/ui/src/i18n/tr.ts +++ b/packages/ui/src/i18n/tr.ts @@ -133,6 +133,7 @@ export const dict = { "ui.message.copyMessage": "Mesajı kopyala", "ui.message.copyResponse": "Yanıtı kopyala", "ui.message.copied": "Kopyalandı", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "Kesildi", "ui.message.queued": "Sırada", "ui.message.attachment.alt": "ek", diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index 571574d92e6..7c3b1b1e38b 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -131,6 +131,7 @@ export const dict = { "ui.message.copyMessage": "复制消息", "ui.message.copyResponse": "复制回复", "ui.message.copied": "已复制!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "已中断", "ui.message.queued": "排队中", "ui.message.attachment.alt": "附件", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index edbc96b12f4..6a5637d8a30 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -131,6 +131,7 @@ export const dict = { "ui.message.copyMessage": "複製訊息", "ui.message.copyResponse": "複製回覆", "ui.message.copied": "已複製!", + "ui.message.revert": "Revert to here", "ui.message.interrupted": "已中斷", "ui.message.queued": "排隊中", "ui.message.attachment.alt": "附件",