mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge branch 'main' into feat/local-recall-tool
This commit is contained in:
@@ -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:",
|
||||
},
|
||||
|
||||
+1
-1
@@ -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": {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kilocode/kilo-ui",
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<boolean>("claudeCodeCompat", false)
|
||||
this.postMessage({
|
||||
type: "claudeCompatSettingLoaded",
|
||||
enabled: enabled ?? false,
|
||||
})
|
||||
}
|
||||
|
||||
/** Re-fetch all server-side state after an auth change. */
|
||||
private async reloadAfterAuthChange(): Promise<void> {
|
||||
await Promise.all([
|
||||
|
||||
@@ -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<void>
|
||||
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<typeof MigrationService.setMigrationStatus>[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<void> {
|
||||
if (!ctx.extensionContext) return
|
||||
await ctx.disposeGlobal()
|
||||
await MigrationService.setMigrationStatus(
|
||||
ctx.extensionContext as Parameters<typeof MigrationService.setMigrationStatus>[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<void> {
|
||||
if (!ctx.extensionContext) return
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<MigrationResultItem[]> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<MigrationSessionProgress, "session" | "index" | "total">) => {
|
||||
onProgress({
|
||||
session: meta.session,
|
||||
index: meta.index,
|
||||
total: meta.total,
|
||||
phase: progress.phase,
|
||||
error: progress.error,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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<ReturnType<typeof parseSession>>
|
||||
payload?: Awaited<ReturnType<typeof parseSession>>
|
||||
}
|
||||
| {
|
||||
ok: false
|
||||
payload: Awaited<ReturnType<typeof parseSession>>
|
||||
payload?: Awaited<ReturnType<typeof parseSession>>
|
||||
message: string
|
||||
}
|
||||
|
||||
export async function migrate(id: string, context: vscode.ExtensionContext, client: KiloClient): Promise<Result> {
|
||||
type Progress = Omit<MigrationSessionProgress, "session" | "index" | "total">
|
||||
type ProgressCallback = (progress: Progress) => void
|
||||
type Payload = Awaited<ReturnType<typeof parseSession>>
|
||||
|
||||
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<Result> {
|
||||
const dir = vscode.Uri.joinPath(context.globalStorageUri, "tasks").fsPath
|
||||
const items = context.globalState.get<LegacyHistoryItem[]>("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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<boolean>("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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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" }])
|
||||
})
|
||||
})
|
||||
@@ -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<ForceReimportDialogProps> = (props) => {
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
|
||||
return (
|
||||
<Dialog title={language.t("migration.forceReimport.title")} fit>
|
||||
<div class="dialog-confirm-body">
|
||||
<p>
|
||||
{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) }),
|
||||
})}
|
||||
</p>
|
||||
<div class="dialog-confirm-actions">
|
||||
<Button variant="secondary" size="large" onClick={() => dialog.close()}>
|
||||
{language.t("common.cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="large"
|
||||
onClick={() => {
|
||||
props.onConfirm()
|
||||
dialog.close()
|
||||
}}
|
||||
>
|
||||
{language.t("migration.forceReimport.proceed")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default ForceReimportDialog
|
||||
@@ -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<MigrationWizardProps> = (props) => {
|
||||
const vscode = useVSCode()
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
|
||||
const [screen, setScreen] = createSignal<Screen>("whats-new")
|
||||
@@ -184,7 +198,7 @@ const MigrationWizard: Component<MigrationWizardProps> = (props) => {
|
||||
const [providers, setProviders] = createSignal<MigrationProviderInfo[]>([])
|
||||
const [mcpServers, setMcpServers] = createSignal<MigrationMcpServerInfo[]>([])
|
||||
const [customModes, setCustomModes] = createSignal<MigrationCustomModeInfo[]>([])
|
||||
const [sessions, setSessions] = createSignal<string[]>([])
|
||||
const [sessions, setSessions] = createSignal<MigrationSessionInfo[]>([])
|
||||
const [defaultModel, setDefaultModel] = createSignal<{ provider: string; model: string } | undefined>(undefined)
|
||||
const [legacySettings, setLegacySettings] = createSignal<LegacySettings | undefined>(undefined)
|
||||
|
||||
@@ -201,6 +215,9 @@ const MigrationWizard: Component<MigrationWizardProps> = (props) => {
|
||||
// Progress tracking
|
||||
const [progressEntries, setProgressEntries] = createSignal<ProgressEntry[]>([])
|
||||
const [results, setResults] = createSignal<MigrationResultItem[]>([])
|
||||
const [sessionProgress, setSessionProgress] = createSignal<SessionMigrationProgressState | undefined>(undefined)
|
||||
const [sessionSummary, setSessionSummary] = createSignal<SessionSummaryState>(createSessionSummary())
|
||||
const [running, setRunning] = createSignal(false)
|
||||
|
||||
// Cleanup preference
|
||||
const [clearLegacyData, setClearLegacyData] = createSignal(false)
|
||||
@@ -253,7 +270,7 @@ const MigrationWizard: Component<MigrationWizardProps> = (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<MigrationWizardProps> = (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<MigrationWizardProps> = (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<MigrationWizardProps> = (props) => {
|
||||
]
|
||||
|
||||
setProgressEntries(entries)
|
||||
setSessionSummary(createSessionSummary())
|
||||
setSessionProgress(undefined)
|
||||
setRunning(true)
|
||||
setPhase("migrating")
|
||||
|
||||
vscode.postMessage({
|
||||
@@ -369,7 +404,7 @@ const MigrationWizard: Component<MigrationWizardProps> = (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<MigrationWizardProps> = (props) => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleForceReimport = (ids: string[]) => {
|
||||
dialog.show(() => (
|
||||
<ForceReimportDialog
|
||||
count={ids.length}
|
||||
onConfirm={() => {
|
||||
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(() => (
|
||||
<RunningMigrationDialog
|
||||
onConfirm={() => {
|
||||
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<MigrationWizardProps> = (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<MigrationWizardProps> = (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<MigrationWizardProps> = (props) => {
|
||||
|
||||
const StatusIcon = (gProps: { group: string }): JSX.Element => {
|
||||
const status = () => groupStatus(gProps.group)
|
||||
const spinning = () => (gProps.group === "sessions" ? sessionIconSpinning() : status() === "migrating")
|
||||
return (
|
||||
<>
|
||||
<Show when={status() === "pending"}>
|
||||
<Show when={status() === "pending" && !spinning()}>
|
||||
<div class="migration-wizard__status-icon migration-wizard__status-icon--pending" />
|
||||
</Show>
|
||||
<Show when={status() === "migrating"}>
|
||||
<Show when={spinning()}>
|
||||
<div class="migration-wizard__status-icon">
|
||||
<div class="migration-wizard__spinner" />
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={status() === "success"}>
|
||||
<Show when={status() === "success" && !spinning()}>
|
||||
<div class="migration-wizard__status-icon migration-wizard__status-icon--success">
|
||||
<SuccessCheckSvg />
|
||||
</div>
|
||||
@@ -693,28 +785,13 @@ const MigrationWizard: Component<MigrationWizardProps> = (props) => {
|
||||
<div class="desc">
|
||||
{language.t("migration.migrate.sessionsDetected", { count: String(sessions().length) })}
|
||||
</div>
|
||||
<Show
|
||||
when={
|
||||
(phase() === "error" || phase() === "done") &&
|
||||
groupStatus("sessions") === "error" &&
|
||||
groupMessage("sessions")
|
||||
}
|
||||
>
|
||||
<div class="migration-wizard__error-box">
|
||||
<div class="migration-wizard__error-box-header">
|
||||
<div class="migration-wizard__error-box-title">
|
||||
{language.t("migration.error.sessionFailed")}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="migration-wizard__copy-btn"
|
||||
onClick={() => void copySessionError(groupMessage("sessions")!)}
|
||||
>
|
||||
{language.t("migration.error.action.copy")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="migration-wizard__error-text">{groupMessage("sessions")}</div>
|
||||
</div>
|
||||
<Show when={migrateSessions() && phase() !== "selecting" && sessionProgress()}>
|
||||
<Show
|
||||
when={sessionProgress()?.phase === "summary"}
|
||||
fallback={<SessionMigrationProgress progress={sessionProgress()!} />}
|
||||
>
|
||||
<SessionMigrationSummary summary={sessionSummary()} onForce={handleForceReimport} />
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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<RunningMigrationDialogProps> = (props) => {
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
|
||||
return (
|
||||
<Dialog title={language.t("migration.running.title")} fit>
|
||||
<div class="dialog-confirm-body">
|
||||
<p>{language.t("migration.running.description.line1")}</p>
|
||||
<p>{language.t("migration.running.description.line2")}</p>
|
||||
<div class="dialog-confirm-actions">
|
||||
<Button variant="secondary" size="large" onClick={() => dialog.close()}>
|
||||
{language.t("migration.running.stay")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="large"
|
||||
onClick={() => {
|
||||
props.onConfirm()
|
||||
dialog.close()
|
||||
}}
|
||||
>
|
||||
{language.t("migration.running.proceed")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default RunningMigrationDialog
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { Component, JSX } from "solid-js"
|
||||
|
||||
interface SessionMigrationCardProps {
|
||||
children: JSX.Element
|
||||
}
|
||||
|
||||
const SessionMigrationCard: Component<SessionMigrationCardProps> = (props) => {
|
||||
return <div class="migration-session-card">{props.children}</div>
|
||||
}
|
||||
|
||||
export default SessionMigrationCard
|
||||
+102
@@ -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<typeof useLanguage>, 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<SessionMigrationProgressProps> = (props) => {
|
||||
const language = useLanguage()
|
||||
|
||||
return (
|
||||
<SessionMigrationCard>
|
||||
<div class="migration-session-progress">
|
||||
<div class="migration-session-progress__header">
|
||||
{language.t("migration.sessionProgress.header", {
|
||||
current: String(props.progress.index),
|
||||
total: String(props.progress.total),
|
||||
})}
|
||||
</div>
|
||||
<div class="migration-session-progress__meta">
|
||||
<div
|
||||
class="migration-session-progress__directory"
|
||||
title={props.progress.session.directory || language.t("migration.sessionFormat.unknown")}
|
||||
>
|
||||
{formatText(language, props.progress.session.directory)}
|
||||
</div>
|
||||
<div class="migration-session-progress__meta-row">
|
||||
<span
|
||||
class="migration-session-progress__title"
|
||||
title={props.progress.session.title || language.t("migration.sessionFormat.unknown")}
|
||||
>
|
||||
{formatText(language, props.progress.session.title)}
|
||||
</span>
|
||||
<span class="migration-session-progress__date">{formatDate(language, props.progress.session.time)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="migration-session-progress__steps">
|
||||
<For each={steps}>
|
||||
{(step) => (
|
||||
<div class="migration-session-progress__step">
|
||||
<div
|
||||
class={`migration-session-progress__dot migration-session-progress__dot--${state(step, props.progress.phase)}`}
|
||||
/>
|
||||
<div class="migration-session-progress__step-text">
|
||||
<span>{label(language, step, props.progress)}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</SessionMigrationCard>
|
||||
)
|
||||
}
|
||||
|
||||
export default SessionMigrationProgress
|
||||
@@ -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<SessionMigrationSummaryProps> = (props) => {
|
||||
const language = useLanguage()
|
||||
const [all, setAll] = createSignal(false)
|
||||
const [selected, setSelected] = createSignal<string[]>([])
|
||||
|
||||
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 (
|
||||
<SessionMigrationCard>
|
||||
<div class="migration-session-summary">
|
||||
<div class="migration-session-summary__row">
|
||||
<div class="migration-session-summary__title">{language.t("migration.sessionSummary.title")}</div>
|
||||
<button type="button" class="migration-wizard__copy-btn" onClick={() => void handleCopy()}>
|
||||
{language.t("migration.sessionSummary.copy")}
|
||||
</button>
|
||||
</div>
|
||||
<div class="migration-session-summary__section">
|
||||
<div class="migration-session-summary__label">
|
||||
{label(language.t("migration.sessionSummary.successful"), props.summary.imported.length)}
|
||||
</div>
|
||||
<div class="migration-session-summary__list migration-session-summary__list--success">
|
||||
<For each={props.summary.imported.length > 0 ? props.summary.imported : [undefined]}>
|
||||
{(item) => (
|
||||
<div class="migration-session-summary__item">
|
||||
{item ? line(language, item) : language.t("migration.sessionSummary.none")}
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
<Show when={props.summary.skipped.length > 0}>
|
||||
<div class="migration-session-summary__section">
|
||||
<div class="migration-session-summary__label">
|
||||
{label(
|
||||
language.t("migration.sessionSummary.skipped"),
|
||||
props.summary.skipped.length,
|
||||
language.t("migration.sessionSummary.alreadyMigrated"),
|
||||
)}
|
||||
</div>
|
||||
<div class="migration-session-summary__list migration-session-summary__list--skipped">
|
||||
<For each={props.summary.skipped}>
|
||||
{(item) => (
|
||||
<label class="migration-session-summary__pick">
|
||||
<span class="migration-session-summary__item">{line(language, item)}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={all() || selected().includes(item.id)}
|
||||
onChange={(event) => toggle(item.id, event.currentTarget.checked)}
|
||||
/>
|
||||
<span class="migration-session-summary__pick-mark">
|
||||
<svg
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
stroke="#fff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="2.5 6 5 8.5 9.5 3.5" />
|
||||
</svg>
|
||||
</span>
|
||||
</label>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<div class="migration-session-summary__actions">
|
||||
<label class="migration-session-summary__all">
|
||||
<span>{language.t("migration.forceReimport.all")}</span>
|
||||
<input type="checkbox" checked={all()} onChange={(event) => handleAll(event.currentTarget.checked)} />
|
||||
<span class="migration-session-summary__pick-mark migration-session-summary__pick-mark--all">
|
||||
<svg
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
stroke="#fff"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<polyline points="2.5 6 5 8.5 9.5 3.5" />
|
||||
</svg>
|
||||
</span>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
class="migration-wizard__copy-btn"
|
||||
disabled={picked().length === 0}
|
||||
onClick={() => handleForce()}
|
||||
>
|
||||
{language.t("migration.forceReimport.button")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.summary.errored.length > 0}>
|
||||
<div class="migration-session-summary__section">
|
||||
<div class="migration-session-summary__label">
|
||||
{label(language.t("migration.sessionSummary.errored"), props.summary.errored.length)}
|
||||
</div>
|
||||
<div class="migration-session-summary__list migration-session-summary__list--errored">
|
||||
<For each={errored(language, props.summary)}>
|
||||
{(item) =>
|
||||
item.kind === "detail" ? (
|
||||
<div class="migration-session-summary__detail">{item.text}</div>
|
||||
) : (
|
||||
<div class="migration-session-summary__item">{item.text}</div>
|
||||
)
|
||||
}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</SessionMigrationCard>
|
||||
)
|
||||
}
|
||||
|
||||
export default SessionMigrationSummary
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+49
@@ -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")
|
||||
}
|
||||
+76
@@ -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
|
||||
}
|
||||
@@ -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<AgentView>("list")
|
||||
const [editingAgent, setEditingAgent] = createSignal<string>("")
|
||||
@@ -999,6 +1009,29 @@ const AgentBehaviourTab: Component = () => {
|
||||
)}
|
||||
</For>
|
||||
</Card>
|
||||
|
||||
{/* Claude Code compatibility */}
|
||||
<h4 style={{ "margin-top": "16px", "margin-bottom": "8px" }}>
|
||||
{language.t("settings.agentBehaviour.claudeCompat.heading")}
|
||||
</h4>
|
||||
<Card>
|
||||
<SettingsRow
|
||||
title={language.t("settings.agentBehaviour.claudeCompat.title")}
|
||||
description={language.t("settings.agentBehaviour.claudeCompat.description")}
|
||||
last
|
||||
>
|
||||
<Switch
|
||||
checked={claudeCompat()}
|
||||
onChange={(checked: boolean) => {
|
||||
setClaudeCompat(checked)
|
||||
vscode.postMessage({ type: "updateSetting", key: "claudeCodeCompat", value: checked })
|
||||
}}
|
||||
hideLabel
|
||||
>
|
||||
{language.t("settings.agentBehaviour.claudeCompat.title")}
|
||||
</Switch>
|
||||
</SettingsRow>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ export const LanguageProvider: ParentComponent<LanguageProviderProps> = (props)
|
||||
// Expose locale + setLocale for the LanguageTab
|
||||
import { createContext, useContext } from "solid-js"
|
||||
|
||||
interface LanguageContextValue {
|
||||
export interface LanguageContextValue {
|
||||
locale: Accessor<Locale>
|
||||
setLocale: (locale: Locale | "") => void
|
||||
userOverride: Accessor<Locale | "">
|
||||
|
||||
+34
@@ -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": "التفاصيل",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
+33
@@ -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",
|
||||
|
||||
+36
@@ -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",
|
||||
|
||||
+34
@@ -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": "詳細",
|
||||
|
||||
+34
@@ -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": "상세 정보",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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": "Подробности",
|
||||
|
||||
+34
@@ -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": "รายละเอียด",
|
||||
|
||||
+34
@@ -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",
|
||||
|
||||
+34
@@ -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": "Деталі",
|
||||
|
||||
+33
@@ -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": "详细信息",
|
||||
|
||||
+33
@@ -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": "詳細資訊",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -9,7 +9,6 @@ const target = (input: unknown) => input as never
|
||||
|
||||
export namespace SessionImportService {
|
||||
export async function project(input: SessionImportType.Project): Promise<SessionImportType.Result> {
|
||||
|
||||
// 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<SessionImportType.Result> {
|
||||
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()
|
||||
})
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<string, unknown>) {
|
||||
return {
|
||||
onConflictDoUpdate() {
|
||||
return {
|
||||
run() {
|
||||
rows.session = { ...input }
|
||||
},
|
||||
}
|
||||
},
|
||||
run() {
|
||||
rows.session = { ...input }
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const rows = {
|
||||
session: undefined as Record<string, unknown> | 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" })
|
||||
})
|
||||
})
|
||||
@@ -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": {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -4599,6 +4599,7 @@ export type KilocodeSessionImportSessionData = {
|
||||
body?: {
|
||||
id: string
|
||||
projectID: string
|
||||
force?: boolean
|
||||
workspaceID?: string
|
||||
parentID?: string
|
||||
slug: string
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:"
|
||||
},
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "7.1.20",
|
||||
"version": "7.1.21",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user