diff --git a/bun.lock b/bun.lock index 870af0cd652..073c5364420 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@kilocode/kilo-i18n": "workspace:*", "@kilocode/kilo-ui": "workspace:*", @@ -79,7 +79,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -112,7 +112,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -142,7 +142,7 @@ }, "packages/kilo-docs": { "name": "@kilocode/kilo-docs", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@docsearch/css": "^4", "@docsearch/js": "^4", @@ -171,7 +171,7 @@ }, "packages/kilo-gateway": { "name": "@kilocode/kilo-gateway", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@ai-sdk/anthropic": "2.0.65", "@ai-sdk/openai": "2.0.101", @@ -206,7 +206,7 @@ }, "packages/kilo-i18n": { "name": "@kilocode/kilo-i18n", - "version": "7.1.20", + "version": "7.1.21", "devDependencies": { "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -219,7 +219,7 @@ }, "packages/kilo-telemetry": { "name": "@kilocode/kilo-telemetry", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@kilocode/kilo-gateway": "workspace:*", "@opentelemetry/api": "1.9.0", @@ -239,7 +239,7 @@ }, "packages/kilo-ui": { "name": "@kilocode/kilo-ui", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@kobalte/core": "0.13.11", "@opencode-ai/util": "workspace:*", @@ -274,7 +274,7 @@ }, "packages/kilo-vscode": { "name": "kilo-code", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@anthropic-ai/sdk": "^0.39.0", "@kilocode/kilo-i18n": "workspace:*", @@ -327,7 +327,7 @@ }, "packages/opencode": { "name": "@kilocode/cli", - "version": "7.1.20", + "version": "7.1.21", "bin": { "kilo": "./bin/kilo", "kilocode": "./bin/kilo", @@ -451,7 +451,7 @@ }, "packages/plugin": { "name": "@kilocode/plugin", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@kilocode/sdk": "workspace:*", "zod": "catalog:", @@ -465,14 +465,14 @@ }, "packages/script": { "name": "@opencode-ai/script", - "version": "7.1.20", + "version": "7.1.21", "devDependencies": { "@types/bun": "catalog:", }, }, "packages/sdk/js": { "name": "@kilocode/sdk", - "version": "7.1.20", + "version": "7.1.21", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -483,7 +483,7 @@ }, "packages/storybook": { "name": "@opencode-ai/storybook", - "version": "7.1.20", + "version": "7.1.21", "devDependencies": { "@opencode-ai/ui": "workspace:*", "@solidjs/meta": "catalog:", @@ -506,7 +506,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "@kilocode/sdk": "workspace:*", "@kobalte/core": "catalog:", @@ -553,7 +553,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "7.1.20", + "version": "7.1.21", "dependencies": { "zod": "catalog:", }, diff --git a/package.json b/package.json index 904a5a290d6..921e2911bd3 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.1.20", + "version": "7.1.21", "peerDependencies": {} } diff --git a/packages/app/package.json b/packages/app/package.json index 5a118458382..22b1ae01ec4 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "7.1.20", + "version": "7.1.21", "description": "", "type": "module", "exports": { diff --git a/packages/desktop-electron/package.json b/packages/desktop-electron/package.json index fda4582038e..d21d46182a8 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.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "homepage": "https://opencode.ai", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index d13399bae9e..ad500440bfa 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/desktop", "private": true, - "version": "7.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 522d8ecbbb0..4026a0d9708 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "kilo" name = "Kilo" description = "The open source coding agent." -version = "7.1.20" +version = "7.1.21" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/Kilo-Org/kilocode" @@ -11,26 +11,26 @@ name = "Kilo" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-darwin-arm64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.21/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-darwin-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.21/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-linux-arm64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.21/opencode-linux-arm64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-linux-x64.tar.gz" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.21/opencode-linux-x64.tar.gz" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.20/opencode-windows-x64.zip" +archive = "https://github.com/Kilo-Org/kilocode/releases/download/v7.1.21/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/kilo-docs/lib/nav/kiloclaw.ts b/packages/kilo-docs/lib/nav/kiloclaw.ts index 695801fc49d..5b232a18f4e 100644 --- a/packages/kilo-docs/lib/nav/kiloclaw.ts +++ b/packages/kilo-docs/lib/nav/kiloclaw.ts @@ -43,6 +43,7 @@ export const KiloClawNav: NavSection[] = [ subLinks: [ { href: "/kiloclaw/triggers", children: "Overview" }, { href: "/kiloclaw/triggers/webhooks", children: "Webhooks" }, + { href: "/kiloclaw/triggers/scheduled", children: "Scheduled" }, ], }, { diff --git a/packages/kilo-docs/package.json b/packages/kilo-docs/package.json index 35af7893fb5..924318f63bb 100644 --- a/packages/kilo-docs/package.json +++ b/packages/kilo-docs/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-docs", - "version": "7.1.20", + "version": "7.1.21", "private": true, "scripts": { "dev": "next dev --webpack --port 3002", diff --git a/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md b/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md index 967ec981698..fc511e0e225 100644 --- a/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md +++ b/packages/kilo-docs/pages/code-with-ai/platforms/cloud-agent.md @@ -112,30 +112,43 @@ Cloud Agents are great for: - **Automated refactors or tech debt cleanup** driven by Kilo Code - **Offloading CI-like tasks**, experiments, or batch updates -## Webhook Triggers +## Triggers -Webhook triggers allow you to initiate cloud agent sessions via HTTP requests. This enables integration with external services and automation workflows. +Triggers allow you to initiate cloud agent sessions automatically, either via HTTP requests (webhooks) or on a recurring schedule. This enables integration with external services and time-based automation workflows. {% callout type="note" %} -Webhook triggers are currently in beta and subject to change. +Triggers are currently in beta and subject to change. {% /callout %} -### Accessing Webhooks +### Accessing Triggers -Webhook triggers are accessible from the main sidebar with an entry named **Webhook** and link to [https://app.kilo.ai/cloud/webhooks](https://app.kilo.ai/cloud/webhooks) for personal accounts. Organization-level webhook configurations are available through your organization's sidebar. +Triggers are accessible from the main sidebar under **Webhooks / Triggers** and link to [https://app.kilo.ai/cloud/triggers](https://app.kilo.ai/cloud/triggers) for personal accounts. Organization-level trigger configurations are available through your organization's sidebar. + +### Activation Modes + +When creating a trigger, you choose an **activation mode** that cannot be changed after creation: + +- **Webhook**: Fires when an external service sends an HTTP request to the trigger's URL +- **Scheduled**: Fires on a recurring schedule defined by a cron expression ### Configuration -Webhook triggers utilize [agent environment profiles](#agent-environment-profiles) to configure the execution environment for triggered sessions. The agent resolves the profile at runtime, so profile updates apply automatically to future executions. Profiles referenced by triggers cannot be deleted until those triggers are updated or removed. +Triggers utilize [agent environment profiles](#agent-environment-profiles) to configure the execution environment for triggered sessions. The agent resolves the profile at runtime, so profile updates apply automatically to future executions. Profiles referenced by triggers cannot be deleted until those triggers are updated or removed. -Webhook triggers do not support manual env var or setup command overrides at this time. +Triggers do not support manual env var or setup command overrides at this time. + +### Scheduled Triggers + +Scheduled triggers fire on a recurring schedule using cron expressions. You can configure them with a simple frequency picker (every 10 minutes, hourly, daily, weekly) or enter a raw cron expression for full control. Each trigger has a configurable timezone (default: UTC) and handles daylight saving time transitions automatically. + +The minimum schedule interval is 10 minutes. Scheduled triggers use `{{scheduledTime}}` and `{{timestamp}}` as prompt template variables (webhook-specific variables like `{{body}}` are not available since there is no inbound HTTP request). ### Trigger Limits and Guidance -Webhook triggers are designed for low-volume invocations from trusted sources and are best suited for short-lived tasks. +Triggers are designed for low-volume invocations from trusted sources and are best suited for short-lived tasks. -- **Personal webhooks**: Execute in the same sandbox container as a user's Cloud Agent sessions. You can view/join invocations live. -- **Organization webhooks**: Execute in dedicated compute resources as a bot user, similar to Code Review sessions. You can share/fork the sessions when they're complete. +- **Personal triggers**: Execute in the same sandbox container as a user's Cloud Agent sessions. You can view/join invocations live. +- **Organization triggers**: Execute in dedicated compute resources as a bot user, similar to Code Review sessions. You can share/fork the sessions when they're complete. Additional limits: @@ -144,11 +157,13 @@ Additional limits: - **Retention**: only the **most recent 100 requests per trigger** are retained - **In-flight cap**: at most **20 requests per trigger** can be in `captured` or `inprogress` at once (returns `429`) -The webhook endpoint will return rate limit responses when the number of queued or processing requests exceeds system capacity. +The trigger endpoint will return rate limit responses when the number of queued or processing requests exceeds system capacity. -### Webhook Prompt Template Variables +### Prompt Template Variables -You can reference request data in a trigger’s prompt template using these placeholders: +You can reference data in a trigger’s prompt template using these placeholders. + +**Webhook triggers:** - `{{body}}` - raw request body (string) - `{{bodyJson}}` - pretty-printed JSON if parseable, otherwise raw body @@ -159,6 +174,11 @@ You can reference request data in a trigger’s prompt template using these plac - `{{sourceIp}}` - client IP if provided (falls back to `unknown`) - `{{timestamp}}` - capture timestamp (ISO string) +**Scheduled triggers:** + +- `{{scheduledTime}}` - the time the schedule fired (ISO string) +- `{{timestamp}}` - capture timestamp (ISO string) + {% callout type="warning" title="Security Considerations" %} Care should be taken when deciding to use webhooks as they are susceptible to prompt injection attacks. Especially in scenarios where webhook payloads may contain untrusted input. At this time we recommend using webhooks only for trusted sources. {% /callout %} diff --git a/packages/kilo-docs/pages/kiloclaw/triggers/index.md b/packages/kilo-docs/pages/kiloclaw/triggers/index.md index 10412d71eb3..ae5941d37f9 100644 --- a/packages/kilo-docs/pages/kiloclaw/triggers/index.md +++ b/packages/kilo-docs/pages/kiloclaw/triggers/index.md @@ -7,26 +7,31 @@ description: "Automate your KiloClaw agent with webhooks and scheduled triggers" Triggers let external events and schedules drive your KiloClaw agent automatically. Instead of typing every instruction yourself, triggers deliver messages to your agent on your behalf. This lets it react to real-world events or run tasks on a schedule without polling. -All triggers are managed from the **Settings** tab on your [KiloClaw dashboard](/docs/kiloclaw/dashboard). +All triggers are managed from the **Settings** page in the KiloClaw section of the sidebar. ## Trigger Types -| Type | Description | Status | -| --- | --- | --- | -| [**Webhooks**](/docs/kiloclaw/triggers/webhooks) | Receive HTTP requests from external services (GitHub, Stripe, monitoring tools, etc.) and deliver them as chat messages to your agent | Available | -| **Time-based** | Run tasks on a schedule using cron expressions | Coming soon | +| Type | Description | +| --- | --- | +| [**Webhooks**](/docs/kiloclaw/triggers/webhooks) | Receive HTTP requests from external services (GitHub, Stripe, monitoring tools, etc.) and deliver them as chat messages to your agent | +| [**Scheduled**](/docs/kiloclaw/triggers/scheduled) | Run tasks on a recurring schedule (e.g. every 15 minutes, daily at 9 AM, weekdays only) | ## How Triggers Work -1. An event occurs (an HTTP request arrives, or a schedule fires) -2. The trigger validates the request and renders the payload through a **prompt template** -3. The rendered message is delivered to your KiloClaw instance as a chat message +1. A trigger fires +2. Your **prompt template** is rendered into a message +3. That message is delivered to your KiloClaw instance as a chat message 4. Your agent processes and responds like any other conversation -Prompt templates give you control over how payloads are presented to your agent. You can include instructions, context, and formatting alongside the raw event data. +Each trigger type has its own set of template variables. See the [Webhooks](/docs/kiloclaw/triggers/webhooks) and [Scheduled](/docs/kiloclaw/triggers/scheduled) pages for details. + +{% callout type="warning" title="Triggers send prompts directly to your agent" %} +When a trigger fires, the rendered message is sent directly to your KiloClaw agent as a prompt. If your instance is configured with a permission model that allows all actions, the agent will execute commands automatically without your explicit approval. This means triggers can cause your agent to take actions without you being aware. Review your instance's [permission settings](/docs/kiloclaw/control-ui/exec-approvals) and prompt templates carefully before enabling triggers. +{% /callout %} ## Related - [Webhooks](/docs/kiloclaw/triggers/webhooks) +- [Scheduled Triggers](/docs/kiloclaw/triggers/scheduled) - [KiloClaw Overview](/docs/kiloclaw/overview) - [Dashboard Reference](/docs/kiloclaw/dashboard) diff --git a/packages/kilo-docs/pages/kiloclaw/triggers/scheduled.md b/packages/kilo-docs/pages/kiloclaw/triggers/scheduled.md new file mode 100644 index 00000000000..1ca5de20c1c --- /dev/null +++ b/packages/kilo-docs/pages/kiloclaw/triggers/scheduled.md @@ -0,0 +1,123 @@ +--- +title: "Scheduled Triggers" +description: "Run tasks on a schedule using cron expressions" +--- + +# Scheduled Triggers + +Scheduled triggers let your KiloClaw agent run tasks automatically on a recurring schedule. Instead of waiting for an external event, a scheduled trigger fires at the times you define using cron expressions. When it fires, the prompt template is rendered and delivered as a chat message to your KiloClaw instance, just like a webhook. + +## Setup + +1. Go to **Settings** under the KiloClaw section in the sidebar +2. Find the **Scheduled Triggers** section and click **Add Scheduled Trigger** +3. Give your trigger a name (minimum 8 characters) +4. Configure the schedule and prompt template +5. Click **Save** + +Each KiloClaw instance supports up to **5 scheduled triggers** alongside its single webhook. + +## Configuring a Schedule + +The schedule builder defaults to a friendly picker view. For more control, click **<> Advanced** to switch to raw cron input. + +### Simple Mode (default) + +Pick a frequency, time, and (optionally) days of the week from dropdown menus. The builder generates the cron expression for you behind the scenes and shows a preview of the next 5 upcoming runs. + +- **Repeat**: Every 10 minutes, every 15 minutes, every 30 minutes, hourly, daily, weekly +- **At**: Select the time of day (for daily and weekly frequencies) +- **Day of week**: Select which days the trigger should fire (for weekly frequency) + +### Advanced Mode + +Click **<> Advanced** to enter a raw cron expression directly. This gives you full control over the schedule. The expression is validated in real time with a preview of upcoming fire times. + +Cron expressions use the standard five-field format: + +``` +┌───────── minute (0-59) +│ ┌───────── hour (0-23) +│ │ ┌───────── day of month (1-31) +│ │ │ ┌───────── month (1-12) +│ │ │ │ ┌───────── day of week (0-7, where 0 and 7 are Sunday) +│ │ │ │ │ +* * * * * +``` + +**Examples:** + +| Expression | Meaning | +| --- | --- | +| `*/15 * * * *` | Every 15 minutes | +| `0 9 * * 1-5` | 9:00 AM on weekdays | +| `0 0 1 * *` | Midnight on the first of each month | +| `30 14 * * 3` | 2:30 PM every Wednesday | + +{% callout type="note" title="Minimum interval" %} +The minimum interval between scheduled trigger runs is 10 minutes. Schedules more frequent than that are rejected. +{% /callout %} + +### Timezone + +Select a timezone for your schedule. The default is UTC. All fire times are calculated relative to the selected timezone, including automatic handling of daylight saving time transitions. + +## Prompt Template + +The prompt template controls what message your agent receives when the schedule fires. You can customize it from the trigger's settings. + +**Default template:** + +``` +Run your scheduled task. Triggered at {{scheduledTime}}. +``` + +**Available variables:** + +| Variable | Description | +| --- | --- | +| `{{scheduledTime}}` | The time the schedule fired (ISO string) | +| `{{timestamp}}` | Capture timestamp (ISO string) | + +{% callout type="note" title="Webhook variables are not available" %} +Since scheduled triggers do not receive an HTTP request, variables like `{{body}}`, `{{bodyJson}}`, `{{headers}}`, `{{method}}`, `{{path}}`, and `{{query}}` are not populated. Use `{{scheduledTime}}` and `{{timestamp}}` instead. +{% /callout %} + +## Managing Scheduled Triggers + +### Pause and Resume + +Toggle the **Active/Paused** switch to temporarily stop a trigger from firing. When paused, the schedule is suspended but the configuration is preserved. Resume at any time to restart the schedule. + +### Edit + +You can update the cron expression, timezone, and prompt template of an existing scheduled trigger at any time. The activation mode (webhook vs. scheduled) cannot be changed after creation. + +### Delete + +Remove a scheduled trigger from the inline controls in the Settings panel. A confirmation dialog is shown before deletion. + +## Viewing Scheduled Trigger Activity + +Scheduled trigger invocations appear in the same request history as webhooks. The **Source** column shows a **Scheduled** badge to distinguish them from webhook-triggered requests. Click into a request to see the scheduled fire time and other details. + +## Example: Daily Standup Summary + +Create a scheduled trigger that fires every weekday morning and asks your agent to summarize overnight activity: + +1. Add a scheduled trigger in your KiloClaw Settings +2. Set the frequency to **Weekly** on **Monday through Friday** at **9:00 AM** in your local timezone +3. Customize the prompt template: + +``` +Good morning! Please summarize any overnight activity in the #engineering Slack channel and list open pull requests that need review today. Triggered at {{scheduledTime}}. +``` + +Your agent will receive this message every weekday at 9:00 AM and respond with the summary. + +## Related + +- [Webhooks](/docs/kiloclaw/triggers/webhooks) +- [Triggers Overview](/docs/kiloclaw/triggers) +- [KiloClaw Overview](/docs/kiloclaw/overview) +- [Dashboard Reference](/docs/kiloclaw/dashboard) diff --git a/packages/kilo-docs/pages/kiloclaw/triggers/webhooks.md b/packages/kilo-docs/pages/kiloclaw/triggers/webhooks.md index c2c04cdabbf..2e57f8e97fc 100644 --- a/packages/kilo-docs/pages/kiloclaw/triggers/webhooks.md +++ b/packages/kilo-docs/pages/kiloclaw/triggers/webhooks.md @@ -9,7 +9,7 @@ KiloClaw supports inbound webhooks so external events can trigger your agent aut ## Setup -1. Go to the **Settings** tab on your [KiloClaw dashboard](/docs/kiloclaw/dashboard) +1. Go to **Settings** under the KiloClaw section in the sidebar 2. Find the **Webhook Integration** card and click **Manage** 3. Click **Set Up Webhook** @@ -104,6 +104,8 @@ Now every push to that repository sends a payload to your agent. Customize the p ## Related +- [Scheduled Triggers](/docs/kiloclaw/triggers/scheduled) +- [Triggers Overview](/docs/kiloclaw/triggers) - [KiloClaw Overview](/docs/kiloclaw/overview) - [Dashboard Reference](/docs/kiloclaw/dashboard) - [GitHub Integration](/docs/kiloclaw/development-tools/github) diff --git a/packages/kilo-gateway/package.json b/packages/kilo-gateway/package.json index 2fe42fe6c7d..0eea002047f 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.1.20", + "version": "7.1.21", "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 6799fd9ba2f..61b5898bfa9 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.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "description": "Kilo-specific i18n translations and overrides", diff --git a/packages/kilo-telemetry/package.json b/packages/kilo-telemetry/package.json index ce9af0d3fd7..8cd77dd621f 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.1.20", + "version": "7.1.21", "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 fb213597db2..4a7a4047fd9 100644 --- a/packages/kilo-ui/package.json +++ b/packages/kilo-ui/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/kilo-ui", - "version": "7.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "exports": { diff --git a/packages/kilo-vscode/package.json b/packages/kilo-vscode/package.json index f6cc9503fdd..8b7d9b1221d 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.1.20", + "version": "7.1.21", "icon": "assets/icons/logo-outline-black.png", "galleryBanner": { "color": "#FFFFFF", @@ -704,6 +704,11 @@ "default": false, "description": "Enable chat textarea autocomplete" }, + "kilo-code.new.claudeCodeCompat": { + "type": "boolean", + "default": false, + "description": "Load CLAUDE.md instructions and skills from your Claude Code configuration directory into Kilo sessions. Enable this if you want Kilo to use your Claude Code instructions and skills." + }, "kilo-code.new.browserAutomation.enabled": { "type": "boolean", "default": false, diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 633fb7e3c34..372d076d5c4 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -45,6 +45,7 @@ import { checkAndShowMigrationWizard, handleRequestLegacyMigrationData, handleStartLegacyMigration, + handleFinalizeLegacyMigration, handleSkipLegacyMigration, handleClearLegacyData, type MigrationContext, @@ -786,6 +787,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper case "requestBrowserSettings": this.sendBrowserSettings() break + case "requestClaudeCompatSetting": + this.sendClaudeCompatSetting() + break case "requestNotificationSettings": this.sendNotificationSettings() break @@ -891,6 +895,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper case "clearLegacyData": void handleClearLegacyData(this.migrationCtx) break + case "finalizeLegacyMigration": + void handleFinalizeLegacyMigration(this.migrationCtx) + break // legacy-migration end case "enhancePrompt": { const sdkClient = this.client @@ -2551,6 +2558,17 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper }) } + /** + * Read the current Claude Code compatibility setting and push it to the webview. + */ + private sendClaudeCompatSetting(): void { + const enabled = vscode.workspace.getConfiguration("kilo-code.new").get("claudeCodeCompat", false) + this.postMessage({ + type: "claudeCompatSettingLoaded", + enabled: enabled ?? false, + }) + } + /** Re-fetch all server-side state after an auth change. */ private async reloadAfterAuthChange(): Promise { await Promise.all([ diff --git a/packages/kilo-vscode/src/kilo-provider/handlers/migration.ts b/packages/kilo-vscode/src/kilo-provider/handlers/migration.ts index b95d630610f..a0a06c210c0 100644 --- a/packages/kilo-vscode/src/kilo-provider/handlers/migration.ts +++ b/packages/kilo-vscode/src/kilo-provider/handlers/migration.ts @@ -6,7 +6,11 @@ */ import type { KiloClient } from "@kilocode/sdk/v2/client" -import type { LegacyMigrationData, MigrationSelections } from "../../legacy-migration/legacy-types" +import type { + LegacyMigrationData, + MigrationSelections, + MigrationSessionProgress, +} from "../../legacy-migration/legacy-types" import * as MigrationService from "../../legacy-migration/migration-service" /** Subset of vscode.ExtensionContext needed by migration handlers. */ @@ -31,10 +35,22 @@ export interface MigrationContext { refreshSessions(): void cachedLegacyData: LegacyMigrationData | null migrationCheckInFlight: boolean + lastMigrationHadErrors?: boolean disposeGlobal(): Promise broadcastComplete(): void } +function postSessionProgress(ctx: MigrationContext, progress: MigrationSessionProgress): void { + ctx.postMessage({ + type: "legacyMigrationSessionProgress", + session: progress.session, + index: progress.index, + total: progress.total, + phase: progress.phase, + error: progress.error, + }) +} + /** * Check for legacy data on first run and send migration state to the webview * if the user has not yet been prompted. @@ -111,26 +127,17 @@ export async function handleStartLegacyMigration( (item, status, message) => { ctx.postMessage({ type: "legacyMigrationProgress", item, status, message }) }, + (progress: MigrationSessionProgress) => { + postSessionProgress(ctx, progress) + }, ctx.cachedLegacyData?.settings, + ctx.cachedLegacyData?.sessions, ) - const failed = results.some((r) => r.status === "error") - const success = results.some((r) => r.status === "success") - - if (!failed && success) { - // Dispose all instances after a fully successful migration. - // Reloading the data will be handled once the server replies with a global.disposed event. - await ctx.disposeGlobal() - await MigrationService.setMigrationStatus( - ctx.extensionContext as Parameters[0], - "completed", - ) - ctx.broadcastComplete() - ctx.refreshSessions() - } - + ctx.lastMigrationHadErrors = results.some((item) => item.status === "error") ctx.postMessage({ type: "legacyMigrationComplete", results }) } catch (error) { + ctx.lastMigrationHadErrors = true console.error("[Kilo New] KiloProvider: ❌ Migration failed", error) ctx.postMessage({ type: "legacyMigrationComplete", @@ -146,6 +153,17 @@ export async function handleStartLegacyMigration( } } +export async function handleFinalizeLegacyMigration(ctx: MigrationContext): Promise { + if (!ctx.extensionContext) return + await ctx.disposeGlobal() + await MigrationService.setMigrationStatus( + ctx.extensionContext as Parameters[0], + ctx.lastMigrationHadErrors ? "completed_with_errors" : "completed", + ) + ctx.broadcastComplete() + ctx.refreshSessions() +} + /** Record that the user skipped migration and broadcast to all instances. */ export async function handleSkipLegacyMigration(ctx: MigrationContext): Promise { if (!ctx.extensionContext) return diff --git a/packages/kilo-vscode/src/legacy-migration/legacy-types.ts b/packages/kilo-vscode/src/legacy-migration/legacy-types.ts index 15dfa1a01e3..489bf0abab7 100644 --- a/packages/kilo-vscode/src/legacy-migration/legacy-types.ts +++ b/packages/kilo-vscode/src/legacy-migration/legacy-types.ts @@ -299,11 +299,18 @@ export interface MigrationCustomModeInfo { nativeSlug?: string } +export interface MigrationSessionInfo { + id: string + title: string + directory: string + time: number +} + export interface LegacyMigrationData { providers: MigrationProviderInfo[] mcpServers: MigrationMcpServerInfo[] customModes: MigrationCustomModeInfo[] - sessions?: string[] + sessions?: MigrationSessionInfo[] defaultModel?: { provider: string; model: string } settings?: LegacySettings hasData: boolean @@ -330,11 +337,26 @@ export interface MigrationSettingsSelections { autocomplete: boolean } +export interface MigrationSessionSelection { + id: string + force?: boolean +} + export interface MigrationSelections { providers: string[] mcpServers: string[] customModes: string[] - sessions?: string[] + sessions?: MigrationSessionSelection[] defaultModel: boolean settings: MigrationSettingsSelections } + +export type MigrationSessionPhase = "preparing" | "storing" | "skipped" | "done" | "summary" | "error" + +export interface MigrationSessionProgress { + session: MigrationSessionInfo + index: number + total: number + phase: MigrationSessionPhase + error?: string +} diff --git a/packages/kilo-vscode/src/legacy-migration/migration-service.ts b/packages/kilo-vscode/src/legacy-migration/migration-service.ts index 54b02206f71..7a2bb2036b0 100644 --- a/packages/kilo-vscode/src/legacy-migration/migration-service.ts +++ b/packages/kilo-vscode/src/legacy-migration/migration-service.ts @@ -33,7 +33,10 @@ import type { MigrationProviderInfo, MigrationMcpServerInfo, MigrationCustomModeInfo, + MigrationSessionInfo, + MigrationSessionProgress, } from "./legacy-types" +import { buildSessionMeta, buildSessionProgress } from "./migration-session-progress" import type { MigrationResultItem } from "./migration-types" import { createSessionID } from "./sessions/lib/ids" import { migrate as migrateSession } from "./sessions/migrate" @@ -46,7 +49,7 @@ const SECRET_KEY = "roo_cline_config_api_config" const CODEX_OAUTH_SECRET_KEY = "openai-codex-oauth-credentials" const MIGRATION_STATUS_KEY = "kilo.legacyMigrationStatus" -type MigrationStatus = "completed" | "skipped" +type MigrationStatus = "completed" | "completed_with_errors" | "skipped" // --------------------------------------------------------------------------- // Status helpers @@ -114,18 +117,27 @@ export async function detectLegacyData(context: vscode.ExtensionContext): Promis } async function readSessionsInGlobalStorage(context: vscode.ExtensionContext) { - const items = context.globalState.get<{ id: string }[]>("taskHistory", []) + const items = context.globalState.get<{ id: string; task?: string; workspace?: string; ts?: number }[]>( + "taskHistory", + [], + ) const base = vscode.Uri.joinPath(context.globalStorageUri, "tasks") - const ids: string[] = [] + const sessions: MigrationSessionInfo[] = [] for (const item of items) { const file = vscode.Uri.joinPath(base, item.id, "api_conversation_history.json") const exists = await vscode.workspace.fs.stat(file).then( () => true, () => false, ) - if (exists) ids.push(item.id) + if (!exists) continue + sessions.push({ + id: item.id, + title: item.task?.trim() || item.id, + directory: item.workspace?.trim() || "", + time: item.ts ?? 0, + }) } - return ids + return sessions } // --------------------------------------------------------------------------- @@ -138,6 +150,11 @@ export type ProgressCallback = ( message?: string, ) => void +export type SessionProgressCallback = (progress: MigrationSessionProgress) => void + +const SESSION_DELAY = 300 +const SESSION_SUMMARY_DELAY = 1000 + /** * Executes migration for the selected items. * Calls onProgress for each item with real-time status updates. @@ -150,13 +167,16 @@ export async function migrate( client: KiloClient, selections: MigrationSelections, onProgress: ProgressCallback, + onSessionProgress?: SessionProgressCallback, cachedSettings?: LegacySettings, + cachedSessions?: MigrationSessionInfo[], ): Promise { const profiles = await readLegacyProviderProfiles(context) const mcpSettings = await readLegacyMcpSettings(context) const customModes = await readLegacyCustomModes(context) const prompts = readLegacyCustomModePrompts(context) const legacySettings = cachedSettings ?? readLegacySettings(context) + const sessions = cachedSessions ?? (await readSessionsInGlobalStorage(context)) const results: MigrationResultItem[] = [] @@ -257,17 +277,35 @@ export async function migrate( } if (selections.sessions?.length) { - for (const id of selections.sessions) { - onProgress(id, "migrating") - const result = await migrateSession(id, context, client) + const list = selections.sessions + for (const [index, item] of list.entries()) { + onProgress(item.id, "migrating") + const session = sessions.find((entry: MigrationSessionInfo) => entry.id === item.id) + const meta = buildSessionMeta(session, index, list.length) + const progress = buildSessionProgress(meta, onSessionProgress) + const result = await migrateSession(item, context, client, meta, progress) const reason = result.ok ? "Session migrated" : result.message results.push({ - item: id, + item: item.id, category: "session", status: result.ok ? "success" : "error", message: reason, }) - onProgress(id, result.ok ? "success" : "error", reason) + onProgress(item.id, result.ok ? "success" : "error", reason) + if (index < list.length - 1) { + await new Promise((resolve) => setTimeout(resolve, SESSION_DELAY)) + } + } + const last = list.at(-1) + const session = last ? sessions.find((item: MigrationSessionInfo) => item.id === last.id) : undefined + if (session && onSessionProgress) { + onSessionProgress({ + session, + index: list.length, + total: list.length, + phase: "summary", + }) + await new Promise((resolve) => setTimeout(resolve, SESSION_SUMMARY_DELAY)) } } diff --git a/packages/kilo-vscode/src/legacy-migration/migration-session-progress.ts b/packages/kilo-vscode/src/legacy-migration/migration-session-progress.ts new file mode 100644 index 00000000000..128cefa10a2 --- /dev/null +++ b/packages/kilo-vscode/src/legacy-migration/migration-session-progress.ts @@ -0,0 +1,37 @@ +import type { MigrationSessionInfo, MigrationSessionProgress } from "./legacy-types" +import type { SessionProgressCallback } from "./migration-service" + +export interface MigrationSessionMeta { + session: MigrationSessionInfo + index: number + total: number +} + +export function buildSessionMeta( + session: MigrationSessionInfo | undefined, + index: number, + total: number, +): MigrationSessionMeta | undefined { + if (!session) return undefined + return { + session, + index: index + 1, + total, + } +} + +export function buildSessionProgress( + meta: MigrationSessionMeta | undefined, + onProgress: SessionProgressCallback | undefined, +) { + if (!meta || !onProgress) return undefined + return (progress: Omit) => { + onProgress({ + session: meta.session, + index: meta.index, + total: meta.total, + phase: progress.phase, + error: progress.error, + }) + } +} diff --git a/packages/kilo-vscode/src/legacy-migration/sessions/migrate.ts b/packages/kilo-vscode/src/legacy-migration/sessions/migrate.ts index 0fa38fdaf0d..a77ca130fa2 100644 --- a/packages/kilo-vscode/src/legacy-migration/sessions/migrate.ts +++ b/packages/kilo-vscode/src/legacy-migration/sessions/migrate.ts @@ -1,6 +1,8 @@ import * as vscode from "vscode" import type { KiloClient } from "@kilocode/sdk/v2/client" import { getMigrationErrorMessage } from "../errors/migration-error" +import type { MigrationSessionInfo, MigrationSessionProgress, MigrationSessionSelection } from "../legacy-types" +import { createSessionID } from "./lib/ids" import type { LegacyHistoryItem } from "./lib/legacy-types" import { parseSession } from "./parser" @@ -8,21 +10,71 @@ type Result = | { ok: true skipped?: boolean - payload: Awaited> + payload?: Awaited> } | { ok: false - payload: Awaited> + payload?: Awaited> message: string } -export async function migrate(id: string, context: vscode.ExtensionContext, client: KiloClient): Promise { +type Progress = Omit +type ProgressCallback = (progress: Progress) => void +type Payload = Awaited> + +function trimError(input: string) { + return input.length <= 100 ? input : `${input.slice(0, 100)}...` +} + +export async function migrate( + input: MigrationSessionSelection, + context: vscode.ExtensionContext, + client: KiloClient, + meta?: { + session: MigrationSessionInfo + index: number + total: number + }, + onProgress?: ProgressCallback, +): Promise { const dir = vscode.Uri.joinPath(context.globalStorageUri, "tasks").fsPath const items = context.globalState.get("taskHistory", []) - const item = items.find((item) => item.id === id) - const payload = await parseSession(id, dir, item) + const item = items.find((item) => item.id === input.id) + + const progress = (next: Progress) => { + if (!meta || !onProgress) return + onProgress(next) + } + + const skip = () => { + progress({ phase: "skipped" }) + return { + ok: true as const, + skipped: true, + } + } + + const fail = (error: unknown, payload?: Payload) => { + progress({ + phase: "error", + error: trimError(getMigrationErrorMessage(error)), + }) + return { + ok: false as const, + ...(payload ? { payload } : {}), + message: getMigrationErrorMessage(error), + } + } try { + if (!input.force) { + const result = await client.session.get({ sessionID: createSessionID(input.id) }) + if (result.data) return skip() + } + + progress({ phase: "preparing" }) + const payload = await parseSession(input.id, dir, item) + progress({ phase: "storing" }) const project = await client.kilocode.sessionImport.project(payload.project, { throwOnError: true }) const projectID = project.data?.id ?? payload.project.id const session = await client.kilocode.sessionImport.session( @@ -31,11 +83,13 @@ export async function migrate(id: string, context: vscode.ExtensionContext, clie projectID, query_directory: payload.session.directory, body_directory: payload.session.directory, + ...(input.force ? { force: true } : {}), }, { throwOnError: true }, ) // Skip child imports when the session already exists so rerunning migration only imports missing sessions. if (session.data?.skipped) { + progress({ phase: "skipped" }) return { ok: true, skipped: true, @@ -51,15 +105,13 @@ export async function migrate(id: string, context: vscode.ExtensionContext, clie await client.kilocode.sessionImport.part(part, { throwOnError: true }) } + progress({ phase: "done" }) + return { ok: true, payload, } } catch (error) { - return { - ok: false, - payload, - message: getMigrationErrorMessage(error), - } + return fail(error) } } diff --git a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts index 4b08a6284e7..63c77e1d8fd 100644 --- a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts +++ b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts @@ -66,6 +66,7 @@ export class ServerManager { return new Promise((resolve, reject) => { console.log("[Kilo New] ServerManager: 🎬 Spawning CLI process:", cliPath, ["serve", "--port", "0"]) + const claudeCompat = vscode.workspace.getConfiguration("kilo-code.new").get("claudeCodeCompat", false) const serverProcess = spawn(cliPath, ["serve", "--port", "0"], { env: { ...process.env, @@ -80,6 +81,7 @@ export class ServerManager { KILO_MACHINE_ID: vscode.env.machineId, KILO_APP_VERSION: this.context.extension.packageJSON.version, KILO_VSCODE_VERSION: vscode.version, + ...(!claudeCompat && { KILO_DISABLE_CLAUDE_CODE: "true" }), }, stdio: ["ignore", "pipe", "pipe"], detached: true, diff --git a/packages/kilo-vscode/tests/unit/legacy-migration/migrate.test.ts b/packages/kilo-vscode/tests/unit/legacy-migration/migrate.test.ts index 5eede710e73..55412c700ff 100644 --- a/packages/kilo-vscode/tests/unit/legacy-migration/migrate.test.ts +++ b/packages/kilo-vscode/tests/unit/legacy-migration/migrate.test.ts @@ -1,4 +1,5 @@ import { beforeEach, describe, expect, it, mock } from "bun:test" +import { createSessionID } from "../../../src/legacy-migration/sessions/lib/ids" const parseSession = mock(async () => ({ project: { @@ -43,8 +44,12 @@ function ctx() { function client() { const calls: Array<{ name: string; body: unknown }> = [] + const get = mock(async () => ({ data: null as { id: string } | null })) return { calls, + session: { + get, + }, kilocode: { sessionImport: { project: async (body: unknown) => { @@ -73,9 +78,57 @@ describe("legacy migration migrate", () => { parseSession.mockClear() }) + it("skips before parsing when the migrated session already exists and force is false", async () => { + const api = { + session: { + get: async (body: unknown) => { + expect(body).toEqual({ sessionID: createSessionID("legacy-task-1") }) + return { data: { id: createSessionID("legacy-task-1") } } + }, + }, + kilocode: { + sessionImport: { + project: async () => { + throw new Error("should not import project") + }, + session: async () => { + throw new Error("should not import session") + }, + message: async () => { + throw new Error("should not import message") + }, + part: async () => { + throw new Error("should not import part") + }, + }, + }, + } + + const result = await migrate({ id: "legacy-task-1" }, ctx() as never, api as never) + + expect(result.ok).toBe(true) + expect(result).toHaveProperty("skipped", true) + expect(parseSession).not.toHaveBeenCalled() + }) + + it("continues with import when force is true even if the migrated session already exists", async () => { + const api = client() + api.session.get.mockImplementation(async () => ({ data: { id: createSessionID("legacy-task-1") } })) + + await migrate({ id: "legacy-task-1", force: true }, ctx() as never, api as never) + + expect(parseSession).toHaveBeenCalledTimes(1) + const call = api.calls.find((item) => item.name === "session") + expect(call).toBeDefined() + expect((call?.body as { force?: boolean }).force).toBe(true) + }) + it("inserts project then session then message then part in the correct order", async () => { const calls: string[] = [] const api = { + session: { + get: async () => ({ data: null }), + }, kilocode: { sessionImport: { project: async () => { @@ -144,7 +197,7 @@ describe("legacy migration migrate", () => { ] as never, }) - await migrate("legacy-task-1", ctx() as never, api as never) + await migrate({ id: "legacy-task-1" }, ctx() as never, api as never) expect(calls).toEqual(["project", "session", "message", "part"]) }) @@ -152,7 +205,7 @@ describe("legacy migration migrate", () => { it("uses the projectID returned by backend when inserting the session", async () => { const api = client() - await migrate("legacy-task-1", ctx() as never, api as never) + await migrate({ id: "legacy-task-1" }, ctx() as never, api as never) const call = api.calls.find((x) => x.name === "session") expect(call).toBeDefined() @@ -161,6 +214,9 @@ describe("legacy migration migrate", () => { it("returns ok false without throwing when one backend insert fails", async () => { const api = { + session: { + get: async () => ({ data: null }), + }, kilocode: { sessionImport: { project: async () => ({ data: { id: "project-real" } }), @@ -173,7 +229,7 @@ describe("legacy migration migrate", () => { }, } - const result = await migrate("legacy-task-1", ctx() as never, api as never) + const result = await migrate({ id: "legacy-task-1" }, ctx() as never, api as never) expect(result.ok).toBe(false) }) @@ -181,6 +237,9 @@ describe("legacy migration migrate", () => { it("skips message and part imports when backend reports the session already exists", async () => { const calls: string[] = [] const api = { + session: { + get: async () => ({ data: null }), + }, kilocode: { sessionImport: { project: async () => { @@ -203,7 +262,7 @@ describe("legacy migration migrate", () => { }, } - const result = await migrate("legacy-task-1", ctx() as never, api as never) + const result = await migrate({ id: "legacy-task-1" }, ctx() as never, api as never) expect(result.ok).toBe(true) expect(result).toHaveProperty("skipped", true) diff --git a/packages/kilo-vscode/tests/unit/legacy-migration/session-summary-state.test.ts b/packages/kilo-vscode/tests/unit/legacy-migration/session-summary-state.test.ts new file mode 100644 index 00000000000..275c0f6cdc9 --- /dev/null +++ b/packages/kilo-vscode/tests/unit/legacy-migration/session-summary-state.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "bun:test" +import { + createSessionItem, + createSessionSummary, + updateSessionSummary, +} from "../../../webview-ui/src/components/migration/session-migration-summary-state" + +const session = createSessionItem({ + id: "legacy-1", + title: "Legacy task", + directory: "/workspace/testing", + time: 1, +}) + +describe("session migration summary state", () => { + it("moves a session from skipped to imported when a force rerun finishes successfully", () => { + const skipped = updateSessionSummary(createSessionSummary(), session, "skipped") + const done = updateSessionSummary(skipped, session, "done") + + expect(done.skipped).toHaveLength(0) + expect(done.errored).toHaveLength(0) + expect(done.imported).toEqual([session]) + }) + + it("moves a session into errored and removes it from the other buckets", () => { + const done = updateSessionSummary(createSessionSummary(), session, "done") + const next = updateSessionSummary(done, { ...session, error: "Boom\nstack" }, "error") + + expect(next.imported).toHaveLength(0) + expect(next.skipped).toHaveLength(0) + expect(next.errored).toEqual([{ ...session, error: "Boom\nstack" }]) + }) +}) diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/ForceReimportDialog.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/ForceReimportDialog.tsx new file mode 100644 index 00000000000..b3cee915d88 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/ForceReimportDialog.tsx @@ -0,0 +1,47 @@ +import type { Component } from "solid-js" +import { Dialog } from "@kilocode/kilo-ui/dialog" +import { Button } from "@kilocode/kilo-ui/button" +import { useDialog } from "@kilocode/kilo-ui/context/dialog" +import { useLanguage } from "../../context/language" + +interface ForceReimportDialogProps { + count: number + onConfirm: () => void +} + +const ForceReimportDialog: Component = (props) => { + const dialog = useDialog() + const language = useLanguage() + + return ( + +
+

+ {language.t("migration.forceReimport.description", { + target: + props.count === 1 + ? language.t("migration.forceReimport.target.one") + : language.t("migration.forceReimport.target.many", { count: String(props.count) }), + })} +

+
+ + +
+
+
+ ) +} + +export default ForceReimportDialog diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx index 7900ef1de3f..e22ab9df206 100644 --- a/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/migration/MigrationWizard.tsx @@ -8,18 +8,31 @@ import { Show, createSignal, onMount, onCleanup } from "solid-js" import type { Component, JSX } from "solid-js" +import { useDialog } from "@kilocode/kilo-ui/context/dialog" import { showToast } from "@kilocode/kilo-ui/toast" import { useVSCode } from "../../context/vscode" import { useLanguage } from "../../context/language" +import SessionMigrationProgress, { type SessionMigrationProgressState } from "./SessionMigrationProgress" +import SessionMigrationSummary from "./SessionMigrationSummary" +import ForceReimportDialog from "./ForceReimportDialog" +import RunningMigrationDialog from "./RunningMigrationDialog" +import { + createSessionItem, + createSessionSummary, + updateSessionSummary, + type SessionSummaryState, +} from "./session-migration-summary-state" import type { MigrationProviderInfo, MigrationMcpServerInfo, MigrationCustomModeInfo, + MigrationSessionInfo, MigrationResultItem, MigrationAutoApprovalSelections, LegacySettings, LegacyMigrationDataMessage, LegacyMigrationProgressMessage, + LegacyMigrationSessionProgressMessage, LegacyMigrationCompleteMessage, } from "../../types/messages" import "./migration.css" @@ -175,6 +188,7 @@ export interface MigrationWizardProps { const MigrationWizard: Component = (props) => { const vscode = useVSCode() + const dialog = useDialog() const language = useLanguage() const [screen, setScreen] = createSignal("whats-new") @@ -184,7 +198,7 @@ const MigrationWizard: Component = (props) => { const [providers, setProviders] = createSignal([]) const [mcpServers, setMcpServers] = createSignal([]) const [customModes, setCustomModes] = createSignal([]) - const [sessions, setSessions] = createSignal([]) + const [sessions, setSessions] = createSignal([]) const [defaultModel, setDefaultModel] = createSignal<{ provider: string; model: string } | undefined>(undefined) const [legacySettings, setLegacySettings] = createSignal(undefined) @@ -201,6 +215,9 @@ const MigrationWizard: Component = (props) => { // Progress tracking const [progressEntries, setProgressEntries] = createSignal([]) const [results, setResults] = createSignal([]) + const [sessionProgress, setSessionProgress] = createSignal(undefined) + const [sessionSummary, setSessionSummary] = createSignal(createSessionSummary()) + const [running, setRunning] = createSignal(false) // Cleanup preference const [clearLegacyData, setClearLegacyData] = createSignal(false) @@ -253,7 +270,7 @@ const MigrationWizard: Component = (props) => { const existing = prev.findIndex((e) => e.item === update.item) const entry: ProgressEntry = { item: update.item, - group: existing >= 0 ? prev[existing].group : update.item, + group: existing >= 0 ? prev[existing]?.group || update.item : update.item, status: update.status, message: update.message, } @@ -261,9 +278,24 @@ const MigrationWizard: Component = (props) => { }) } + if (msg?.type === "legacyMigrationSessionProgress") { + const update = msg as LegacyMigrationSessionProgressMessage + setSessionSummary((prev) => + updateSessionSummary(prev, createSessionItem(update.session, update.error), update.phase), + ) + setSessionProgress({ + session: update.session, + index: update.index, + total: update.total, + phase: update.phase, + error: update.error, + }) + } + if (msg?.type === "legacyMigrationComplete") { const complete = msg as LegacyMigrationCompleteMessage setResults(complete.results) + setRunning(false) const hasErrors = complete.results.some((r) => r.status === "error") setPhase(hasErrors ? "error" : "done") if (!hasErrors) { @@ -329,7 +361,7 @@ const MigrationWizard: Component = (props) => { return { item: mode?.name ?? slug, group: "customModes", status: "pending" as const } }), ...(migrateSessions() - ? sessions().map((id) => ({ item: id, group: "sessions", status: "pending" as const })) + ? sessions().map((session) => ({ item: session.id, group: "sessions", status: "pending" as const })) : []), ...(migrateDefaultModel() && defaultModel() ? [{ item: "Default model", group: "defaultModel", status: "pending" as const }] @@ -361,6 +393,9 @@ const MigrationWizard: Component = (props) => { ] setProgressEntries(entries) + setSessionSummary(createSessionSummary()) + setSessionProgress(undefined) + setRunning(true) setPhase("migrating") vscode.postMessage({ @@ -369,7 +404,7 @@ const MigrationWizard: Component = (props) => { providers: selectedProviderNames, mcpServers: selectedMcpNames, customModes: selectedModesSlugs, - sessions: migrateSessions() ? sessions() : [], + sessions: migrateSessions() ? sessions().map((session) => ({ id: session.id })) : [], defaultModel: migrateDefaultModel(), settings: { autoApproval, @@ -380,18 +415,70 @@ const MigrationWizard: Component = (props) => { }) } + const handleForceReimport = (ids: string[]) => { + dialog.show(() => ( + { + setRunning(true) + setPhase("migrating") + setSessionProgress(undefined) + setResults((prev) => prev.filter((item) => item.category !== "session")) + setProgressEntries((prev) => { + const keep = prev.filter((item) => item.group !== "sessions") + const next = ids.map((id) => ({ item: id, group: "sessions", status: "pending" as const })) + return [...keep, ...next] + }) + vscode.postMessage({ + type: "startLegacyMigration", + selections: { + providers: [], + mcpServers: [], + customModes: [], + sessions: ids.map((id) => ({ id, force: true })), + defaultModel: false, + settings: { + autoApproval: { + commandRules: false, + readPermission: false, + writePermission: false, + executePermission: false, + mcpPermission: false, + taskPermission: false, + }, + language: false, + autocomplete: false, + }, + }, + }) + showToast({ variant: "success", title: language.t("migration.forceReimport.toast.started") }) + }} + /> + )) + } + const handleDone = () => { + if (running()) { + dialog.show(() => ( + { + vscode.postMessage({ type: "finalizeLegacyMigration" }) + if (clearLegacyData()) { + vscode.postMessage({ type: "clearLegacyData" }) + } + props.onComplete() + }} + /> + )) + return + } + vscode.postMessage({ type: "finalizeLegacyMigration" }) if (clearLegacyData()) { vscode.postMessage({ type: "clearLegacyData" }) } props.onComplete() } - const copySessionError = async (text: string) => { - await navigator.clipboard.writeText(text) - showToast({ variant: "success", title: language.t("migration.error.toast.copied") }) - } - // --------------------------------------------------------------------------- // Data helpers // --------------------------------------------------------------------------- @@ -443,6 +530,9 @@ const MigrationWizard: Component = (props) => { const groupStatus = (group: string): ProgressEntry["status"] => { const entries = progressEntries().filter((entry) => entry.group === group) if (entries.length === 0) return "pending" + if (group === "sessions" && running()) { + if (entries.some((entry) => entry.status === "migrating" || entry.status === "pending")) return "migrating" + } if (entries.some((entry) => entry.status === "error")) return "error" if (entries.some((entry) => entry.status === "warning")) return "warning" if (entries.every((entry) => entry.status === "success")) return "success" @@ -454,6 +544,7 @@ const MigrationWizard: Component = (props) => { const totalCount = () => results().length const groupMessage = (group: string) => progressEntries().find((entry) => entry.group === group && entry.status === "error")?.message + const sessionIconSpinning = () => phase() === "migrating" && migrateSessions() && hasSessions() // --------------------------------------------------------------------------- // Status icon renderer @@ -461,17 +552,18 @@ const MigrationWizard: Component = (props) => { const StatusIcon = (gProps: { group: string }): JSX.Element => { const status = () => groupStatus(gProps.group) + const spinning = () => (gProps.group === "sessions" ? sessionIconSpinning() : status() === "migrating") return ( <> - +
- +
- +
@@ -693,28 +785,13 @@ const MigrationWizard: Component = (props) => {
{language.t("migration.migrate.sessionsDetected", { count: String(sessions().length) })}
- -
-
-
- {language.t("migration.error.sessionFailed")} -
- -
-
{groupMessage("sessions")}
-
+ + } + > + +
diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/RunningMigrationDialog.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/RunningMigrationDialog.tsx new file mode 100644 index 00000000000..b72c1d47e34 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/RunningMigrationDialog.tsx @@ -0,0 +1,40 @@ +import type { Component } from "solid-js" +import { Dialog } from "@kilocode/kilo-ui/dialog" +import { Button } from "@kilocode/kilo-ui/button" +import { useDialog } from "@kilocode/kilo-ui/context/dialog" +import { useLanguage } from "../../context/language" + +interface RunningMigrationDialogProps { + onConfirm: () => void +} + +const RunningMigrationDialog: Component = (props) => { + const dialog = useDialog() + const language = useLanguage() + + return ( + +
+

{language.t("migration.running.description.line1")}

+

{language.t("migration.running.description.line2")}

+
+ + +
+
+
+ ) +} + +export default RunningMigrationDialog diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationCard.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationCard.tsx new file mode 100644 index 00000000000..e438a904ac0 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationCard.tsx @@ -0,0 +1,11 @@ +import type { Component, JSX } from "solid-js" + +interface SessionMigrationCardProps { + children: JSX.Element +} + +const SessionMigrationCard: Component = (props) => { + return
{props.children}
+} + +export default SessionMigrationCard diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationProgress.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationProgress.tsx new file mode 100644 index 00000000000..c6e0b8daeb5 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationProgress.tsx @@ -0,0 +1,102 @@ +import { For } from "solid-js" +import type { Component } from "solid-js" +import type { LegacyMigrationSessionPhase, MigrationSessionInfo } from "../../types/messages" +import { useLanguage } from "../../context/language" +import SessionMigrationCard from "./SessionMigrationCard" +import { formatDate, formatText } from "./session-migration-format" + +export interface SessionMigrationProgressState { + session: MigrationSessionInfo + index: number + total: number + phase: LegacyMigrationSessionPhase + error?: string +} + +interface SessionMigrationProgressProps { + progress: SessionMigrationProgressState +} + +type Step = "preparing" | "storing" +type StepState = "pending" | "active" | "success" + +const steps: Step[] = ["preparing", "storing"] + +const order: Step[] = ["preparing", "storing"] + +function current(phase: LegacyMigrationSessionPhase): Step | undefined { + if (phase === "preparing" || phase === "storing") { + return phase + } + if (phase === "skipped") return "storing" + if (phase === "done") return "storing" + if (phase === "error") return undefined + return undefined +} + +function state(step: Step, phase: LegacyMigrationSessionPhase): StepState { + const active = current(phase) + if (!active) return phase === "done" ? "success" : "pending" + if (step === "preparing" && phase === "preparing") return "active" + const i = order.indexOf(step) + const a = order.indexOf(active) + if (i < a) return "success" + if (i === a) return phase === "done" ? "success" : "active" + return "pending" +} + +function label(language: ReturnType, step: Step, progress: SessionMigrationProgressState) { + if (step === "storing" && progress.phase === "skipped") return language.t("migration.sessionProgress.skipped") + if (step === "preparing") return language.t("migration.sessionProgress.preparing") + return language.t("migration.sessionProgress.storing") +} + +const SessionMigrationProgress: Component = (props) => { + const language = useLanguage() + + return ( + +
+
+ {language.t("migration.sessionProgress.header", { + current: String(props.progress.index), + total: String(props.progress.total), + })} +
+
+
+ {formatText(language, props.progress.session.directory)} +
+
+ + {formatText(language, props.progress.session.title)} + + {formatDate(language, props.progress.session.time)} +
+
+
+ + {(step) => ( +
+
+
+ {label(language, step, props.progress)} +
+
+ )} + +
+
+ + ) +} + +export default SessionMigrationProgress diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationSummary.tsx b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationSummary.tsx new file mode 100644 index 00000000000..c36d904c27e --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/SessionMigrationSummary.tsx @@ -0,0 +1,164 @@ +import type { Component } from "solid-js" +import { For, Show, createMemo, createSignal } from "solid-js" +import SessionMigrationCard from "./SessionMigrationCard" +import type { SessionSummaryState } from "./session-migration-summary-state" +import { showToast } from "@kilocode/kilo-ui/toast" +import { errored, line, report } from "./session-migration-summary-format" +import { useLanguage } from "../../context/language" + +interface SessionMigrationSummaryProps { + summary: SessionSummaryState + onForce: (ids: string[]) => void +} + +const SessionMigrationSummary: Component = (props) => { + const language = useLanguage() + const [all, setAll] = createSignal(false) + const [selected, setSelected] = createSignal([]) + + const label = (name: string, count: number, desc?: string) => { + const suffix = count > 0 ? ` (${count})` : "" + const extra = desc ? ` - ${desc}` : "" + return `${name}${extra}${suffix}:` + } + + const handleCopy = async () => { + const text = report(language, props.summary) + if (!text) return + await navigator.clipboard.writeText(text) + showToast({ variant: "success", title: language.t("migration.sessionSummary.toast.copied") }) + } + + const skipped = createMemo(() => props.summary.skipped) + const ids = createMemo(() => skipped().map((item) => item.id)) + const picked = createMemo(() => (all() ? ids() : selected())) + + const toggle = (id: string, next: boolean) => { + setAll(false) + setSelected((prev) => (next ? [...prev.filter((item) => item !== id), id] : prev.filter((item) => item !== id))) + } + + const handleAll = (next: boolean) => { + setAll(next) + if (next) { + setSelected([]) + return + } + } + + const handleForce = () => { + const list = picked() + if (list.length === 0) return + props.onForce(list) + } + + return ( + +
+
+
{language.t("migration.sessionSummary.title")}
+ +
+
+
+ {label(language.t("migration.sessionSummary.successful"), props.summary.imported.length)} +
+
+ 0 ? props.summary.imported : [undefined]}> + {(item) => ( +
+ {item ? line(language, item) : language.t("migration.sessionSummary.none")} +
+ )} +
+
+
+ 0}> +
+
+ {label( + language.t("migration.sessionSummary.skipped"), + props.summary.skipped.length, + language.t("migration.sessionSummary.alreadyMigrated"), + )} +
+
+ + {(item) => ( + + )} + +
+
+ + +
+
+
+ 0}> +
+
+ {label(language.t("migration.sessionSummary.errored"), props.summary.errored.length)} +
+
+ + {(item) => + item.kind === "detail" ? ( +
{item.text}
+ ) : ( +
{item.text}
+ ) + } +
+
+
+
+
+
+ ) +} + +export default SessionMigrationSummary diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/index.ts b/packages/kilo-vscode/webview-ui/src/components/migration/index.ts index 824db6d8440..64ca5ee12f9 100644 --- a/packages/kilo-vscode/webview-ui/src/components/migration/index.ts +++ b/packages/kilo-vscode/webview-ui/src/components/migration/index.ts @@ -3,3 +3,6 @@ * Delete this entire directory when dropping legacy migration support. */ export { default as MigrationWizard } from "./MigrationWizard" +export { default as SessionMigrationCard } from "./SessionMigrationCard" +export { default as SessionMigrationProgress } from "./SessionMigrationProgress" +export { default as SessionMigrationSummary } from "./SessionMigrationSummary" diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/migration.css b/packages/kilo-vscode/webview-ui/src/components/migration/migration.css index 8700ef023a2..e3457639c4e 100644 --- a/packages/kilo-vscode/webview-ui/src/components/migration/migration.css +++ b/packages/kilo-vscode/webview-ui/src/components/migration/migration.css @@ -343,6 +343,306 @@ word-break: break-word; } +.migration-session-card { + margin-top: 12px; + padding: 12px; + border: 1px solid var(--vscode-panel-border); + border-radius: 12px; + background: color-mix(in srgb, var(--vscode-editor-background) 94%, var(--vscode-button-background) 6%); +} + +.migration-session-summary__title { + font-size: 12px; + font-weight: 700; + line-height: 1.4; + color: var(--vscode-foreground); +} + +.migration-session-summary { + display: flex; + flex-direction: column; + gap: 10px; +} + +.migration-session-summary__section { + display: flex; + flex-direction: column; + gap: 2px; +} + +.migration-session-summary__list { + display: flex; + flex-direction: column; + gap: 0; + max-height: calc(1.7em * 4 + 18px); + overflow: auto; + padding-right: 2px; + border: 1px solid var(--vscode-panel-border); + border-radius: 8px; + background: color-mix(in srgb, var(--vscode-editor-background) 96%, white 4%); + padding: 0; +} + +.migration-session-summary__item { + font-size: 13px; + line-height: 1.7; + color: var(--vscode-descriptionForeground); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + min-height: 1.7em; + padding: 2px 10px; + border-radius: 0; + background: transparent; +} + +.migration-session-summary__list > :nth-child(odd) { + background: color-mix(in srgb, var(--vscode-editor-background) 88%, white 12%); +} + +.migration-session-summary__list > * + * { + border-top: 1px solid color-mix(in srgb, var(--vscode-panel-border) 80%, transparent 20%); +} + +.migration-session-summary__detail { + margin-left: 14px; + font-size: 12px; + line-height: 1.55; + color: color-mix(in srgb, var(--vscode-descriptionForeground) 88%, white 12%); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding: 2px 10px 4px 10px; + background: transparent; +} + +.migration-session-summary__list--success { + border-color: color-mix(in srgb, var(--vscode-testing-iconPassed, #34c759) 45%, var(--vscode-panel-border) 55%); +} + +.migration-session-summary__list--skipped { + border-color: color-mix(in srgb, var(--vscode-testing-iconQueued, #d7ba7d) 55%, var(--vscode-panel-border) 45%); +} + +.migration-session-summary__pick { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + min-height: 1.7em; + padding: 2px 10px; + cursor: pointer; + position: relative; +} + +.migration-session-summary__pick input { + position: absolute; + opacity: 0; + width: 16px; + height: 16px; + margin: 0; + pointer-events: none; + right: 8px; +} + +.migration-session-summary__pick-mark { + width: 16px; + height: 16px; + border-radius: 4px; + border: 1px solid color-mix(in srgb, var(--vscode-foreground) 34%, transparent); + background: color-mix(in srgb, var(--vscode-editor-background) 88%, white 12%); + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: all 0.15s; +} + +.migration-session-summary__pick-mark svg { + width: 10px; + height: 10px; + opacity: 0; + transition: opacity 0.15s; +} + +.migration-session-summary__pick input:checked + .migration-session-summary__pick-mark { + border-color: color-mix(in srgb, var(--vscode-foreground) 46%, transparent); +} + +.migration-session-summary__pick input:checked + .migration-session-summary__pick-mark svg { + opacity: 1; +} + +.migration-session-summary__pick .migration-session-summary__item { + padding: 0; + flex: 1; + min-width: 0; +} + +.migration-session-summary__actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 12px; + margin-top: 8px; +} + +.migration-session-summary__all { + display: inline-flex; + align-items: center; + justify-content: flex-start; + gap: 10px; + font-size: 11px; + color: var(--vscode-descriptionForeground); + position: relative; + cursor: pointer; +} + +.migration-session-summary__all input { + position: absolute; + opacity: 0; + width: 16px; + height: 16px; + margin: 0; + pointer-events: none; + right: 0; +} + +.migration-session-summary__all input:checked + .migration-session-summary__pick-mark { + border-color: color-mix(in srgb, var(--vscode-foreground) 46%, transparent); +} + +.migration-session-summary__all input:checked + .migration-session-summary__pick-mark svg { + opacity: 1; +} + +.migration-session-summary__pick-mark--all { + margin-left: auto; +} + +.migration-session-summary__list--errored { + border-color: color-mix(in srgb, var(--vscode-errorForeground) 55%, var(--vscode-panel-border) 45%); +} + +.migration-session-summary__row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.migration-session-summary__label, +.migration-session-summary__value { + font-size: 12px; + line-height: 1.5; + color: var(--vscode-foreground); +} + +.migration-session-summary__value { + color: var(--vscode-descriptionForeground); + white-space: pre-wrap; + word-break: break-word; +} + +.migration-session-progress__header { + font-size: 12px; + font-weight: 700; + line-height: 1.4; + color: var(--vscode-foreground); + white-space: nowrap; +} + +.migration-session-progress__meta { + display: flex; + flex-direction: column; + gap: 4px; + width: 100%; + margin-top: 4px; + font-size: 11px; + line-height: 1.45; + color: var(--vscode-descriptionForeground); +} + +.migration-session-progress__meta-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + min-width: 0; +} + +.migration-session-progress__directory { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.migration-session-progress__title { + min-width: 0; + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.migration-session-progress__date { + flex-shrink: 0; + white-space: nowrap; +} + +.migration-session-progress__steps { + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 10px; +} + +.migration-session-progress__step { + display: flex; + align-items: center; + gap: 8px; +} + +.migration-session-progress__dot { + width: 9px; + height: 9px; + border-radius: 999px; + flex-shrink: 0; + background: color-mix(in srgb, var(--vscode-foreground) 16%, transparent); +} + +.migration-session-progress__dot--active { + background: var(--vscode-button-background); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--vscode-button-background) 18%, transparent); +} + +.migration-session-progress__dot--success { + background: var(--vscode-testing-iconPassed, #34c759); +} + +.migration-session-progress__step-text { + min-width: 0; + flex: 1; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-size: 12px; + line-height: 1.4; + color: var(--vscode-foreground); +} + +.migration-session-progress__step-text span:first-child { + white-space: nowrap; +} + +.migration-session-progress__count { + flex-shrink: 0; + font-size: 11px; + color: var(--vscode-descriptionForeground); +} + .migration-wizard__copy-btn { appearance: none; border: 1px solid var(--vscode-panel-border); diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-format.ts b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-format.ts new file mode 100644 index 00000000000..39dbf130cf6 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-format.ts @@ -0,0 +1,30 @@ +import type { LanguageContextValue } from "../../context/language" + +function pad(value: number) { + return String(value).padStart(2, "0") +} + +export function formatDate(language: LanguageContextValue, time: number) { + if (!time) return language.t("migration.sessionFormat.unknownDate") + const value = new Date(time) + return `${pad(value.getHours())}:${pad(value.getMinutes())} ${pad(value.getMonth() + 1)}/${pad(value.getDate())}/${value.getFullYear()}` +} + +export function formatPath(language: LanguageContextValue, value: string) { + const text = value.trim() + if (!text) return language.t("migration.sessionFormat.unknown") + const parts = text.split(/[\\/]/).filter(Boolean) + const last = parts.at(-1) + if (!last) return text + return `.../${last}` +} + +export function formatText(language: LanguageContextValue, value: string) { + const text = value.trim() + return text || language.t("migration.sessionFormat.unknown") +} + +export function formatError(language: LanguageContextValue, value?: string) { + if (!value) return language.t("migration.sessionFormat.unknownError") + return value.split("\n")[0]?.trim() || value +} diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-format.ts b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-format.ts new file mode 100644 index 00000000000..9a3d40690d2 --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-format.ts @@ -0,0 +1,49 @@ +import type { SessionSummaryItem, SessionSummaryState } from "./session-migration-summary-state" +import type { LanguageContextValue } from "../../context/language" +import { formatDate, formatError, formatPath, formatText } from "./session-migration-format" + +export function line(language: LanguageContextValue, item: SessionSummaryItem) { + const dir = formatPath(language, item.directory) + const title = formatText(language, item.title) + return `${dir} ${title} ${formatDate(language, item.time)}` +} + +export function short(language: LanguageContextValue, error?: string) { + return formatError(language, error) +} + +export function detail(language: LanguageContextValue, item: SessionSummaryItem) { + return short(language, item.error) +} + +export function errored(language: LanguageContextValue, summary: SessionSummaryState) { + if (summary.errored.length === 0) return [{ kind: "row", text: language.t("migration.sessionSummary.none") }] + return summary.errored.flatMap((item) => [ + { kind: "row", text: line(language, item) }, + { kind: "detail", text: detail(language, item) }, + ]) +} + +export function report(language: LanguageContextValue, summary: SessionSummaryState) { + const block = (title: string, items: SessionSummaryItem[], full?: boolean) => { + const rows = + items.length > 0 + ? items + .map((item) => (full ? `${line(language, item)}\n ${short(language, item.error)}` : line(language, item))) + .join("\n") + : language.t("migration.sessionSummary.none") + return `${title}\n${rows}` + } + + return [ + language.t("migration.sessionSummary.title"), + "", + block(language.t("migration.sessionSummary.successful"), summary.imported), + "", + block(language.t("migration.sessionSummary.skipped"), summary.skipped), + "", + block(language.t("migration.sessionSummary.errored"), summary.errored, true), + ] + .filter(Boolean) + .join("\n") +} diff --git a/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-state.ts b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-state.ts new file mode 100644 index 00000000000..9352ca42dbf --- /dev/null +++ b/packages/kilo-vscode/webview-ui/src/components/migration/session-migration-summary-state.ts @@ -0,0 +1,76 @@ +import type { MigrationSessionInfo } from "../../types/messages" + +export interface SessionSummaryItem { + id: string + title: string + directory: string + time: number + error?: string +} + +export interface SessionSummaryState { + imported: SessionSummaryItem[] + skipped: SessionSummaryItem[] + errored: SessionSummaryItem[] +} + +export function createSessionItem(session: MigrationSessionInfo, error?: string): SessionSummaryItem { + return { + id: session.id, + title: session.title, + directory: session.directory, + time: session.time, + error, + } +} + +export function createSessionSummary(): SessionSummaryState { + return { + imported: [], + skipped: [], + errored: [], + } +} + +function strip(state: SessionSummaryState, id: string) { + return { + imported: state.imported.filter((entry) => entry.id !== id), + skipped: state.skipped.filter((entry) => entry.id !== id), + errored: state.errored.filter((entry) => entry.id !== id), + } +} + +export function updateSessionSummary( + state: SessionSummaryState, + item: SessionSummaryItem, + phase: string, +): SessionSummaryState { + if (phase === "skipped") { + const next = strip(state, item.id) + return { + ...state, + ...next, + skipped: [...next.skipped, item], + } + } + + if (phase === "error") { + const next = strip(state, item.id) + return { + ...state, + ...next, + errored: [...next.errored, item], + } + } + + if (phase === "done") { + const next = strip(state, item.id) + return { + ...state, + ...next, + imported: [...next.imported, item], + } + } + + return state +} diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 3210a800f44..1b3eac83992 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -1,4 +1,4 @@ -import { Component, createSignal, createMemo, createEffect, For, Show } from "solid-js" +import { Component, createSignal, createMemo, createEffect, For, Show, onCleanup } from "solid-js" import { Select } from "@kilocode/kilo-ui/select" import { TextField } from "@kilocode/kilo-ui/text-field" import { Card } from "@kilocode/kilo-ui/card" @@ -55,8 +55,18 @@ const AgentBehaviourTab: Component = () => { const [newSkillPath, setNewSkillPath] = createSignal("") const [newSkillUrl, setNewSkillUrl] = createSignal("") const [newInstruction, setNewInstruction] = createSignal("") + const [claudeCompat, setClaudeCompat] = createSignal(false) const browse = () => vscode.postMessage({ type: "openMarketplacePanel" }) + // Load the VS Code setting for Claude Code compatibility + vscode.postMessage({ type: "requestClaudeCompatSetting" }) + const unsubClaudeCompat = vscode.onMessage((msg) => { + if (msg.type === "claudeCompatSettingLoaded") { + setClaudeCompat(msg.enabled) + } + }) + onCleanup(unsubClaudeCompat) + // Agent view state const [agentView, setAgentView] = createSignal("list") const [editingAgent, setEditingAgent] = createSignal("") @@ -999,6 +1009,29 @@ const AgentBehaviourTab: Component = () => { )} + + {/* Claude Code compatibility */} +

+ {language.t("settings.agentBehaviour.claudeCompat.heading")} +

+ + + { + setClaudeCompat(checked) + vscode.postMessage({ type: "updateSetting", key: "claudeCodeCompat", value: checked }) + }} + hideLabel + > + {language.t("settings.agentBehaviour.claudeCompat.title")} + + +
) diff --git a/packages/kilo-vscode/webview-ui/src/context/language.tsx b/packages/kilo-vscode/webview-ui/src/context/language.tsx index 76bfde6c068..c78a633fffb 100644 --- a/packages/kilo-vscode/webview-ui/src/context/language.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/language.tsx @@ -211,7 +211,7 @@ export const LanguageProvider: ParentComponent = (props) // Expose locale + setLocale for the LanguageTab import { createContext, useContext } from "solid-js" -interface LanguageContextValue { +export interface LanguageContextValue { locale: Accessor setLocale: (locale: Locale | "") => void userOverride: Accessor diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 66aacd7f5da..801c067983e 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -1143,6 +1143,10 @@ export const dict = { "القواعد هي ملفات تعليمات توجه سلوك الوكيل. يتم تضمينها في موجه النظام لكل محادثة. أضف مسارات الملفات أدناه لتضمين قواعد إضافية.", "settings.agentBehaviour.instructionFiles": "ملفات تعليمات إضافية", "settings.agentBehaviour.instructionFiles.description": "مسارات ملفات التعليمات الإضافية في موجه النظام", + "settings.agentBehaviour.claudeCompat.heading": "توافق Claude Code", + "settings.agentBehaviour.claudeCompat.title": "تحميل ملفات Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "تحميل تعليمات ومهارات CLAUDE.md من مجلد إعدادات Claude Code إلى الجلسات. قم بتمكين هذا الخيار إذا كنت ترغب في أن يستخدم Kilo مهارات وتعليمات Claude Code الخاصة بك. يتطلب إعادة التشغيل.", "settings.agentBehaviour.mcpDetail.command": "الأمر", "settings.agentBehaviour.mcpDetail.args": "الوسائط", "settings.agentBehaviour.mcpDetail.env": "البيئة", @@ -1279,6 +1283,36 @@ export const dict = { "migration.error.continue": "متابعة", "migration.error.action.copy": "نسخ", "migration.error.toast.copied": "تم نسخ الخطأ إلى الحافظة", + + "migration.sessionSummary.title": "الملخص:", + "migration.sessionSummary.copy": "نسخ التقرير", + "migration.sessionSummary.toast.copied": "تم نسخ التقرير", + "migration.sessionSummary.successful": "ناجحة", + "migration.sessionSummary.skipped": "تم تخطيها", + "migration.sessionSummary.alreadyMigrated": "تم ترحيلها بالفعل", + "migration.sessionSummary.errored": "حدثت بها أخطاء", + "migration.sessionSummary.none": "لا يوجد", + "migration.forceReimport.title": "فرض إعادة الاستيراد", + "migration.forceReimport.description": + "ستؤدي إعادة استيراد {{target}} إلى استبدالها وحذف أي رسائل جديدة تم إنشاؤها بالفعل في تلك الجلسات.", + "migration.forceReimport.target.one": "هذه الجلسة", + "migration.forceReimport.target.many": "هذه الجلسات الـ {{count}}", + "migration.forceReimport.button": "فرض إعادة الاستيراد", + "migration.forceReimport.all": "إعادة استيراد الكل", + "migration.forceReimport.proceed": "متابعة", + "migration.forceReimport.toast.started": "بدأت إعادة الاستيراد القسرية", + "migration.running.title": "الترحيل قيد التنفيذ", + "migration.running.description.line1": "أنت على وشك الإنهاء بينما لا تزال هناك جلسات قيد الترحيل.", + "migration.running.description.line2": "إذا غادرت الآن، فقد تبقى بعض الجلسات غير مكتملة.", + "migration.running.stay": "البقاء", + "migration.running.proceed": "متابعة", + "migration.sessionProgress.preparing": "جارٍ تحضير الجلسة", + "migration.sessionProgress.storing": "جارٍ حفظ الجلسة", + "migration.sessionProgress.skipped": "تم تخطي الجلسة", + "migration.sessionProgress.header": "جارٍ ترحيل {{current}} من {{total}}", + "migration.sessionFormat.unknownDate": "تاريخ غير معروف", + "migration.sessionFormat.unknown": "غير معروف", + "migration.sessionFormat.unknownError": "خطأ غير معروف", // legacy-migration end "error.details.show": "التفاصيل", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index a2b694c3aad..54184cd4122 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -1164,6 +1164,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Arquivos de instruções adicionais", "settings.agentBehaviour.instructionFiles.description": "Caminhos para arquivos de instruções adicionais no prompt do sistema", + "settings.agentBehaviour.claudeCompat.heading": "Compatibilidade com Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Carregar Arquivos do Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Carrega as instruções e skills do CLAUDE.md a partir do seu diretório de configuração do Claude Code para as sessões. Ative esta opção se deseja que o Kilo utilize suas instruções e skills do Claude Code. Requer reinicialização.", "settings.agentBehaviour.mcpDetail.command": "Comando", "settings.agentBehaviour.mcpDetail.args": "Argumentos", "settings.agentBehaviour.mcpDetail.env": "Ambiente", @@ -1308,6 +1312,36 @@ export const dict = { "migration.error.continue": "Continuar", "migration.error.action.copy": "Copiar", "migration.error.toast.copied": "Erro copiado para a área de transferência", + + "migration.sessionSummary.title": "Resumo:", + "migration.sessionSummary.copy": "Copiar relatório", + "migration.sessionSummary.toast.copied": "Relatório copiado", + "migration.sessionSummary.successful": "Bem-sucedidas", + "migration.sessionSummary.skipped": "Ignoradas", + "migration.sessionSummary.alreadyMigrated": "Já migradas", + "migration.sessionSummary.errored": "Com erro", + "migration.sessionSummary.none": "Nenhuma", + "migration.forceReimport.title": "Forçar reimportação", + "migration.forceReimport.description": + "Reimportar {{target}} vai sobrescrevê-los e apagar quaisquer novas mensagens já criadas nessas sessões.", + "migration.forceReimport.target.one": "esta sessão", + "migration.forceReimport.target.many": "estas {{count}} sessões", + "migration.forceReimport.button": "Forçar reimportação", + "migration.forceReimport.all": "Reimportar tudo", + "migration.forceReimport.proceed": "Prosseguir", + "migration.forceReimport.toast.started": "Reimportação forçada iniciada", + "migration.running.title": "Migração em andamento", + "migration.running.description.line1": "Você está prestes a concluir enquanto ainda há sessões sendo migradas.", + "migration.running.description.line2": "Se você sair agora, algumas sessões podem ficar incompletas.", + "migration.running.stay": "Ficar", + "migration.running.proceed": "Prosseguir", + "migration.sessionProgress.preparing": "Preparando sessão", + "migration.sessionProgress.storing": "Salvando sessão", + "migration.sessionProgress.skipped": "Sessão ignorada", + "migration.sessionProgress.header": "Migrando {{current}} de {{total}}", + "migration.sessionFormat.unknownDate": "Data desconhecida", + "migration.sessionFormat.unknown": "Desconhecido", + "migration.sessionFormat.unknownError": "Erro desconhecido", // legacy-migration end "error.details.show": "Detalhes", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index d42635010fb..e17c8c4b917 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -1160,6 +1160,10 @@ export const dict = { "Pravila su datoteke uputa koje usmjeravaju ponašanje agenta. Uključena su u sistemski prompt za svaki razgovor. Dodajte putanje datoteka ispod kako biste uključili dodatna pravila.", "settings.agentBehaviour.instructionFiles": "Dodatne datoteke uputa", "settings.agentBehaviour.instructionFiles.description": "Putanje do dodatnih datoteka uputa u sistemskom promptu", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code kompatibilnost", + "settings.agentBehaviour.claudeCompat.title": "Učitaj Claude Code datoteke", + "settings.agentBehaviour.claudeCompat.description": + "Učitajte CLAUDE.md instrukcije i vještine iz vašeg Claude Code konfiguracijskog direktorija u sesije. Omogućite ovo ako želite da Kilo koristi vaše Claude Code instrukcije i vještine. Zahtijeva ponovno pokretanje.", "settings.agentBehaviour.mcpDetail.command": "Naredba", "settings.agentBehaviour.mcpDetail.args": "Argumenti", "settings.agentBehaviour.mcpDetail.env": "Okruženje", @@ -1304,6 +1308,36 @@ export const dict = { "migration.error.continue": "Nastavi", "migration.error.action.copy": "Kopiraj", "migration.error.toast.copied": "Greška kopirana u međuspremnik", + + "migration.sessionSummary.title": "Sažetak:", + "migration.sessionSummary.copy": "Kopiraj izvještaj", + "migration.sessionSummary.toast.copied": "Izvještaj kopiran", + "migration.sessionSummary.successful": "Uspješne", + "migration.sessionSummary.skipped": "Preskočene", + "migration.sessionSummary.alreadyMigrated": "Već migrirane", + "migration.sessionSummary.errored": "S greškom", + "migration.sessionSummary.none": "Nijedna", + "migration.forceReimport.title": "Prisilni ponovni uvoz", + "migration.forceReimport.description": + "Ponovni uvoz {{target}} će ih prepisati i obrisati sve nove poruke koje su već napravljene u tim sesijama.", + "migration.forceReimport.target.one": "ovu sesiju", + "migration.forceReimport.target.many": "ovih {{count}} sesija", + "migration.forceReimport.button": "Prisilni ponovni uvoz", + "migration.forceReimport.all": "Ponovo uvezi sve", + "migration.forceReimport.proceed": "Nastavi", + "migration.forceReimport.toast.started": "Prisilni ponovni uvoz je pokrenut", + "migration.running.title": "Migracija je u toku", + "migration.running.description.line1": "Upravo ćete završiti dok se neke sesije još uvijek migriraju.", + "migration.running.description.line2": "Ako sada izađete, neke sesije mogu ostati nedovršene.", + "migration.running.stay": "Ostani", + "migration.running.proceed": "Nastavi", + "migration.sessionProgress.preparing": "Priprema se sesija", + "migration.sessionProgress.storing": "Spremanje sesije", + "migration.sessionProgress.skipped": "Sesija je preskočena", + "migration.sessionProgress.header": "Migrira se {{current}} od {{total}}", + "migration.sessionFormat.unknownDate": "Nepoznat datum", + "migration.sessionFormat.unknown": "Nepoznato", + "migration.sessionFormat.unknownError": "Nepoznata greška", // legacy-migration end "error.details.show": "Detalji", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 7111a2194b7..e82c786f017 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -1153,6 +1153,10 @@ export const dict = { "Regler er instruktionsfiler, der styrer agentens adfærd. De inkluderes i systemprompten for hver samtale. Tilføj filstier nedenfor for at inkludere yderligere regler.", "settings.agentBehaviour.instructionFiles": "Yderligere instruktionsfiler", "settings.agentBehaviour.instructionFiles.description": "Stier til yderligere instruktionsfiler i systemprompten", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code-kompatibilitet", + "settings.agentBehaviour.claudeCompat.title": "Indlæs Claude Code-filer", + "settings.agentBehaviour.claudeCompat.description": + "Indlæs CLAUDE.md-instruktioner og -færdigheder fra din Claude Code-konfigurationsmappe i sessioner. Aktivér dette, hvis du vil have Kilo til at bruge dine Claude Code-instruktioner og -færdigheder. Kræver genstart.", "settings.agentBehaviour.mcpDetail.command": "Kommando", "settings.agentBehaviour.mcpDetail.args": "Argumenter", "settings.agentBehaviour.mcpDetail.env": "Miljø", @@ -1295,6 +1299,36 @@ export const dict = { "migration.error.continue": "Fortsæt", "migration.error.action.copy": "Kopiér", "migration.error.toast.copied": "Fejl kopieret til udklipsholder", + + "migration.sessionSummary.title": "Opsummering:", + "migration.sessionSummary.copy": "Kopiér rapport", + "migration.sessionSummary.toast.copied": "Rapport kopieret", + "migration.sessionSummary.successful": "Vellykkede", + "migration.sessionSummary.skipped": "Sprunget over", + "migration.sessionSummary.alreadyMigrated": "Allerede migreret", + "migration.sessionSummary.errored": "Med fejl", + "migration.sessionSummary.none": "Ingen", + "migration.forceReimport.title": "Tving genimport", + "migration.forceReimport.description": + "Genimport af {{target}} vil overskrive dem og slette alle nye beskeder, der allerede er oprettet i disse sessioner.", + "migration.forceReimport.target.one": "denne session", + "migration.forceReimport.target.many": "disse {{count}} sessioner", + "migration.forceReimport.button": "Tving genimport", + "migration.forceReimport.all": "Genimportér alle", + "migration.forceReimport.proceed": "Fortsæt", + "migration.forceReimport.toast.started": "Tvungen genimport er startet", + "migration.running.title": "Migrering i gang", + "migration.running.description.line1": "Du er ved at afslutte, mens der stadig er sessioner, som bliver migreret.", + "migration.running.description.line2": "Hvis du forlader nu, kan nogle sessioner forblive ufuldstændige.", + "migration.running.stay": "Bliv", + "migration.running.proceed": "Fortsæt", + "migration.sessionProgress.preparing": "Forbereder session", + "migration.sessionProgress.storing": "Gemmer session", + "migration.sessionProgress.skipped": "Session sprunget over", + "migration.sessionProgress.header": "Migrerer {{current}} af {{total}}", + "migration.sessionFormat.unknownDate": "Ukendt dato", + "migration.sessionFormat.unknown": "Ukendt", + "migration.sessionFormat.unknownError": "Ukendt fejl", // legacy-migration end "error.details.show": "Detaljer", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index c2708b7a0bd..f77dedaff6c 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -1176,6 +1176,10 @@ export const dict = { "Regeln sind Anweisungsdateien, die das Verhalten des Agenten steuern. Sie werden in den System-Prompt für jede Konversation eingebunden. Fügen Sie unten Dateipfade hinzu, um zusätzliche Regeln einzubinden.", "settings.agentBehaviour.instructionFiles": "Zusätzliche Anweisungsdateien", "settings.agentBehaviour.instructionFiles.description": "Pfade zu zusätzlichen Anweisungsdateien im System-Prompt", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code-Kompatibilität", + "settings.agentBehaviour.claudeCompat.title": "Claude Code-Dateien laden", + "settings.agentBehaviour.claudeCompat.description": + "Lädt CLAUDE.md-Anweisungen und Skills aus Ihrem Claude Code-Konfigurationsverzeichnis in Sitzungen. Aktivieren Sie dies, wenn Kilo Ihre Claude Code-Anweisungen und Skills verwenden soll. Neustart erforderlich.", "settings.agentBehaviour.mcpDetail.command": "Befehl", "settings.agentBehaviour.mcpDetail.args": "Argumente", "settings.agentBehaviour.mcpDetail.env": "Umgebung", @@ -1322,6 +1326,36 @@ export const dict = { "migration.error.continue": "Weiter", "migration.error.action.copy": "Kopieren", "migration.error.toast.copied": "Fehler in die Zwischenablage kopiert", + + "migration.sessionSummary.title": "Zusammenfassung:", + "migration.sessionSummary.copy": "Bericht kopieren", + "migration.sessionSummary.toast.copied": "Bericht kopiert", + "migration.sessionSummary.successful": "Erfolgreich", + "migration.sessionSummary.skipped": "Übersprungen", + "migration.sessionSummary.alreadyMigrated": "Bereits migriert", + "migration.sessionSummary.errored": "Fehlgeschlagen", + "migration.sessionSummary.none": "Keine", + "migration.forceReimport.title": "Erneuten Import erzwingen", + "migration.forceReimport.description": + "Ein erneuter Import von {{target}} überschreibt diese und löscht alle neuen Nachrichten, die in diesen Sitzungen bereits erstellt wurden.", + "migration.forceReimport.target.one": "diese Sitzung", + "migration.forceReimport.target.many": "diese {{count}} Sitzungen", + "migration.forceReimport.button": "Erneuten Import erzwingen", + "migration.forceReimport.all": "Alle erneut importieren", + "migration.forceReimport.proceed": "Fortfahren", + "migration.forceReimport.toast.started": "Erneuter Import gestartet", + "migration.running.title": "Migration läuft", + "migration.running.description.line1": "Sie sind dabei abzuschließen, während noch Sitzungen migriert werden.", + "migration.running.description.line2": "Wenn Sie jetzt gehen, bleiben einige Sitzungen möglicherweise unvollständig.", + "migration.running.stay": "Bleiben", + "migration.running.proceed": "Fortfahren", + "migration.sessionProgress.preparing": "Sitzung wird vorbereitet", + "migration.sessionProgress.storing": "Sitzung wird gespeichert", + "migration.sessionProgress.skipped": "Sitzung übersprungen", + "migration.sessionProgress.header": "Migriere {{current}} von {{total}}", + "migration.sessionFormat.unknownDate": "Unbekanntes Datum", + "migration.sessionFormat.unknown": "Unbekannt", + "migration.sessionFormat.unknownError": "Unbekannter Fehler", // legacy-migration end "error.details.show": "Details", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 6b66eaa58fb..63125949253 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -1107,6 +1107,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Additional Instruction Files", "settings.agentBehaviour.instructionFiles.description": "Paths to additional instruction files that are included in the system prompt", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code Compatibility", + "settings.agentBehaviour.claudeCompat.title": "Load Claude Code Files", + "settings.agentBehaviour.claudeCompat.description": + "Load CLAUDE.md instructions and skills from your Claude Code configuration directory into sessions. Enable this if you want Kilo to use your Claude Code instructions and skills. Requires restart.", "settings.agentBehaviour.removeMcp.title": "Remove MCP server", "settings.agentBehaviour.removeMcp.confirm": 'Remove MCP server "{{name}}"? This will remove it from your config.', "settings.agentBehaviour.removeMcp.button": "Remove", @@ -1304,6 +1308,35 @@ export const dict = { "migration.error.continue": "Continue", "migration.error.action.copy": "Copy", "migration.error.toast.copied": "Error copied to clipboard", + "migration.sessionSummary.title": "Summary:", + "migration.sessionSummary.copy": "Copy Report", + "migration.sessionSummary.toast.copied": "Copied report", + "migration.sessionSummary.successful": "Successful", + "migration.sessionSummary.skipped": "Skipped", + "migration.sessionSummary.alreadyMigrated": "Already migrated", + "migration.sessionSummary.errored": "Errored", + "migration.sessionSummary.none": "None", + "migration.forceReimport.title": "Force Re-import", + "migration.forceReimport.description": + "Re-importing {{target}} will overwrite them and delete any new messages already made in those sessions.", + "migration.forceReimport.target.one": "this session", + "migration.forceReimport.target.many": "these {{count}} sessions", + "migration.forceReimport.button": "Force Re-import", + "migration.forceReimport.all": "Re-import all", + "migration.forceReimport.proceed": "Proceed", + "migration.forceReimport.toast.started": "Force re-import started", + "migration.running.title": "Migration in Progress", + "migration.running.description.line1": "You are about to finish while there are still sessions being migrated.", + "migration.running.description.line2": "If you leave now, some sessions may remain incomplete.", + "migration.running.stay": "Stay", + "migration.running.proceed": "Proceed", + "migration.sessionProgress.preparing": "Preparing session", + "migration.sessionProgress.storing": "Storing session", + "migration.sessionProgress.skipped": "Session skipped", + "migration.sessionProgress.header": "Migrating {{current}} of {{total}}", + "migration.sessionFormat.unknownDate": "Unknown date", + "migration.sessionFormat.unknown": "Unknown", + "migration.sessionFormat.unknownError": "Unknown error", // legacy-migration end "error.details.show": "Details", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index aa1f9a7b330..be87b6b6e01 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -1168,6 +1168,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Archivos de instrucciones adicionales", "settings.agentBehaviour.instructionFiles.description": "Rutas a archivos de instrucciones adicionales incluidos en el prompt del sistema", + "settings.agentBehaviour.claudeCompat.heading": "Compatibilidad con Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Cargar archivos de Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Carga las instrucciones y habilidades de CLAUDE.md desde tu directorio de configuración de Claude Code en las sesiones. Activa esta opción si quieres que Kilo utilice tus instrucciones y habilidades de Claude Code. Requiere reiniciar.", "settings.agentBehaviour.mcpDetail.command": "Comando", "settings.agentBehaviour.mcpDetail.args": "Argumentos", "settings.agentBehaviour.mcpDetail.env": "Entorno", @@ -1312,6 +1316,35 @@ export const dict = { "migration.error.continue": "Continuar", "migration.error.action.copy": "Copiar", "migration.error.toast.copied": "Error copiado al portapapeles", + "migration.sessionSummary.title": "Resumen:", + "migration.sessionSummary.copy": "Copiar informe", + "migration.sessionSummary.toast.copied": "Informe copiado", + "migration.sessionSummary.successful": "Correctas", + "migration.sessionSummary.skipped": "Omitidas", + "migration.sessionSummary.alreadyMigrated": "Ya migradas", + "migration.sessionSummary.errored": "Con error", + "migration.sessionSummary.none": "Ninguna", + "migration.forceReimport.title": "Forzar reimportación", + "migration.forceReimport.description": + "Reimportar {{target}} sobrescribirá las sesiones y eliminará los mensajes nuevos ya realizados en ellas.", + "migration.forceReimport.target.one": "esta sesión", + "migration.forceReimport.target.many": "estas {{count}} sesiones", + "migration.forceReimport.button": "Forzar reimportación", + "migration.forceReimport.all": "Reimportar todo", + "migration.forceReimport.proceed": "Proceder", + "migration.forceReimport.toast.started": "Reimportación forzada iniciada", + "migration.running.title": "Migración en curso", + "migration.running.description.line1": "Vas a terminar mientras todavía hay sesiones migrándose.", + "migration.running.description.line2": "Si sales ahora, algunas sesiones pueden quedar incompletas.", + "migration.running.stay": "Quedarse", + "migration.running.proceed": "Proceder", + "migration.sessionProgress.preparing": "Preparando sesión", + "migration.sessionProgress.storing": "Guardando sesión", + "migration.sessionProgress.skipped": "Sesión omitida", + "migration.sessionProgress.header": "Migrando {{current}} de {{total}}", + "migration.sessionFormat.unknownDate": "Fecha desconocida", + "migration.sessionFormat.unknown": "Desconocido", + "migration.sessionFormat.unknownError": "Error desconocido", // legacy-migration end "error.details.show": "Detalles", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 5d9fb773a9c..c46f4c5f4bc 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -1180,6 +1180,10 @@ export const dict = { "Les règles sont des fichiers d'instructions qui guident le comportement de l'agent. Elles sont incluses dans le prompt système pour chaque conversation. Ajoutez des chemins de fichiers ci-dessous pour inclure des règles supplémentaires.", "settings.agentBehaviour.instructionFiles": "Fichiers d'instructions supplémentaires", "settings.agentBehaviour.instructionFiles.description": "Chemins vers des fichiers d'instructions supplémentaires", + "settings.agentBehaviour.claudeCompat.heading": "Compatibilité Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Charger les fichiers Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Charge les instructions et les compétences de CLAUDE.md depuis votre répertoire de configuration Claude Code dans les sessions. Activez cette option si vous souhaitez que Kilo utilise vos instructions et compétences Claude Code. Nécessite un redémarrage.", "settings.agentBehaviour.mcpDetail.command": "Commande", "settings.agentBehaviour.mcpDetail.args": "Arguments", "settings.agentBehaviour.mcpDetail.env": "Environnement", @@ -1325,6 +1329,38 @@ export const dict = { "migration.error.continue": "Continuer", "migration.error.action.copy": "Copier", "migration.error.toast.copied": "Erreur copiée dans le presse-papiers", + + "migration.sessionSummary.title": "Résumé :", + "migration.sessionSummary.copy": "Copier le rapport", + "migration.sessionSummary.toast.copied": "Rapport copié", + "migration.sessionSummary.successful": "Réussies", + "migration.sessionSummary.skipped": "Ignorées", + "migration.sessionSummary.alreadyMigrated": "Déjà migrées", + "migration.sessionSummary.errored": "En erreur", + "migration.sessionSummary.none": "Aucune", + "migration.forceReimport.title": "Forcer la réimportation", + "migration.forceReimport.description": + "Réimporter {{target}} les écrasera et supprimera tous les nouveaux messages déjà créés dans ces sessions.", + "migration.forceReimport.target.one": "cette session", + "migration.forceReimport.target.many": "ces {{count}} sessions", + "migration.forceReimport.button": "Forcer la réimportation", + "migration.forceReimport.all": "Tout réimporter", + "migration.forceReimport.proceed": "Continuer", + "migration.forceReimport.toast.started": "Réimportation forcée lancée", + "migration.running.title": "Migration en cours", + "migration.running.description.line1": + "Vous êtes sur le point de terminer alors que certaines sessions sont encore en cours de migration.", + "migration.running.description.line2": + "Si vous quittez maintenant, certaines sessions risquent de rester incomplètes.", + "migration.running.stay": "Rester", + "migration.running.proceed": "Continuer", + "migration.sessionProgress.preparing": "Préparation de la session", + "migration.sessionProgress.storing": "Enregistrement de la session", + "migration.sessionProgress.skipped": "Session ignorée", + "migration.sessionProgress.header": "Migration de {{current}} sur {{total}}", + "migration.sessionFormat.unknownDate": "Date inconnue", + "migration.sessionFormat.unknown": "Inconnu", + "migration.sessionFormat.unknownError": "Erreur inconnue", // legacy-migration end "error.details.show": "Détails", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index aa9c0f5f5e3..8e5275e3a82 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -1154,6 +1154,10 @@ export const dict = { "ルールはエージェントの動作を導く指示ファイルです。すべての会話のシステムプロンプトに含まれます。追加のルールを含めるには、以下にファイルパスを追加してください。", "settings.agentBehaviour.instructionFiles": "追加の指示ファイル", "settings.agentBehaviour.instructionFiles.description": "システムプロンプトに含まれる追加の指示ファイルへのパス", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code 互換性", + "settings.agentBehaviour.claudeCompat.title": "Claude Code ファイルを読み込む", + "settings.agentBehaviour.claudeCompat.description": + "Claude Code の設定ディレクトリから CLAUDE.md のインストラクションとスキルをセッションに読み込みます。Kilo に Claude Code のインストラクションとスキルを使用させる場合は、これを有効にしてください。再起動が必要です。", "settings.agentBehaviour.mcpDetail.command": "コマンド", "settings.agentBehaviour.mcpDetail.args": "引数", "settings.agentBehaviour.mcpDetail.env": "環境", @@ -1294,6 +1298,36 @@ export const dict = { "migration.error.continue": "続行", "migration.error.action.copy": "コピー", "migration.error.toast.copied": "エラーをクリップボードにコピーしました", + + "migration.sessionSummary.title": "概要:", + "migration.sessionSummary.copy": "レポートをコピー", + "migration.sessionSummary.toast.copied": "レポートをコピーしました", + "migration.sessionSummary.successful": "成功", + "migration.sessionSummary.skipped": "スキップ", + "migration.sessionSummary.alreadyMigrated": "移行済み", + "migration.sessionSummary.errored": "エラーあり", + "migration.sessionSummary.none": "なし", + "migration.forceReimport.title": "再インポートを強制", + "migration.forceReimport.description": + "{{target}} を再インポートすると上書きされ、それらのセッションで既に作成された新しいメッセージは削除されます。", + "migration.forceReimport.target.one": "このセッション", + "migration.forceReimport.target.many": "これら {{count}} 件のセッション", + "migration.forceReimport.button": "再インポートを強制", + "migration.forceReimport.all": "すべて再インポート", + "migration.forceReimport.proceed": "続行", + "migration.forceReimport.toast.started": "強制再インポートを開始しました", + "migration.running.title": "移行を実行中", + "migration.running.description.line1": "まだ移行中のセッションがある状態で終了しようとしています。", + "migration.running.description.line2": "今離れると、一部のセッションは未完了のままになる可能性があります。", + "migration.running.stay": "このままにする", + "migration.running.proceed": "続行", + "migration.sessionProgress.preparing": "セッションを準備中", + "migration.sessionProgress.storing": "セッションを保存中", + "migration.sessionProgress.skipped": "セッションをスキップしました", + "migration.sessionProgress.header": "{{total}} 件中 {{current}} 件を移行中", + "migration.sessionFormat.unknownDate": "不明な日付", + "migration.sessionFormat.unknown": "不明", + "migration.sessionFormat.unknownError": "不明なエラー", // legacy-migration end "error.details.show": "詳細", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 942b479fffd..65a11e1936a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -1148,6 +1148,10 @@ export const dict = { "규칙은 에이전트 동작을 안내하는 지시 파일입니다. 모든 대화의 시스템 프롬프트에 포함됩니다. 추가 규칙을 포함하려면 아래에 파일 경로를 추가하세요.", "settings.agentBehaviour.instructionFiles": "추가 지시 파일", "settings.agentBehaviour.instructionFiles.description": "시스템 프롬프트에 포함되는 추가 지시 파일 경로", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code 호환성", + "settings.agentBehaviour.claudeCompat.title": "Claude Code 파일 로드", + "settings.agentBehaviour.claudeCompat.description": + "Claude Code 설정 디렉터리에서 세션으로 CLAUDE.md 지침 및 스킬을 로드합니다. Kilo가 Claude Code 지침 및 스킬을 사용하게 하려면 활성화하세요. 다시 시작해야 합니다.", "settings.agentBehaviour.mcpDetail.command": "명령어", "settings.agentBehaviour.mcpDetail.args": "인수", "settings.agentBehaviour.mcpDetail.env": "환경", @@ -1282,6 +1286,36 @@ export const dict = { "migration.error.continue": "계속", "migration.error.action.copy": "복사", "migration.error.toast.copied": "오류가 클립보드에 복사되었습니다", + + "migration.sessionSummary.title": "요약:", + "migration.sessionSummary.copy": "보고서 복사", + "migration.sessionSummary.toast.copied": "보고서가 복사되었습니다", + "migration.sessionSummary.successful": "성공", + "migration.sessionSummary.skipped": "건너뜀", + "migration.sessionSummary.alreadyMigrated": "이미 마이그레이션됨", + "migration.sessionSummary.errored": "오류 발생", + "migration.sessionSummary.none": "없음", + "migration.forceReimport.title": "강제 재가져오기", + "migration.forceReimport.description": + "{{target}}을 다시 가져오면 덮어쓰게 되며, 해당 세션에서 이미 생성된 새 메시지는 삭제됩니다.", + "migration.forceReimport.target.one": "이 세션", + "migration.forceReimport.target.many": "이 {{count}}개 세션", + "migration.forceReimport.button": "강제 재가져오기", + "migration.forceReimport.all": "모두 다시 가져오기", + "migration.forceReimport.proceed": "진행", + "migration.forceReimport.toast.started": "강제 재가져오기가 시작되었습니다", + "migration.running.title": "마이그레이션 진행 중", + "migration.running.description.line1": "아직 마이그레이션 중인 세션이 남아 있는 상태에서 종료하려고 합니다.", + "migration.running.description.line2": "지금 나가면 일부 세션이 완료되지 않은 상태로 남을 수 있습니다.", + "migration.running.stay": "머무르기", + "migration.running.proceed": "진행", + "migration.sessionProgress.preparing": "세션 준비 중", + "migration.sessionProgress.storing": "세션 저장 중", + "migration.sessionProgress.skipped": "세션 건너뜀", + "migration.sessionProgress.header": "{{total}}개 중 {{current}}개 마이그레이션 중", + "migration.sessionFormat.unknownDate": "알 수 없는 날짜", + "migration.sessionFormat.unknown": "알 수 없음", + "migration.sessionFormat.unknownError": "알 수 없는 오류", // legacy-migration end "error.details.show": "상세 정보", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index 0277c42f964..9f3f77c9f0d 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -1125,6 +1125,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Aanvullende Instructiebestanden", "settings.agentBehaviour.instructionFiles.description": "Paden naar aanvullende instructiebestanden die zijn opgenomen in de systeem prompt", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code-compatibiliteit", + "settings.agentBehaviour.claudeCompat.title": "Claude Code-bestanden laden", + "settings.agentBehaviour.claudeCompat.description": + "Laad CLAUDE.md instructies en vaardigheden uit je Claude Code configuratiemap in sessies. Schakel dit in als je wilt dat Kilo je Claude Code instructies en vaardigheden gebruikt. Herstart vereist.", "settings.agentBehaviour.removeMcp.title": "Verwijder MCP-server", "settings.agentBehaviour.removeMcp.confirm": 'MCP-server "{{name}}" verwijderen? Dit zal deze uit je configuratie verwijderen.', @@ -1299,6 +1303,36 @@ export const dict = { "migration.error.continue": "Doorgaan", "migration.error.action.copy": "Kopiëren", "migration.error.toast.copied": "Fout gekopieerd naar het klembord", + + "migration.sessionSummary.title": "Samenvatting:", + "migration.sessionSummary.copy": "Rapport kopiëren", + "migration.sessionSummary.toast.copied": "Rapport gekopieerd", + "migration.sessionSummary.successful": "Geslaagd", + "migration.sessionSummary.skipped": "Overgeslagen", + "migration.sessionSummary.alreadyMigrated": "Al gemigreerd", + "migration.sessionSummary.errored": "Met fouten", + "migration.sessionSummary.none": "Geen", + "migration.forceReimport.title": "Herimport forceren", + "migration.forceReimport.description": + "Het opnieuw importeren van {{target}} zal deze overschrijven en alle nieuwe berichten verwijderen die al in die sessies zijn gemaakt.", + "migration.forceReimport.target.one": "deze sessie", + "migration.forceReimport.target.many": "deze {{count}} sessies", + "migration.forceReimport.button": "Herimport forceren", + "migration.forceReimport.all": "Alles opnieuw importeren", + "migration.forceReimport.proceed": "Doorgaan", + "migration.forceReimport.toast.started": "Geforceerde herimport gestart", + "migration.running.title": "Migratie bezig", + "migration.running.description.line1": "Je staat op het punt af te ronden terwijl er nog sessies worden gemigreerd.", + "migration.running.description.line2": "Als je nu vertrekt, kunnen sommige sessies onvolledig blijven.", + "migration.running.stay": "Blijven", + "migration.running.proceed": "Doorgaan", + "migration.sessionProgress.preparing": "Sessie voorbereiden", + "migration.sessionProgress.storing": "Sessie opslaan", + "migration.sessionProgress.skipped": "Sessie overgeslagen", + "migration.sessionProgress.header": "Bezig met migreren van {{current}} van {{total}}", + "migration.sessionFormat.unknownDate": "Onbekende datum", + "migration.sessionFormat.unknown": "Onbekend", + "migration.sessionFormat.unknownError": "Onbekende fout", // legacy-migration end "error.details.show": "Details", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 8090513ffbd..1d783ea1a89 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -1156,6 +1156,10 @@ export const dict = { "Regler er instruksjonsfiler som styrer agentens atferd. De inkluderes i systemprompten for hver samtale. Legg til filstier nedenfor for å inkludere ekstra regler.", "settings.agentBehaviour.instructionFiles": "Ekstra instruksjonsfiler", "settings.agentBehaviour.instructionFiles.description": "Stier til ekstra instruksjonsfiler i systemprompten", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code-kompatibilitet", + "settings.agentBehaviour.claudeCompat.title": "Last inn Claude Code-filer", + "settings.agentBehaviour.claudeCompat.description": + "Last inn CLAUDE.md-instruksjoner og ferdigheter fra Claude Code-konfigurasjonsmappen din i økter. Aktiver dette hvis du vil at Kilo skal bruke dine Claude Code-instruksjoner og ferdigheter. Krever omstart.", "settings.agentBehaviour.mcpDetail.command": "Kommando", "settings.agentBehaviour.mcpDetail.args": "Argumenter", "settings.agentBehaviour.mcpDetail.env": "Miljø", @@ -1295,6 +1299,36 @@ export const dict = { "migration.error.continue": "Fortsett", "migration.error.action.copy": "Kopier", "migration.error.toast.copied": "Feil kopiert til utklippstavlen", + + "migration.sessionSummary.title": "Oppsummering:", + "migration.sessionSummary.copy": "Kopier rapport", + "migration.sessionSummary.toast.copied": "Rapport kopiert", + "migration.sessionSummary.successful": "Vellykkede", + "migration.sessionSummary.skipped": "Hoppet over", + "migration.sessionSummary.alreadyMigrated": "Allerede migrert", + "migration.sessionSummary.errored": "Med feil", + "migration.sessionSummary.none": "Ingen", + "migration.forceReimport.title": "Tving ny import", + "migration.forceReimport.description": + "Hvis du importerer {{target}} på nytt, blir de overskrevet og alle nye meldinger som allerede er opprettet i disse øktene blir slettet.", + "migration.forceReimport.target.one": "denne økten", + "migration.forceReimport.target.many": "disse {{count}} øktene", + "migration.forceReimport.button": "Tving ny import", + "migration.forceReimport.all": "Importer alle på nytt", + "migration.forceReimport.proceed": "Fortsett", + "migration.forceReimport.toast.started": "Tvungen ny import startet", + "migration.running.title": "Migrering pågår", + "migration.running.description.line1": "Du er i ferd med å avslutte mens det fortsatt er økter som migreres.", + "migration.running.description.line2": "Hvis du går nå, kan noen økter forbli ufullstendige.", + "migration.running.stay": "Bli", + "migration.running.proceed": "Fortsett", + "migration.sessionProgress.preparing": "Forbereder økt", + "migration.sessionProgress.storing": "Lagrer økt", + "migration.sessionProgress.skipped": "Økt hoppet over", + "migration.sessionProgress.header": "Migrerer {{current}} av {{total}}", + "migration.sessionFormat.unknownDate": "Ukjent dato", + "migration.sessionFormat.unknown": "Ukjent", + "migration.sessionFormat.unknownError": "Ukjent feil", // legacy-migration end "task.todos.progress": "{{done}}/{{total}} oppgaver fullført", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 95e19d34563..c45d4612ddd 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -1160,6 +1160,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Dodatkowe pliki instrukcji", "settings.agentBehaviour.instructionFiles.description": "Ścieżki do dodatkowych plików instrukcji w prompcie systemowym", + "settings.agentBehaviour.claudeCompat.heading": "Kompatybilność z Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Wczytuj pliki Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Wczytuje instrukcje CLAUDE.md oraz umiejętności z katalogu konfiguracyjnego Claude Code do sesji. Włącz tę opcję, jeśli chcesz, aby Kilo korzystał z Twoich instrukcji i umiejętności Claude Code. Wymaga ponownego uruchomienia.", "settings.agentBehaviour.mcpDetail.command": "Polecenie", "settings.agentBehaviour.mcpDetail.args": "Argumenty", "settings.agentBehaviour.mcpDetail.env": "Środowisko", @@ -1303,6 +1307,36 @@ export const dict = { "migration.error.continue": "Kontynuuj", "migration.error.action.copy": "Kopiuj", "migration.error.toast.copied": "Błąd skopiowano do schowka", + + "migration.sessionSummary.title": "Podsumowanie:", + "migration.sessionSummary.copy": "Kopiuj raport", + "migration.sessionSummary.toast.copied": "Skopiowano raport", + "migration.sessionSummary.successful": "Udane", + "migration.sessionSummary.skipped": "Pominięte", + "migration.sessionSummary.alreadyMigrated": "Już zmigrowane", + "migration.sessionSummary.errored": "Z błędem", + "migration.sessionSummary.none": "Brak", + "migration.forceReimport.title": "Wymuś ponowny import", + "migration.forceReimport.description": + "Ponowny import {{target}} spowoduje ich nadpisanie i usunięcie wszystkich nowych wiadomości już utworzonych w tych sesjach.", + "migration.forceReimport.target.one": "tej sesji", + "migration.forceReimport.target.many": "tych {{count}} sesji", + "migration.forceReimport.button": "Wymuś ponowny import", + "migration.forceReimport.all": "Zaimportuj ponownie wszystko", + "migration.forceReimport.proceed": "Kontynuuj", + "migration.forceReimport.toast.started": "Rozpoczęto wymuszony ponowny import", + "migration.running.title": "Migracja w toku", + "migration.running.description.line1": "Zaraz zakończysz, podczas gdy część sesji wciąż się migruje.", + "migration.running.description.line2": "Jeśli wyjdziesz teraz, niektóre sesje mogą pozostać niekompletne.", + "migration.running.stay": "Zostań", + "migration.running.proceed": "Kontynuuj", + "migration.sessionProgress.preparing": "Przygotowywanie sesji", + "migration.sessionProgress.storing": "Zapisywanie sesji", + "migration.sessionProgress.skipped": "Sesja pominięta", + "migration.sessionProgress.header": "Migracja {{current}} z {{total}}", + "migration.sessionFormat.unknownDate": "Nieznana data", + "migration.sessionFormat.unknown": "Nieznane", + "migration.sessionFormat.unknownError": "Nieznany błąd", // legacy-migration end "error.details.show": "Szczegóły", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 08fc5f3b61d..29690a2d705 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -1161,6 +1161,10 @@ export const dict = { "Правила — это файлы инструкций, которые направляют поведение агента. Они включаются в системный промпт для каждого разговора. Добавьте пути к файлам ниже, чтобы включить дополнительные правила.", "settings.agentBehaviour.instructionFiles": "Дополнительные файлы инструкций", "settings.agentBehaviour.instructionFiles.description": "Пути к дополнительным файлам инструкций в системном промпте", + "settings.agentBehaviour.claudeCompat.heading": "Совместимость с Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Загружать файлы Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Загружать инструкции CLAUDE.md и навыки из каталога конфигурации Claude Code в сессии. Включите эту опцию, если хотите, чтобы Kilo использовал ваши инструкции и навыки Claude Code. Требуется перезапуск.", "settings.agentBehaviour.mcpDetail.command": "Команда", "settings.agentBehaviour.mcpDetail.args": "Аргументы", "settings.agentBehaviour.mcpDetail.env": "Окружение", @@ -1302,6 +1306,36 @@ export const dict = { "migration.error.continue": "Продолжить", "migration.error.action.copy": "Копировать", "migration.error.toast.copied": "Ошибка скопирована в буфер обмена", + + "migration.sessionSummary.title": "Сводка:", + "migration.sessionSummary.copy": "Скопировать отчёт", + "migration.sessionSummary.toast.copied": "Отчёт скопирован", + "migration.sessionSummary.successful": "Успешно", + "migration.sessionSummary.skipped": "Пропущено", + "migration.sessionSummary.alreadyMigrated": "Уже перенесено", + "migration.sessionSummary.errored": "С ошибкой", + "migration.sessionSummary.none": "Нет", + "migration.forceReimport.title": "Принудительный повторный импорт", + "migration.forceReimport.description": + "Повторный импорт {{target}} перезапишет их и удалит все новые сообщения, уже созданные в этих сессиях.", + "migration.forceReimport.target.one": "эту сессию", + "migration.forceReimport.target.many": "эти {{count}} сессии", + "migration.forceReimport.button": "Принудительно импортировать снова", + "migration.forceReimport.all": "Импортировать всё заново", + "migration.forceReimport.proceed": "Продолжить", + "migration.forceReimport.toast.started": "Принудительный повторный импорт запущен", + "migration.running.title": "Миграция выполняется", + "migration.running.description.line1": "Вы собираетесь завершить процесс, пока некоторые сессии всё ещё переносятся.", + "migration.running.description.line2": "Если вы уйдёте сейчас, некоторые сессии могут остаться незавершёнными.", + "migration.running.stay": "Остаться", + "migration.running.proceed": "Продолжить", + "migration.sessionProgress.preparing": "Подготовка сессии", + "migration.sessionProgress.storing": "Сохранение сессии", + "migration.sessionProgress.skipped": "Сессия пропущена", + "migration.sessionProgress.header": "Перенос {{current}} из {{total}}", + "migration.sessionFormat.unknownDate": "Неизвестная дата", + "migration.sessionFormat.unknown": "Неизвестно", + "migration.sessionFormat.unknownError": "Неизвестная ошибка", // legacy-migration end "error.details.show": "Подробности", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 4ec44cfb486..8d9c11fb50a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -1144,6 +1144,10 @@ export const dict = { "กฎคือไฟล์คำสั่งที่แนะนำพฤติกรรมของเอเจนต์ กฎเหล่านี้จะถูกรวมอยู่ในพรอมต์ระบบสำหรับทุกการสนทนา เพิ่มเส้นทางไฟล์ด้านล่างเพื่อรวมกฎเพิ่มเติม", "settings.agentBehaviour.instructionFiles": "ไฟล์คำสั่งเพิ่มเติม", "settings.agentBehaviour.instructionFiles.description": "เส้นทางไฟล์คำสั่งเพิ่มเติมในพรอมต์ระบบ", + "settings.agentBehaviour.claudeCompat.heading": "ความเข้ากันได้กับ Claude Code", + "settings.agentBehaviour.claudeCompat.title": "โหลดไฟล์ Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "โหลดคำแนะนำและทักษะจาก CLAUDE.md ในไดเรกทอรีการกำหนดค่า Claude Code ของคุณลงในเซสชัน เปิดใช้งานตัวเลือกนี้หากคุณต้องการให้ Kilo ใช้คำแนะนำและทักษะจาก Claude Code ของคุณ จำเป็นต้องรีสตาร์ท", "settings.agentBehaviour.mcpDetail.command": "คำสั่ง", "settings.agentBehaviour.mcpDetail.args": "อาร์กิวเมนต์", "settings.agentBehaviour.mcpDetail.env": "สภาพแวดล้อม", @@ -1278,6 +1282,36 @@ export const dict = { "migration.error.continue": "ดำเนินการต่อ", "migration.error.action.copy": "คัดลอก", "migration.error.toast.copied": "คัดลอกข้อผิดพลาดไปยังคลิปบอร์ดแล้ว", + + "migration.sessionSummary.title": "สรุป:", + "migration.sessionSummary.copy": "คัดลอกรายงาน", + "migration.sessionSummary.toast.copied": "คัดลอกรายงานแล้ว", + "migration.sessionSummary.successful": "สำเร็จ", + "migration.sessionSummary.skipped": "ข้ามแล้ว", + "migration.sessionSummary.alreadyMigrated": "ย้ายแล้ว", + "migration.sessionSummary.errored": "มีข้อผิดพลาด", + "migration.sessionSummary.none": "ไม่มี", + "migration.forceReimport.title": "บังคับนำเข้าใหม่", + "migration.forceReimport.description": + "การนำเข้า {{target}} ใหม่จะเขียนทับและลบข้อความใหม่ใด ๆ ที่สร้างไว้แล้วในเซสชันเหล่านั้น", + "migration.forceReimport.target.one": "เซสชันนี้", + "migration.forceReimport.target.many": "{{count}} เซสชันเหล่านี้", + "migration.forceReimport.button": "บังคับนำเข้าใหม่", + "migration.forceReimport.all": "นำเข้าทั้งหมดใหม่", + "migration.forceReimport.proceed": "ดำเนินการต่อ", + "migration.forceReimport.toast.started": "เริ่มการนำเข้าใหม่แบบบังคับแล้ว", + "migration.running.title": "กำลังย้ายข้อมูล", + "migration.running.description.line1": "คุณกำลังจะเสร็จสิ้นในขณะที่ยังมีบางเซสชันกำลังย้ายข้อมูลอยู่", + "migration.running.description.line2": "หากคุณออกตอนนี้ บางเซสชันอาจยังไม่สมบูรณ์", + "migration.running.stay": "อยู่ต่อ", + "migration.running.proceed": "ดำเนินการต่อ", + "migration.sessionProgress.preparing": "กำลังเตรียมเซสชัน", + "migration.sessionProgress.storing": "กำลังบันทึกเซสชัน", + "migration.sessionProgress.skipped": "ข้ามเซสชันแล้ว", + "migration.sessionProgress.header": "กำลังย้าย {{current}} จาก {{total}}", + "migration.sessionFormat.unknownDate": "ไม่ทราบวันที่", + "migration.sessionFormat.unknown": "ไม่ทราบ", + "migration.sessionFormat.unknownError": "ข้อผิดพลาดที่ไม่ทราบสาเหตุ", // legacy-migration end "error.details.show": "รายละเอียด", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index 48a68f975ff..62e46cdd179 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -1121,6 +1121,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Ek Talimat Dosyaları", "settings.agentBehaviour.instructionFiles.description": "Sistem komutuna dahil edilen ek talimat dosyalarının yolları", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code Uyumluluğu", + "settings.agentBehaviour.claudeCompat.title": "Claude Code Dosyalarını Yükle", + "settings.agentBehaviour.claudeCompat.description": + "Claude Code yapılandırma dizininizdeki CLAUDE.md talimatlarını ve becerilerini oturumlara yükleyin. Kilo'nun Claude Code talimatlarınızı ve becerilerinizi kullanmasını istiyorsanız bunu etkinleştirin. Yeniden başlatma gerektirir.", "settings.agentBehaviour.removeMcp.title": "MCP sunucusunu kaldır", "settings.agentBehaviour.removeMcp.confirm": '"{{name}}" MCP sunucusu kaldırılsın mı? Bu, yapılandırmanızdan kaldırılacak.', @@ -1291,6 +1295,36 @@ export const dict = { "migration.error.continue": "Devam et", "migration.error.action.copy": "Kopyala", "migration.error.toast.copied": "Hata panoya kopyalandı", + + "migration.sessionSummary.title": "Özet:", + "migration.sessionSummary.copy": "Raporu kopyala", + "migration.sessionSummary.toast.copied": "Rapor kopyalandı", + "migration.sessionSummary.successful": "Başarılı", + "migration.sessionSummary.skipped": "Atlandı", + "migration.sessionSummary.alreadyMigrated": "Zaten taşındı", + "migration.sessionSummary.errored": "Hatalı", + "migration.sessionSummary.none": "Yok", + "migration.forceReimport.title": "Yeniden içe aktarmayı zorla", + "migration.forceReimport.description": + "{{target}} yeniden içe aktarılırsa üzerlerine yazılır ve bu oturumlarda zaten oluşturulmuş yeni mesajlar silinir.", + "migration.forceReimport.target.one": "bu oturum", + "migration.forceReimport.target.many": "bu {{count}} oturum", + "migration.forceReimport.button": "Yeniden içe aktarmayı zorla", + "migration.forceReimport.all": "Hepsini yeniden içe aktar", + "migration.forceReimport.proceed": "Devam et", + "migration.forceReimport.toast.started": "Zorunlu yeniden içe aktarma başlatıldı", + "migration.running.title": "Taşıma sürüyor", + "migration.running.description.line1": "Hâlâ taşınan oturumlar varken işlemi bitirmek üzeresiniz.", + "migration.running.description.line2": "Şimdi çıkarsanız bazı oturumlar eksik kalabilir.", + "migration.running.stay": "Kal", + "migration.running.proceed": "Devam et", + "migration.sessionProgress.preparing": "Oturum hazırlanıyor", + "migration.sessionProgress.storing": "Oturum kaydediliyor", + "migration.sessionProgress.skipped": "Oturum atlandı", + "migration.sessionProgress.header": "{{total}} içinden {{current}} taşınıyor", + "migration.sessionFormat.unknownDate": "Bilinmeyen tarih", + "migration.sessionFormat.unknown": "Bilinmiyor", + "migration.sessionFormat.unknownError": "Bilinmeyen hata", // legacy-migration end "error.details.show": "Ayrıntılar", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts index ba0c29266e9..38c9bea9857 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/uk.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/uk.ts @@ -1123,6 +1123,10 @@ export const dict = { "settings.agentBehaviour.instructionFiles": "Додаткові файли інструкцій", "settings.agentBehaviour.instructionFiles.description": "Шляхи до додаткових файлів інструкцій, що включаються до системного запиту", + "settings.agentBehaviour.claudeCompat.heading": "Сумісність з Claude Code", + "settings.agentBehaviour.claudeCompat.title": "Завантажувати файли Claude Code", + "settings.agentBehaviour.claudeCompat.description": + "Завантажувати інструкції та навички CLAUDE.md з вашого каталогу конфігурації Claude Code у сесії. Увімкніть це, якщо ви хочете, щоб Kilo використовував ваші інструкції та навички Claude Code. Потребує перезапуску.", "settings.agentBehaviour.removeMcp.title": "Видалити MCP-сервер", "settings.agentBehaviour.removeMcp.confirm": 'Видалити MCP-сервер "{{name}}"? Це видалить його з вашої конфігурації.', "settings.agentBehaviour.removeMcp.button": "Видалити", @@ -1292,6 +1296,36 @@ export const dict = { "migration.error.continue": "Продовжити", "migration.error.action.copy": "Копіювати", "migration.error.toast.copied": "Помилку скопійовано до буфера обміну", + + "migration.sessionSummary.title": "Підсумок:", + "migration.sessionSummary.copy": "Скопіювати звіт", + "migration.sessionSummary.toast.copied": "Звіт скопійовано", + "migration.sessionSummary.successful": "Успішно", + "migration.sessionSummary.skipped": "Пропущено", + "migration.sessionSummary.alreadyMigrated": "Уже перенесено", + "migration.sessionSummary.errored": "З помилкою", + "migration.sessionSummary.none": "Немає", + "migration.forceReimport.title": "Примусово імпортувати повторно", + "migration.forceReimport.description": + "Повторний імпорт {{target}} перезапише їх і видалить усі нові повідомлення, уже створені в цих сесіях.", + "migration.forceReimport.target.one": "цю сесію", + "migration.forceReimport.target.many": "ці {{count}} сесії", + "migration.forceReimport.button": "Примусово імпортувати повторно", + "migration.forceReimport.all": "Імпортувати все повторно", + "migration.forceReimport.proceed": "Продовжити", + "migration.forceReimport.toast.started": "Примусовий повторний імпорт розпочато", + "migration.running.title": "Триває перенесення", + "migration.running.description.line1": "Ви збираєтеся завершити роботу, поки деякі сесії ще переносяться.", + "migration.running.description.line2": "Якщо ви вийдете зараз, деякі сесії можуть залишитися незавершеними.", + "migration.running.stay": "Залишитися", + "migration.running.proceed": "Продовжити", + "migration.sessionProgress.preparing": "Підготовка сесії", + "migration.sessionProgress.storing": "Збереження сесії", + "migration.sessionProgress.skipped": "Сесію пропущено", + "migration.sessionProgress.header": "Перенесення {{current}} з {{total}}", + "migration.sessionFormat.unknownDate": "Невідома дата", + "migration.sessionFormat.unknown": "Невідомо", + "migration.sessionFormat.unknownError": "Невідома помилка", // legacy-migration end "error.details.show": "Деталі", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index ae9ffb14229..33a831a0c0d 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -1128,6 +1128,10 @@ export const dict = { "规则是指导代理行为的指令文件。它们会被包含在每次对话的系统提示词中。在下方添加文件路径以包含额外的规则。", "settings.agentBehaviour.instructionFiles": "附加指令文件", "settings.agentBehaviour.instructionFiles.description": "包含在系统提示词中的附加指令文件路径", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code 兼容性", + "settings.agentBehaviour.claudeCompat.title": "加载 Claude Code 文件", + "settings.agentBehaviour.claudeCompat.description": + "将 Claude Code 配置目录中的 CLAUDE.md 指令和技能加载到会话中。如果您希望 Kilo 使用您的 Claude Code 指令和技能,请启用此选项。需要重启。", "settings.agentBehaviour.mcpDetail.command": "命令", "settings.agentBehaviour.mcpDetail.args": "参数", "settings.agentBehaviour.mcpDetail.env": "环境", @@ -1254,6 +1258,35 @@ export const dict = { "migration.error.continue": "继续", "migration.error.action.copy": "复制", "migration.error.toast.copied": "错误已复制到剪贴板", + + "migration.sessionSummary.title": "摘要:", + "migration.sessionSummary.copy": "复制报告", + "migration.sessionSummary.toast.copied": "报告已复制", + "migration.sessionSummary.successful": "成功", + "migration.sessionSummary.skipped": "已跳过", + "migration.sessionSummary.alreadyMigrated": "已迁移", + "migration.sessionSummary.errored": "出错", + "migration.sessionSummary.none": "无", + "migration.forceReimport.title": "强制重新导入", + "migration.forceReimport.description": "重新导入 {{target}} 将覆盖它们,并删除这些会话中已创建的所有新消息。", + "migration.forceReimport.target.one": "这个会话", + "migration.forceReimport.target.many": "这 {{count}} 个会话", + "migration.forceReimport.button": "强制重新导入", + "migration.forceReimport.all": "重新导入全部", + "migration.forceReimport.proceed": "继续", + "migration.forceReimport.toast.started": "已开始强制重新导入", + "migration.running.title": "迁移进行中", + "migration.running.description.line1": "仍有会话正在迁移时,你即将结束流程。", + "migration.running.description.line2": "如果你现在离开,某些会话可能会保持未完成状态。", + "migration.running.stay": "留下", + "migration.running.proceed": "继续", + "migration.sessionProgress.preparing": "正在准备会话", + "migration.sessionProgress.storing": "正在保存会话", + "migration.sessionProgress.skipped": "已跳过会话", + "migration.sessionProgress.header": "正在迁移第 {{current}} / {{total}} 个", + "migration.sessionFormat.unknownDate": "未知日期", + "migration.sessionFormat.unknown": "未知", + "migration.sessionFormat.unknownError": "未知错误", // legacy-migration end "error.details.show": "详细信息", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 0980f4782a7..6c6f3e8cae0 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -1131,6 +1131,10 @@ export const dict = { "規則是引導代理行為的指令檔案。它們會被包含在每次對話的系統提示詞中。在下方新增檔案路徑以包含額外的規則。", "settings.agentBehaviour.instructionFiles": "附加指令檔案", "settings.agentBehaviour.instructionFiles.description": "包含在系統提示詞中的附加指令檔案路徑", + "settings.agentBehaviour.claudeCompat.heading": "Claude Code 相容性", + "settings.agentBehaviour.claudeCompat.title": "載入 Claude Code 檔案", + "settings.agentBehaviour.claudeCompat.description": + "從您的 Claude Code 設定目錄將 CLAUDE.md 指示與技能載入至工作階段中。如果您希望 Kilo 使用您的 Claude Code 指示與技能,請啟用此選項。需要重新啟動。", "settings.agentBehaviour.mcpDetail.command": "指令", "settings.agentBehaviour.mcpDetail.args": "引數", "settings.agentBehaviour.mcpDetail.env": "環境", @@ -1257,6 +1261,35 @@ export const dict = { "migration.error.continue": "繼續", "migration.error.action.copy": "複製", "migration.error.toast.copied": "錯誤已複製到剪貼簿", + + "migration.sessionSummary.title": "摘要:", + "migration.sessionSummary.copy": "複製報告", + "migration.sessionSummary.toast.copied": "報告已複製", + "migration.sessionSummary.successful": "成功", + "migration.sessionSummary.skipped": "已略過", + "migration.sessionSummary.alreadyMigrated": "已遷移", + "migration.sessionSummary.errored": "發生錯誤", + "migration.sessionSummary.none": "無", + "migration.forceReimport.title": "強制重新匯入", + "migration.forceReimport.description": "重新匯入 {{target}} 將會覆寫它們,並刪除這些工作階段中已建立的所有新訊息。", + "migration.forceReimport.target.one": "這個工作階段", + "migration.forceReimport.target.many": "這 {{count}} 個工作階段", + "migration.forceReimport.button": "強制重新匯入", + "migration.forceReimport.all": "全部重新匯入", + "migration.forceReimport.proceed": "繼續", + "migration.forceReimport.toast.started": "已開始強制重新匯入", + "migration.running.title": "遷移進行中", + "migration.running.description.line1": "目前仍有工作階段正在遷移,但你即將結束流程。", + "migration.running.description.line2": "如果你現在離開,部分工作階段可能會維持未完成狀態。", + "migration.running.stay": "留下", + "migration.running.proceed": "繼續", + "migration.sessionProgress.preparing": "正在準備工作階段", + "migration.sessionProgress.storing": "正在儲存工作階段", + "migration.sessionProgress.skipped": "已略過工作階段", + "migration.sessionProgress.header": "正在遷移第 {{current}} / {{total}} 個", + "migration.sessionFormat.unknownDate": "未知日期", + "migration.sessionFormat.unknown": "未知", + "migration.sessionFormat.unknownError": "未知錯誤", // legacy-migration end "error.details.show": "詳細資訊", diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 1cff80d8045..4dce5ea0069 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -1047,9 +1047,16 @@ export interface LegacySettings { autocomplete?: LegacyAutocompleteSettings } +export interface MigrationSessionInfo { + id: string + title: string + directory: string + time: number +} + export interface MigrationResultItem { item: string - category: "provider" | "mcpServer" | "customMode" | "defaultModel" | "settings" + category: "provider" | "mcpServer" | "customMode" | "session" | "defaultModel" | "settings" status: "success" | "warning" | "error" message?: string } @@ -1061,7 +1068,7 @@ export interface MigrationStateMessage { providers: MigrationProviderInfo[] mcpServers: MigrationMcpServerInfo[] customModes: MigrationCustomModeInfo[] - sessions?: string[] + sessions?: MigrationSessionInfo[] defaultModel?: { provider: string; model: string } settings?: LegacySettings } @@ -1073,7 +1080,7 @@ export interface LegacyMigrationDataMessage { providers: MigrationProviderInfo[] mcpServers: MigrationMcpServerInfo[] customModes: MigrationCustomModeInfo[] - sessions?: string[] + sessions?: MigrationSessionInfo[] defaultModel?: { provider: string; model: string } settings?: LegacySettings } @@ -1086,6 +1093,17 @@ export interface LegacyMigrationProgressMessage { message?: string } +export type LegacyMigrationSessionPhase = "preparing" | "storing" | "skipped" | "done" | "summary" | "error" + +export interface LegacyMigrationSessionProgressMessage { + type: "legacyMigrationSessionProgress" + session: MigrationSessionInfo + index: number + total: number + phase: LegacyMigrationSessionPhase + error?: string +} + export interface LegacyMigrationCompleteMessage { type: "legacyMigrationComplete" results: MigrationResultItem[] @@ -1104,13 +1122,18 @@ export interface MigrationAutoApprovalSelections { taskPermission: boolean } +export interface MigrationSessionSelection { + id: string + force?: boolean +} + export interface StartLegacyMigrationMessage { type: "startLegacyMigration" selections: { providers: string[] mcpServers: string[] customModes: string[] - sessions?: string[] + sessions?: MigrationSessionSelection[] defaultModel: boolean settings: { autoApproval: MigrationAutoApprovalSelections @@ -1127,6 +1150,10 @@ export interface SkipLegacyMigrationMessage { export interface ClearLegacyDataMessage { type: "clearLegacyData" } + +export interface FinalizeLegacyMigrationMessage { + type: "finalizeLegacyMigration" +} // legacy-migration end // Enhance prompt result (extension → webview) @@ -1291,6 +1318,7 @@ export type ExtensionMessage = | QuestionResolvedMessage | QuestionErrorMessage | BrowserSettingsLoadedMessage + | ClaudeCompatSettingLoadedMessage | ConfigLoadedMessage | ConfigUpdatedMessage | GlobalConfigLoadedMessage @@ -1329,6 +1357,7 @@ export type ExtensionMessage = | MigrationStateMessage | LegacyMigrationDataMessage | LegacyMigrationProgressMessage + | LegacyMigrationSessionProgressMessage | LegacyMigrationCompleteMessage // legacy-migration end | EnhancePromptResultMessage @@ -1639,6 +1668,15 @@ export interface RequestBrowserSettingsMessage { type: "requestBrowserSettings" } +export interface RequestClaudeCompatSettingMessage { + type: "requestClaudeCompatSetting" +} + +export interface ClaudeCompatSettingLoadedMessage { + type: "claudeCompatSettingLoaded" + enabled: boolean +} + export interface RequestConfigMessage { type: "requestConfig" } @@ -2099,6 +2137,7 @@ export type WebviewMessage = | ChatCompletionAcceptedMessage | UpdateSettingRequest | RequestBrowserSettingsMessage + | RequestClaudeCompatSettingMessage | RequestConfigMessage | RequestGlobalConfigMessage | UpdateConfigMessage @@ -2152,6 +2191,7 @@ export type WebviewMessage = | StartLegacyMigrationMessage | SkipLegacyMigrationMessage | ClearLegacyDataMessage + | FinalizeLegacyMigrationMessage // legacy-migration end | ApplyWorktreeDiffMessage | EnhancePromptRequest diff --git a/packages/opencode/package.json b/packages/opencode/package.json index ceaca556f92..d8b506216e8 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "7.1.20", + "version": "7.1.21", "name": "@kilocode/cli", "type": "module", "license": "MIT", diff --git a/packages/opencode/src/kilocode/session-import/service.ts b/packages/opencode/src/kilocode/session-import/service.ts index d3eab7ab5bb..5fb09adb2d9 100644 --- a/packages/opencode/src/kilocode/session-import/service.ts +++ b/packages/opencode/src/kilocode/session-import/service.ts @@ -9,7 +9,6 @@ const target = (input: unknown) => input as never export namespace SessionImportService { export async function project(input: SessionImportType.Project): Promise { - // Do not resolve an empty legacy worktree, because that would fall back to the current // process directory and silently attach the migrated session to the wrong project. if (!input.worktree.trim()) { @@ -22,9 +21,14 @@ export namespace SessionImportService { export async function session(input: SessionImportType.Session): Promise { const row = Database.use((db) => db.select().from(SessionTable).where(eq(target(SessionTable.id), input.id)).get()) - if (row) return { ok: true, id: input.id, skipped: true } + if (row && !input.force) return { ok: true, id: input.id, skipped: true } Database.use((db) => { + if (row && input.force) { + db.delete(SessionTable).where(eq(target(SessionTable.id), input.id)).run() + } + // We still keep onConflictDoUpdate here so forced reimports can recreate the session row + // and non-forced calls remain idempotent if they reach the DB after the existence guard. db.insert(SessionTable) .values({ id: input.id, @@ -47,8 +51,28 @@ export namespace SessionImportService { time_compacting: input.timeCompacting, time_archived: input.timeArchived, }) - .onConflictDoNothing({ + .onConflictDoUpdate({ target: key(SessionTable.id), + set: { + project_id: input.projectID, + workspace_id: input.workspaceID, + parent_id: input.parentID, + slug: input.slug, + directory: input.directory, + title: input.title, + version: input.version, + share_url: input.shareURL, + summary_additions: input.summary?.additions, + summary_deletions: input.summary?.deletions, + summary_files: input.summary?.files, + summary_diffs: input.summary?.diffs as never, + revert: input.revert, + permission: input.permission as never, + time_created: input.timeCreated, + time_updated: input.timeUpdated, + time_compacting: input.timeCompacting, + time_archived: input.timeArchived, + }, }) .run() }) diff --git a/packages/opencode/src/kilocode/session-import/types.ts b/packages/opencode/src/kilocode/session-import/types.ts index 7bd5d6b9f14..b22f2c8b5e0 100644 --- a/packages/opencode/src/kilocode/session-import/types.ts +++ b/packages/opencode/src/kilocode/session-import/types.ts @@ -151,6 +151,7 @@ export namespace SessionImportType { export const Session = z.object({ id: z.string(), projectID: z.string(), + force: z.boolean().optional(), workspaceID: z.string().optional(), parentID: z.string().optional(), slug: z.string(), diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index ad2abb10e0a..7f3b12b1171 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -104,7 +104,8 @@ export namespace Server { // kilocode_change start // kilocode change add telemetry because it is high volume // add early return to prevent logging timing - const skipLogging = c.req.path === "/log" || c.req.path === "/telemetry/capture" + const skipLogging = + c.req.path === "/log" || c.req.path === "/telemetry/capture" || c.req.path === "/global/health" if (skipLogging) { await next() return diff --git a/packages/opencode/test/kilocode/session-import-service.test.ts b/packages/opencode/test/kilocode/session-import-service.test.ts new file mode 100644 index 00000000000..2e70005a2ea --- /dev/null +++ b/packages/opencode/test/kilocode/session-import-service.test.ts @@ -0,0 +1,121 @@ +import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test" + +const use = mock((fn: (db: any) => unknown) => fn(db)) +const eq = (a: unknown, b: unknown) => ({ a, b }) + +mock.module("../../src/storage/db", () => ({ + Database: { use, close() {} }, + eq, +})) + +const { SessionImportService } = await import("../../src/kilocode/session-import/service") + +const sessionTable = { id: "session.id" } +const db = { + select() { + return { + from() { + return { + where() { + return { + get() { + return rows.session + }, + } + }, + } + }, + } + }, + delete() { + return { + where() { + return { + run() { + deletes.push("session") + rows.session = undefined + rows.messages = [] + rows.parts = [] + }, + } + }, + } + }, + insert() { + return { + values(input: Record) { + return { + onConflictDoUpdate() { + return { + run() { + rows.session = { ...input } + }, + } + }, + run() { + rows.session = { ...input } + }, + } + }, + } + }, +} + +const rows = { + session: undefined as Record | undefined, + messages: [] as string[], + parts: [] as string[], +} + +const deletes: string[] = [] + +function input(force?: boolean) { + return { + id: "ses_migrated_test", + projectID: "proj_test", + slug: "legacy-task", + directory: "/workspace/testing", + title: force ? "Reimported task" : "Legacy task", + version: "v2", + timeCreated: 1, + timeUpdated: 1, + ...(force ? { force: true } : {}), + } +} + +describe("SessionImportService.session", () => { + beforeEach(() => { + use.mockClear() + deletes.length = 0 + rows.session = undefined + rows.messages = [] + rows.parts = [] + }) + + afterEach(() => { + use.mockClear() + }) + + test("returns skipped when the session already exists and force is false", async () => { + rows.session = { id: "ses_migrated_test", title: "Legacy task" } + + const result = await SessionImportService.session(input()) + + expect(result).toEqual({ ok: true, id: "ses_migrated_test", skipped: true }) + expect(deletes).toEqual([]) + }) + + test("deletes and recreates the session when force is true", async () => { + rows.session = { id: "ses_migrated_test", title: "Legacy task" } + rows.messages = ["msg_test"] + rows.parts = ["prt_test"] + + const result = await SessionImportService.session(input(true)) + + expect(result).toEqual({ ok: true, id: "ses_migrated_test" }) + expect(deletes).toEqual(["session"]) + expect(rows.messages).toEqual([]) + expect(rows.parts).toEqual([]) + expect(rows.session).toMatchObject({ title: "Reimported task" }) + }) +}) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index ff5eb6e80d2..308da306fe3 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/plugin", - "version": "7.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/script/package.json b/packages/script/package.json index 1356f952e88..53005964b4e 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -8,7 +8,7 @@ "exports": { ".": "./src/index.ts" }, - "version": "7.1.20", + "version": "7.1.21", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 4423b02360f..20b7e545812 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@kilocode/sdk", - "version": "7.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "scripts": { diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 99f4020b7c1..522e01b4eac 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -3184,6 +3184,7 @@ export class SessionImport extends HeyApiClient { workspace?: string id?: string projectID?: string + force?: boolean workspaceID?: string parentID?: string slug?: string @@ -3228,6 +3229,7 @@ export class SessionImport extends HeyApiClient { { in: "query", key: "workspace" }, { in: "body", key: "id" }, { in: "body", key: "projectID" }, + { in: "body", key: "force" }, { in: "body", key: "workspaceID" }, { in: "body", key: "parentID" }, { in: "body", key: "slug" }, diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 9d8ebdb980d..3c0fd23c396 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -4599,6 +4599,7 @@ export type KilocodeSessionImportSessionData = { body?: { id: string projectID: string + force?: boolean workspaceID?: string parentID?: string slug: string diff --git a/packages/storybook/package.json b/packages/storybook/package.json index 60ff61ce99e..0f2bddf958e 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -26,7 +26,7 @@ "typescript": "catalog:", "vite": "catalog:" }, - "version": "7.1.20", + "version": "7.1.21", "dependencies": {}, "peerDependencies": {} } diff --git a/packages/ui/package.json b/packages/ui/package.json index 9e9f4f9db51..3a78cc37940 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "7.1.20", + "version": "7.1.21", "type": "module", "license": "MIT", "exports": { diff --git a/packages/util/package.json b/packages/util/package.json index 7d91217bac9..42fd480cc09 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/util", - "version": "7.1.20", + "version": "7.1.21", "private": true, "type": "module", "license": "MIT", diff --git a/script/upstream/package.json b/script/upstream/package.json index 01c7bf0ffc0..cf1090f4fc9 100644 --- a/script/upstream/package.json +++ b/script/upstream/package.json @@ -1,6 +1,6 @@ { "name": "@kilocode/upstream-merge", - "version": "7.1.20", + "version": "7.1.21", "private": true, "type": "module", "description": "Scripts for automating upstream opencode merges into Kilo", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 35bf406f11b..1e75ac84daf 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "7.1.20", + "version": "7.1.21", "publisher": "sst-dev", "repository": { "type": "git",