diff --git a/.github/workflows/source-check-links.yml b/.github/workflows/source-check-links.yml new file mode 100644 index 00000000000..60df85b4b54 --- /dev/null +++ b/.github/workflows/source-check-links.yml @@ -0,0 +1,24 @@ +name: Check Source Links + +on: + pull_request: + paths: + - "packages/kilo-vscode/src/**" + - "packages/kilo-vscode/webview-ui/**" + - "packages/opencode/src/**" + - "packages/kilo-docs/source-links.md" + - "script/extract-source-links.ts" + - ".github/workflows/source-check-links.yml" + workflow_dispatch: # Allow manual trigger + +jobs: + source-links-freshness: + if: github.repository == 'Kilo-Org/kilocode' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + + - name: Check source-links.md is up to date + run: bun run script/extract-source-links.ts --check diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2b363519d7b..4aabf87953f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -65,6 +65,20 @@ }, "problemMatcher": [] }, + { + "label": "VSCode - Install", + "type": "shell", + "command": "bun", + "args": ["install", "--frozen-lockfile"], + "group": "build", + "presentation": { + "reveal": "silent" + }, + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, { "label": "VSCode - Compile", "type": "shell", @@ -77,6 +91,7 @@ "options": { "cwd": "${workspaceFolder}/packages/kilo-vscode" }, + "dependsOn": ["VSCode - Install"], "problemMatcher": ["$tsc", "$eslint-stylish"] }, { diff --git a/bun.lock b/bun.lock index 5ba57f8c2ed..3f8de6704ad 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -79,7 +79,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -112,7 +112,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -142,7 +142,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -171,7 +171,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.0.51", + "version": "7.1.0", "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.51", + "version": "7.1.0", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -213,7 +213,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -233,7 +233,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", @@ -268,7 +268,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -321,7 +321,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.0.51", + "version": "7.1.0", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -443,7 +443,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@kilocode/sdk": "workspace:*", "zod": "catalog:", @@ -457,14 +457,14 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.0.51", + "version": "7.1.0", "devDependencies": { "@types/bun": "catalog:", }, }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.0.51", + "version": "7.1.0", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -475,7 +475,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.0.51", + "version": "7.1.0", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -498,7 +498,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -545,7 +545,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.0.51", + "version": "7.1.0", "dependencies": { "zod": "catalog:", }, diff --git a/nix/hashes.json b/nix/hashes.json index 6ea6b6b344a..2009eae3304 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-2SnZbJPIvgCkb4jNh49CnbDAOpghgO9XihSiTlL6rYI=", - "aarch64-linux": "sha256-HV/Sm4rBAZPjxG+SQJ95634yTyJXDjlSeYemMYg8eCE=", - "aarch64-darwin": "sha256-PAJSd1VkNc7LUSrOAeG+rmYUw8VefR8GfkAIy8H3iV0=", - "x86_64-darwin": "sha256-Qdk8nu4FoGjp6+7Ji5vuHw2HhM1Z+ivE7meqJivTiHk=" + "x86_64-linux": "sha256-h4RHYUp03Kpy2GCPv5B7pjfcHxZ9M9R475svzkwzpH4=", + "aarch64-linux": "sha256-zLCL5Z5NRvWBfsxnjdMGEWAYBNU120G2/YQ0KFaq+ZA=", + "aarch64-darwin": "sha256-KZPpNosE6S3rW0RSCiADi26ysPIt74TeULQdYF7dDOE=", + "x86_64-darwin": "sha256-XkEYBrRiD1DRhWtQ73afzBNRk0bZHRFpxqAcwnsraE8=" } } diff --git a/nix/node_modules.nix b/nix/node_modules.nix index 98bfbae5bdd..0041d45e443 100644 --- a/nix/node_modules.nix +++ b/nix/node_modules.nix @@ -31,7 +31,6 @@ stdenvNoCC.mkDerivation { ../package.json ../patches ../install # required by desktop build (cli.rs include_str!) - ../.github/TEAM_MEMBERS # required by @opencode-ai/script ] ); }; diff --git a/package.json b/package.json index f4b976a307b..1058a5c3fb5 100644 --- a/package.json +++ b/package.json @@ -112,6 +112,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.51", + "version": "7.1.0", "peerDependencies": {} } diff --git a/packages/app/package.json b/packages/app/package.json index c3a9230a644..6c2929a0cde 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.0.51", + "version": "7.1.0", "description": "", "type": "module", "exports": { diff --git a/packages/app/src/context/language.tsx b/packages/app/src/context/language.tsx index 586d5055072..b49e68aa93f 100644 --- a/packages/app/src/context/language.tsx +++ b/packages/app/src/context/language.tsx @@ -19,6 +19,7 @@ import { dict as no } from "@/i18n/no" import { dict as br } from "@/i18n/br" import { dict as th } from "@/i18n/th" import { dict as bs } from "@/i18n/bs" +import { dict as nl } from "@/i18n/nl" import { dict as tr } from "@/i18n/tr" import { dict as uiEn } from "@opencode-ai/ui/i18n/en" import { dict as uiZh } from "@opencode-ai/ui/i18n/zh" @@ -36,6 +37,7 @@ import { dict as uiNo } from "@opencode-ai/ui/i18n/no" import { dict as uiBr } from "@opencode-ai/ui/i18n/br" import { dict as uiTh } from "@opencode-ai/ui/i18n/th" import { dict as uiBs } from "@opencode-ai/ui/i18n/bs" +import { dict as uiNl } from "@opencode-ai/ui/i18n/nl" import { dict as uiTr } from "@opencode-ai/ui/i18n/tr" // kilocode_change start @@ -55,6 +57,7 @@ import { dict as kiloNo } from "@kilocode/kilo-i18n/no" import { dict as kiloBr } from "@kilocode/kilo-i18n/br" import { dict as kiloTh } from "@kilocode/kilo-i18n/th" import { dict as kiloBs } from "@kilocode/kilo-i18n/bs" +import { dict as kiloNl } from "@kilocode/kilo-i18n/nl" import { dict as kiloTr } from "@kilocode/kilo-i18n/tr" // kilocode_change end @@ -75,6 +78,7 @@ export type Locale = | "br" | "th" | "bs" + | "nl" | "tr" type RawDictionary = typeof en & typeof uiEn & typeof kiloEn // kilocode_change @@ -97,6 +101,7 @@ const LOCALES: readonly Locale[] = [ "pl", "ru", "bs", + "nl", "ar", "no", "br", @@ -121,6 +126,8 @@ const INTL: Record = { br: "pt-BR", th: "th", bs: "bs", + nl: "nl", + tr: "tr", } @@ -141,6 +148,8 @@ const LABEL_KEY: Record = { br: "language.br", th: "language.th", bs: "language.bs", + nl: "language.nl", + tr: "language.tr", } @@ -162,6 +171,7 @@ const DICT: Record = { br: { ...base, ...i18n.flatten({ ...br, ...uiBr, ...kiloBr }) }, th: { ...base, ...i18n.flatten({ ...th, ...uiTh, ...kiloTh }) }, bs: { ...base, ...i18n.flatten({ ...bs, ...uiBs, ...kiloBs }) }, + nl: { ...base, ...i18n.flatten({ ...nl, ...uiNl, ...kiloNl }) }, tr: { ...base, ...i18n.flatten({ ...tr, ...uiTr, ...kiloTr }) }, } @@ -185,6 +195,7 @@ const localeMatchers: Array<{ locale: Locale; match: (language: string) => boole { locale: "br", match: (language) => language.startsWith("pt") }, { locale: "th", match: (language) => language.startsWith("th") }, { locale: "bs", match: (language) => language.startsWith("bs") }, + { locale: "nl", match: (language) => language.startsWith("nl") }, { locale: "tr", match: (language) => language.startsWith("tr") }, ] @@ -205,6 +216,7 @@ const PARITY_CHECK: Record, Record> = { br, th, bs, + nl, tr, } void PARITY_CHECK diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 2e4b92956b8..f4b7589747b 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -402,6 +402,7 @@ export const dict = { "language.no": "Norsk", "language.br": "Português (Brasil)", "language.bs": "Bosanski", + "language.nl": "Nederlands", "language.th": "ไทย", "language.tr": "Türkçe", diff --git a/packages/app/src/i18n/nl.ts b/packages/app/src/i18n/nl.ts new file mode 100644 index 00000000000..376aaa42bbf --- /dev/null +++ b/packages/app/src/i18n/nl.ts @@ -0,0 +1,855 @@ +export const dict = { + "command.category.suggested": "Voorgesteld", + "command.category.view": "Weergave", + "command.category.project": "Project", + "command.category.provider": "Provider", + "command.category.server": "Server", + "command.category.session": "Sessie", + "command.category.theme": "Thema", + "command.category.language": "Taal", + "command.category.file": "Bestand", + "command.category.context": "Context", + "command.category.terminal": "Terminal", + "command.category.model": "Model", + "command.category.mcp": "MCP", + "command.category.agent": "Agent", + "command.category.permissions": "Machtigingen", + "command.category.workspace": "Werkruimte", + "command.category.settings": "Instellingen", + + "theme.scheme.system": "Systeem", + "theme.scheme.light": "Licht", + "theme.scheme.dark": "Donker", + + "command.sidebar.toggle": "Zijbalk in-/uitschakelen", + "command.project.open": "Project openen", + "command.provider.connect": "Provider verbinden", + "command.server.switch": "Server wisselen", + "command.settings.open": "Instellingen openen", + "command.session.previous": "Vorige sessie", + "command.session.next": "Volgende sessie", + "command.session.previous.unseen": "Vorige ongelezen sessie", + "command.session.next.unseen": "Volgende ongelezen sessie", + "command.session.archive": "Sessie archiveren", + + "command.palette": "Opdrachtenpalet", + + "command.theme.cycle": "Volgend thema", + "command.theme.set": "Gebruik thema: {{theme}}", + "command.theme.scheme.cycle": "Volgend kleurenschema", + "command.theme.scheme.set": "Gebruik kleurenschema: {{scheme}}", + + "command.language.cycle": "Volgende taal", + "command.language.set": "Gebruik taal: {{language}}", + + "command.session.new": "Nieuwe sessie", + "command.file.open": "Bestand openen", + "command.tab.close": "Tabblad sluiten", + "command.context.addSelection": "Selectie toevoegen aan context", + "command.context.addSelection.description": "Geselecteerde regels van het huidige bestand toevoegen", + "command.input.focus": "Invoer focussen", + "command.terminal.toggle": "Terminal in-/uitschakelen", + "command.fileTree.toggle": "Bestandsboom in-/uitschakelen", + "command.review.toggle": "Review in-/uitschakelen", + "command.terminal.new": "Nieuwe terminal", + "command.terminal.new.description": "Een nieuw terminal-tabblad maken", + "command.steps.toggle": "Stappen in-/uitschakelen", + "command.steps.toggle.description": "Stappen voor het huidige bericht tonen of verbergen", + "command.message.previous": "Vorig bericht", + "command.message.previous.description": "Ga naar het vorige gebruikersbericht", + "command.message.next": "Volgend bericht", + "command.message.next.description": "Ga naar het volgende gebruikersbericht", + "command.model.choose": "Model kiezen", + "command.model.choose.description": "Selecteer een ander model", + "command.mcp.toggle": "MCPs in-/uitschakelen", + "command.mcp.toggle.description": "MCPs in-/uitschakelen", + "command.agent.cycle": "Volgende agent", + "command.agent.cycle.description": "Overschakelen naar de volgende agent", + "command.agent.cycle.reverse": "Vorige agent", + "command.agent.cycle.reverse.description": "Overschakelen naar de vorige agent", + "command.model.variant.cycle": "Volgende denkinspanning", + "command.model.variant.cycle.description": "Overschakelen naar het volgende inspanningsniveau", + "command.prompt.mode.shell": "Shell", + "command.prompt.mode.normal": "Prompt", + "command.permissions.autoaccept.enable": "Machtigingen automatisch accepteren", + "command.permissions.autoaccept.disable": "Machtigingen niet langer automatisch accepteren", + "command.workspace.toggle": "Werkruimtes in-/uitschakelen", + "command.workspace.toggle.description": "Meerdere werkruimtes in de zijbalk in- of uitschakelen", + "command.session.undo": "Ongedaan maken", + "command.session.undo.description": "Laatste bericht ongedaan maken", + "command.session.redo": "Opnieuw uitvoeren", + "command.session.redo.description": "Het laatst ongedaan gemaakte bericht opnieuw uitvoeren", + "command.session.compact": "Sessie comprimeren", + "command.session.compact.description": "Sessie samenvatten om contextgrootte te verkleinen", + "command.session.fork": "Afsplitsen van bericht", + "command.session.fork.description": "Nieuwe sessie maken van een eerder bericht", + "command.session.share": "Sessie delen", + "command.session.share.description": "Deze sessie delen en de URL naar klembord kopiëren", + "command.session.unshare": "Sessie niet meer delen", + "command.session.unshare.description": "Stoppen met het delen van deze sessie", + + "palette.search.placeholder": "Zoek bestanden, opdrachten en sessies", + "palette.empty": "Geen resultaten gevonden", + "palette.group.commands": "Opdrachten", + "palette.group.files": "Bestanden", + + "dialog.provider.search.placeholder": "Zoek providers", + "dialog.provider.empty": "Geen providers gevonden", + "dialog.provider.group.popular": "Populair", + "dialog.provider.group.other": "Overig", + "dialog.provider.tag.recommended": "Aanbevolen", + "dialog.provider.opencode.note": "Geselecteerde modellen inclusief Claude, GPT, Gemini en meer", + "dialog.provider.opencode.tagline": "Betrouwbare geoptimaliseerde modellen", + "dialog.provider.opencodeGo.tagline": "Goedkoop abonnement voor iedereen", + "dialog.provider.anthropic.note": "Directe toegang tot Claude modellen, inclusief Pro en Max", + "dialog.provider.copilot.note": "AI-modellen voor codeerassistentie via GitHub Copilot", + "dialog.provider.openai.note": "GPT modellen voor snelle, capabele algemene AI-taken", + "dialog.provider.google.note": "Gemini modellen voor snelle, gestructureerde antwoorden", + "dialog.provider.openrouter.note": "Toegang tot alle ondersteunde modellen via één provider", + "dialog.provider.vercel.note": "Geünificeerde toegang tot AI-modellen met slimme routering", + + "dialog.model.select.title": "Selecteer model", + "dialog.model.search.placeholder": "Zoek modellen", + "dialog.model.empty": "Geen modelresultaten", + "dialog.model.manage": "Modellen beheren", + "dialog.model.manage.description": "Pas aan welke modellen in de modelkiezer verschijnen.", + "dialog.model.manage.provider.toggle": "Alle {{provider}} modellen in-/uitschakelen", + + "dialog.model.unpaid.freeModels.title": "Gratis modellen aangeboden door Kilo", + "dialog.model.unpaid.addMore.title": "Meer modellen toevoegen van populaire providers", + + "dialog.provider.viewAll": "Toon meer providers", + + "provider.connect.title": "{{provider}} verbinden", + "provider.connect.title.anthropicProMax": "Inloggen met Claude Pro/Max", + "provider.connect.selectMethod": "Selecteer inlogmethode voor {{provider}}.", + "provider.connect.method.apiKey": "API key", + "provider.connect.status.inProgress": "Autorisatie in uitvoering...", + "provider.connect.status.waiting": "Wachten op autorisatie...", + "provider.connect.status.failed": "Autorisatie mislukt: {{error}}", + "provider.connect.apiKey.description": + "Voer uw {{provider}} API key in om uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.apiKey.label": "{{provider}} API key", + "provider.connect.apiKey.placeholder": "API key", + "provider.connect.apiKey.required": "API key is vereist", + "provider.connect.opencodeZen.line1": + "OpenCode Zen geeft u toegang tot een geselecteerde set betrouwbare en geoptimaliseerde modellen voor coderingsagenten.", + "provider.connect.opencodeZen.line2": + "Met een enkele API key krijgt u toegang tot modellen zoals Claude, GPT, Gemini, GLM en meer.", + "provider.connect.opencodeZen.visit.prefix": "Bezoek ", + "provider.connect.opencodeZen.visit.link": "opencode.ai/zen", + "provider.connect.opencodeZen.visit.suffix": " om uw API key te verkrijgen.", + "provider.connect.oauth.code.visit.prefix": "Bezoek ", + "provider.connect.oauth.code.visit.link": "deze link", + "provider.connect.oauth.code.visit.suffix": + " om uw autorisatiecode te verkrijgen, uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.oauth.code.label": "{{method}} autorisatiecode", + "provider.connect.oauth.code.placeholder": "Autorisatiecode", + "provider.connect.oauth.code.required": "Autorisatiecode is vereist", + "provider.connect.oauth.code.invalid": "Ongeldige autorisatiecode", + "provider.connect.oauth.auto.visit.prefix": "Bezoek ", + "provider.connect.oauth.auto.visit.link": "deze link", + "provider.connect.oauth.auto.visit.suffix": + " en voer de onderstaande code in om uw account te verbinden en {{provider}} modellen te gebruiken in Kilo.", + "provider.connect.oauth.auto.confirmationCode": "Bevestigingscode", + "provider.connect.toast.connected.title": "{{provider}} verbonden", + "provider.connect.toast.connected.description": "{{provider}} modellen zijn nu beschikbaar om te gebruiken.", + + "provider.custom.title": "Aangepaste provider", + "provider.custom.description.prefix": "Configureer een OpenAI-compatibele provider. Zie de ", + "provider.custom.description.link": "provider configuratiedocumentatie", + "provider.custom.description.suffix": ".", + "provider.custom.field.providerID.label": "Provider ID", + "provider.custom.field.providerID.placeholder": "myprovider", + "provider.custom.field.providerID.description": "Kleine letters, cijfers, koppeltekens of underscores", + "provider.custom.field.name.label": "Weergavenaam", + "provider.custom.field.name.placeholder": "Mijn AI Provider", + "provider.custom.field.baseURL.label": "Basis-URL", + "provider.custom.field.baseURL.placeholder": "https://api.myprovider.com/v1", + "provider.custom.field.apiKey.label": "API key", + "provider.custom.field.apiKey.placeholder": "API key", + "provider.custom.field.apiKey.description": "Optioneel. Laat leeg als u auth via headers beheert.", + "provider.custom.models.label": "Modellen", + "provider.custom.models.id.label": "ID", + "provider.custom.models.id.placeholder": "model-id", + "provider.custom.models.name.label": "Naam", + "provider.custom.models.name.placeholder": "Weergavenaam", + "provider.custom.models.remove": "Model verwijderen", + "provider.custom.models.add": "Model toevoegen", + "provider.custom.headers.label": "Headers (optioneel)", + "provider.custom.headers.key.label": "Header", + "provider.custom.headers.key.placeholder": "Header-Naam", + "provider.custom.headers.value.label": "Waarde", + "provider.custom.headers.value.placeholder": "waarde", + "provider.custom.headers.remove": "Header verwijderen", + "provider.custom.headers.add": "Header toevoegen", + "provider.custom.error.providerID.required": "Provider ID is vereist", + "provider.custom.error.providerID.format": "Gebruik kleine letters, cijfers, koppeltekens of underscores", + "provider.custom.error.providerID.exists": "Deze provider ID bestaat al", + "provider.custom.error.name.required": "Weergavenaam is vereist", + "provider.custom.error.baseURL.required": "Basis-URL is vereist", + "provider.custom.error.baseURL.format": "Moet beginnen met http:// of https://", + "provider.custom.error.required": "Vereist", + "provider.custom.error.duplicate": "Duplicaat", + + "provider.disconnect.toast.disconnected.title": "{{provider}} losgekoppeld", + "provider.disconnect.toast.disconnected.description": "{{provider}} modellen zijn niet langer beschikbaar.", + + "model.tag.free": "Gratis", + "model.tag.latest": "Nieuwste", + "model.provider.anthropic": "Anthropic", + "model.provider.openai": "OpenAI", + "model.provider.google": "Google", + "model.provider.xai": "xAI", + "model.provider.meta": "Meta", + "model.input.text": "tekst", + "model.input.image": "afbeelding", + "model.input.audio": "audio", + "model.input.video": "video", + "model.input.pdf": "pdf", + "model.tooltip.allows": "Staat toe: {{inputs}}", + "model.tooltip.reasoning.allowed": "Staat redenering toe", + "model.tooltip.reasoning.none": "Geen redenering", + "model.tooltip.context": "Contextlimiet {{limit}}", + + "common.search.placeholder": "Zoeken", + "common.goBack": "Ga terug", + "common.goForward": "Ga vooruit", + "common.loading": "Laden", + "common.loading.ellipsis": "...", + "common.cancel": "Annuleren", + "common.open": "Openen", + "common.connect": "Verbinden", + "common.disconnect": "Loskoppelen", + "common.submit": "Verzenden", + "common.save": "Opslaan", + "common.saving": "Opslaan...", + "common.default": "Standaard", + "common.attachment": "bijlage", + + "prompt.placeholder.shell": "Voer shell-opdracht in...", + "prompt.placeholder.normal": 'Vraag alles... "{{example}}"', + "prompt.placeholder.simple": "Vraag alles...", + "prompt.placeholder.summarizeComments": "Reacties samenvatten...", + "prompt.placeholder.summarizeComment": "Reactie samenvatten...", + "prompt.mode.shell": "Shell", + "prompt.mode.normal": "Prompt", + "prompt.mode.shell.exit": "esc om te verlaten", + + "prompt.example.1": "Fix een TODO in de codebase", + "prompt.example.2": "Wat is de tech stack van dit project?", + "prompt.example.3": "Repareer kapotte tests", + "prompt.example.4": "Leg uit hoe authenticatie werkt", + "prompt.example.5": "Vind en herstel beveiligingskwetsbaarheden", + "prompt.example.6": "Voeg unittests toe voor de gebruikersservice", + "prompt.example.7": "Herschrijf deze functie om deze beter leesbaar te maken", + "prompt.example.8": "Wat betekent deze fout?", + "prompt.example.9": "Help me met het debuggen van dit probleem", + "prompt.example.10": "Genereer API-documentatie", + "prompt.example.11": "Optimaliseer databasequery's", + "prompt.example.12": "Voeg invoervalidatie toe", + "prompt.example.13": "Maak een nieuwe component voor...", + "prompt.example.14": "Hoe implementeer ik dit project?", + "prompt.example.15": "Bekijk mijn code voor best practices", + "prompt.example.16": "Voeg foutafhandeling toe aan deze functie", + "prompt.example.17": "Leg dit regex-patroon uit", + "prompt.example.18": "Zet dit om naar TypeScript", + "prompt.example.19": "Voeg logging toe in de hele codebase", + "prompt.example.20": "Welke afhankelijkheden zijn verouderd?", + "prompt.example.21": "Help me een migratiescript te schrijven", + "prompt.example.22": "Implementeer caching voor dit eindpunt", + "prompt.example.23": "Voeg paginering toe aan deze lijst", + "prompt.example.24": "Maak een CLI-opdracht voor...", + "prompt.example.25": "Hoe werken omgevingsvariabelen hier?", + + "prompt.popover.emptyResults": "Geen overeenkomende resultaten", + "prompt.popover.emptyCommands": "Geen overeenkomende opdrachten", + "prompt.dropzone.label": "Sleep afbeeldingen of PDF's hierheen", + "prompt.dropzone.file.label": "Sleep om bestand te @vermelden", + "prompt.slash.badge.custom": "aangepast", + "prompt.slash.badge.skill": "skill", + "prompt.slash.badge.mcp": "mcp", + "prompt.context.active": "actief", + "prompt.context.includeActiveFile": "Neem actief bestand op", + "prompt.context.removeActiveFile": "Verwijder actief bestand uit context", + "prompt.context.removeFile": "Verwijder bestand uit context", + "prompt.action.attachFile": "Bestand toevoegen", + "prompt.attachment.remove": "Bijlage verwijderen", + "prompt.action.send": "Verzenden", + "prompt.action.stop": "Stop", + + "prompt.toast.pasteUnsupported.title": "Niet-ondersteunde plakbewerking", + "prompt.toast.pasteUnsupported.description": "Hier kunnen alleen afbeeldingen of PDF's worden geplakt.", + "prompt.toast.modelAgentRequired.title": "Selecteer een agent en model", + "prompt.toast.modelAgentRequired.description": "Kies een agent en model voordat u een prompt verzendt.", + "prompt.toast.worktreeCreateFailed.title": "Maken van worktree mislukt", + "prompt.toast.sessionCreateFailed.title": "Maken van sessie mislukt", + "prompt.toast.shellSendFailed.title": "Verzenden van shell-opdracht mislukt", + "prompt.toast.commandSendFailed.title": "Verzenden van opdracht mislukt", + "prompt.toast.promptSendFailed.title": "Verzenden van prompt mislukt", + "prompt.toast.promptSendFailed.description": "Kan sessie niet ophalen", + + "dialog.mcp.title": "MCPs", + "dialog.mcp.description": "{{enabled}} van {{total}} ingeschakeld", + "dialog.mcp.empty": "Geen MCP's geconfigureerd", + + "dialog.lsp.empty": "LSP's automatisch gedetecteerd aan de hand van bestandstypen", + "dialog.plugins.empty": "Plug-ins geconfigureerd in opencode.json", + + "mcp.status.connected": "verbonden", + "mcp.status.failed": "mislukt", + "mcp.status.needs_auth": "authenticatie vereist", + "mcp.status.disabled": "uitgeschakeld", + + "dialog.fork.empty": "Geen berichten om van af te splitsen", + + "dialog.directory.search.placeholder": "Zoek mappen", + "dialog.directory.empty": "Geen mappen gevonden", + + "dialog.server.title": "Servers", + "dialog.server.description": "Wissel met welke Kilo server deze app verbindt.", + "dialog.server.search.placeholder": "Zoek servers", + "dialog.server.empty": "Nog geen servers", + "dialog.server.add.title": "Server toevoegen", + "dialog.server.add.url": "Serveradres", + "dialog.server.add.placeholder": "http://localhost:4096", + "dialog.server.add.error": "Kan geen verbinding maken met server", + "dialog.server.add.checking": "Controleren...", + "dialog.server.add.button": "Server toevoegen", + "dialog.server.add.name": "Servernaam (optioneel)", + "dialog.server.add.namePlaceholder": "Localhost", + "dialog.server.add.username": "Gebruikersnaam (optioneel)", + "dialog.server.add.password": "Wachtwoord (optioneel)", + "dialog.server.edit.title": "Server bewerken", + "dialog.server.default.title": "Standaardserver", + "dialog.server.default.description": + "Maak verbinding met deze server bij de lancering van de app in plaats van een lokale server te starten. Vereist een herstart.", + "dialog.server.default.none": "Geen server geselecteerd", + "dialog.server.default.set": "Huidige server als standaard instellen", + "dialog.server.default.clear": "Wissen", + "dialog.server.action.remove": "Server verwijderen", + + "dialog.server.menu.edit": "Bewerken", + "dialog.server.menu.default": "Als standaard instellen", + "dialog.server.menu.defaultRemove": "Standaard verwijderen", + "dialog.server.menu.delete": "Verwijderen", + "dialog.server.current": "Huidige Server", + "dialog.server.status.default": "Standaard", + + "dialog.project.edit.title": "Project bewerken", + "dialog.project.edit.name": "Naam", + "dialog.project.edit.icon": "Icoon", + "dialog.project.edit.icon.alt": "Projecticoon", + "dialog.project.edit.icon.hint": "Klik of sleep een afbeelding", + "dialog.project.edit.icon.recommended": "Aanbevolen: 128x128px", + "dialog.project.edit.color": "Kleur", + "dialog.project.edit.color.select": "Selecteer {{color}} kleur", + "dialog.project.edit.worktree.startup": "Werkruimte opstartscript", + "dialog.project.edit.worktree.startup.description": + "Wordt uitgevoerd na het maken van een nieuwe werkruimte (worktree).", + "dialog.project.edit.worktree.startup.placeholder": "bijv. bun install", + + "dialog.releaseNotes.action.getStarted": "Aan de slag", + "dialog.releaseNotes.action.next": "Volgende", + "dialog.releaseNotes.action.hideFuture": "Toon deze niet in de toekomst", + "dialog.releaseNotes.media.alt": "Releasevoorbeeld", + + "context.breakdown.title": "Contextverdeling", + "context.breakdown.note": 'Geschatte verdeling van invoertokens. "Overig" bevat tooldefinities en overhead.', + "context.breakdown.system": "Systeem", + "context.breakdown.user": "Gebruiker", + "context.breakdown.assistant": "Assistent", + "context.breakdown.tool": "Tool-aanroepen", + "context.breakdown.other": "Overig", + + "context.systemPrompt.title": "Systeemprompt", + "context.rawMessages.title": "Ruwe berichten", + + "context.stats.session": "Sessie", + "context.stats.messages": "Berichten", + "context.stats.provider": "Provider", + "context.stats.model": "Model", + "context.stats.limit": "Contextlimiet", + "context.stats.totalTokens": "Totaal Tokens", + "context.stats.usage": "Gebruik", + "context.stats.inputTokens": "Invoertokens", + "context.stats.outputTokens": "Uitvoertokens", + "context.stats.reasoningTokens": "Redeneertokens", + "context.stats.cacheTokens": "Cachetokens (lezen/schrijven)", + "context.stats.userMessages": "Gebruikersberichten", + "context.stats.assistantMessages": "Assistentberichten", + "context.stats.totalCost": "Totale Kosten", + "context.stats.sessionCreated": "Sessie Aangemaakt", + "context.stats.lastActivity": "Laatste Activiteit", + + "context.usage.tokens": "Tokens", + "context.usage.usage": "Gebruik", + "context.usage.cost": "Kosten", + "context.usage.clickToView": "Klik om context te bekijken", + "context.usage.view": "Contextgebruik bekijken", + + "language.en": "English", + "language.zh": "简体中文", + "language.zht": "繁體中文", + "language.ko": "한국어", + "language.de": "Deutsch", + "language.es": "Español", + "language.fr": "Français", + "language.da": "Dansk", + "language.ja": "日本語", + "language.pl": "Polski", + "language.ru": "Русский", + "language.ar": "العربية", + "language.no": "Norsk", + "language.br": "Português (Brasil)", + "language.bs": "Bosanski", + "language.nl": "Nederlands", + "language.th": "ไทย", + "language.tr": "Türkçe", + + "toast.language.title": "Taal", + "toast.language.description": "Omgeschakeld naar {{language}}", + + "toast.theme.title": "Thema gewisseld", + "toast.scheme.title": "Kleurenschema", + + "toast.workspace.enabled.title": "Werkruimtes ingeschakeld", + "toast.workspace.enabled.description": "Meerdere worktrees worden nu weergegeven in de zijbalk", + "toast.workspace.disabled.title": "Werkruimtes uitgeschakeld", + "toast.workspace.disabled.description": "Alleen de hoofdworktree wordt weergegeven in de zijbalk", + + "toast.permissions.autoaccept.on.title": "Machtigingen automatisch accepteren", + "toast.permissions.autoaccept.on.description": "Toestemmingsverzoeken worden automatisch goedgekeurd", + "toast.permissions.autoaccept.off.title": "Gestopt met automatisch accepteren van machtigingen", + "toast.permissions.autoaccept.off.description": "Toestemmingsverzoeken vereisen goedkeuring", + + "toast.model.none.title": "Geen model geselecteerd", + "toast.model.none.description": "Verbind een provider om deze sessie samen te vatten", + + "toast.file.loadFailed.title": "Laden van bestand mislukt", + "toast.file.listFailed.title": "Lijst met bestanden ophalen mislukt", + + "toast.context.noLineSelection.title": "Geen regelselectie", + "toast.context.noLineSelection.description": "Selecteer eerst een regelbereik in een bestandstabblad.", + + "toast.session.share.copyFailed.title": "Kopiëren van URL naar klembord mislukt", + "toast.session.share.success.title": "Sessie gedeeld", + "toast.session.share.success.description": "Deel-URL naar klembord gekopieerd!", + "toast.session.share.failed.title": "Delen van sessie mislukt", + "toast.session.share.failed.description": "Er is een fout opgetreden bij het delen van de sessie", + + "toast.session.unshare.success.title": "Sessie niet meer gedeeld", + "toast.session.unshare.success.description": "Sessie succesvol niet meer gedeeld!", + "toast.session.unshare.failed.title": "Sessie niet meer delen mislukt", + "toast.session.unshare.failed.description": + "Er is een fout opgetreden bij het ongedaan maken van delen van de sessie", + + "toast.session.listFailed.title": "Laden van sessies voor {{project}} mislukt", + "toast.project.reloadFailed.title": "Herladen van {{project}} mislukt", + + "toast.update.title": "Update beschikbaar", + "toast.update.description": "Een nieuwe versie van Kilo ({{version}}) is nu beschikbaar om te installeren.", + "toast.update.action.installRestart": "Installeren en herstarten", + "toast.update.action.notYet": "Nog niet", + + "error.page.title": "Er is iets misgegaan", + "error.page.description": "Er is een fout opgetreden tijdens het laden van de applicatie.", + "error.page.details.label": "Foutdetails", + "error.page.action.restart": "Herstarten", + "error.page.action.checking": "Controleren...", + "error.page.action.checkUpdates": "Controleren op updates", + "error.page.action.updateTo": "Updaten naar {{version}}", + "error.page.report.prefix": "Meld deze fout alstublieft aan het Kilo team", + "error.page.report.discord": "op Discord", + "error.page.version": "Versie: {{version}}", + + "error.dev.rootNotFound": + "Root-element niet gevonden. Bent u vergeten dit toe te voegen aan uw index.html? Of misschien is het id-attribuut verkeerd gespeld?", + + "error.globalSync.connectFailed": "Kon geen verbinding maken met server. Draait er een server op `{{url}}`?", + "directory.error.invalidUrl": "Ongeldige map in URL.", + + "error.chain.unknown": "Onbekende fout", + "error.server.invalidConfiguration": "Ongeldige configuratie", + "error.chain.causedBy": "Veroorzaakt door:", + "error.chain.apiError": "API-fout", + "error.chain.status": "Status: {{status}}", + "error.chain.retryable": "Opnieuw te proberen: {{retryable}}", + "error.chain.responseBody": "Reactie-body:\n{{body}}", + "error.chain.didYouMean": "Bedoelde u: {{suggestions}}", + "error.chain.modelNotFound": "Model niet gevonden: {{provider}}/{{model}}", + "error.chain.checkConfig": "Controleer uw config (opencode.json) provider/modelnamen", + "error.chain.mcpFailed": 'MCP-server "{{name}}" is mislukt. Let op, Kilo ondersteunt nog geen MCP-authenticatie.', + "error.chain.providerAuthFailed": "Providerauthenticatie mislukt ({{provider}}): {{message}}", + "error.chain.providerInitFailed": + 'Initialiseren van provider "{{provider}}" mislukt. Controleer referenties en configuratie.', + "error.chain.configJsonInvalid": "Configuratiebestand op {{path}} is geen geldige JSON(C)", + "error.chain.configJsonInvalidWithMessage": "Configuratiebestand op {{path}} is geen geldige JSON(C): {{message}}", + "error.chain.configDirectoryTypo": + 'Map "{{dir}}" in {{path}} is niet geldig. Hernoem de map naar "{{suggestion}}" of verwijder deze. Dit is een veelvoorkomende typfout.', + "error.chain.configFrontmatterError": "Parsen van frontmatter mislukt in {{path}}:\n{{message}}", + "error.chain.configInvalid": "Configuratiebestand op {{path}} is ongeldig", + "error.chain.configInvalidWithMessage": "Configuratiebestand op {{path}} is ongeldig: {{message}}", + + "notification.permission.title": "Machtiging vereist", + "notification.permission.description": "{{sessionTitle}} in {{projectName}} heeft machtiging nodig", + "notification.question.title": "Vraag", + "notification.question.description": "{{sessionTitle}} in {{projectName}} heeft een vraag", + "notification.action.goToSession": "Ga naar sessie", + + "notification.session.responseReady.title": "Antwoord gereed", + "notification.session.error.title": "Sessiefout", + "notification.session.error.fallbackDescription": "Er is een fout opgetreden", + + "home.recentProjects": "Recente projecten", + "home.empty.title": "Geen recente projecten", + "home.empty.description": "Ga aan de slag door een lokaal project te openen", + + "session.tab.session": "Sessie", + "session.tab.review": "Review", + "session.tab.context": "Context", + "session.panel.reviewAndFiles": "Review en bestanden", + "session.review.filesChanged": "{{count}} Bestanden Gewijzigd", + "session.review.change.one": "Wijziging", + "session.review.change.other": "Wijzigingen", + "session.review.loadingChanges": "Wijzigingen laden...", + "session.review.empty": "Nog geen wijzigingen in deze sessie", + "session.review.noVcs": "Geen Git Version Control System gedetecteerd, wijzigingen niet weergegeven", + "session.review.noSnapshot": + "Snapshot-tracking is uitgeschakeld in configuratie, dus sessiewijzigingen zijn niet beschikbaar", + "session.review.noChanges": "Geen wijzigingen", + + "session.files.selectToOpen": "Selecteer een bestand om te openen", + "session.files.all": "Alle bestanden", + "session.files.empty": "Geen bestanden", + "session.files.binaryContent": "Binair bestand (inhoud kan niet worden weergegeven)", + + "session.messages.renderEarlier": "Eerdere berichten renderen", + "session.messages.loadingEarlier": "Eerdere berichten laden...", + "session.messages.loadEarlier": "Eerdere berichten laden", + "session.messages.loading": "Berichten laden...", + "session.messages.jumpToLatest": "Spring naar nieuwste", + + "session.context.addToContext": "Voeg {{selection}} toe aan context", + "session.todo.title": "To-do's", + "session.todo.collapse": "Inklappen", + "session.todo.expand": "Uitklappen", + + "session.new.title": "Bouw wat u wilt", + "session.new.worktree.main": "Hoofdbranch", + "session.new.worktree.mainWithBranch": "Hoofdbranch ({{branch}})", + "session.new.worktree.create": "Nieuwe worktree maken", + "session.new.lastModified": "Laatst gewijzigd", + + "session.header.search.placeholder": "Zoek {{project}}", + "session.header.searchFiles": "Zoek bestanden", + "session.header.openIn": "Openen in", + "session.header.open.action": "Open {{app}}", + "session.header.open.ariaLabel": "Openen in {{app}}", + "session.header.open.menu": "Open-opties", + "session.header.open.copyPath": "Pad kopiëren", + + "status.popover.trigger": "Status", + "status.popover.ariaLabel": "Serverconfiguraties", + "status.popover.tab.servers": "Servers", + "status.popover.tab.mcp": "MCP", + "status.popover.tab.lsp": "LSP", + "status.popover.tab.plugins": "Plug-ins", + "status.popover.action.manageServers": "Servers beheren", + + "session.share.popover.title": "Op web publiceren", + "session.share.popover.description.shared": + "Deze sessie is openbaar op het web. Het is toegankelijk voor iedereen met de link.", + "session.share.popover.description.unshared": + "Sessie openbaar delen op het web. Het zal toegankelijk zijn voor iedereen met de link.", + "session.share.action.share": "Delen", + "session.share.action.publish": "Publiceren", + "session.share.action.publishing": "Publiceren...", + "session.share.action.unpublish": "Publicatie ongedaan maken", + "session.share.action.unpublishing": "Publicatie ongedaan maken...", + "session.share.action.view": "Bekijken", + "session.share.copy.copied": "Gekopieerd", + "session.share.copy.copyLink": "Link kopiëren", + + "lsp.tooltip.none": "Geen LSP-servers", + "lsp.label.connected": "{{count}} LSP", + + "prompt.loading": "Prompt laden...", + "terminal.loading": "Terminal laden...", + "terminal.title": "Terminal", + "terminal.title.numbered": "Terminal {{number}}", + "terminal.close": "Terminal sluiten", + "terminal.connectionLost.title": "Verbinding verbroken", + "terminal.connectionLost.description": + "De terminalverbinding is onderbroken. Dit kan gebeuren wanneer de server herstart.", + + "common.closeTab": "Tabblad sluiten", + "common.dismiss": "Negeren", + "common.moreCountSuffix": " (nog +{{count}})", + "common.requestFailed": "Verzoek mislukt", + "common.moreOptions": "Meer opties", + "common.learnMore": "Meer informatie", + "common.rename": "Hernoemen", + "common.reset": "Reset", + "common.archive": "Archiveren", + "common.delete": "Verwijderen", + "common.close": "Sluiten", + "common.edit": "Bewerken", + "common.loadMore": "Meer laden", + "common.key.esc": "ESC", + + "common.time.justNow": "Zojuist", + "common.time.minutesAgo.short": "{{count}}m geleden", + "common.time.hoursAgo.short": "{{count}}u geleden", + "common.time.daysAgo.short": "{{count}}d geleden", + + "sidebar.menu.toggle": "Menu in-/uitschakelen", + "sidebar.nav.projectsAndSessions": "Projecten en sessies", + "sidebar.settings": "Instellingen", + "sidebar.help": "Help", + "sidebar.workspaces.enable": "Werkruimtes inschakelen", + "sidebar.workspaces.disable": "Werkruimtes uitschakelen", + "sidebar.gettingStarted.title": "Aan de slag", + "sidebar.gettingStarted.line1": "Kilo bevat gratis modellen zodat u direct kunt beginnen.", + "sidebar.gettingStarted.line2": "Verbind een provider om modellen te gebruiken, incl. Claude, GPT, Gemini etc.", + "sidebar.project.recentSessions": "Recente sessies", + "sidebar.project.viewAllSessions": "Bekijk alle sessies", + "sidebar.project.clearNotifications": "Meldingen wissen", + + "app.name.desktop": "Kilo Desktop", + + "settings.section.desktop": "Desktop", + "settings.section.server": "Server", + "settings.tab.general": "Algemeen", + "settings.tab.shortcuts": "Sneltoetsen", + "settings.desktop.section.wsl": "WSL", + "settings.desktop.wsl.title": "WSL-integratie", + "settings.desktop.wsl.description": "Draai de Kilo server binnen WSL op Windows.", + + "settings.general.section.appearance": "Uiterlijk", + "settings.general.section.notifications": "Systeemmeldingen", + "settings.general.section.updates": "Updates", + "settings.general.section.sounds": "Geluidseffecten", + "settings.general.section.feed": "Feed", + "settings.general.section.display": "Weergave", + + "settings.general.row.language.title": "Taal", + "settings.general.row.language.description": "Wijzig de weergavetaal voor Kilo", + "settings.general.row.appearance.title": "Uiterlijk", + "settings.general.row.appearance.description": "Pas aan hoe Kilo eruitziet op uw apparaat", + "settings.general.row.theme.title": "Thema", + "settings.general.row.theme.description": "Pas het thema van Kilo aan.", + "settings.general.row.font.title": "Lettertype", + "settings.general.row.font.description": "Pas het monospace-lettertype in codeblokken aan", + "settings.general.row.reasoningSummaries.title": "Redeneersamenvattingen weergeven", + "settings.general.row.reasoningSummaries.description": "Toon model-redeneersamenvattingen in de tijdlijn", + "settings.general.row.shellToolPartsExpanded.title": "Shell-toolonderdelen uitklappen", + "settings.general.row.shellToolPartsExpanded.description": + "Toon shell-toolonderdelen standaard uitgeklapt in de tijdlijn", + "settings.general.row.editToolPartsExpanded.title": "Bewerk-toolonderdelen uitklappen", + "settings.general.row.editToolPartsExpanded.description": + "Toon bewerk-, schrijf- en patch-toolonderdelen standaard uitgeklapt in de tijdlijn", + + "settings.general.row.wayland.title": "Gebruik native Wayland", + "settings.general.row.wayland.description": "Schakel X11-terugval uit op Wayland. Vereist een herstart.", + "settings.general.row.wayland.tooltip": + "Op Linux met monitoren met gemengde verversingssnelheden kan native Wayland stabieler zijn.", + + "settings.general.row.releaseNotes.title": "Release notes", + "settings.general.row.releaseNotes.description": "Toon Wat is nieuw pop-ups na updates", + + "settings.updates.row.startup.title": "Controleren op updates bij opstarten", + "settings.updates.row.startup.description": "Automatisch op updates controleren wanneer Kilo start", + "settings.updates.row.check.title": "Controleren op updates", + "settings.updates.row.check.description": "Handmatig op updates controleren en installeren indien beschikbaar", + "settings.updates.action.checkNow": "Nu controleren", + "settings.updates.action.checking": "Controleren...", + "settings.updates.toast.latest.title": "U bent up-to-date", + "settings.updates.toast.latest.description": "U draait de nieuwste versie van Kilo.", + "font.option.ibmPlexMono": "IBM Plex Mono", + "font.option.cascadiaCode": "Cascadia Code", + "font.option.firaCode": "Fira Code", + "font.option.hack": "Hack", + "font.option.inconsolata": "Inconsolata", + "font.option.intelOneMono": "Intel One Mono", + "font.option.iosevka": "Iosevka", + "font.option.jetbrainsMono": "JetBrains Mono", + "font.option.mesloLgs": "Meslo LGS", + "font.option.robotoMono": "Roboto Mono", + "font.option.sourceCodePro": "Source Code Pro", + "font.option.ubuntuMono": "Ubuntu Mono", + "font.option.geistMono": "Geist Mono", + "sound.option.none": "Geen", + "sound.option.alert01": "Melding 01", + "sound.option.alert02": "Melding 02", + "sound.option.alert03": "Melding 03", + "sound.option.alert04": "Melding 04", + "sound.option.alert05": "Melding 05", + "sound.option.alert06": "Melding 06", + "sound.option.alert07": "Melding 07", + "sound.option.alert08": "Melding 08", + "sound.option.alert09": "Melding 09", + "sound.option.alert10": "Melding 10", + "sound.option.bipbop01": "Bip-bop 01", + "sound.option.bipbop02": "Bip-bop 02", + "sound.option.bipbop03": "Bip-bop 03", + "sound.option.bipbop04": "Bip-bop 04", + "sound.option.bipbop05": "Bip-bop 05", + "sound.option.bipbop06": "Bip-bop 06", + "sound.option.bipbop07": "Bip-bop 07", + "sound.option.bipbop08": "Bip-bop 08", + "sound.option.bipbop09": "Bip-bop 09", + "sound.option.bipbop10": "Bip-bop 10", + "sound.option.staplebops01": "Staplebops 01", + "sound.option.staplebops02": "Staplebops 02", + "sound.option.staplebops03": "Staplebops 03", + "sound.option.staplebops04": "Staplebops 04", + "sound.option.staplebops05": "Staplebops 05", + "sound.option.staplebops06": "Staplebops 06", + "sound.option.staplebops07": "Staplebops 07", + "sound.option.nope01": "Nee 01", + "sound.option.nope02": "Nee 02", + "sound.option.nope03": "Nee 03", + "sound.option.nope04": "Nee 04", + "sound.option.nope05": "Nee 05", + "sound.option.nope06": "Nee 06", + "sound.option.nope07": "Nee 07", + "sound.option.nope08": "Nee 08", + "sound.option.nope09": "Nee 09", + "sound.option.nope10": "Nee 10", + "sound.option.nope11": "Nee 11", + "sound.option.nope12": "Nee 12", + "sound.option.yup01": "Ja 01", + "sound.option.yup02": "Ja 02", + "sound.option.yup03": "Ja 03", + "sound.option.yup04": "Ja 04", + "sound.option.yup05": "Ja 05", + "sound.option.yup06": "Ja 06", + + "settings.general.notifications.agent.title": "Agent", + "settings.general.notifications.agent.description": + "Toon systeemmelding wanneer de agent klaar is of aandacht nodig heeft", + "settings.general.notifications.permissions.title": "Machtigingen", + "settings.general.notifications.permissions.description": "Toon systeemmelding wanneer een machtiging vereist is", + "settings.general.notifications.errors.title": "Fouten", + "settings.general.notifications.errors.description": "Toon systeemmelding wanneer er een fout optreedt", + + "settings.general.sounds.agent.title": "Agent", + "settings.general.sounds.agent.description": "Speel geluid af wanneer de agent klaar is of aandacht nodig heeft", + "settings.general.sounds.permissions.title": "Machtigingen", + "settings.general.sounds.permissions.description": "Speel geluid af wanneer een machtiging vereist is", + "settings.general.sounds.errors.title": "Fouten", + "settings.general.sounds.errors.description": "Speel geluid af wanneer er een fout optreedt", + + "settings.shortcuts.title": "Sneltoetsen", + "settings.shortcuts.reset.button": "Terugzetten naar standaard", + "settings.shortcuts.reset.toast.title": "Sneltoetsen gereset", + "settings.shortcuts.reset.toast.description": "Sneltoetsen zijn teruggezet naar de standaardwaarden.", + "settings.shortcuts.conflict.title": "Sneltoets al in gebruik", + "settings.shortcuts.conflict.description": "{{keybind}} is al toegewezen aan {{titles}}.", + "settings.shortcuts.unassigned": "Niet toegewezen", + "settings.shortcuts.pressKeys": "Druk op toetsen", + "settings.shortcuts.search.placeholder": "Zoek sneltoetsen", + "settings.shortcuts.search.empty": "Geen sneltoetsen gevonden", + + "settings.shortcuts.group.general": "Algemeen", + "settings.shortcuts.group.session": "Sessie", + "settings.shortcuts.group.navigation": "Navigatie", + "settings.shortcuts.group.modelAndAgent": "Model en agent", + "settings.shortcuts.group.terminal": "Terminal", + "settings.shortcuts.group.prompt": "Prompt", + + "settings.providers.title": "Providers", + "settings.providers.description": "Provider-instellingen kunnen hier worden geconfigureerd.", + "settings.providers.section.connected": "Verbonden providers", + "settings.providers.connected.empty": "Geen verbonden providers", + "settings.providers.connected.environmentDescription": "Verbonden vanuit uw omgevingsvariabelen", + "settings.providers.section.popular": "Populaire providers", + "settings.providers.custom.description": "Voeg een OpenAI-compatibele provider toe via basis-URL.", + "settings.providers.tag.environment": "Omgeving", + "settings.providers.tag.config": "Config", + "settings.providers.tag.custom": "Aangepast", + "settings.providers.tag.other": "Overig", + "settings.models.title": "Modellen", + "settings.models.description": "Model-instellingen kunnen hier worden geconfigureerd.", + "settings.agents.title": "Agenten", + "settings.agents.description": "Agent-instellingen kunnen hier worden geconfigureerd.", + "settings.commands.title": "Opdrachten", + "settings.commands.description": "Opdracht-instellingen kunnen hier worden geconfigureerd.", + "settings.mcp.title": "MCP", + "settings.mcp.description": "MCP-instellingen kunnen hier worden geconfigureerd.", + + "settings.permissions.title": "Machtigingen", + "settings.permissions.description": "Bepaal welke tools de server standaard mag gebruiken.", + "settings.permissions.section.tools": "Tools", + "settings.permissions.toast.updateFailed.title": "Bijwerken van machtigingen mislukt", + + "settings.permissions.action.allow": "Toestaan", + "settings.permissions.action.ask": "Vragen", + "settings.permissions.action.deny": "Weigeren", + + "settings.permissions.tool.read.title": "Lezen (Read)", + "settings.permissions.tool.read.description": "Een bestand lezen (komt overeen met het bestandspad)", + "settings.permissions.tool.edit.title": "Bewerken (Edit)", + "settings.permissions.tool.edit.description": + "Bestanden wijzigen, inclusief bewerkingen, wegschrijven, patches en multi-edits", + "settings.permissions.tool.glob.title": "Glob", + "settings.permissions.tool.glob.description": "Bestanden matchen met glob-patronen", + "settings.permissions.tool.grep.title": "Grep", + "settings.permissions.tool.grep.description": "Bestandsinhoud doorzoeken met behulp van reguliere expressies", + "settings.permissions.tool.list.title": "Lijst (List)", + "settings.permissions.tool.list.description": "Bestanden in een map weergeven", + "settings.permissions.tool.bash.title": "Bash", + "settings.permissions.tool.bash.description": "Shell-opdrachten uitvoeren", + "settings.permissions.tool.task.title": "Taak (Task)", + "settings.permissions.tool.task.description": "Sub-agenten lanceren", + "settings.permissions.tool.skill.title": "Skill", + "settings.permissions.tool.skill.description": "Een skill laden op naam", + "settings.permissions.tool.lsp.title": "LSP", + "settings.permissions.tool.lsp.description": "Language server query's uitvoeren", + "settings.permissions.tool.todoread.title": "To-do lezen (Todo Read)", + "settings.permissions.tool.todoread.description": "De to-do lijst lezen", + "settings.permissions.tool.todowrite.title": "To-do schrijven (Todo Write)", + "settings.permissions.tool.todowrite.description": "De to-do lijst bijwerken", + "settings.permissions.tool.webfetch.title": "Web ophalen (Web Fetch)", + "settings.permissions.tool.webfetch.description": "Inhoud ophalen van een URL", + "settings.permissions.tool.websearch.title": "Web zoeken (Web Search)", + "settings.permissions.tool.websearch.description": "Het web doorzoeken", + "settings.permissions.tool.codesearch.title": "Code zoeken (Code Search)", + "settings.permissions.tool.codesearch.description": "Zoeken naar code op het web", + "settings.permissions.tool.external_directory.title": "Externe Map", + "settings.permissions.tool.external_directory.description": "Toegang tot bestanden buiten de projectmap", + "settings.permissions.tool.doom_loop.title": "Eindeloze Loop (Doom Loop)", + "settings.permissions.tool.doom_loop.description": "Gedetecteerde herhaalde tool-aanroepen met identieke invoer", + + "session.delete.failed.title": "Verwijderen van sessie mislukt", + "session.delete.title": "Sessie verwijderen", + "session.delete.confirm": 'Sessie "{{name}}" verwijderen?', + "session.delete.button": "Sessie verwijderen", + + "workspace.new": "Nieuwe werkruimte", + "workspace.type.local": "lokaal", + "workspace.type.sandbox": "sandbox", + "workspace.create.failed.title": "Maken van werkruimte mislukt", + "workspace.delete.failed.title": "Verwijderen van werkruimte mislukt", + "workspace.resetting.title": "Werkruimte resetten", + "workspace.resetting.description": "Dit kan een minuut duren.", + "workspace.reset.failed.title": "Resetten van werkruimte mislukt", + "workspace.reset.success.title": "Werkruimte gereset", + "workspace.reset.success.description": "Werkruimte komt nu overeen met de standaardbranch.", + "workspace.error.stillPreparing": "Werkruimte is nog aan het voorbereiden", + "workspace.status.checking": "Controleren op ongemergde wijzigingen...", + "workspace.status.error": "Kan git-status niet verifiëren.", + "workspace.status.clean": "Geen ongemergde wijzigingen gedetecteerd.", + "workspace.status.dirty": "Ongemergde wijzigingen gedetecteerd in deze werkruimte.", + "workspace.delete.title": "Werkruimte verwijderen", + "workspace.delete.confirm": 'Werkruimte "{{name}}" verwijderen?', + "workspace.delete.button": "Werkruimte verwijderen", + "workspace.reset.title": "Werkruimte resetten", + "workspace.reset.confirm": 'Werkruimte "{{name}}" resetten?', + "workspace.reset.button": "Werkruimte resetten", + "workspace.reset.archived.none": "Geen actieve sessies zullen worden gearchiveerd.", + "workspace.reset.archived.one": "1 sessie zal worden gearchiveerd.", + "workspace.reset.archived.many": "{{count}} sessies zullen worden gearchiveerd.", + "workspace.reset.note": "Dit zal de werkruimte resetten zodat deze overeenkomt met de standaardbranch.", +} diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index 77fd3d4e5b0..47b3a27c758 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.51", + "version": "7.1.0", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop-electron/src/renderer/i18n/index.ts b/packages/desktop-electron/src/renderer/i18n/index.ts index be87f94f915..2a7a7b188e9 100644 --- a/packages/desktop-electron/src/renderer/i18n/index.ts +++ b/packages/desktop-electron/src/renderer/i18n/index.ts @@ -15,6 +15,7 @@ import { dict as desktopAr } from "./ar" import { dict as desktopNo } from "./no" import { dict as desktopBr } from "./br" import { dict as desktopBs } from "./bs" +import { dict as desktopNl } from "./nl" import { dict as appEn } from "../../../../app/src/i18n/en" import { dict as appZh } from "../../../../app/src/i18n/zh" @@ -31,6 +32,7 @@ import { dict as appAr } from "../../../../app/src/i18n/ar" import { dict as appNo } from "../../../../app/src/i18n/no" import { dict as appBr } from "../../../../app/src/i18n/br" import { dict as appBs } from "../../../../app/src/i18n/bs" +import { dict as appNl } from "../../../../app/src/i18n/nl" export type Locale = | "en" @@ -48,6 +50,7 @@ export type Locale = | "no" | "br" | "bs" + | "nl" type RawDictionary = typeof appEn & typeof desktopEn type Dictionary = i18n.Flatten @@ -65,6 +68,7 @@ const LOCALES: readonly Locale[] = [ "pl", "ru", "bs", + "nl", "ar", "no", "br", @@ -98,6 +102,7 @@ function detectLocale(): Locale { return "no" if (language.toLowerCase().startsWith("pt")) return "br" if (language.toLowerCase().startsWith("bs")) return "bs" + if (language.toLowerCase().startsWith("nl")) return "nl" } return "en" @@ -152,6 +157,7 @@ function build(locale: Locale): Dictionary { if (locale === "no") return { ...base, ...i18n.flatten(appNo), ...i18n.flatten(desktopNo) } if (locale === "br") return { ...base, ...i18n.flatten(appBr), ...i18n.flatten(desktopBr) } if (locale === "bs") return { ...base, ...i18n.flatten(appBs), ...i18n.flatten(desktopBs) } + if (locale === "nl") return { ...base, ...i18n.flatten(appNl), ...i18n.flatten(desktopNl) } return { ...base, ...i18n.flatten(appKo), ...i18n.flatten(desktopKo) } } diff --git a/packages/desktop-electron/src/renderer/i18n/nl.ts b/packages/desktop-electron/src/renderer/i18n/nl.ts new file mode 100644 index 00000000000..2f8ca9fd423 --- /dev/null +++ b/packages/desktop-electron/src/renderer/i18n/nl.ts @@ -0,0 +1,28 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Controleren op updates...", + "desktop.menu.installCli": "CLI installeren...", + "desktop.menu.reloadWebview": "Webview herladen", + "desktop.menu.restart": "Opnieuw opstarten", + + "desktop.dialog.chooseFolder": "Kies een map", + "desktop.dialog.chooseFile": "Kies een bestand", + "desktop.dialog.saveFile": "Bestand opslaan", + + "desktop.updater.checkFailed.title": "Controleren op updates mislukt", + "desktop.updater.checkFailed.message": "Kan niet controleren op updates", + "desktop.updater.none.title": "Geen update beschikbaar", + "desktop.updater.none.message": "Je gebruikt al de nieuwste versie van OpenCode", + "desktop.updater.downloadFailed.title": "Update mislukt", + "desktop.updater.downloadFailed.message": "Downloaden van update mislukt", + "desktop.updater.downloaded.title": "Update gedownload", + "desktop.updater.downloaded.prompt": + "Versie {{version}} van OpenCode is gedownload. Wil je deze installeren en opnieuw opstarten?", + "desktop.updater.installFailed.title": "Update mislukt", + "desktop.updater.installFailed.message": "Installeren van update mislukt", + + "desktop.cli.installed.title": "CLI geïnstalleerd", + "desktop.cli.installed.message": + "CLI geïnstalleerd in {{path}}\n\nHerstart je terminal om de opdracht 'opencode' te gebruiken.", + "desktop.cli.failed.title": "Installatie mislukt", + "desktop.cli.failed.message": "Installeren van CLI mislukt: {{error}}", +} diff --git a/packages/desktop/package.json b/packages/desktop/package.json index ae2eb348af5..c93a2597295 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "7.0.51", + "version": "7.1.0", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/desktop/src/i18n/index.ts b/packages/desktop/src/i18n/index.ts index e1c1e63d970..13d9cf00998 100644 --- a/packages/desktop/src/i18n/index.ts +++ b/packages/desktop/src/i18n/index.ts @@ -16,6 +16,7 @@ import { dict as desktopAr } from "./ar" import { dict as desktopNo } from "./no" import { dict as desktopBr } from "./br" import { dict as desktopBs } from "./bs" +import { dict as desktopNl } from "./nl" import { dict as appEn } from "../../../app/src/i18n/en" import { dict as appZh } from "../../../app/src/i18n/zh" @@ -32,6 +33,7 @@ import { dict as appAr } from "../../../app/src/i18n/ar" import { dict as appNo } from "../../../app/src/i18n/no" import { dict as appBr } from "../../../app/src/i18n/br" import { dict as appBs } from "../../../app/src/i18n/bs" +import { dict as appNl } from "../../../app/src/i18n/nl" export type Locale = | "en" @@ -49,6 +51,7 @@ export type Locale = | "no" | "br" | "bs" + | "nl" type RawDictionary = typeof appEn & typeof desktopEn type Dictionary = i18n.Flatten @@ -66,6 +69,7 @@ const LOCALES: readonly Locale[] = [ "pl", "ru", "bs", + "nl", "ar", "no", "br", @@ -99,6 +103,7 @@ function detectLocale(): Locale { return "no" if (language.toLowerCase().startsWith("pt")) return "br" if (language.toLowerCase().startsWith("bs")) return "bs" + if (language.toLowerCase().startsWith("nl")) return "nl" } return "en" @@ -153,6 +158,7 @@ function build(locale: Locale): Dictionary { if (locale === "no") return { ...base, ...i18n.flatten(appNo), ...i18n.flatten(desktopNo) } if (locale === "br") return { ...base, ...i18n.flatten(appBr), ...i18n.flatten(desktopBr) } if (locale === "bs") return { ...base, ...i18n.flatten(appBs), ...i18n.flatten(desktopBs) } + if (locale === "nl") return { ...base, ...i18n.flatten(appNl), ...i18n.flatten(desktopNl) } return { ...base, ...i18n.flatten(appKo), ...i18n.flatten(desktopKo) } } diff --git a/packages/desktop/src/i18n/nl.ts b/packages/desktop/src/i18n/nl.ts new file mode 100644 index 00000000000..99cc2fae11d --- /dev/null +++ b/packages/desktop/src/i18n/nl.ts @@ -0,0 +1,62 @@ +export const dict = { + "desktop.menu.checkForUpdates": "Controleren op updates...", + "desktop.menu.installCli": "CLI installeren...", + "desktop.menu.reloadWebview": "Webview herladen", + "desktop.menu.restart": "Opnieuw opstarten", + "desktop.menu.app": "Kilo", + "desktop.menu.file": "Bestand", + "desktop.menu.edit": "Bewerken", + "desktop.menu.view": "Weergave", + "desktop.menu.help": "Help", + "desktop.menu.file.newSession": "Nieuwe sessie", + "desktop.menu.file.openProject": "Project openen...", + "desktop.menu.view.toggleSidebar": "Zijbalk in-/uitschakelen", + "desktop.menu.view.toggleTerminal": "Terminal in-/uitschakelen", + "desktop.menu.view.toggleFileTree": "Bestandsstructuur in-/uitschakelen", + "desktop.menu.view.back": "Terug", + "desktop.menu.view.forward": "Vooruit", + "desktop.menu.view.previousSession": "Vorige sessie", + "desktop.menu.view.nextSession": "Volgende sessie", + "desktop.menu.help.documentation": "Kilo documentatie", + "desktop.menu.help.supportForum": "Ondersteuningsforum", + "desktop.menu.help.shareFeedback": "Feedback delen", + "desktop.menu.help.reportBug": "Bug melden", + + "desktop.dialog.chooseFolder": "Kies een map", + "desktop.dialog.chooseFile": "Kies een bestand", + "desktop.dialog.saveFile": "Bestand opslaan", + + "desktop.updater.checkFailed.title": "Controleren op updates mislukt", + "desktop.updater.checkFailed.message": "Kan niet controleren op updates", + "desktop.updater.none.title": "Geen update beschikbaar", + "desktop.updater.none.message": "Je gebruikt al de nieuwste versie van Kilo", + "desktop.updater.downloadFailed.title": "Update mislukt", + "desktop.updater.downloadFailed.message": "Kan update niet downloaden", + "desktop.updater.downloaded.title": "Update gedownload", + "desktop.updater.downloaded.prompt": + "Versie {{version}} van Kilo is gedownload, wil je deze installeren en opnieuw opstarten?", + "desktop.updater.installFailed.title": "Update mislukt", + "desktop.updater.installFailed.message": "Kan update niet installeren", + + "desktop.cli.installed.title": "CLI geïnstalleerd", + "desktop.cli.installed.message": + "CLI geïnstalleerd in {{path}}\n\nStart je terminal opnieuw op om de opdracht 'opencode' te gebruiken.", + "desktop.cli.failed.title": "Installatie mislukt", + "desktop.cli.failed.message": "Kan CLI niet installeren: {{error}}", + "desktop.cli.error.unsupportedPlatform": "CLI-installatie wordt alleen ondersteund op macOS en Linux.", + "desktop.cli.error.sidecarMissing": "Kilo CLI binary ontbreekt. Probeer de desktop-app opnieuw te installeren.", + "desktop.cli.error.scriptWriteFailed": "Kan CLI-installatiescript niet voorbereiden.", + "desktop.cli.error.scriptPermissionFailed": "Kan CLI-installatieprogramma niet uitvoerbaar maken.", + "desktop.cli.error.scriptRunFailed": "Kan CLI-installatiescript niet uitvoeren.", + "desktop.cli.error.scriptFailed": "CLI-installatieprogramma mislukt.", + "desktop.cli.error.installPathUnknown": "Kon niet bepalen waar de CLI is geïnstalleerd.", + "desktop.cli.error.unknown": "Onbekende installatiefout", + + "desktop.loading.status.initial": "Een ogenblik geduld...", + "desktop.loading.status.done": "Helemaal klaar", + "desktop.loading.status.migrating": "Je database wordt gemigreerd", + "desktop.loading.status.waiting": "Dit kan een paar minuten duren", + "desktop.loading.progressAria": "Voortgang database-migratie", + + "desktop.server.local": "Lokale server", +} diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 2ed5f5947e2..2daa2c6cabf 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "1.2.24" +version = "7.1.0" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.24/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.0/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.24/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.0/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.24/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.0/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.24/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.0/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v1.2.24/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.0/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/lychee.toml b/packages/kilo-docs/lychee.toml index d82b560f8d7..627a395310a 100644 --- a/packages/kilo-docs/lychee.toml +++ b/packages/kilo-docs/lychee.toml @@ -30,4 +30,6 @@ exclude = [ 'https://tbench.ai/', # GitHub URLs cause persistent HTTP/2 protocol errors when checked from GitHub Actions runners '^https?://github\.com/', + # Redirects to login page, blocked by bots + '^https?://vercel\.link/', ] diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index f6c0da826d1..e5d389331c7 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.0.51", + "version": "7.1.0", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", diff --git a/packages/kilo-docs/pages/contributing/index.md b/packages/kilo-docs/pages/contributing/index.md index cfffd6d8409..ba8960f7be3 100644 --- a/packages/kilo-docs/pages/contributing/index.md +++ b/packages/kilo-docs/pages/contributing/index.md @@ -119,9 +119,9 @@ Documentation improvements are highly valued contributions: 2. Test your documentation changes by running the docs site locally: ```bash - cd apps/kilocode-docs + cd packages/kilo-docs pnpm install - pnpm start + pnpm dev ``` 3. Submit a PR with your documentation changes diff --git a/packages/kilo-docs/source-links.md b/packages/kilo-docs/source-links.md new file mode 100644 index 00000000000..9938c82f3df --- /dev/null +++ b/packages/kilo-docs/source-links.md @@ -0,0 +1,161 @@ +# Source Code Links + + + + +- + +- + + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + + +- + +- + +- + +- + + +- + +- + + +- + + +- + +- + +- + + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + +- + diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index 3bd5aa4f88e..e0f7a5e61fa 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.51", + "version": "7.1.0", "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 00b20c52f4a..0b9486558c4 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.51", + "version": "7.1.0", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-i18n/src/nl.ts b/packages/kilo-i18n/src/nl.ts new file mode 100644 index 00000000000..d306f4fdd80 --- /dev/null +++ b/packages/kilo-i18n/src/nl.ts @@ -0,0 +1,74 @@ +// Kilo-specific translations and overrides +// Keys here will override any matching keys from upstream translations +export const dict = { + // Kilo Gateway provider translations + "provider.connect.kiloGateway.line1": + "Kilo Gateway geeft je toegang tot een gecureerde set van betrouwbare, geoptimaliseerde modellen voor coding agents.", + "provider.connect.kiloGateway.line2": + "Met één enkele API key krijg je toegang tot modellen zoals Claude, GPT, Gemini, GLM en meer.", + "provider.connect.kiloGateway.visit.prefix": "Bezoek ", + "provider.connect.kiloGateway.visit.link": "kilo.ai", + "provider.connect.kiloGateway.visit.suffix": " om je API key op te halen.", + + // Provider dialog translations + "dialog.provider.group.recommended": "Aanbevolen", + "dialog.provider.kilo.note": "Toegang tot 500+ AI modellen", + + // Reasoning block label + "ui.permission.run": "Uitvoeren", + "ui.reasoning.label": "Redenering", + + // Marketplace + "marketplace.tab.skills": "Skills", + "marketplace.tab.mcpServers": "MCP Servers", + "marketplace.tab.modes": "Modi", + "marketplace.category.all": "Alle", + "marketplace.placeholder": "Nog te implementeren", + "marketplace.card.installed": "Geïnstalleerd", + "marketplace.card.install": "Installeren", + "marketplace.card.remove": "Verwijderen", + "marketplace.card.removeScope": "Verwijderen ({{scope}})", + "marketplace.card.showMore": "Toon meer", + "marketplace.card.showLess": "Toon minder", + "marketplace.install.title": "Installeer {{name}}", + "marketplace.install.scope": "Scope", + "marketplace.install.scope.project": "Project", + "marketplace.install.scope.global": "Globaal", + "marketplace.install.prerequisites": "Vereisten", + "marketplace.install.installing": "Installeren...", + "marketplace.install.cancel": "Annuleren", + "marketplace.install.success": "Succesvol geïnstalleerd!", + "marketplace.install.failed": "Installatie mislukt", + "marketplace.install.done": "Klaar", + "marketplace.install.close": "Sluiten", + "marketplace.remove.title": "{{name}} verwijderen?", + "marketplace.remove.confirm": + "Weet je zeker dat je deze {{type}} wilt verwijderen? Dit verwijdert het uit je {{scope}} configuratie.", + "marketplace.remove.cancel": "Annuleren", + "marketplace.remove.confirm.button": "Verwijderen", + "marketplace.tab.mcp": "MCP", + "marketplace.search": "Zoeken...", + "marketplace.filter.all": "Alle items", + "marketplace.filter.notInstalled": "Niet geïnstalleerd", + "marketplace.empty": "Geen items gevonden", + "marketplace.badge.mcpServer": "MCP Server", + "marketplace.badge.mode": "Modus", + "marketplace.card.by": "door {{author}}", + "marketplace.install.method": "Installatiemethode", + "marketplace.install.parameters": "Parameters", + "marketplace.install.optional": "(optioneel)", + "marketplace.install.required": "{{name}} is vereist", + "marketplace.scope.project": "project", + "marketplace.scope.global": "globaal", + "marketplace.remove.type.mcp": "MCP server", + "marketplace.remove.type.skill": "skill", + "marketplace.remove.type.mode": "modus", + "marketplace.remove.failed": "Verwijderen van {{name}} mislukt", + "marketplace.install": "Installeren", + "marketplace.filter.installed": "Geïnstalleerd", + "marketplace.error.dismiss": "Sluiten", + "marketplace.warning.busyOne": "Er is één sessie actief en deze zal worden onderbroken", + "marketplace.warning.busyMany": "Er zijn meerdere sessies actief en deze zullen worden onderbroken", + "marketplace.warning.installAnyway": "Toch installeren", + "marketplace.warning.cancel": "Annuleren", +} diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index 7766d1b31bd..24c15c60eee 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.51", + "version": "7.1.0", "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 3116adf7bb0..d65b1f4e579 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.0.51", + "version": "7.1.0", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css index 8525ffcbaa5..cac42ad5f26 100644 --- a/packages/kilo-ui/src/components/message-part.css +++ b/packages/kilo-ui/src/components/message-part.css @@ -246,13 +246,22 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] { } } - /* Collapse/expand animation via Kobalte's CSS variable */ + /* Collapse/expand animation via Kobalte's CSS variable. + Uses grid trick: the outer wrapper transitions grid-template-rows + between 0fr (collapsed) and 1fr (expanded) so the content smoothly + collapses without needing to know the pixel height up front. */ [data-slot="collapsible-content"] { - animation: slideUp 300ms ease-out forwards; + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 250ms ease-out; overflow: hidden; + > * { + overflow: hidden; + } + &[data-expanded] { - animation: slideDown 200ms ease-out forwards; + grid-template-rows: 1fr; } } diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx index f495ab74369..d2fc659fad4 100644 --- a/packages/kilo-ui/src/components/message-part.tsx +++ b/packages/kilo-ui/src/components/message-part.tsx @@ -419,11 +419,21 @@ export function AssistantParts(props: { if (part.type === "tool") return part.callID || part.id return part.id } - const parts = props.messages.flatMap((message) => - list(data.store.part?.[message.id], emptyParts) - .filter((part) => renderable(part, props.showReasoningSummaries ?? true)) - .map((part) => ({ message, part })), - ) + const parts = props.messages.flatMap((message) => { + const filtered = list(data.store.part?.[message.id], emptyParts).filter((part) => + renderable(part, props.showReasoningSummaries ?? true), + ) + // Ensure reasoning parts appear before text parts within each message. + // During streaming the reasoning part may arrive after the text part + // in the store (SSE order), but visually reasoning always precedes text. + const reasoning: typeof filtered = [] + const rest: typeof filtered = [] + for (const p of filtered) { + if (p.type === "reasoning") reasoning.push(p) + else rest.push(p) + } + return [...reasoning, ...rest].map((part) => ({ message, part })) + }) let start = -1 @@ -1190,6 +1200,9 @@ PART_MAPPING["text"] = function TextPartDisplay(props) { // store object (causing to recreate the component) the new instance // knows the part was just streaming and can animate the collapse. const streamed = new Set() +// Tracks parts that have already been auto-collapsed once, so component +// recreation (from store updates while other parts stream) won't collapse again. +const autocollapsed = new Set() // Overrides upstream flat markdown render with streaming reasoning block + auto-collapse. // Also filters encrypted reasoning data from OpenRouter that appears as [REDACTED]. @@ -1222,13 +1235,13 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProp const [open, setOpen] = createSignal(!done() || was) // Auto-collapse once when reasoning finishes (streaming → done transition). - // Uses a flag so manual reopens are not auto-closed again. - let collapsed = false + // Collapses immediately so the grid transition runs in sync with the + // streaming-height removal. Module-level Set prevents re-triggering on + // component recreation or when the user manually reopens. createEffect(() => { - if (done() && open() && !collapsed) { - collapsed = true - const timer = setTimeout(() => setOpen(false), 500) - onCleanup(() => clearTimeout(timer)) + if (done() && open() && !autocollapsed.has(id)) { + autocollapsed.add(id) + setOpen(false) } }) diff --git a/packages/kilo-ui/src/i18n/nl.ts b/packages/kilo-ui/src/i18n/nl.ts new file mode 100644 index 00000000000..3ffed965402 --- /dev/null +++ b/packages/kilo-ui/src/i18n/nl.ts @@ -0,0 +1 @@ +export * from "@opencode-ai/ui/i18n/nl" diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index 2ff92795c50..f1e11b2d713 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.51", + "version": "7.1.0", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", @@ -15,7 +15,7 @@ "directory": "packages/kilo-vscode" }, "engines": { - "vscode": "^1.108.0" + "vscode": "^1.105.1" }, "author": { "name": "Kilo Code" @@ -45,7 +45,13 @@ "kilocode" ], "activationEvents": [ - "onWebviewPanel:kilo-code.new.AgentManagerPanel" + "onWebviewPanel:kilo-code.new.AgentManagerPanel", + "onWebviewPanel:kilo-code.new.TabPanel", + "onWebviewPanel:kilo-code.new.settingsPanel", + "onWebviewPanel:kilo-code.new.profilePanel", + "onWebviewPanel:kilo-code.new.marketplacePanel", + "onWebviewPanel:kilo-code.new.DiffViewerPanel", + "onWebviewPanel:kilo-code.new.SubAgentViewerPanel" ], "main": "./dist/extension.js", "contributes": { @@ -642,6 +648,7 @@ "th", "bs", "tr" + "nl" ], "enumDescriptions": [ "Auto (VS Code language)", @@ -662,6 +669,7 @@ "ภาษาไทย", "Bosanski", "Türkçe" + "Nederlands" ] }, "kilo-code.new.model.providerID": { @@ -787,7 +795,7 @@ "@types/mocha": "^10.0.10", "@types/node": "22.x", "@types/qrcode": "^1.5.6", - "@types/vscode": "^1.108.0", + "@types/vscode": "^1.105.1", "@vscode/test-cli": "^0.0.12", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^3.7.1", diff --git a/packages/kilo-vscode/src/DiffViewerProvider.ts b/packages/kilo-vscode/src/DiffViewerProvider.ts index 5650e220cc2..78005a93125 100644 --- a/packages/kilo-vscode/src/DiffViewerProvider.ts +++ b/packages/kilo-vscode/src/DiffViewerProvider.ts @@ -48,21 +48,32 @@ export class DiffViewerProvider implements vscode.Disposable { return } - this.panel = vscode.window.createWebviewPanel(DiffViewerProvider.viewType, "Changes", vscode.ViewColumn.One, { + const panel = vscode.window.createWebviewPanel(DiffViewerProvider.viewType, "Changes", vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true, localResourceRoots: [this.extensionUri], }) - this.panel.iconPath = { + this.wirePanel(panel) + } + + /** Re-wire a deserialized panel after extension restart. */ + public deserializePanel(panel: vscode.WebviewPanel): void { + this.wirePanel(panel) + } + + private wirePanel(panel: vscode.WebviewPanel): void { + this.panel = panel + + panel.iconPath = { light: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-light.svg"), dark: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-dark.svg"), } - this.panel.webview.onDidReceiveMessage((msg) => this.onMessage(msg), undefined, []) - this.panel.webview.html = this.getHtml(this.panel.webview) + panel.webview.onDidReceiveMessage((msg) => this.onMessage(msg), undefined, []) + panel.webview.html = this.getHtml(panel.webview) - this.panel.onDidDispose(() => { + panel.onDidDispose(() => { this.log("Panel disposed") this.stopDiffPolling() this.panel = undefined diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 100440cb837..469ff3a6e72 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -15,8 +15,7 @@ import type { import { type KiloConnectionService, type KilocodeNotification, ServerStartupError } from "./services/cli-backend" import type { EditorContext } from "./services/cli-backend/types" import { FileIgnoreController } from "./services/autocomplete/shims/FileIgnoreController" -import { handleChatCompletionRequest } from "./services/autocomplete/chat-autocomplete/handleChatCompletionRequest" -import { handleChatCompletionAccepted } from "./services/autocomplete/chat-autocomplete/handleChatCompletionAccepted" +import { ChatTextAreaAutocomplete } from "./services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete" import { buildWebviewHtml } from "./utils" import { TelemetryProxy, type TelemetryPropertiesProvider } from "./services/telemetry" import { @@ -140,6 +139,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private ignoreController: FileIgnoreController | null = null private ignoreControllerDir: string | null = null private marketplace: MarketplaceService | null = null + private chatAutocomplete: ChatTextAreaAutocomplete | null = null private projectDirectory: string | null | undefined private slimEditMetadata = true @@ -624,13 +624,19 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } break } - case "requestChatCompletion": - void handleChatCompletionRequest( + case "requestChatCompletion": { + if (!this.chatAutocomplete) { + this.chatAutocomplete = new ChatTextAreaAutocomplete(this.connectionService) + } + void this.chatAutocomplete.handle( { type: "requestChatCompletion", text: message.text, requestId: message.requestId }, - { postMessage: (msg) => this.postMessage(msg) }, - this.connectionService, + { + postMessage: (msg: { type: "chatCompletionResult"; text: string; requestId: string }) => + this.postMessage(msg), + }, ) break + } case "requestFileSearch": { const sdkClient = this.client if (sdkClient) { @@ -659,7 +665,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper break } case "chatCompletionAccepted": - handleChatCompletionAccepted({ type: "chatCompletionAccepted", suggestionLength: message.suggestionLength }) + this.chatAutocomplete?.telemetry.captureAcceptSuggestion(message.suggestionLength) break case "deleteSession": await this.handleDeleteSession(message.sessionID) @@ -2577,6 +2583,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper this.sessionDirectories.clear() this.sessionStatusMap.clear() this.ignoreController?.dispose() + this.chatAutocomplete?.dispose() this.marketplace?.dispose() } } diff --git a/packages/kilo-vscode/src/SettingsEditorProvider.ts b/packages/kilo-vscode/src/SettingsEditorProvider.ts index c60d9ebc756..afaa819944b 100644 --- a/packages/kilo-vscode/src/SettingsEditorProvider.ts +++ b/packages/kilo-vscode/src/SettingsEditorProvider.ts @@ -42,6 +42,15 @@ export class SettingsEditorProvider implements vscode.Disposable { return resolvePanelProjectDirectory(active, vscode.workspace.workspaceFolders) } + /** Extract the PanelView from a viewType string like "kilo-code.new.settingsPanel". */ + static viewFromType(type: string): PanelView | undefined { + const match = type.match(/^kilo-code\.new\.(\w+)Panel$/) + if (!match) return undefined + const view = match[1] as PanelView + if (!(view in PANEL_TITLES)) return undefined + return view + } + openPanel(view: PanelView, tab?: string): void { if (tab) this.tabs.set(view, tab) @@ -57,14 +66,31 @@ export class SettingsEditorProvider implements vscode.Disposable { return } - const title = PANEL_TITLES[view] + const panel = vscode.window.createWebviewPanel( + `kilo-code.new.${view}Panel`, + PANEL_TITLES[view], + vscode.ViewColumn.One, + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [this.extensionUri], + }, + ) - const panel = vscode.window.createWebviewPanel(`kilo-code.new.${view}Panel`, title, vscode.ViewColumn.One, { - enableScripts: true, - retainContextWhenHidden: true, - localResourceRoots: [this.extensionUri], - }) + this.wirePanel(panel, view, projectDirectory) + } + /** Re-wire a deserialized panel after extension restart. */ + deserializePanel(panel: vscode.WebviewPanel): void { + const view = SettingsEditorProvider.viewFromType(panel.viewType) + if (!view) { + panel.dispose() + return + } + this.wirePanel(panel, view, this.getProjectDirectory()) + } + + private wirePanel(panel: vscode.WebviewPanel, view: PanelView, projectDirectory: string | null): void { panel.iconPath = { light: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-light.svg"), dark: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-dark.svg"), @@ -105,6 +131,7 @@ export class SettingsEditorProvider implements vscode.Disposable { this.panels.set(view, panel) this.providers.set(view, provider) + const title = PANEL_TITLES[view] panel.onDidDispose(() => { console.log(`[Kilo New] ${title} panel disposed`) closePanelDisposable.dispose() diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index 3ad1197e470..66261401745 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -66,6 +66,25 @@ export function activate(context: vscode.ExtensionContext) { }), ) + // Register serializer so "Open in Tab" restores when VS Code restarts + context.subscriptions.push( + vscode.window.registerWebviewPanelSerializer("kilo-code.new.TabPanel", { + deserializeWebviewPanel(panel: vscode.WebviewPanel) { + const tabProvider = new KiloProvider(context.extensionUri, connectionService, context) + tabProvider.resolveWebviewPanel(panel) + panel.onDidDispose( + () => { + console.log("[Kilo New] Tab panel restored from restart disposed") + tabProvider.dispose() + }, + null, + context.subscriptions, + ) + return Promise.resolve() + }, + }), + ) + // Create standalone diff viewer provider for the sidebar "Show Changes" action const diffViewerProvider = new DiffViewerProvider(context.extensionUri, connectionService) diffViewerProvider.setCommentHandler((comments) => { @@ -81,6 +100,39 @@ export function activate(context: vscode.ExtensionContext) { const subAgentViewerProvider = new SubAgentViewerProvider(context.extensionUri, connectionService, context) context.subscriptions.push(subAgentViewerProvider) + // Register serializers so settings/diff/sub-agent panels restore on restart + const settingsViews = ["settingsPanel", "profilePanel", "marketplacePanel"] as const + for (const suffix of settingsViews) { + context.subscriptions.push( + vscode.window.registerWebviewPanelSerializer(`kilo-code.new.${suffix}`, { + deserializeWebviewPanel(panel: vscode.WebviewPanel) { + settingsEditorProvider.deserializePanel(panel) + return Promise.resolve() + }, + }), + ) + } + + context.subscriptions.push( + vscode.window.registerWebviewPanelSerializer(DiffViewerProvider.viewType, { + deserializeWebviewPanel(panel: vscode.WebviewPanel) { + diffViewerProvider.deserializePanel(panel) + return Promise.resolve() + }, + }), + ) + + context.subscriptions.push( + vscode.window.registerWebviewPanelSerializer("kilo-code.new.SubAgentViewerPanel", { + deserializeWebviewPanel(panel: vscode.WebviewPanel) { + // Sub-agent viewer requires a session ID that can't be recovered + // after restart, so dispose the stale panel cleanly. + panel.dispose() + return Promise.resolve() + }, + }), + ) + // Register toolbar button command handlers context.subscriptions.push( vscode.commands.registerCommand("kilo-code.new.plusButtonClicked", () => { 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 6dc2bb97c9b..690f0e1261a 100644 --- a/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts +++ b/packages/kilo-vscode/src/services/autocomplete/chat-autocomplete/ChatTextAreaAutocomplete.ts @@ -1,18 +1,68 @@ +import * as vscode from "vscode" import { AutocompleteModel } from "../AutocompleteModel" import { AutocompleteContext, VisibleCodeContext } from "../types" import { removePrefixOverlap } from "../continuedev/core/autocomplete/postprocessing/removePrefixOverlap.js" import { AutocompleteTelemetry } from "../classic-auto-complete/AutocompleteTelemetry" import { postprocessAutocompleteSuggestion } from "../classic-auto-complete/uselessSuggestionFilter" +import { VisibleCodeTracker } from "../context/VisibleCodeTracker" +import { FileIgnoreController } from "../shims/FileIgnoreController" import type { KiloConnectionService } from "../../cli-backend" +import type { ChatCompletionRequestMessage, ChatCompletionResponseSender } from "./handleChatCompletionRequest" import { finalizeChatSuggestion, buildChatPrefix } from "./chat-autocomplete-utils" +/** + * Chat textarea autocomplete with cached per-request objects. + * + * Caches FileIgnoreController (refreshed when workspace changes or when + * .kilocodeignore / .gitignore files are modified) and shares a single + * AutocompleteTelemetry instance across requests so that request and + * acceptance events correlate. + */ export class ChatTextAreaAutocomplete { private model: AutocompleteModel - private telemetry: AutocompleteTelemetry + readonly telemetry: AutocompleteTelemetry + private ignore: FileIgnoreController | null = null + private dir = "" + private watcher: vscode.FileSystemWatcher | undefined - constructor(connectionService: KiloConnectionService) { + constructor(connectionService: KiloConnectionService, telemetry?: AutocompleteTelemetry) { this.model = new AutocompleteModel(connectionService) - this.telemetry = new AutocompleteTelemetry("chat-textarea") + this.telemetry = telemetry ?? new AutocompleteTelemetry("chat-textarea") + this.watcher = vscode.workspace.createFileSystemWatcher("**/{.kilocodeignore,.gitignore}") + const invalidate = () => { + // Don't dispose — an in-flight request may still hold a reference. + // The old instance will be garbage collected once no longer referenced. + this.ignore = null + } + this.watcher.onDidChange(invalidate) + this.watcher.onDidCreate(invalidate) + this.watcher.onDidDelete(invalidate) + } + + /** + * Full request handler — resolves visible code context, generates a + * completion, and posts the result back to the webview. + */ + async handle(message: ChatCompletionRequestMessage, sender: ChatCompletionResponseSender): Promise { + const { text, requestId } = message + if (!text || !requestId) return + + const workspace = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? "" + + // Re-initialize the ignore controller only when the workspace changes + if (!this.ignore || this.dir !== workspace) { + this.ignore?.dispose() + this.ignore = new FileIgnoreController(workspace) + await this.ignore.initialize() + this.dir = workspace + } + + const tracker = new VisibleCodeTracker(workspace, this.ignore) + const context = await tracker.captureVisibleCode() + + const { suggestion } = await this.getCompletion(text, context) + + sender.postMessage({ type: "chatCompletionResult", text: suggestion, requestId }) } async getCompletion(userText: string, visibleCodeContext?: VisibleCodeContext): Promise<{ suggestion: string }> { @@ -137,4 +187,10 @@ TASK: Complete the user's message naturally. if (cleaned === undefined) return "" return finalizeChatSuggestion(cleaned) } + + dispose() { + this.watcher?.dispose() + this.ignore?.dispose() + this.ignore = null + } } diff --git a/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts b/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts index b30b2d2834d..2c873ad1d17 100644 --- a/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts +++ b/packages/kilo-vscode/src/services/autocomplete/i18n/nl.ts @@ -1,4 +1,5 @@ -// nl runtime translations for autocomplete +// Dutch runtime translations for autocomplete (kilocode:autocomplete.* namespace) +// Source: src/i18n/locales/nl/kilocode.json → "autocomplete" section export const dict = { "kilocode:autocomplete.statusBar.enabled": "$(kilo-logo) Autocomplete", @@ -7,14 +8,14 @@ export const dict = { "kilocode:autocomplete.statusBar.tooltip.basic": "Kilo Code Autocomplete", "kilocode:autocomplete.statusBar.tooltip.disabled": "Kilo Code Autocomplete (uitgeschakeld)", "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}})", + "**Geen autocomplete-model geconfigureerd**\n\nVoeg een profiel toe met een van deze ondersteunde providers om autocomplete in te schakelen: {{providers}}.\n\n[Instellingen openen]({{command}})", "kilocode:autocomplete.statusBar.tooltip.sessionTotal": "Totale sessiekosten:", "kilocode:autocomplete.statusBar.tooltip.provider": "Provider:", "kilocode:autocomplete.statusBar.tooltip.model": "Model:", "kilocode:autocomplete.statusBar.tooltip.profile": "Profiel: ", "kilocode:autocomplete.statusBar.tooltip.defaultProfile": "Standaard", "kilocode:autocomplete.statusBar.tooltip.completionSummary": - "{{count}} voltooiingen uitgevoerd tussen {{startTime}} en {{endTime}}, voor een totale kostprijs van {{cost}}.", + "{{count}} aanvullingen uitgevoerd tussen {{startTime}} en {{endTime}}, voor totale kosten van {{cost}}.", "kilocode:autocomplete.statusBar.tooltip.providerInfo": "Automatische aanvullingen geleverd door {{model}} via {{provider}}.", "kilocode:autocomplete.statusBar.cost.zero": "$0.00", @@ -24,21 +25,21 @@ export const dict = { "kilocode:autocomplete.progress.analyzing": "Je code analyseren...", "kilocode:autocomplete.progress.generating": "Voorgestelde bewerkingen genereren...", "kilocode:autocomplete.progress.processing": "Voorgestelde bewerkingen verwerken...", - "kilocode:autocomplete.progress.showing": "Voorgestelde bewerkingen tonen...", - "kilocode:autocomplete.input.title": "Kilo Code: Snelle Taak", - "kilocode:autocomplete.input.placeholder": "bijv., 'refactor deze functie om efficiënter te zijn'", - "kilocode:autocomplete.commands.generateSuggestions": "Kilo Code: Voorgestelde Bewerkingen Genereren", - "kilocode:autocomplete.commands.displaySuggestions": "Voorgestelde Bewerkingen Tonen", - "kilocode:autocomplete.commands.cancelSuggestions": "Voorgestelde Bewerkingen Annuleren", - "kilocode:autocomplete.commands.applyCurrentSuggestion": "Huidige Voorgestelde Bewerking Toepassen", - "kilocode:autocomplete.commands.applyAllSuggestions": "Alle Voorgestelde Bewerkingen Toepassen", + "kilocode:autocomplete.progress.showing": "Voorgestelde bewerkingen weergeven...", + "kilocode:autocomplete.input.title": "Kilo Code: Snelle taak", + "kilocode:autocomplete.input.placeholder": "bijv. 'herschrijf deze functie om efficiënter te zijn'", + "kilocode:autocomplete.commands.generateSuggestions": "Kilo Code: Voorgestelde bewerkingen genereren", + "kilocode:autocomplete.commands.displaySuggestions": "Voorgestelde bewerkingen weergeven", + "kilocode:autocomplete.commands.cancelSuggestions": "Voorgestelde bewerkingen annuleren", + "kilocode:autocomplete.commands.applyCurrentSuggestion": "Huidige voorgestelde bewerking toepassen", + "kilocode:autocomplete.commands.applyAllSuggestions": "Alle voorgestelde bewerkingen toepassen", "kilocode:autocomplete.commands.category": "Kilo Code", - "kilocode:autocomplete.codeAction.title": "Kilo Code: Voorgestelde Bewerkingen", + "kilocode:autocomplete.codeAction.title": "Kilo Code: Voorgestelde bewerkingen", "kilocode:autocomplete.chatParticipant.fullName": "Kilo Code Agent", "kilocode:autocomplete.chatParticipant.name": "Agent", "kilocode:autocomplete.chatParticipant.description": "Ik kan je helpen met snelle taken en voorgestelde bewerkingen.", "kilocode:autocomplete.incompatibilityExtensionPopup.message": - "De Kilo Code Autocomplete wordt geblokkeerd door een conflict met GitHub Copilot. Om dit op te lossen, moet je Copilot's inline suggesties uitschakelen.", - "kilocode:autocomplete.incompatibilityExtensionPopup.disableCopilot": "Copilot Uitschakelen", - "kilocode:autocomplete.incompatibilityExtensionPopup.disableInlineAssist": "Autocomplete Uitschakelen", + "De Kilo Code Autocomplete wordt geblokkeerd door een conflict met GitHub Copilot. Om dit op te lossen, moet je de inline suggesties van Copilot uitschakelen.", + "kilocode:autocomplete.incompatibilityExtensionPopup.disableCopilot": "Copilot uitschakelen", + "kilocode:autocomplete.incompatibilityExtensionPopup.disableInlineAssist": "Autocomplete uitschakelen", } diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/index.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/index.ts index d65d99290e9..88163caafbc 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/index.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/index.ts @@ -1,6 +1,7 @@ import { dict as ar } from "./ar" import { dict as br } from "./br" import { dict as bs } from "./bs" +import { dict as nl } from "./nl" import { dict as da } from "./da" import { dict as de } from "./de" import { dict as en } from "./en" @@ -21,6 +22,7 @@ const bundles: Record> = { ar, br, bs, + nl, da, de, en, diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts new file mode 100644 index 00000000000..fd8097f446f --- /dev/null +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts @@ -0,0 +1,4 @@ +export const dict = { + "server.processExited": "CLI-proces is afgesloten met code {{code}} voordat de server is gestart", + "server.startupTimeout": "Time-out bij opstarten van server na {{seconds}} seconden", +} as const diff --git a/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts new file mode 100644 index 00000000000..cf6b39fce00 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/agent-manager/i18n/nl.ts @@ -0,0 +1,167 @@ +export const dict = { + "agentManager.local": "lokaal", + "agentManager.section.worktrees": "WORKTREES", + "agentManager.section.sessions": "SESSIES", + "agentManager.notGitRepo": "Geen git repository", + + "agentManager.worktree.settings": "Worktree instellingen", + "agentManager.worktree.new": "Nieuwe worktree", + "agentManager.worktree.setupScript": "Worktree setup script", + "agentManager.worktree.delete": "Worktree verwijderen", + "agentManager.worktree.confirmDelete": "Verwijderen?", + "agentManager.worktree.stale": "Verouderd", + "agentManager.worktree.staleTooltip": "Ontbreekt op schijf of wordt niet meer gevolgd door git worktree", + "agentManager.worktree.removeStale": "Verouderde worktree verwijderen", + "agentManager.worktree.doubleClickRename": "Dubbelklik om te hernoemen", + "agentManager.worktree.versions": "{{count}} versies", + "agentManager.worktree.advancedOptions": "Geavanceerde worktree opties", + "agentManager.worktree.defaultBaseBranch": "Standaard basis branch", + "agentManager.worktree.defaultBaseBranchAuto": "Automatisch detecteren", + + "agentManager.hoverCard.branch": "BRANCH", + "agentManager.hoverCard.base": "Basis", + "agentManager.hoverCard.sessions": "Sessies", + "agentManager.hoverCard.files": "Bestanden", + "agentManager.hoverCard.changes": "Wijzigingen", + "agentManager.hoverCard.commits": "Commits", + + "agentManager.session.new": "Nieuwe sessie", + "agentManager.session.untitled": "Naamloos", + "agentManager.session.newSession": "Nieuwe sessie", + "agentManager.session.openInWorktree": "Openen in worktree", + "agentManager.session.readonly": "Alleen-lezen sessie", + "agentManager.session.noSessions": "Geen open sessies", + + "agentManager.tab.close": "Sluiten", + "agentManager.tab.closeTab": "Tabblad sluiten", + "agentManager.tab.forkSession": "Sessie forken", + "agentManager.tab.terminal": "Terminal", + "agentManager.tab.openTerminal": "Terminal openen", + + "agentManager.setup.failed": "Worktree setup mislukt", + "agentManager.setup.settingUp": "Worktree instellen", + "agentManager.setup.error.git_not_found": + "Git is niet geïnstalleerd of niet gevonden in PATH. Installeer Git en herstart VS Code.", + "agentManager.setup.error.not_git_repo": "Open een map die een git repository bevat om worktrees te gebruiken.", + "agentManager.setup.error.lfs_missing": + "Deze repository gebruikt Git LFS, maar git-lfs is niet gevonden. Installeer Git LFS.", + "agentManager.shortcuts.title": "Sneltoetsen", + "agentManager.shortcuts.category.sidebar": "Zijbalk", + "agentManager.shortcuts.category.tabs": "Tabbladen", + "agentManager.shortcuts.category.terminal": "Terminal", + "agentManager.shortcuts.category.global": "Globaal", + "agentManager.shortcuts.previousItem": "Vorig item", + "agentManager.shortcuts.nextItem": "Volgend item", + "agentManager.shortcuts.newWorktree": "Nieuwe worktree", + "agentManager.shortcuts.openWorktree": "Worktree openen", + "agentManager.shortcuts.advancedWorktree": "Geavanceerde worktree", + "agentManager.shortcuts.deleteWorktree": "Worktree verwijderen", + "agentManager.shortcuts.previousTab": "Vorig tabblad", + "agentManager.shortcuts.nextTab": "Volgend tabblad", + "agentManager.shortcuts.newTab": "Nieuw tabblad", + "agentManager.shortcuts.closeTab": "Tabblad sluiten", + "agentManager.shortcuts.toggleTerminal": "Terminal in-/uitschakelen", + "agentManager.shortcuts.openAgentManager": "Agent Manager openen", + "agentManager.shortcuts.cycleAgentMode": "Volgende agent modus", + "agentManager.shortcuts.cyclePreviousAgentMode": "Vorige agent modus", + "agentManager.shortcuts.showShortcuts": "Sneltoetsen tonen", + + "agentManager.dialog.removeStaleWorktree.title": "Verouderde worktree verwijderen", + "agentManager.dialog.removeStaleWorktree.messagePre": "Verouderde worktree ", + "agentManager.dialog.removeStaleWorktree.messagePost": + "? Dit verwijdert alleen de Agent Manager koppeling en laat bestanden op de schijf ongemoeid.", + "agentManager.dialog.removeStaleWorktree.cancel": "Annuleren", + "agentManager.dialog.removeStaleWorktree.confirm": "Verouderde worktree verwijderen", + + "agentManager.dialog.openWorktree": "Nieuwe worktree", + "agentManager.dialog.tab.new": "Nieuw", + "agentManager.dialog.tab.import": "Importeren", + "agentManager.dialog.namePlaceholder": "Worktree naam (optioneel)", + "agentManager.dialog.promptPlaceholder.mac": "Typ een bericht (\u2318Enter om te verzenden)", + "agentManager.dialog.promptPlaceholder.other": "Typ een bericht (Ctrl+Enter om te verzenden)", + "agentManager.dialog.advancedOptions": "Geavanceerde opties", + "agentManager.dialog.branchName": "Branch naam", + "agentManager.dialog.branchNamePlaceholder": "automatisch gegenereerd", + "agentManager.dialog.baseBranch": "Basis branch", + "agentManager.dialog.searchBranches": "Zoeken naar branches...", + "agentManager.dialog.branchBadge.default": "standaard", + "agentManager.dialog.branchBadge.remote": "remote", + "agentManager.dialog.versions": "Versies", + "agentManager.dialog.versionHint": "{{count}} worktrees zullen parallel draaien", + "agentManager.dialog.compareModels": "Modellen vergelijken", + "agentManager.dialog.compareModels.tooltip": + "Draai agents parallel op verschillende modellen om resultaten te vergelijken", + "agentManager.dialog.compareModels.searchModels": "Zoeken naar modellen...", + "agentManager.dialog.compareModels.selectModels": "Modellen selecteren...", + "agentManager.dialog.creating": "Maken...", + "agentManager.dialog.createWorktree": "Worktree maken", + "agentManager.dialog.removeImage": "Afbeelding verwijderen", + "agentManager.dialog.advanced": "Geavanceerd...", + + "agentManager.diff.toggle": "Diff in-/uitschakelen", + "agentManager.diff.openFile": "Bestand openen", + "agentManager.open.button": "Openen", + "agentManager.open.tooltip": "Open deze worktree in VS Code", + "agentManager.apply.button": "Toepassen op lokaal", + "agentManager.apply.globalButton": "Toepassen", + "agentManager.apply.tooltip": "Geselecteerde worktree wijzigingen toepassen op lokale branch", + "agentManager.apply.dialogTitle": "Wijzigingen toepassen op lokale branch", + "agentManager.apply.confirm": "Nu toepassen", + "agentManager.apply.retry": "Toepassen opnieuw proberen", + "agentManager.apply.previewTitle": "Deze wijzigingen toepassen op lokale branch?", + "agentManager.apply.previewSummary": "{{files}} bestanden, +{{additions}} -{{deletions}}", + "agentManager.apply.selectionSummary": "{{selected}} van {{total}} bestanden geselecteerd", + "agentManager.apply.selectAll": "Alles selecteren", + "agentManager.apply.selectNone": "Niets selecteren", + "agentManager.apply.moreFiles": "nog +{{count}}", + "agentManager.apply.moreReasons": "{{reason}} (nog +{{count}})", + "agentManager.apply.checking": "Controleren...", + "agentManager.apply.applying": "Toepassen...", + "agentManager.apply.success": "Wijzigingen toegepast", + "agentManager.apply.conflict": "Toepassen heeft conflicten", + "agentManager.apply.conflictToast": "{{count}} conflicten in {{files}} bestanden. Bekijk details in Toepassen.", + "agentManager.apply.error": "Toepassen mislukt", + "agentManager.apply.conflictsTitle": "Conflicten", + "agentManager.apply.unknownFile": "Onopgelost bestand", + "agentManager.apply.reason.index": "Lokaal bestand verschilt van verwachte versie", + "agentManager.apply.reason.patch": "Patch kan niet netjes worden toegepast", + "agentManager.apply.reason.contents": "Kan huidige lokale bestandsinhoud niet lezen", + "agentManager.apply.reason.unknown": "Conflict gedetecteerd", + "agentManager.apply.inline.success": "Toegepast", + "agentManager.apply.inline.conflict": "Conflicten", + "agentManager.apply.inline.error": "Mislukt", + "agentManager.shortcuts.toggleDiff": "Diff-paneel in-/uitschakelen", + "agentManager.shortcuts.category.quickSwitch": "Snel wisselen", + "agentManager.shortcuts.jumpToItem": "Spring naar item 1\u20139", + "agentManager.review.sendAllToChat": "Alles naar chat sturen", + "agentManager.review.sendAllToChatWithCount": "Alles naar chat sturen ({{count}})", + "agentManager.review.sendAllShortcut.mac": "⌘Enter", + "agentManager.review.sendAllShortcut.other": "Ctrl+Enter", + "agentManager.review.modalTitle": "Opmerking bekijken", + "agentManager.review.inlineCount": "Opmerkingen bekijken ({{count}})", + "agentManager.review.clearAll": "Alles wissen", + "agentManager.review.commentOnLine": "Opmerking op regel {{line}}", + "agentManager.review.editCommentOnLine": "Opmerking op regel {{line}} bewerken", + "agentManager.review.commentPlaceholder": "Laat een opmerking achter...", + "agentManager.review.commentAction": "Opmerking", + "agentManager.review.sendToChat": "Naar chat sturen", + "agentManager.review.metaFile": "Bestand", + "agentManager.review.metaLine": "Regel", + "agentManager.review.metaComment": "Gebruikersopmerking", + "agentManager.review.collapsedOnly": "{{count}} ingeklapt", + "agentManager.review.collapsedWithLarge": "{{collapsed}} ingeklapt, {{large}} groot", + "agentManager.review.largeFileCollapsed": "Groot bestand (ingeklapt)", + "agentManager.review.endOfLongDiff": "Je hebt het einde bereikt!", + + "agentManager.import.pullRequest": "Pull Request", + "agentManager.import.pastePrUrl": "Plak PR URL...", + "agentManager.import.open": "Openen", + "agentManager.import.branches": "Branches", + "agentManager.import.selectBranch": "Selecteer branch...", + "agentManager.import.loading": "Laden...", + "agentManager.import.loadingBranches": "Branches laden...", + "agentManager.import.noMatchingBranches": "Geen overeenkomende branches", + "agentManager.import.noBranchesFound": "Geen branches gevonden.", + "agentManager.import.noBranchesHint": "Plak hierboven een PR URL of maak een nieuwe worktree.", + "agentManager.import.failed": "Importeren mislukt", +} 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 03930a5c801..6ab4a50dab0 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/PromptInput.tsx @@ -3,7 +3,7 @@ * Text input with send/abort buttons, ghost-text autocomplete, and @ file mention support */ -import { Component, createSignal, createEffect, on, For, Index, onCleanup, onMount, Show, untrack } from "solid-js" +import { Component, createSignal, createEffect, on, For, Index, onCleanup, Show, untrack } from "solid-js" import { Button } from "@kilocode/kilo-ui/button" import { Dialog } from "@kilocode/kilo-ui/dialog" import { IconButton } from "@kilocode/kilo-ui/icon-button" @@ -20,6 +20,7 @@ import { ModeSwitcher } from "../shared/ModeSwitcher" import { ThinkingSelector } from "../shared/ThinkingSelector" import { useFileMention } from "../../hooks/useFileMention" import { useSlashCommand } from "../../hooks/useSlashCommand" +import { useGhostText } from "../../hooks/useGhostText" import { useImageAttachments } from "../../hooks/useImageAttachments" import { usePromptHistory } from "../../hooks/usePromptHistory" import { WandSparkles } from "@kilocode/kilo-ui/lucide" @@ -27,9 +28,6 @@ import { fileName, dirName, buildHighlightSegments, atEnd } from "./prompt-input import type { ReviewComment, TextPart } from "../../types/messages" import { formatReviewCommentsMarkdown } from "../../utils/review-comment-markdown" -const AUTOCOMPLETE_DEBOUNCE_MS = 500 -const MIN_TEXT_LENGTH = 3 - // Per-session input text storage (module-level so it survives remounts) const drafts = new Map() const reviewDrafts = new Map() @@ -63,13 +61,13 @@ export const PromptInput: Component = (props) => { const sessionKey = () => session.currentSessionID() ?? "__new__" const [text, setText] = createSignal("") - const [ghostText, setGhostText] = createSignal("") const [reviewComments, setReviewComments] = createSignal([]) - const [chatAutocompleteEnabled, setChatAutocompleteEnabled] = createSignal(false) const [enhancing, setEnhancing] = createSignal(false) let enhanceCounter = 0 let preEnhanceText: string | null = null + const ghost = useGhostText(vscode, text, () => server.isConnected()) + const replaceReviewComments = (next: ReviewComment[]) => { setReviewComments(next) if (next.length === 0) { @@ -137,8 +135,6 @@ export const PromptInput: Component = (props) => { let highlightRef: HTMLDivElement | undefined let dropdownRef: HTMLDivElement | undefined let slashDropdownRef: HTMLDivElement | undefined - let debounceTimer: ReturnType | undefined - let requestCounter = 0 // Save/restore input text when switching sessions. // Uses `on()` to track only sessionKey — avoids re-running on every keystroke. createEffect( @@ -152,7 +148,6 @@ export const PromptInput: Component = (props) => { const draft = drafts.get(key) ?? "" const pending = reviewDrafts.get(key) ?? [] setText(draft) - setGhostText("") setReviewComments(pending) history.reset() if (textareaRef) { @@ -228,23 +223,8 @@ export const PromptInput: Component = (props) => { } const unsubscribe = vscode.onMessage((message) => { - if (message.type === "chatCompletionResult") { - const result = message as { type: "chatCompletionResult"; text: string; requestId: string } - if (result.requestId !== `chat-ac-${requestCounter}`) return - if (result.text && isAtEnd()) { - setGhostText(result.text) - return - } - setGhostText("") - } - - if (message.type === "autocompleteSettingsLoaded") { - setChatAutocompleteEnabled(message.settings.enableChatAutocomplete) - } - if (message.type === "setChatBoxMessage") { setText(message.text) - setGhostText("") if (textareaRef) { textareaRef.value = message.text adjustHeight() @@ -256,12 +236,12 @@ export const PromptInput: Component = (props) => { const separator = current && !current.endsWith("\n") ? "\n\n" : "" const next = current + separator + message.text setText(next) - setGhostText("") if (textareaRef) { textareaRef.value = next adjustHeight() textareaRef.focus() textareaRef.scrollTop = textareaRef.scrollHeight + syncHighlightScroll() } } @@ -285,7 +265,6 @@ export const PromptInput: Component = (props) => { if (target === sessionKey() && !text().trim() && imageAttach.images().length === 0) { if (failed.text) { setText(failed.text) - setGhostText("") if (textareaRef) { textareaRef.value = failed.text adjustHeight() @@ -312,7 +291,6 @@ export const PromptInput: Component = (props) => { const result = message as import("../../types/messages").EnhancePromptResultMessage if (result.requestId === `enhance-${enhanceCounter}`) { setText(result.text) - setGhostText("") setEnhancing(false) if (textareaRef) { textareaRef.value = result.text @@ -330,10 +308,6 @@ export const PromptInput: Component = (props) => { } }) - onMount(() => { - vscode.postMessage({ type: "requestAutocompleteSettings" }) - }) - onCleanup(() => { // Persist current draft before unmounting const current = text() @@ -342,39 +316,23 @@ export const PromptInput: Component = (props) => { if (pending.length > 0) reviewDrafts.set(sessionKey(), pending) else reviewDrafts.delete(sessionKey()) unsubscribe() - if (debounceTimer) clearTimeout(debounceTimer) }) - const requestAutocomplete = (val: string) => { - if (val.length < MIN_TEXT_LENGTH || isDisabled() || !chatAutocompleteEnabled() || !isAtEnd()) { - setGhostText("") - requestCounter++ - return - } - requestCounter++ - vscode.postMessage({ type: "requestChatCompletion", text: val, requestId: `chat-ac-${requestCounter}` }) - } - const acceptSuggestion = () => { - const suggestion = ghostText() - if (!suggestion) return + const result = ghost.accept() + if (!result) return - const newText = text() + suggestion - setText(newText) - setGhostText("") - vscode.postMessage({ type: "chatCompletionAccepted", suggestionLength: suggestion.length }) + const val = text() + result.text + setText(val) if (textareaRef) { - textareaRef.value = newText + textareaRef.value = val adjustHeight() + syncHighlightScroll() } } - const dismissSuggestion = () => setGhostText("") - const clearIfNotAtEnd = () => { - if (isAtEnd()) return - setGhostText("") - } + const syncGhost = () => ghost.sync(textareaRef) const scrollToActiveItem = () => { if (!dropdownRef) return @@ -419,21 +377,13 @@ export const PromptInput: Component = (props) => { setText(val) preEnhanceText = null adjustHeight() - setGhostText("") syncHighlightScroll() history.reset() slash.onInput(val, target.selectionStart ?? val.length) mention.onInput(val, target.selectionStart ?? val.length) - - if (slash.show() || mention.showMention()) { - setGhostText("") - if (debounceTimer) clearTimeout(debounceTimer) - return - } - - if (debounceTimer) clearTimeout(debounceTimer) - debounceTimer = setTimeout(() => requestAutocomplete(val), AUTOCOMPLETE_DEBOUNCE_MS) + ghost.setMentionOpen(slash.show() || mention.showMention()) + ghost.scheduleRequest(val, textareaRef) } const handleKeyDown = (e: KeyboardEvent) => { @@ -443,7 +393,6 @@ export const PromptInput: Component = (props) => { const restored = preEnhanceText preEnhanceText = null setText(restored) - setGhostText("") if (textareaRef) { textareaRef.value = restored adjustHeight() @@ -452,13 +401,13 @@ export const PromptInput: Component = (props) => { } if (slash.onKeyDown(e, textareaRef, setText, adjustHeight)) { - setGhostText("") + ghost.setMentionOpen(slash.show()) queueMicrotask(scrollToActiveSlashItem) return } if (mention.onKeyDown(e, textareaRef, setText, adjustHeight)) { - setGhostText("") + ghost.setMentionOpen(mention.showMention()) queueMicrotask(scrollToActiveItem) return } @@ -474,7 +423,6 @@ export const PromptInput: Component = (props) => { if (entry !== null) { e.preventDefault() setText(entry) - setGhostText("") if (textareaRef) { textareaRef.value = entry adjustHeight() @@ -485,22 +433,22 @@ export const PromptInput: Component = (props) => { } } - if (e.key === "Tab" && ghostText()) { + if (e.key === "Tab" && ghost.text()) { if (!isAtEnd()) return e.preventDefault() acceptSuggestion() return } - if (e.key === "ArrowRight" && ghostText()) { + if (e.key === "ArrowRight" && ghost.text()) { if (!isAtEnd()) return e.preventDefault() acceptSuggestion() return } - if (e.key === "Escape" && ghostText()) { + if (e.key === "Escape" && ghost.text()) { e.preventDefault() e.stopPropagation() - dismissSuggestion() + ghost.dismiss() return } if (e.key === "Escape" && isBusy()) { @@ -511,7 +459,6 @@ export const PromptInput: Component = (props) => { } if (e.key === "Enter" && !e.shiftKey) { e.preventDefault() - dismissSuggestion() handleSend() } } @@ -524,7 +471,6 @@ export const PromptInput: Component = (props) => { if (!draft) { const description = language.t("prompt.action.enhanceDescription") setText(description) - setGhostText("") if (textareaRef) { textareaRef.value = description adjustHeight() @@ -553,10 +499,8 @@ export const PromptInput: Component = (props) => { // Client-side slash command — runs locally without a backend round-trip if (matched?.action) { setText("") - setGhostText("") clearReviewComments() imageAttach.clear() - if (debounceTimer) clearTimeout(debounceTimer) mention.closeMention() slash.close() drafts.delete(sessionKey()) @@ -589,12 +533,9 @@ export const PromptInput: Component = (props) => { history.append(draft) history.reset() - requestCounter++ setText("") - setGhostText("") clearReviewComments() imageAttach.clear() - if (debounceTimer) clearTimeout(debounceTimer) mention.closeMention() slash.close() drafts.delete(sessionKey()) @@ -783,8 +724,8 @@ export const PromptInput: Component = (props) => { )} - - {ghostText()} + + {ghost.text()}