mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-07 09:39:46 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fa56a8a71 | |||
| b76df6c359 | |||
| e3366180ae |
@@ -322,7 +322,6 @@ jobs:
|
|||||||
working-directory: packages/desktop
|
working-directory: packages/desktop
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: --max-old-space-size=4096
|
NODE_OPTIONS: --max-old-space-size=4096
|
||||||
OPENCODE_VERSION: ${{ needs.version.outputs.version }}
|
|
||||||
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
|
OPENCODE_CHANNEL: ${{ (github.ref_name == 'beta' && 'beta') || 'prod' }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
|
SENTRY_ORG: ${{ vars.SENTRY_ORG }}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"packages/app": {
|
"packages/app": {
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@corvu/drawer": "catalog:",
|
"@corvu/drawer": "catalog:",
|
||||||
"@dnd-kit/abstract": "0.5.0",
|
"@dnd-kit/abstract": "0.5.0",
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
"name": "@opencode-ai/cli",
|
"name": "@opencode-ai/cli",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"bin": {
|
"bin": {
|
||||||
"lildax": "./bin/lildax.cjs",
|
"lildax": "./bin/lildax.cjs",
|
||||||
},
|
},
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
"packages/codemode": {
|
"packages/codemode": {
|
||||||
"name": "@opencode-ai/codemode",
|
"name": "@opencode-ai/codemode",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "8.15.0",
|
"acorn": "8.15.0",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
@@ -194,7 +194,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/core": {
|
"packages/console/core": {
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"@jsx-email/render": "1.1.1",
|
"@jsx-email/render": "1.1.1",
|
||||||
@@ -221,7 +221,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/function": {
|
"packages/console/function": {
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "3.0.82",
|
"@ai-sdk/anthropic": "3.0.82",
|
||||||
"@ai-sdk/openai": "3.0.48",
|
"@ai-sdk/openai": "3.0.48",
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/mail": {
|
"packages/console/mail": {
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
},
|
},
|
||||||
"packages/console/support": {
|
"packages/console/support": {
|
||||||
"name": "@opencode-ai/console-support",
|
"name": "@opencode-ai/console-support",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@opencode-ai/console-core": "workspace:*",
|
"@opencode-ai/console-core": "workspace:*",
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@opencode-ai/core",
|
"name": "@opencode-ai/core",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -381,7 +381,7 @@
|
|||||||
},
|
},
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zip.js/zip.js": "2.7.62",
|
"@zip.js/zip.js": "2.7.62",
|
||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
@@ -435,7 +435,7 @@
|
|||||||
},
|
},
|
||||||
"packages/effect-drizzle-sqlite": {
|
"packages/effect-drizzle-sqlite": {
|
||||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"drizzle-orm": "catalog:",
|
"drizzle-orm": "catalog:",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
@@ -449,7 +449,7 @@
|
|||||||
},
|
},
|
||||||
"packages/effect-sqlite-node": {
|
"packages/effect-sqlite-node": {
|
||||||
"name": "@opencode-ai/effect-sqlite-node",
|
"name": "@opencode-ai/effect-sqlite-node",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -461,7 +461,7 @@
|
|||||||
},
|
},
|
||||||
"packages/enterprise": {
|
"packages/enterprise": {
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hono/standard-validator": "catalog:",
|
"@hono/standard-validator": "catalog:",
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
@@ -493,7 +493,7 @@
|
|||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
@@ -509,7 +509,7 @@
|
|||||||
},
|
},
|
||||||
"packages/http-recorder": {
|
"packages/http-recorder": {
|
||||||
"name": "@opencode-ai/http-recorder",
|
"name": "@opencode-ai/http-recorder",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@effect/platform-node": "4.0.0-beta.83",
|
"@effect/platform-node": "4.0.0-beta.83",
|
||||||
"@effect/platform-node-shared": "4.0.0-beta.83",
|
"@effect/platform-node-shared": "4.0.0-beta.83",
|
||||||
@@ -540,7 +540,7 @@
|
|||||||
},
|
},
|
||||||
"packages/llm": {
|
"packages/llm": {
|
||||||
"name": "@opencode-ai/llm",
|
"name": "@opencode-ai/llm",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
"@smithy/eventstream-codec": "4.2.14",
|
"@smithy/eventstream-codec": "4.2.14",
|
||||||
@@ -559,7 +559,7 @@
|
|||||||
},
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
@@ -690,7 +690,7 @@
|
|||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/provider": "3.0.8",
|
"@ai-sdk/provider": "3.0.8",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
@@ -766,7 +766,7 @@
|
|||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-spawn": "catalog:",
|
"cross-spawn": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -781,7 +781,7 @@
|
|||||||
},
|
},
|
||||||
"packages/server": {
|
"packages/server": {
|
||||||
"name": "@opencode-ai/server",
|
"name": "@opencode-ai/server",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
"@opencode-ai/protocol": "workspace:*",
|
"@opencode-ai/protocol": "workspace:*",
|
||||||
@@ -796,7 +796,7 @@
|
|||||||
},
|
},
|
||||||
"packages/session-ui": {
|
"packages/session-ui": {
|
||||||
"name": "@opencode-ai/session-ui",
|
"name": "@opencode-ai/session-ui",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
|
"@opencode-ai/client": "file:../app/vendor/opencode-ai-client-1.17.13-v2.tgz",
|
||||||
@@ -836,7 +836,7 @@
|
|||||||
},
|
},
|
||||||
"packages/slack": {
|
"packages/slack": {
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@slack/bolt": "^3.17.1",
|
"@slack/bolt": "^3.17.1",
|
||||||
@@ -849,7 +849,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/app": {
|
"packages/stats/app": {
|
||||||
"name": "@opencode-ai/stats-app",
|
"name": "@opencode-ai/stats-app",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
@@ -883,7 +883,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/core": {
|
"packages/stats/core": {
|
||||||
"name": "@opencode-ai/stats-core",
|
"name": "@opencode-ai/stats-core",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-athena": "3.933.0",
|
"@aws-sdk/client-athena": "3.933.0",
|
||||||
"@planetscale/database": "1.19.0",
|
"@planetscale/database": "1.19.0",
|
||||||
@@ -902,7 +902,7 @@
|
|||||||
},
|
},
|
||||||
"packages/stats/server": {
|
"packages/stats/server": {
|
||||||
"name": "@opencode-ai/stats-server",
|
"name": "@opencode-ai/stats-server",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-firehose": "3.933.0",
|
"@aws-sdk/client-firehose": "3.933.0",
|
||||||
"@effect/platform-node": "catalog:",
|
"@effect/platform-node": "catalog:",
|
||||||
@@ -944,7 +944,7 @@
|
|||||||
},
|
},
|
||||||
"packages/tui": {
|
"packages/tui": {
|
||||||
"name": "@opencode-ai/tui",
|
"name": "@opencode-ai/tui",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/core": "workspace:*",
|
"@opencode-ai/core": "workspace:*",
|
||||||
"@opencode-ai/plugin": "workspace:*",
|
"@opencode-ai/plugin": "workspace:*",
|
||||||
@@ -971,7 +971,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@pierre/diffs": "catalog:",
|
"@pierre/diffs": "catalog:",
|
||||||
@@ -1022,7 +1022,7 @@
|
|||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
@@ -1078,7 +1078,6 @@
|
|||||||
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
"@ai-sdk/google@3.0.73": "patches/@ai-sdk%2Fgoogle@3.0.73.patch",
|
||||||
"pacote@21.5.0": "patches/pacote@21.5.0.patch",
|
"pacote@21.5.0": "patches/pacote@21.5.0.patch",
|
||||||
"@dnd-kit/dom@0.5.0": "patches/@dnd-kit%2Fdom@0.5.0.patch",
|
"@dnd-kit/dom@0.5.0": "patches/@dnd-kit%2Fdom@0.5.0.patch",
|
||||||
"@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch",
|
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@opentui/core": "catalog:",
|
"@opentui/core": "catalog:",
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"nodeModules": {
|
"nodeModules": {
|
||||||
"x86_64-linux": "sha256-uduwrM143NDSc+tXsi4lVVfoMll2a3BDHRUjuO7GB68=",
|
"x86_64-linux": "sha256-GRjnvvyj37H36RqiCB7dz5ALAEwvw16izwuk1wsHEpU=",
|
||||||
"aarch64-linux": "sha256-6DUda78XdXY6DP86lIUkweSjys3iG4Y4mo1PiaNuXbg=",
|
"aarch64-linux": "sha256-0OIn1o6dpqIQ5XgIMzpenMCMqsYzraaYVJk+te5eINU=",
|
||||||
"aarch64-darwin": "sha256-AkJwfLULLZVwwz+XU1QcFUZoIS7oVPCn+n/MXEaxrqE=",
|
"aarch64-darwin": "sha256-sQSQcuox78d8wT1lsKYHqVBl11NusiszQ+gu2XYXZi8=",
|
||||||
"x86_64-darwin": "sha256-hAxKGdiITTxQ2uujQt6prNjo3NxGAMMeo+9HlMWK6GU="
|
"x86_64-darwin": "sha256-SINkhMRd4oM1zABSs1Uf3OAzxJ1lgcycl1U4fmi+baY="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -158,7 +158,6 @@
|
|||||||
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
|
"@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
|
||||||
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
"@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
|
||||||
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
|
"effect@4.0.0-beta.83": "patches/effect@4.0.0-beta.83.patch",
|
||||||
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch",
|
"@tanstack/virtual-core@3.17.3": "patches/@tanstack%2Fvirtual-core@3.17.3.patch"
|
||||||
"@ai-sdk/openai-compatible@2.0.41": "patches/@ai-sdk%2Fopenai-compatible@2.0.41.patch"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,7 @@
|
|||||||
- NEVER hardcode user-visible English strings in production code. ALWAYS use an i18n key for visible copy, placeholders, accessible labels, tooltips, menus, dialogs, toasts, empty states, and displayed errors.
|
- NEVER hardcode user-visible English strings in production code. ALWAYS use an i18n key for visible copy, placeholders, accessible labels, tooltips, menus, dialogs, toasts, empty states, and displayed errors.
|
||||||
- When migrating existing copy to i18n, preserve the English text byte-for-byte unless the task explicitly requests a copy change.
|
- When migrating existing copy to i18n, preserve the English text byte-for-byte unless the task explicitly requests a copy change.
|
||||||
- NEVER change existing English text or English keys to facilitate translation. English is intentional, designer-written source copy; adapt locale-specific translations and i18n mechanics around it.
|
- NEVER change existing English text or English keys to facilitate translation. English is intentional, designer-written source copy; adapt locale-specific translations and i18n mechanics around it.
|
||||||
- Keep locale complexity behind the shared typed i18n APIs. Feature and component code should use `language.t(...)` for ordinary copy and `language.plural(baseKey, count, params)` for count-sensitive copy. It must not inspect the locale, call `Intl.PluralRules`, construct or select plural-category keys such as `.one` or `.other`, or branch on locale-specific grammar.
|
|
||||||
- Prefer complete translated phrases. Do not concatenate grammatical fragments or make call sites assemble sentences. Keep placeholders to irreducible dynamic values such as names, paths, and counts.
|
|
||||||
- If a translation cannot be expressed by the current API, deepen the shared language/UI i18n module so one typed call owns locale selection, plural resolution, fallback, and interpolation. Do not leak that machinery into product code.
|
|
||||||
- Do not translate from model knowledge alone. Verify terminology and grammar with Unicode CLDR locale/plural data, Microsoft Localization Style Guides and terminology, Apple localization/style guidance and localized platform UI, Mozilla localization style guides, Mozilla Pontoon, and the Firefox localization corpus at `github.com/mozilla-l10n/firefox-l10n`.
|
- Do not translate from model knowledge alone. Verify terminology and grammar with Unicode CLDR locale/plural data, Microsoft Localization Style Guides and terminology, Apple localization/style guidance and localized platform UI, Mozilla localization style guides, Mozilla Pontoon, and the Firefox localization corpus at `github.com/mozilla-l10n/firefox-l10n`.
|
||||||
- For developer-facing terminology, prefer the words already used by the target language's developer community over literal dictionary translations. Cross-check maintained localized developer products such as Firefox, KDE, and VS Code; use at least two independent corpora when they are available. If established practice keeps an English loanword or acronym, keep it rather than inventing a translation.
|
|
||||||
- Translate complete UI phrases in context. A glossary hit is evidence, not permission to translate word-by-word. Check terse labels such as session, prompt, agent, model, fork, shell, terminal, workspace, and worktree in the same grammatical role before choosing a term.
|
|
||||||
- Before a locale is ready, audit recurring concepts for one consistent translation and review every value that still equals English. Classify retained English as a product name, provider/tool name, URL, code token, keyboard legend, acronym, asset name, or established borrowing; translate unexplained leftovers.
|
|
||||||
- In translation review notes, name the corpora used and call out uncertain or region-specific terminology so native speakers can focus review where it matters.
|
|
||||||
- Also use the relevant language authority or official dictionary for the locale (for example RAE/Fundéu, FranceTerme, Duden, TDK, Kotus/Kielitoimiston sanakirja, Språkrådet/Bokmålsordboka, Rada Języka Polskiego/PWN, the Russian and Arabic language academies, the Ukrainian Orthography, Taiwan MOE dictionaries, or the Royal Society of Thailand). Treat the English dictionary as the semantic source of truth and preserve placeholders, code identifiers, product names, and keyboard labels.
|
- Also use the relevant language authority or official dictionary for the locale (for example RAE/Fundéu, FranceTerme, Duden, TDK, Kotus/Kielitoimiston sanakirja, Språkrådet/Bokmålsordboka, Rada Języka Polskiego/PWN, the Russian and Arabic language academies, the Ukrainian Orthography, Taiwan MOE dictionaries, or the Royal Society of Thailand). Treat the English dictionary as the semantic source of truth and preserve placeholders, code identifiers, product names, and keyboard labels.
|
||||||
|
|
||||||
## Tool Calling
|
## Tool Calling
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
import { useLanguage } from "@/context/language"
|
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
import { Dialog } from "@opencode-ai/ui/dialog"
|
import { Dialog } from "@opencode-ai/ui/dialog"
|
||||||
@@ -15,7 +14,6 @@ export type DialogGoUpsellProps = {
|
|||||||
|
|
||||||
export function DialogUsageExceeded(props: DialogGoUpsellProps) {
|
export function DialogUsageExceeded(props: DialogGoUpsellProps) {
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const language = useLanguage()
|
|
||||||
const platform = usePlatform()
|
const platform = usePlatform()
|
||||||
|
|
||||||
const runAction = () => {
|
const runAction = () => {
|
||||||
@@ -34,7 +32,7 @@ export function DialogUsageExceeded(props: DialogGoUpsellProps) {
|
|||||||
<div class="flex flex-col gap-4 pl-6 pr-2.5 pb-3">
|
<div class="flex flex-col gap-4 pl-6 pr-2.5 pb-3">
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<Button variant="ghost" size="large" onClick={dismiss}>
|
<Button variant="ghost" size="large" onClick={dismiss}>
|
||||||
{language.t("dialog.usageExceeded.dontShowAgain")}
|
Don't show again
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" size="large" onClick={runAction}>
|
<Button variant="primary" size="large" onClick={runAction}>
|
||||||
{props.actionLabel}
|
{props.actionLabel}
|
||||||
|
|||||||
@@ -5,15 +5,12 @@ import { checksum } from "@opencode-ai/core/util/encode"
|
|||||||
import { findLast } from "@opencode-ai/core/util/array"
|
import { findLast } from "@opencode-ai/core/util/array"
|
||||||
import { same } from "@/utils/same"
|
import { same } from "@/utils/same"
|
||||||
import { Icon } from "@opencode-ai/ui/icon"
|
import { Icon } from "@opencode-ai/ui/icon"
|
||||||
import { Button } from "@opencode-ai/ui/button"
|
|
||||||
import { Accordion } from "@opencode-ai/ui/accordion"
|
import { Accordion } from "@opencode-ai/ui/accordion"
|
||||||
import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
|
import { StickyAccordionHeader } from "@opencode-ai/ui/sticky-accordion-header"
|
||||||
import { File } from "@opencode-ai/session-ui/file"
|
import { File } from "@opencode-ai/session-ui/file"
|
||||||
import { Markdown } from "@opencode-ai/session-ui/markdown"
|
import { Markdown } from "@opencode-ai/session-ui/markdown"
|
||||||
import { ScrollView } from "@opencode-ai/ui/scroll-view"
|
import { ScrollView } from "@opencode-ai/ui/scroll-view"
|
||||||
import type { Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client"
|
import type { Message, Part, UserMessage } from "@opencode-ai/sdk/v2/client"
|
||||||
import { showToast } from "@/utils/toast"
|
|
||||||
import { downloadSessionExport, fetchSessionExport, sessionExportFilename } from "@/utils/session-export"
|
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useProviders } from "@/hooks/use-providers"
|
import { useProviders } from "@/hooks/use-providers"
|
||||||
import { useSDK } from "@/context/sdk"
|
import { useSDK } from "@/context/sdk"
|
||||||
@@ -123,8 +120,7 @@ export function SessionContextTab() {
|
|||||||
() => {
|
() => {
|
||||||
const revert = info()?.revert?.messageID
|
const revert = info()?.revert?.messageID
|
||||||
if (!revert) return userMessages()
|
if (!revert) return userMessages()
|
||||||
const boundary = userMessages().findIndex((message) => message.id === revert)
|
return userMessages().filter((m) => m.id < revert)
|
||||||
return boundary < 0 ? userMessages() : userMessages().slice(0, boundary)
|
|
||||||
},
|
},
|
||||||
emptyUserMessages,
|
emptyUserMessages,
|
||||||
{ equals: same },
|
{ equals: same },
|
||||||
@@ -224,31 +220,6 @@ export function SessionContextTab() {
|
|||||||
{ label: "context.stats.lastActivity", value: () => formatter().time(ctx()?.message.time.created) },
|
{ label: "context.stats.lastActivity", value: () => formatter().time(ctx()?.message.time.created) },
|
||||||
] satisfies { label: string; value: () => JSX.Element }[]
|
] satisfies { label: string; value: () => JSX.Element }[]
|
||||||
|
|
||||||
const exportSession = async () => {
|
|
||||||
const sessionID = params.id
|
|
||||||
if (!sessionID) return
|
|
||||||
try {
|
|
||||||
const data = await fetchSessionExport({
|
|
||||||
sessionID,
|
|
||||||
client: sdk().client,
|
|
||||||
})
|
|
||||||
const filename = sessionExportFilename(data.info)
|
|
||||||
downloadSessionExport(filename, data)
|
|
||||||
showToast({
|
|
||||||
variant: "success",
|
|
||||||
icon: "circle-check",
|
|
||||||
title: language.t("toast.session.export.success.title"),
|
|
||||||
description: language.t("toast.session.export.success.description", { filename }),
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: language.t("toast.session.export.failed.title"),
|
|
||||||
description: err instanceof Error ? err.message : language.t("toast.session.export.failed.description"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let scroll: HTMLDivElement | undefined
|
let scroll: HTMLDivElement | undefined
|
||||||
let frame: number | undefined
|
let frame: number | undefined
|
||||||
let pending: { x: number; y: number } | undefined
|
let pending: { x: number; y: number } | undefined
|
||||||
@@ -357,18 +328,7 @@ export function SessionContextTab() {
|
|||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex items-center justify-between">
|
<div class="text-12-regular text-text-weak">{language.t("context.rawMessages.title")}</div>
|
||||||
<div class="text-12-regular text-text-weak">{language.t("context.rawMessages.title")}</div>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="ghost"
|
|
||||||
class="gap-1.5 px-2 text-text-weak hover:text-text-base"
|
|
||||||
onClick={exportSession}
|
|
||||||
>
|
|
||||||
<Icon name="download" size="small" />
|
|
||||||
<span>{language.t("context.export.session")}</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<Accordion multiple>
|
<Accordion multiple>
|
||||||
<For each={messages()}>
|
<For each={messages()}>
|
||||||
{(message) => (
|
{(message) => (
|
||||||
|
|||||||
@@ -628,7 +628,7 @@ function TitlebarUpdateIconButton(props: { state: TitlebarUpdatePillState }) {
|
|||||||
aria-label={props.state.ariaLabel}
|
aria-label={props.state.ariaLabel}
|
||||||
>
|
>
|
||||||
<span class="shrink-0 ml-[8px] mr-px text-[11px] text-v2-text-text-accent [font-weight:530] opacity-0 translate-x-2 motion-safe:transition-all duration-150 ease-out group-hover:opacity-100 group-hover:translate-x-0 group-focus-within:opacity-100 group-focus-within:translate-x-0 motion-reduce:translate-x-0">
|
<span class="shrink-0 ml-[8px] mr-px text-[11px] text-v2-text-text-accent [font-weight:530] opacity-0 translate-x-2 motion-safe:transition-all duration-150 ease-out group-hover:opacity-100 group-hover:translate-x-0 group-focus-within:opacity-100 group-focus-within:translate-x-0 motion-reduce:translate-x-0">
|
||||||
{props.state.label}
|
Update
|
||||||
</span>
|
</span>
|
||||||
<span class="flex size-5 shrink-0 items-center justify-center">
|
<span class="flex size-5 shrink-0 items-center justify-center">
|
||||||
<Show
|
<Show
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ const rootSession = (input: { id: string; parentID?: string; archived?: number }
|
|||||||
},
|
},
|
||||||
}) as Session
|
}) as Session
|
||||||
|
|
||||||
const userMessage = (id: string, sessionID: string, created = 1) =>
|
const userMessage = (id: string, sessionID: string) =>
|
||||||
({
|
({
|
||||||
id,
|
id,
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created },
|
time: { created: 1 },
|
||||||
agent: "assistant",
|
agent: "assistant",
|
||||||
model: { providerID: "openai", modelID: "gpt" },
|
model: { providerID: "openai", modelID: "gpt" },
|
||||||
}) as Message
|
}) as Message
|
||||||
@@ -370,13 +370,13 @@ describe("applyDirectoryEvent", () => {
|
|||||||
const sessionID = "ses_1"
|
const sessionID = "ses_1"
|
||||||
const [store, setStore] = createStore(
|
const [store, setStore] = createStore(
|
||||||
baseState({
|
baseState({
|
||||||
message: { [sessionID]: [userMessage("msg_z", sessionID, 1), userMessage("msg_b", sessionID, 3)] },
|
message: { [sessionID]: [userMessage("msg_1", sessionID), userMessage("msg_3", sessionID)] },
|
||||||
part: { msg_a: [textPart("prt_1", sessionID, "msg_a")] },
|
part: { msg_2: [textPart("prt_1", sessionID, "msg_2")] },
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
applyDirectoryEvent({
|
applyDirectoryEvent({
|
||||||
event: { type: "message.updated", properties: { info: userMessage("msg_a", sessionID, 2) } },
|
event: { type: "message.updated", properties: { info: userMessage("msg_2", sessionID) } },
|
||||||
store,
|
store,
|
||||||
setStore,
|
setStore,
|
||||||
push() {},
|
push() {},
|
||||||
@@ -384,14 +384,14 @@ describe("applyDirectoryEvent", () => {
|
|||||||
loadLsp() {},
|
loadLsp() {},
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(store.message[sessionID]?.map((x) => x.id)).toEqual(["msg_z", "msg_a", "msg_b"])
|
expect(store.message[sessionID]?.map((x) => x.id)).toEqual(["msg_1", "msg_2", "msg_3"])
|
||||||
|
|
||||||
applyDirectoryEvent({
|
applyDirectoryEvent({
|
||||||
event: {
|
event: {
|
||||||
type: "message.updated",
|
type: "message.updated",
|
||||||
properties: {
|
properties: {
|
||||||
info: {
|
info: {
|
||||||
...userMessage("msg_a", sessionID, 2),
|
...userMessage("msg_2", sessionID),
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
} as Message,
|
} as Message,
|
||||||
},
|
},
|
||||||
@@ -403,10 +403,10 @@ describe("applyDirectoryEvent", () => {
|
|||||||
loadLsp() {},
|
loadLsp() {},
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(store.message[sessionID]?.find((x) => x.id === "msg_a")?.role).toBe("assistant")
|
expect(store.message[sessionID]?.find((x) => x.id === "msg_2")?.role).toBe("assistant")
|
||||||
|
|
||||||
applyDirectoryEvent({
|
applyDirectoryEvent({
|
||||||
event: { type: "message.removed", properties: { sessionID, messageID: "msg_a" } },
|
event: { type: "message.removed", properties: { sessionID, messageID: "msg_2" } },
|
||||||
store,
|
store,
|
||||||
setStore,
|
setStore,
|
||||||
push() {},
|
push() {},
|
||||||
@@ -414,8 +414,8 @@ describe("applyDirectoryEvent", () => {
|
|||||||
loadLsp() {},
|
loadLsp() {},
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(store.message[sessionID]?.map((x) => x.id)).toEqual(["msg_z", "msg_b"])
|
expect(store.message[sessionID]?.map((x) => x.id)).toEqual(["msg_1", "msg_3"])
|
||||||
expect(store.part.msg_a).toBeUndefined()
|
expect(store.part.msg_2).toBeUndefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("upserts and prunes message parts", () => {
|
test("upserts and prunes message parts", () => {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import type { State, VcsCache } from "./types"
|
|||||||
import { trimSessions } from "./session-trim"
|
import { trimSessions } from "./session-trim"
|
||||||
import { dropSessionCaches } from "./session-cache"
|
import { dropSessionCaches } from "./session-cache"
|
||||||
import { diffs as list, message as clean } from "@/utils/diffs"
|
import { diffs as list, message as clean } from "@/utils/diffs"
|
||||||
import { messageKey } from "@/utils/session-message"
|
|
||||||
|
|
||||||
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
||||||
const SESSION_CONTENT_EVENTS = new Set([
|
const SESSION_CONTENT_EVENTS = new Set([
|
||||||
@@ -276,7 +275,7 @@ export function applyDirectoryEvent(input: {
|
|||||||
input.setStore("message", info.sessionID, [info])
|
input.setStore("message", info.sessionID, [info])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
const result = Binary.search(messages, messageKey(info), messageKey)
|
const result = Binary.search(messages, info.id, (m) => m.id)
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
input.setStore("message", info.sessionID, result.index, reconcile(info))
|
input.setStore("message", info.sessionID, result.index, reconcile(info))
|
||||||
break
|
break
|
||||||
@@ -296,8 +295,8 @@ export function applyDirectoryEvent(input: {
|
|||||||
produce((draft) => {
|
produce((draft) => {
|
||||||
const messages = draft.message[props.sessionID]
|
const messages = draft.message[props.sessionID]
|
||||||
if (messages) {
|
if (messages) {
|
||||||
const index = messages.findIndex((message) => message.id === props.messageID)
|
const result = Binary.search(messages, props.messageID, (m) => m.id)
|
||||||
if (index >= 0) messages.splice(index, 1)
|
if (result.found) messages.splice(result.index, 1)
|
||||||
}
|
}
|
||||||
const parts = draft.part[props.messageID]
|
const parts = draft.part[props.messageID]
|
||||||
if (parts) {
|
if (parts) {
|
||||||
@@ -323,7 +322,7 @@ export function applyDirectoryEvent(input: {
|
|||||||
input.setStore("part", part.messageID, [part])
|
input.setStore("part", part.messageID, [part])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
const result = Binary.search(parts, part.id, (item) => item.id)
|
const result = Binary.search(parts, part.id, (p) => p.id)
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
input.setStore("part", part.messageID, result.index, reconcile(part))
|
input.setStore("part", part.messageID, result.index, reconcile(part))
|
||||||
break
|
break
|
||||||
@@ -346,13 +345,13 @@ export function applyDirectoryEvent(input: {
|
|||||||
)
|
)
|
||||||
const parts = input.store.part[props.messageID]
|
const parts = input.store.part[props.messageID]
|
||||||
if (!parts) break
|
if (!parts) break
|
||||||
const result = Binary.search(parts, props.partID, (part) => part.id)
|
const result = Binary.search(parts, props.partID, (p) => p.id)
|
||||||
if (result.found) {
|
if (result.found) {
|
||||||
input.setStore(
|
input.setStore(
|
||||||
produce((draft) => {
|
produce((draft) => {
|
||||||
const list = draft.part[props.messageID]
|
const list = draft.part[props.messageID]
|
||||||
if (!list) return
|
if (!list) return
|
||||||
const next = Binary.search(list, props.partID, (part) => part.id)
|
const next = Binary.search(list, props.partID, (p) => p.id)
|
||||||
if (!next.found) return
|
if (!next.found) return
|
||||||
list.splice(next.index, 1)
|
list.splice(next.index, 1)
|
||||||
if (list.length === 0) delete draft.part[props.messageID]
|
if (list.length === 0) delete draft.part[props.messageID]
|
||||||
@@ -365,7 +364,7 @@ export function applyDirectoryEvent(input: {
|
|||||||
const props = event.properties as { messageID: string; partID: string; field: string; delta: string }
|
const props = event.properties as { messageID: string; partID: string; field: string; delta: string }
|
||||||
const parts = input.store.part[props.messageID]
|
const parts = input.store.part[props.messageID]
|
||||||
if (!parts) break
|
if (!parts) break
|
||||||
const result = Binary.search(parts, props.partID, (part) => part.id)
|
const result = Binary.search(parts, props.partID, (p) => p.id)
|
||||||
if (!result.found) break
|
if (!result.found) break
|
||||||
const field = props.field as keyof (typeof parts)[number]
|
const field = props.field as keyof (typeof parts)[number]
|
||||||
const current = parts[result.index]?.[field]
|
const current = parts[result.index]?.[field]
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ import { dict as en } from "@/i18n/en"
|
|||||||
import { dict as uiEn } from "@opencode-ai/ui/i18n/en"
|
import { dict as uiEn } from "@opencode-ai/ui/i18n/en"
|
||||||
import {
|
import {
|
||||||
createDesktopNativeBundle,
|
createDesktopNativeBundle,
|
||||||
detectDesktopNativeLocale,
|
|
||||||
DESKTOP_NATIVE_ENGLISH,
|
DESKTOP_NATIVE_ENGLISH,
|
||||||
DESKTOP_NATIVE_LABELS,
|
|
||||||
DESKTOP_NATIVE_LOCALES,
|
DESKTOP_NATIVE_LOCALES,
|
||||||
DESKTOP_NATIVE_LOCALE_TAGS,
|
|
||||||
type DesktopNativeBundle,
|
type DesktopNativeBundle,
|
||||||
type DesktopNativeLocale,
|
type DesktopNativeLocale,
|
||||||
} from "@/i18n/desktop-native"
|
} from "@/i18n/desktop-native"
|
||||||
@@ -20,7 +17,7 @@ import {
|
|||||||
export type Locale = DesktopNativeLocale
|
export type Locale = DesktopNativeLocale
|
||||||
export type Direction = "ltr" | "rtl"
|
export type Direction = "ltr" | "rtl"
|
||||||
|
|
||||||
const RTL_LOCALES: ReadonlySet<Locale> = new Set(["ar", "ur", "pa", "fa", "dv"])
|
const RTL_LOCALES: ReadonlySet<Locale> = new Set(["ar", "ur", "pa"])
|
||||||
|
|
||||||
function localeDirection(locale: Locale): Direction {
|
function localeDirection(locale: Locale): Direction {
|
||||||
return RTL_LOCALES.has(locale) ? "rtl" : "ltr"
|
return RTL_LOCALES.has(locale) ? "rtl" : "ltr"
|
||||||
@@ -41,7 +38,70 @@ function cookie(locale: Locale) {
|
|||||||
|
|
||||||
const LOCALES: readonly Locale[] = DESKTOP_NATIVE_LOCALES
|
const LOCALES: readonly Locale[] = DESKTOP_NATIVE_LOCALES
|
||||||
|
|
||||||
const INTL = DESKTOP_NATIVE_LOCALE_TAGS
|
const INTL: Record<Locale, string> = {
|
||||||
|
en: "en",
|
||||||
|
zh: "zh-Hans",
|
||||||
|
zht: "zh-Hant",
|
||||||
|
ko: "ko",
|
||||||
|
de: "de",
|
||||||
|
es: "es",
|
||||||
|
fr: "fr",
|
||||||
|
da: "da",
|
||||||
|
ja: "ja",
|
||||||
|
pl: "pl",
|
||||||
|
ru: "ru",
|
||||||
|
uk: "uk",
|
||||||
|
ar: "ar",
|
||||||
|
no: "nb-NO",
|
||||||
|
br: "pt-BR",
|
||||||
|
th: "th",
|
||||||
|
bs: "bs",
|
||||||
|
tr: "tr",
|
||||||
|
hi: "hi-IN",
|
||||||
|
nl: "nl-NL",
|
||||||
|
id: "id-ID",
|
||||||
|
vi: "vi-VN",
|
||||||
|
it: "it-IT",
|
||||||
|
ur: "ur-PK",
|
||||||
|
pa: "pa-Arab-PK",
|
||||||
|
az: "az-Latn-AZ",
|
||||||
|
fi: "fi-FI",
|
||||||
|
sv: "sv-SE",
|
||||||
|
}
|
||||||
|
|
||||||
|
const LABEL_KEY: Partial<Record<Locale, keyof Dictionary>> = {
|
||||||
|
en: "language.en",
|
||||||
|
zh: "language.zh",
|
||||||
|
zht: "language.zht",
|
||||||
|
ko: "language.ko",
|
||||||
|
de: "language.de",
|
||||||
|
es: "language.es",
|
||||||
|
fr: "language.fr",
|
||||||
|
da: "language.da",
|
||||||
|
ja: "language.ja",
|
||||||
|
pl: "language.pl",
|
||||||
|
ru: "language.ru",
|
||||||
|
uk: "language.uk",
|
||||||
|
ar: "language.ar",
|
||||||
|
no: "language.no",
|
||||||
|
br: "language.br",
|
||||||
|
th: "language.th",
|
||||||
|
bs: "language.bs",
|
||||||
|
tr: "language.tr",
|
||||||
|
}
|
||||||
|
|
||||||
|
const LABEL: Partial<Record<Locale, string>> = {
|
||||||
|
hi: "हिन्दी",
|
||||||
|
nl: "Nederlands",
|
||||||
|
id: "Bahasa Indonesia",
|
||||||
|
vi: "Tiếng Việt",
|
||||||
|
it: "Italiano",
|
||||||
|
ur: "اردو",
|
||||||
|
pa: "پنجابی",
|
||||||
|
az: "Azərbaycanca",
|
||||||
|
fi: "Suomi",
|
||||||
|
sv: "Svenska",
|
||||||
|
}
|
||||||
|
|
||||||
const base = i18n.flatten({ ...en, ...uiEn })
|
const base = i18n.flatten({ ...en, ...uiEn })
|
||||||
const dicts = new Map<Locale, Dictionary>([["en", base]])
|
const dicts = new Map<Locale, Dictionary>([["en", base]])
|
||||||
@@ -77,40 +137,6 @@ const loaders: Record<Exclude<Locale, "en">, () => Promise<Dictionary>> = {
|
|||||||
az: () => merge(import("@/i18n/az"), import("@opencode-ai/ui/i18n/az")),
|
az: () => merge(import("@/i18n/az"), import("@opencode-ai/ui/i18n/az")),
|
||||||
fi: () => merge(import("@/i18n/fi"), import("@opencode-ai/ui/i18n/fi")),
|
fi: () => merge(import("@/i18n/fi"), import("@opencode-ai/ui/i18n/fi")),
|
||||||
sv: () => merge(import("@/i18n/sv"), import("@opencode-ai/ui/i18n/sv")),
|
sv: () => merge(import("@/i18n/sv"), import("@opencode-ai/ui/i18n/sv")),
|
||||||
am: () => merge(import("@/i18n/am"), import("@opencode-ai/ui/i18n/am")),
|
|
||||||
bg: () => merge(import("@/i18n/bg"), import("@opencode-ai/ui/i18n/bg")),
|
|
||||||
bn: () => merge(import("@/i18n/bn"), import("@opencode-ai/ui/i18n/bn")),
|
|
||||||
ca: () => merge(import("@/i18n/ca"), import("@opencode-ai/ui/i18n/ca")),
|
|
||||||
cs: () => merge(import("@/i18n/cs"), import("@opencode-ai/ui/i18n/cs")),
|
|
||||||
dv: () => merge(import("@/i18n/dv"), import("@opencode-ai/ui/i18n/dv")),
|
|
||||||
dz: () => merge(import("@/i18n/dz"), import("@opencode-ai/ui/i18n/dz")),
|
|
||||||
el: () => merge(import("@/i18n/el"), import("@opencode-ai/ui/i18n/el")),
|
|
||||||
et: () => merge(import("@/i18n/et"), import("@opencode-ai/ui/i18n/et")),
|
|
||||||
fa: () => merge(import("@/i18n/fa"), import("@opencode-ai/ui/i18n/fa")),
|
|
||||||
fo: () => merge(import("@/i18n/fo"), import("@opencode-ai/ui/i18n/fo")),
|
|
||||||
hr: () => merge(import("@/i18n/hr"), import("@opencode-ai/ui/i18n/hr")),
|
|
||||||
hu: () => merge(import("@/i18n/hu"), import("@opencode-ai/ui/i18n/hu")),
|
|
||||||
hy: () => merge(import("@/i18n/hy"), import("@opencode-ai/ui/i18n/hy")),
|
|
||||||
is: () => merge(import("@/i18n/is"), import("@opencode-ai/ui/i18n/is")),
|
|
||||||
ka: () => merge(import("@/i18n/ka"), import("@opencode-ai/ui/i18n/ka")),
|
|
||||||
km: () => merge(import("@/i18n/km"), import("@opencode-ai/ui/i18n/km")),
|
|
||||||
lo: () => merge(import("@/i18n/lo"), import("@opencode-ai/ui/i18n/lo")),
|
|
||||||
lt: () => merge(import("@/i18n/lt"), import("@opencode-ai/ui/i18n/lt")),
|
|
||||||
lv: () => merge(import("@/i18n/lv"), import("@opencode-ai/ui/i18n/lv")),
|
|
||||||
mk: () => merge(import("@/i18n/mk"), import("@opencode-ai/ui/i18n/mk")),
|
|
||||||
mn: () => merge(import("@/i18n/mn"), import("@opencode-ai/ui/i18n/mn")),
|
|
||||||
ms: () => merge(import("@/i18n/ms"), import("@opencode-ai/ui/i18n/ms")),
|
|
||||||
my: () => merge(import("@/i18n/my"), import("@opencode-ai/ui/i18n/my")),
|
|
||||||
ne: () => merge(import("@/i18n/ne"), import("@opencode-ai/ui/i18n/ne")),
|
|
||||||
ro: () => merge(import("@/i18n/ro"), import("@opencode-ai/ui/i18n/ro")),
|
|
||||||
si: () => merge(import("@/i18n/si"), import("@opencode-ai/ui/i18n/si")),
|
|
||||||
sk: () => merge(import("@/i18n/sk"), import("@opencode-ai/ui/i18n/sk")),
|
|
||||||
sl: () => merge(import("@/i18n/sl"), import("@opencode-ai/ui/i18n/sl")),
|
|
||||||
sq: () => merge(import("@/i18n/sq"), import("@opencode-ai/ui/i18n/sq")),
|
|
||||||
sr: () => merge(import("@/i18n/sr"), import("@opencode-ai/ui/i18n/sr")),
|
|
||||||
tg: () => merge(import("@/i18n/tg"), import("@opencode-ai/ui/i18n/tg")),
|
|
||||||
tk: () => merge(import("@/i18n/tk"), import("@opencode-ai/ui/i18n/tk")),
|
|
||||||
uz: () => merge(import("@/i18n/uz"), import("@opencode-ai/ui/i18n/uz")),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadDict(locale: Locale) {
|
function loadDict(locale: Locale) {
|
||||||
@@ -128,9 +154,63 @@ export function loadLocaleDict(locale: Locale) {
|
|||||||
return loadDict(locale).then(() => undefined)
|
return loadDict(locale).then(() => undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const localeMatchers: Array<{ locale: Locale; match: (language: string) => boolean }> = [
|
||||||
|
{ locale: "en", match: (language) => language.startsWith("en") },
|
||||||
|
{
|
||||||
|
locale: "zht",
|
||||||
|
match: (language) =>
|
||||||
|
language.startsWith("zh") &&
|
||||||
|
(language.includes("hant") || language.includes("-tw") || language.includes("-hk") || language.includes("-mo")),
|
||||||
|
},
|
||||||
|
{ locale: "zh", match: (language) => language.startsWith("zh") },
|
||||||
|
{ locale: "ko", match: (language) => language.startsWith("ko") },
|
||||||
|
{ locale: "de", match: (language) => language.startsWith("de") },
|
||||||
|
{ locale: "es", match: (language) => language.startsWith("es") },
|
||||||
|
{ locale: "fr", match: (language) => language.startsWith("fr") },
|
||||||
|
{ locale: "da", match: (language) => language.startsWith("da") },
|
||||||
|
{ locale: "ja", match: (language) => language.startsWith("ja") },
|
||||||
|
{ locale: "pl", match: (language) => language.startsWith("pl") },
|
||||||
|
{ locale: "ru", match: (language) => language.startsWith("ru") },
|
||||||
|
{ locale: "uk", match: (language) => language.startsWith("uk") },
|
||||||
|
{ locale: "ar", match: (language) => language.startsWith("ar") },
|
||||||
|
{
|
||||||
|
locale: "no",
|
||||||
|
match: (language) => language.startsWith("no") || language.startsWith("nb") || language.startsWith("nn"),
|
||||||
|
},
|
||||||
|
{ locale: "br", match: (language) => language.startsWith("pt") },
|
||||||
|
{ locale: "th", match: (language) => language.startsWith("th") },
|
||||||
|
{ locale: "bs", match: (language) => language.startsWith("bs") },
|
||||||
|
{ locale: "tr", match: (language) => language.startsWith("tr") },
|
||||||
|
{ locale: "hi", match: (language) => language.startsWith("hi") },
|
||||||
|
{ locale: "nl", match: (language) => language.startsWith("nl") },
|
||||||
|
{ locale: "id", match: (language) => language.startsWith("id") },
|
||||||
|
{ locale: "vi", match: (language) => language.startsWith("vi") },
|
||||||
|
{ locale: "it", match: (language) => language.startsWith("it") },
|
||||||
|
{ locale: "ur", match: (language) => language.startsWith("ur") },
|
||||||
|
{
|
||||||
|
locale: "pa",
|
||||||
|
match: (language) => language.startsWith("pa") && (language.includes("arab") || language.includes("-pk")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
locale: "az",
|
||||||
|
match: (language) => language.startsWith("az") && !language.includes("arab") && !language.includes("cyrl"),
|
||||||
|
},
|
||||||
|
{ locale: "fi", match: (language) => language.startsWith("fi") },
|
||||||
|
{ locale: "sv", match: (language) => language.startsWith("sv") },
|
||||||
|
]
|
||||||
|
|
||||||
function detectLocale(): Locale {
|
function detectLocale(): Locale {
|
||||||
if (typeof navigator !== "object") return "en"
|
if (typeof navigator !== "object") return "en"
|
||||||
return detectDesktopNativeLocale(navigator.languages?.length ? navigator.languages : [navigator.language])
|
|
||||||
|
const languages = navigator.languages?.length ? navigator.languages : [navigator.language]
|
||||||
|
for (const language of languages) {
|
||||||
|
if (!language) continue
|
||||||
|
const normalized = language.toLowerCase()
|
||||||
|
const match = localeMatchers.find((entry) => entry.match(normalized))
|
||||||
|
if (match) return match.locale
|
||||||
|
}
|
||||||
|
|
||||||
|
return "en"
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeLocale(value: string): Locale {
|
export function normalizeLocale(value: string): Locale {
|
||||||
@@ -151,17 +231,7 @@ function readStoredLocale() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const warm = readStoredLocale() ?? detectLocale()
|
const warm = readStoredLocale() ?? detectLocale()
|
||||||
const initialLocale =
|
if (warm !== "en") void loadDict(warm)
|
||||||
warm === "en"
|
|
||||||
? Promise.resolve(warm)
|
|
||||||
: loadDict(warm).then(
|
|
||||||
() => warm,
|
|
||||||
() => "en" as const,
|
|
||||||
)
|
|
||||||
|
|
||||||
export function loadInitialLocale() {
|
|
||||||
return initialLocale
|
|
||||||
}
|
|
||||||
|
|
||||||
export const { use: useLanguage, provider: LanguageProvider } = createSimpleContext({
|
export const { use: useLanguage, provider: LanguageProvider } = createSimpleContext({
|
||||||
name: "Language",
|
name: "Language",
|
||||||
@@ -202,12 +272,16 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
|
|||||||
return i18n.resolveTemplate(current[candidate] ?? current[fallback] ?? fallback, { ...params, count })
|
return i18n.resolveTemplate(current[candidate] ?? current[fallback] ?? fallback, { ...params, count })
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = (value: Locale) => DESKTOP_NATIVE_LABELS[value]
|
const label = (value: Locale) => {
|
||||||
|
const key = LABEL_KEY[value]
|
||||||
|
if (key) return t(key)
|
||||||
|
return LABEL[value] ?? value
|
||||||
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (typeof document !== "object") return
|
if (typeof document !== "object") return
|
||||||
const value = locale()
|
const value = locale()
|
||||||
document.documentElement.lang = intl()
|
document.documentElement.lang = value
|
||||||
document.documentElement.dir = direction()
|
document.documentElement.dir = direction()
|
||||||
document.cookie = cookie(value)
|
document.cookie = cookie(value)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ describe("server session", () => {
|
|||||||
|
|
||||||
expect(requests).toEqual([{ sessionID: "root", limit: 20, order: "desc" }])
|
expect(requests).toEqual([{ sessionID: "root", limit: 20, order: "desc" }])
|
||||||
expect(store.data.session_message.root.map((message) => message.id)).toEqual([user.id, assistant.id])
|
expect(store.data.session_message.root.map((message) => message.id)).toEqual([user.id, assistant.id])
|
||||||
expect(store.data.message.root.map((message) => message.id)).toEqual([user.id, assistant.id])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("extends a current page to include the user for split assistant turns", async () => {
|
test("extends a current page to include the user for split assistant turns", async () => {
|
||||||
@@ -1498,7 +1497,7 @@ describe("server session", () => {
|
|||||||
|
|
||||||
await store.sync("child", { force: true })
|
await store.sync("child", { force: true })
|
||||||
|
|
||||||
expect(store.data.message.child).toEqual([older, boundary])
|
expect(store.data.message.child).toEqual([boundary, older])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("preserves a part update for a message being loaded from history", async () => {
|
test("preserves a part update for a message being loaded from history", async () => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { message as cleanMessage } from "@/utils/diffs"
|
|||||||
import { sessionNotFoundError } from "@/utils/server-errors"
|
import { sessionNotFoundError } from "@/utils/server-errors"
|
||||||
import { rootSession } from "@/utils/session-route"
|
import { rootSession } from "@/utils/session-route"
|
||||||
import { normalizeSessionInfo } from "@/utils/session"
|
import { normalizeSessionInfo } from "@/utils/session"
|
||||||
import { compareMessages, messageKey, normalizeSessionMessages } from "@/utils/session-message"
|
import { normalizeSessionMessages } from "@/utils/session-message"
|
||||||
import { dropSessionCaches, pickSessionCacheEvictions, SESSION_CACHE_LIMIT } from "./global-sync/session-cache"
|
import { dropSessionCaches, pickSessionCacheEvictions, SESSION_CACHE_LIMIT } from "./global-sync/session-cache"
|
||||||
import { createV2SessionReducer, type V2SessionReduction } from "./server-session-v2-reducer"
|
import { createV2SessionReducer, type V2SessionReduction } from "./server-session-v2-reducer"
|
||||||
import type { ServerApi } from "@/utils/server"
|
import type { ServerApi } from "@/utils/server"
|
||||||
@@ -26,6 +26,7 @@ import type { ServerApi } from "@/utils/server"
|
|||||||
type MessageApi = ServerApi["message"]
|
type MessageApi = ServerApi["message"]
|
||||||
|
|
||||||
const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0)
|
const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0)
|
||||||
|
const cmpMessage = (a: Message, b: Message) => a.time.created - b.time.created || cmp(a.id, b.id)
|
||||||
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
||||||
const initialMessagePageSize = 20
|
const initialMessagePageSize = 20
|
||||||
const historyMessagePageSize = 200
|
const historyMessagePageSize = 200
|
||||||
@@ -63,7 +64,7 @@ type MessagePage = {
|
|||||||
function legacyMessageSource(items: { info: Message; parts: Part[] }[]): SessionMessageInfo[] {
|
function legacyMessageSource(items: { info: Message; parts: Part[] }[]): SessionMessageInfo[] {
|
||||||
return items
|
return items
|
||||||
.slice()
|
.slice()
|
||||||
.sort((a, b) => compareMessages(a.info, b.info))
|
.sort((a, b) => cmp(a.info.id, b.info.id))
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (item.info.role === "user") {
|
if (item.info.role === "user") {
|
||||||
return {
|
return {
|
||||||
@@ -110,16 +111,17 @@ function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[]) {
|
|||||||
const part = new Map(page.part.map((item) => [item.id, item.part]))
|
const part = new Map(page.part.map((item) => [item.id, item.part]))
|
||||||
const observed: { messageID: string; parts: Part[] }[] = []
|
const observed: { messageID: string; parts: Part[] }[] = []
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const result = Binary.search(session, messageKey(item.message), messageKey)
|
const result = Binary.search(session, item.message.id, (message) => message.id)
|
||||||
const found = result.found
|
if (!result.found) session.splice(result.index, 0, item.message)
|
||||||
if (!found) session.splice(result.index, 0, item.message)
|
|
||||||
const current = part.get(item.message.id)
|
const current = part.get(item.message.id)
|
||||||
const confirmed = found ? item.parts.filter((part) => current?.some((value) => value.id === part.id)) : []
|
const confirmed = result.found
|
||||||
if (found) observed.push({ messageID: item.message.id, parts: confirmed })
|
? item.parts.filter((part) => Binary.search(current ?? [], part.id, (value) => value.id).found)
|
||||||
|
: []
|
||||||
|
if (result.found) observed.push({ messageID: item.message.id, parts: confirmed })
|
||||||
part.set(
|
part.set(
|
||||||
item.message.id,
|
item.message.id,
|
||||||
merge(
|
merge(
|
||||||
found ? (current ?? []) : merge(item.confirmedParts ?? [], current ?? []),
|
result.found ? (current ?? []) : merge(item.confirmedParts ?? [], current ?? []),
|
||||||
item.parts.filter((part) => !confirmed.includes(part)),
|
item.parts.filter((part) => !confirmed.includes(part)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -156,7 +158,6 @@ function reconcileFetched<T extends { id: string }>(
|
|||||||
retained?: ReadonlySet<string>
|
retained?: ReadonlySet<string>
|
||||||
removed?: ReadonlySet<string>
|
removed?: ReadonlySet<string>
|
||||||
preserveUnfetched?: boolean | ((item: T) => boolean)
|
preserveUnfetched?: boolean | ((item: T) => boolean)
|
||||||
compare?: (a: T, b: T) => number
|
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
const result = new Map(fetched.map((item) => [item.id, item]))
|
const result = new Map(fetched.map((item) => [item.id, item]))
|
||||||
@@ -179,8 +180,7 @@ function reconcileFetched<T extends { id: string }>(
|
|||||||
if (!item) result.delete(id)
|
if (!item) result.delete(id)
|
||||||
}
|
}
|
||||||
for (const id of options.removed ?? emptyIDs) result.delete(id)
|
for (const id of options.removed ?? emptyIDs) result.delete(id)
|
||||||
const items = [...result.values()]
|
return [...result.values()].sort((a, b) => cmp(a.id, b.id))
|
||||||
return options.compare ? items.sort(options.compare) : items
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerSessionOptions = { retry?: typeof retry; protocol?: Promise<"v1" | "v2"> }
|
type ServerSessionOptions = { retry?: typeof retry; protocol?: Promise<"v1" | "v2"> }
|
||||||
@@ -413,7 +413,8 @@ export function createServerSession(
|
|||||||
if (!load) return
|
if (!load) return
|
||||||
// A part event keeps an existing parent when the fetched page omits it without overriding fetched metadata.
|
// A part event keeps an existing parent when the fetched page omits it without overriding fetched metadata.
|
||||||
const messages = data.message[sessionID]
|
const messages = data.message[sessionID]
|
||||||
if (messages?.some((message) => message.id === messageID)) load.retainedMessages.add(messageID)
|
if (messages && Binary.search(messages, messageID, (message) => message.id).found)
|
||||||
|
load.retainedMessages.add(messageID)
|
||||||
const parts = load.touchedParts.get(messageID)
|
const parts = load.touchedParts.get(messageID)
|
||||||
if (parts) {
|
if (parts) {
|
||||||
parts.add(partID)
|
parts.add(partID)
|
||||||
@@ -436,14 +437,16 @@ export function createServerSession(
|
|||||||
load.touchedParts.set(messageID, new Set(parts))
|
load.touchedParts.set(messageID, new Set(parts))
|
||||||
load.carriedDeltaParts.set(messageID, new Set(parts))
|
load.carriedDeltaParts.set(messageID, new Set(parts))
|
||||||
const messages = data.message[sessionID]
|
const messages = data.message[sessionID]
|
||||||
if (messages?.some((message) => message.id === messageID)) load.retainedMessages.add(messageID)
|
if (messages && Binary.search(messages, messageID, (message) => message.id).found)
|
||||||
|
load.retainedMessages.add(messageID)
|
||||||
}
|
}
|
||||||
for (const [messageID, parts] of load.removedParts) {
|
for (const [messageID, parts] of load.removedParts) {
|
||||||
const touched = load.touchedParts.get(messageID) ?? new Set<string>()
|
const touched = load.touchedParts.get(messageID) ?? new Set<string>()
|
||||||
parts.forEach((partID) => touched.add(partID))
|
parts.forEach((partID) => touched.add(partID))
|
||||||
load.touchedParts.set(messageID, touched)
|
load.touchedParts.set(messageID, touched)
|
||||||
const messages = data.message[sessionID]
|
const messages = data.message[sessionID]
|
||||||
if (messages?.some((message) => message.id === messageID)) load.retainedMessages.add(messageID)
|
if (messages && Binary.search(messages, messageID, (message) => message.id).found)
|
||||||
|
load.retainedMessages.add(messageID)
|
||||||
}
|
}
|
||||||
for (const [messageID, parts] of load.optimisticParts) {
|
for (const [messageID, parts] of load.optimisticParts) {
|
||||||
load.removedMessages.delete(messageID)
|
load.removedMessages.delete(messageID)
|
||||||
@@ -552,7 +555,7 @@ export function createServerSession(
|
|||||||
const source = pages.flatMap((page) => page.data).toReversed()
|
const source = pages.flatMap((page) => page.data).toReversed()
|
||||||
const normalized = normalizeSessionMessages(sessionID, source)
|
const normalized = normalizeSessionMessages(sessionID, source)
|
||||||
return {
|
return {
|
||||||
session: normalized.messages.sort(compareMessages),
|
session: normalized.messages.sort((a, b) => cmp(a.id, b.id)),
|
||||||
part: [...normalized.parts.entries()]
|
part: [...normalized.parts.entries()]
|
||||||
.map(([id, part]) => ({ id, part: part.sort((a, b) => cmp(a.id, b.id)) }))
|
.map(([id, part]) => ({ id, part: part.sort((a, b) => cmp(a.id, b.id)) }))
|
||||||
.sort((a, b) => cmp(a.id, b.id)),
|
.sort((a, b) => cmp(a.id, b.id)),
|
||||||
@@ -569,7 +572,7 @@ export function createServerSession(
|
|||||||
})
|
})
|
||||||
const items = (response.data ?? []).filter((item) => !!item?.info?.id)
|
const items = (response.data ?? []).filter((item) => !!item?.info?.id)
|
||||||
return {
|
return {
|
||||||
session: items.map((item) => cleanMessage(item.info)).sort(compareMessages),
|
session: items.map((item) => cleanMessage(item.info)).sort((a, b) => cmp(a.id, b.id)),
|
||||||
part: items.map((item) => ({
|
part: items.map((item) => ({
|
||||||
id: item.info.id,
|
id: item.info.id,
|
||||||
part: item.parts.filter((part) => !!part?.id).sort((a, b) => cmp(a.id, b.id)),
|
part: item.parts.filter((part) => !!part?.id).sort((a, b) => cmp(a.id, b.id)),
|
||||||
@@ -693,7 +696,7 @@ export function createServerSession(
|
|||||||
const normalized = normalizeSessionMessages(sessionID, source)
|
const normalized = normalizeSessionMessages(sessionID, source)
|
||||||
return {
|
return {
|
||||||
...page,
|
...page,
|
||||||
session: normalized.messages.sort(compareMessages),
|
session: normalized.messages.sort((a, b) => cmp(a.id, b.id)),
|
||||||
part: [...normalized.parts.entries()]
|
part: [...normalized.parts.entries()]
|
||||||
.map(([id, part]) => ({ id, part: part.sort((a, b) => cmp(a.id, b.id)) }))
|
.map(([id, part]) => ({ id, part: part.sort((a, b) => cmp(a.id, b.id)) }))
|
||||||
.sort((a, b) => cmp(a.id, b.id)),
|
.sort((a, b) => cmp(a.id, b.id)),
|
||||||
@@ -710,7 +713,6 @@ export function createServerSession(
|
|||||||
retained: load?.retainedMessages,
|
retained: load?.retainedMessages,
|
||||||
removed: load?.removedMessages,
|
removed: load?.removedMessages,
|
||||||
preserveUnfetched,
|
preserveUnfetched,
|
||||||
compare: compareMessages,
|
|
||||||
})
|
})
|
||||||
batch(() => {
|
batch(() => {
|
||||||
if (source) setData("session_message", sessionID, reconcile(source))
|
if (source) setData("session_message", sessionID, reconcile(source))
|
||||||
@@ -752,7 +754,7 @@ export function createServerSession(
|
|||||||
try {
|
try {
|
||||||
const page = await fetchMessages(sessionID, limit, before, () => resetMessageLoad(sessionID, load))
|
const page = await fetchMessages(sessionID, limit, before, () => resetMessageLoad(sessionID, load))
|
||||||
const first = page.session.reduce<Message | undefined>(
|
const first = page.session.reduce<Message | undefined>(
|
||||||
(oldest, message) => (!oldest || compareMessages(message, oldest) < 0 ? message : oldest),
|
(oldest, message) => (!oldest || cmpMessage(message, oldest) < 0 ? message : oldest),
|
||||||
undefined,
|
undefined,
|
||||||
)
|
)
|
||||||
if (generations.get(sessionID) !== active) return
|
if (generations.get(sessionID) !== active) return
|
||||||
@@ -802,15 +804,14 @@ export function createServerSession(
|
|||||||
session: merge(
|
session: merge(
|
||||||
page.session,
|
page.session,
|
||||||
parents.map((parent) => parent.message),
|
parents.map((parent) => parent.message),
|
||||||
).sort(compareMessages),
|
),
|
||||||
part: merge(
|
part: merge(
|
||||||
page.part,
|
page.part,
|
||||||
parents.map((parent) => ({ id: parent.message.id, part: parent.parts })),
|
parents.map((parent) => ({ id: parent.message.id, part: parent.parts })),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
const preserveUnfetched =
|
const preserveUnfetched =
|
||||||
mode === "prepend" ||
|
mode === "prepend" || (!result.complete && (!first || ((message: Message) => cmpMessage(message, first) < 0)))
|
||||||
(!result.complete && (!first || ((message: Message) => compareMessages(message, first) < 0)))
|
|
||||||
applyMessagePage(
|
applyMessagePage(
|
||||||
sessionID,
|
sessionID,
|
||||||
result,
|
result,
|
||||||
@@ -927,7 +928,7 @@ export function createServerSession(
|
|||||||
.message({ sessionID, messageID })
|
.message({ sessionID, messageID })
|
||||||
.then((message) => {
|
.then((message) => {
|
||||||
const current = data.session_message[sessionID] ?? []
|
const current = data.session_message[sessionID] ?? []
|
||||||
const messages = [...current.filter((item) => item.id !== message.id), message].sort(compareMessages)
|
const messages = [...current.filter((item) => item.id !== message.id), message].sort((a, b) => cmp(a.id, b.id))
|
||||||
projectV2({ sessionID, messages, touched: [message.id] })
|
projectV2({ sessionID, messages, touched: [message.id] })
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
@@ -1050,7 +1051,7 @@ export function createServerSession(
|
|||||||
setData("message", info.sessionID, [info])
|
setData("message", info.sessionID, [info])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const result = Binary.search(messages, messageKey(info), messageKey)
|
const result = Binary.search(messages, info.id, (message) => message.id)
|
||||||
if (result.found) setData("message", info.sessionID, result.index, reconcile(info))
|
if (result.found) setData("message", info.sessionID, result.index, reconcile(info))
|
||||||
if (!result.found)
|
if (!result.found)
|
||||||
setData("message", info.sessionID, (value = []) => {
|
setData("message", info.sessionID, (value = []) => {
|
||||||
@@ -1083,8 +1084,8 @@ export function createServerSession(
|
|||||||
produce((draft) => {
|
produce((draft) => {
|
||||||
const messages = draft.message[props.sessionID]
|
const messages = draft.message[props.sessionID]
|
||||||
if (messages) {
|
if (messages) {
|
||||||
const index = messages.findIndex((message) => message.id === props.messageID)
|
const result = Binary.search(messages, props.messageID, (message) => message.id)
|
||||||
if (index >= 0) messages.splice(index, 1)
|
if (result.found) messages.splice(result.index, 1)
|
||||||
}
|
}
|
||||||
deleteMessageParts(draft, props.messageID)
|
deleteMessageParts(draft, props.messageID)
|
||||||
}),
|
}),
|
||||||
@@ -1096,7 +1097,7 @@ export function createServerSession(
|
|||||||
if (SKIP_PARTS.has(part.type)) return
|
if (SKIP_PARTS.has(part.type)) return
|
||||||
const messages = data.message[part.sessionID]
|
const messages = data.message[part.sessionID]
|
||||||
const load = messageLoads.get(part.sessionID)
|
const load = messageLoads.get(part.sessionID)
|
||||||
const missing = !messages?.some((message) => message.id === part.messageID)
|
const missing = !messages || !Binary.search(messages, part.messageID, (message) => message.id).found
|
||||||
// Outside a page load, accepting a part without its ordered parent event would create an unbounded orphan.
|
// Outside a page load, accepting a part without its ordered parent event would create an unbounded orphan.
|
||||||
if (
|
if (
|
||||||
missing &&
|
missing &&
|
||||||
@@ -1340,7 +1341,7 @@ export function createServerSession(
|
|||||||
if (items) items.set(input.message.id, { ...input, parts, confirmedParts: [] })
|
if (items) items.set(input.message.id, { ...input, parts, confirmedParts: [] })
|
||||||
if (!items)
|
if (!items)
|
||||||
optimistic.set(input.sessionID, new Map([[input.message.id, { ...input, parts, confirmedParts: [] }]]))
|
optimistic.set(input.sessionID, new Map([[input.message.id, { ...input, parts, confirmedParts: [] }]]))
|
||||||
setData("message", input.sessionID, (messages = []) => merge(messages, [input.message]).sort(compareMessages))
|
setData("message", input.sessionID, (messages = []) => merge(messages, [input.message]))
|
||||||
setData(
|
setData(
|
||||||
"part_text_accum_delta",
|
"part_text_accum_delta",
|
||||||
produce((draft) => {
|
produce((draft) => {
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import { applyOptimisticAdd, applyOptimisticRemove, mergeOptimisticPage } from "
|
|||||||
|
|
||||||
type Text = Extract<Part, { type: "text" }>
|
type Text = Extract<Part, { type: "text" }>
|
||||||
|
|
||||||
const userMessage = (id: string, sessionID: string, created = 1): Message => ({
|
const userMessage = (id: string, sessionID: string): Message => ({
|
||||||
id,
|
id,
|
||||||
sessionID,
|
sessionID,
|
||||||
role: "user",
|
role: "user",
|
||||||
time: { created },
|
time: { created: 1 },
|
||||||
agent: "assistant",
|
agent: "assistant",
|
||||||
model: { providerID: "openai", modelID: "gpt" },
|
model: { providerID: "openai", modelID: "gpt" },
|
||||||
})
|
})
|
||||||
@@ -22,21 +22,21 @@ const textPart = (id: string, sessionID: string, messageID: string): Text => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("sync optimistic reducers", () => {
|
describe("sync optimistic reducers", () => {
|
||||||
test("applyOptimisticAdd inserts by creation time", () => {
|
test("applyOptimisticAdd inserts message in sorted order and stores parts", () => {
|
||||||
const sessionID = "ses_1"
|
const sessionID = "ses_1"
|
||||||
const draft = {
|
const draft = {
|
||||||
message: { [sessionID]: [userMessage("msg_z", sessionID, 1)] },
|
message: { [sessionID]: [userMessage("msg_2", sessionID)] },
|
||||||
part: {} as Record<string, Part[] | undefined>,
|
part: {} as Record<string, Part[] | undefined>,
|
||||||
}
|
}
|
||||||
|
|
||||||
applyOptimisticAdd(draft, {
|
applyOptimisticAdd(draft, {
|
||||||
sessionID,
|
sessionID,
|
||||||
message: userMessage("msg_a", sessionID, 2),
|
message: userMessage("msg_1", sessionID),
|
||||||
parts: [textPart("prt_2", sessionID, "msg_a"), textPart("prt_1", sessionID, "msg_a")],
|
parts: [textPart("prt_2", sessionID, "msg_1"), textPart("prt_1", sessionID, "msg_1")],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(draft.message[sessionID]?.map((x) => x.id)).toEqual(["msg_z", "msg_a"])
|
expect(draft.message[sessionID]?.map((x) => x.id)).toEqual(["msg_1", "msg_2"])
|
||||||
expect(draft.part.msg_a?.map((x) => x.id)).toEqual(["prt_1", "prt_2"])
|
expect(draft.part.msg_1?.map((x) => x.id)).toEqual(["prt_1", "prt_2"])
|
||||||
})
|
})
|
||||||
|
|
||||||
test("applyOptimisticRemove removes message and part entries", () => {
|
test("applyOptimisticRemove removes message and part entries", () => {
|
||||||
@@ -60,33 +60,19 @@ describe("sync optimistic reducers", () => {
|
|||||||
const sessionID = "ses_1"
|
const sessionID = "ses_1"
|
||||||
const page = mergeOptimisticPage(
|
const page = mergeOptimisticPage(
|
||||||
{
|
{
|
||||||
session: [userMessage("msg_z", sessionID, 1)],
|
session: [userMessage("msg_1", sessionID)],
|
||||||
part: [{ id: "msg_z", part: [textPart("prt_1", sessionID, "msg_z")] }],
|
part: [{ id: "msg_1", part: [textPart("prt_1", sessionID, "msg_1")] }],
|
||||||
complete: true,
|
complete: true,
|
||||||
},
|
},
|
||||||
[{ message: userMessage("msg_a", sessionID, 2), parts: [textPart("prt_2", sessionID, "msg_a")] }],
|
[{ message: userMessage("msg_2", sessionID), parts: [textPart("prt_2", sessionID, "msg_2")] }],
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(page.session.map((x) => x.id)).toEqual(["msg_z", "msg_a"])
|
expect(page.session.map((x) => x.id)).toEqual(["msg_1", "msg_2"])
|
||||||
expect(page.part.find((x) => x.id === "msg_a")?.part.map((x) => x.id)).toEqual(["prt_2"])
|
expect(page.part.find((x) => x.id === "msg_2")?.part.map((x) => x.id)).toEqual(["prt_2"])
|
||||||
expect(page.confirmed).toEqual([])
|
expect(page.confirmed).toEqual([])
|
||||||
expect(page.complete).toBe(true)
|
expect(page.complete).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("mergeOptimisticPage uses IDs only to break equal-time ties", () => {
|
|
||||||
const sessionID = "ses_1"
|
|
||||||
const page = mergeOptimisticPage(
|
|
||||||
{
|
|
||||||
session: [userMessage("msg_z", sessionID, 1)],
|
|
||||||
part: [],
|
|
||||||
complete: true,
|
|
||||||
},
|
|
||||||
[{ message: userMessage("msg_a", sessionID, 1), parts: [] }],
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(page.session.map((message) => message.id)).toEqual(["msg_a", "msg_z"])
|
|
||||||
})
|
|
||||||
|
|
||||||
test("mergeOptimisticPage keeps missing optimistic parts until the server has them", () => {
|
test("mergeOptimisticPage keeps missing optimistic parts until the server has them", () => {
|
||||||
const sessionID = "ses_1"
|
const sessionID = "ses_1"
|
||||||
const page = mergeOptimisticPage(
|
const page = mergeOptimisticPage(
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { createMemo } from "solid-js"
|
|||||||
import { useServerSync } from "./server-sync"
|
import { useServerSync } from "./server-sync"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
import type { Message, Part } from "@opencode-ai/sdk/v2/client"
|
import type { Message, Part } from "@opencode-ai/sdk/v2/client"
|
||||||
import { messageKey } from "@/utils/session-message"
|
|
||||||
|
|
||||||
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"])
|
||||||
|
|
||||||
@@ -68,7 +67,7 @@ export function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[])
|
|||||||
const confirmed: string[] = []
|
const confirmed: string[] = []
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const result = Binary.search(session, messageKey(item.message), messageKey)
|
const result = Binary.search(session, item.message.id, (message) => message.id)
|
||||||
const found = result.found
|
const found = result.found
|
||||||
if (!found) session.splice(result.index, 0, item.message)
|
if (!found) session.splice(result.index, 0, item.message)
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ export function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[])
|
|||||||
export function applyOptimisticAdd(draft: OptimisticStore, input: OptimisticAddInput) {
|
export function applyOptimisticAdd(draft: OptimisticStore, input: OptimisticAddInput) {
|
||||||
const messages = draft.message[input.sessionID]
|
const messages = draft.message[input.sessionID]
|
||||||
if (messages) {
|
if (messages) {
|
||||||
const result = Binary.search(messages, messageKey(input.message), messageKey)
|
const result = Binary.search(messages, input.message.id, (m) => m.id)
|
||||||
messages.splice(result.index, 0, input.message)
|
messages.splice(result.index, 0, input.message)
|
||||||
} else {
|
} else {
|
||||||
draft.message[input.sessionID] = [input.message]
|
draft.message[input.sessionID] = [input.message]
|
||||||
@@ -104,8 +103,8 @@ export function applyOptimisticAdd(draft: OptimisticStore, input: OptimisticAddI
|
|||||||
export function applyOptimisticRemove(draft: OptimisticStore, input: OptimisticRemoveInput) {
|
export function applyOptimisticRemove(draft: OptimisticStore, input: OptimisticRemoveInput) {
|
||||||
const messages = draft.message[input.sessionID]
|
const messages = draft.message[input.sessionID]
|
||||||
if (messages) {
|
if (messages) {
|
||||||
const index = messages.findIndex((message) => message.id === input.messageID)
|
const result = Binary.search(messages, input.messageID, (m) => m.id)
|
||||||
if (index >= 0) messages.splice(index, 1)
|
if (result.found) messages.splice(result.index, 1)
|
||||||
}
|
}
|
||||||
delete draft.part[input.messageID]
|
delete draft.part[input.messageID]
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-28
@@ -3,7 +3,6 @@
|
|||||||
import * as Sentry from "@sentry/solid"
|
import * as Sentry from "@sentry/solid"
|
||||||
import { render } from "solid-js/web"
|
import { render } from "solid-js/web"
|
||||||
import { AppBaseProviders, AppInterface } from "@/app"
|
import { AppBaseProviders, AppInterface } from "@/app"
|
||||||
import { loadInitialLocale } from "@/context/language"
|
|
||||||
import { type Platform, PlatformProvider } from "@/context/platform"
|
import { type Platform, PlatformProvider } from "@/context/platform"
|
||||||
import { createBrowserDraftStore } from "@/utils/draft-store"
|
import { createBrowserDraftStore } from "@/utils/draft-store"
|
||||||
import { dict as en } from "@/i18n/en"
|
import { dict as en } from "@/i18n/en"
|
||||||
@@ -150,31 +149,29 @@ if (import.meta.env.VITE_SENTRY_DSN) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (root instanceof HTMLElement) {
|
if (root instanceof HTMLElement) {
|
||||||
void loadInitialLocale().then((locale) => {
|
const auth = authFromToken(new URLSearchParams(location.search).get("auth_token"))
|
||||||
const auth = authFromToken(new URLSearchParams(location.search).get("auth_token"))
|
clearAuthToken()
|
||||||
clearAuthToken()
|
const server: ServerConnection.Http = {
|
||||||
const server: ServerConnection.Http = {
|
type: "http",
|
||||||
type: "http",
|
authToken: !!auth,
|
||||||
authToken: !!auth,
|
http: {
|
||||||
http: {
|
url: getCurrentUrl(),
|
||||||
url: getCurrentUrl(),
|
...auth,
|
||||||
...auth,
|
},
|
||||||
},
|
}
|
||||||
}
|
render(
|
||||||
render(
|
() => (
|
||||||
() => (
|
<PlatformProvider value={platform}>
|
||||||
<PlatformProvider value={platform}>
|
<AppBaseProviders>
|
||||||
<AppBaseProviders locale={locale}>
|
<AppInterface
|
||||||
<AppInterface
|
defaultServer={ServerConnection.Key.make(getDefaultUrl())}
|
||||||
defaultServer={ServerConnection.Key.make(getDefaultUrl())}
|
canonicalLocalServer={ServerConnection.key(server)}
|
||||||
canonicalLocalServer={ServerConnection.key(server)}
|
servers={[server]}
|
||||||
servers={[server]}
|
disableHealthCheck
|
||||||
disableHealthCheck
|
/>
|
||||||
/>
|
</AppBaseProviders>
|
||||||
</AppBaseProviders>
|
</PlatformProvider>
|
||||||
</PlatformProvider>
|
),
|
||||||
),
|
root,
|
||||||
root,
|
)
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -184,9 +184,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "مشاركة هذه الجلسة ونسخ الرابط إلى الحافظة",
|
"command.session.share.description": "مشاركة هذه الجلسة ونسخ الرابط إلى الحافظة",
|
||||||
"command.session.unshare": "إلغاء مشاركة الجلسة",
|
"command.session.unshare": "إلغاء مشاركة الجلسة",
|
||||||
"command.session.unshare.description": "إيقاف مشاركة هذه الجلسة",
|
"command.session.unshare.description": "إيقاف مشاركة هذه الجلسة",
|
||||||
"command.session.export": "تصدير الجلسة",
|
|
||||||
"command.session.export.description": "تصدير النص الكامل للجلسة بصيغة JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "البحث في الملفات والأوامر والجلسات",
|
"palette.search.placeholder": "البحث في الملفات والأوامر والجلسات",
|
||||||
"palette.search.placeholder.home": "البحث في الأوامر والجلسات",
|
"palette.search.placeholder.home": "البحث في الأوامر والجلسات",
|
||||||
"palette.empty": "لا توجد نتائج",
|
"palette.empty": "لا توجد نتائج",
|
||||||
@@ -534,8 +531,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup": "برنامج نصي لبدء تشغيل مساحة العمل",
|
"dialog.project.edit.worktree.startup": "برنامج نصي لبدء تشغيل مساحة العمل",
|
||||||
"dialog.project.edit.worktree.startup.description": "يتم تشغيله بعد إنشاء مساحة عمل جديدة (شجرة عمل).",
|
"dialog.project.edit.worktree.startup.description": "يتم تشغيله بعد إنشاء مساحة عمل جديدة (شجرة عمل).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "مثال: bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "مثال: bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "عدم الإظهار مرة أخرى",
|
|
||||||
|
|
||||||
"context.breakdown.title": "تفصيل السياق",
|
"context.breakdown.title": "تفصيل السياق",
|
||||||
"context.breakdown.note": 'تفصيل تقريبي لرموز الإدخال المميزة. يشمل "أخرى" تعريفات الأدوات والأعباء الإضافية.',
|
"context.breakdown.note": 'تفصيل تقريبي لرموز الإدخال المميزة. يشمل "أخرى" تعريفات الأدوات والأعباء الإضافية.',
|
||||||
"context.breakdown.system": "النظام",
|
"context.breakdown.system": "النظام",
|
||||||
@@ -545,8 +540,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "أخرى",
|
"context.breakdown.other": "أخرى",
|
||||||
"context.systemPrompt.title": "موجّه النظام",
|
"context.systemPrompt.title": "موجّه النظام",
|
||||||
"context.rawMessages.title": "الرسائل الخام",
|
"context.rawMessages.title": "الرسائل الخام",
|
||||||
"context.export.session": "تصدير الجلسة",
|
|
||||||
|
|
||||||
"context.stats.session": "جلسة",
|
"context.stats.session": "جلسة",
|
||||||
"context.stats.messages": "رسائل",
|
"context.stats.messages": "رسائل",
|
||||||
"context.stats.provider": "موفر",
|
"context.stats.provider": "موفر",
|
||||||
@@ -613,11 +606,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "تم إلغاء مشاركة الجلسة بنجاح!",
|
"toast.session.unshare.success.description": "تم إلغاء مشاركة الجلسة بنجاح!",
|
||||||
"toast.session.unshare.failed.title": "فشل إلغاء مشاركة الجلسة",
|
"toast.session.unshare.failed.title": "فشل إلغاء مشاركة الجلسة",
|
||||||
"toast.session.unshare.failed.description": "حدث خطأ أثناء إلغاء مشاركة الجلسة",
|
"toast.session.unshare.failed.description": "حدث خطأ أثناء إلغاء مشاركة الجلسة",
|
||||||
"toast.session.export.success.title": "تم تصدير الجلسة",
|
|
||||||
"toast.session.export.success.description": "تم حفظ الجلسة في \u2068{{filename}}\u2069",
|
|
||||||
"toast.session.export.failed.title": "فشل تصدير الجلسة",
|
|
||||||
"toast.session.export.failed.description": "حدث خطأ أثناء تصدير الجلسة",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "فشل تحميل الجلسات لـ {{project}}",
|
"toast.session.listFailed.title": "فشل تحميل الجلسات لـ {{project}}",
|
||||||
"toast.update.title": "تحديث متاح",
|
"toast.update.title": "تحديث متاح",
|
||||||
"toast.update.description": "يتوفر الآن إصدار جديد من OpenCode ({{version}}) للتثبيت.",
|
"toast.update.description": "يتوفر الآن إصدار جديد من OpenCode ({{version}}) للتثبيت.",
|
||||||
@@ -805,7 +793,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "مزيد من الخيارات",
|
"common.moreOptions": "مزيد من الخيارات",
|
||||||
"common.learnMore": "اطّلع على المزيد",
|
"common.learnMore": "اطّلع على المزيد",
|
||||||
"common.rename": "إعادة تسمية",
|
"common.rename": "إعادة تسمية",
|
||||||
"common.export": "تصدير",
|
|
||||||
"common.reset": "إعادة تعيين",
|
"common.reset": "إعادة تعيين",
|
||||||
"common.archive": "أرشفة",
|
"common.archive": "أرشفة",
|
||||||
"common.delete": "حذف",
|
"common.delete": "حذف",
|
||||||
|
|||||||
@@ -180,9 +180,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Bu sessiyanı paylaş və URL-ni buferə kopyala",
|
"command.session.share.description": "Bu sessiyanı paylaş və URL-ni buferə kopyala",
|
||||||
"command.session.unshare": "Sessiyanın paylaşımını dayandır",
|
"command.session.unshare": "Sessiyanın paylaşımını dayandır",
|
||||||
"command.session.unshare.description": "Bu sessiyanın paylaşımını dayandır",
|
"command.session.unshare.description": "Bu sessiyanın paylaşımını dayandır",
|
||||||
"command.session.export": "Sessiyanı ixrac et",
|
|
||||||
"command.session.export.description": "Sessiyanın tam transkriptini JSON formatında ixrac et",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Fayl, əmr və sessiya axtar",
|
"palette.search.placeholder": "Fayl, əmr və sessiya axtar",
|
||||||
"palette.search.placeholder.home": "Əmr və sessiyaları axtar",
|
"palette.search.placeholder.home": "Əmr və sessiyaları axtar",
|
||||||
"palette.empty": "Nəticə tapılmadı",
|
"palette.empty": "Nəticə tapılmadı",
|
||||||
@@ -544,8 +541,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Növbəti",
|
"dialog.releaseNotes.action.next": "Növbəti",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Gələcəkdə göstərmə",
|
"dialog.releaseNotes.action.hideFuture": "Gələcəkdə göstərmə",
|
||||||
"dialog.releaseNotes.media.alt": "Buraxılış önbaxışı",
|
"dialog.releaseNotes.media.alt": "Buraxılış önbaxışı",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Bir daha göstərmə",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontekst bölgüsü",
|
"context.breakdown.title": "Kontekst bölgüsü",
|
||||||
"context.breakdown.note": 'Giriş tokenlərinin təxmini bölgüsü. "Digər" alət təriflərini və əlavə yükü əhatə edir.',
|
"context.breakdown.note": 'Giriş tokenlərinin təxmini bölgüsü. "Digər" alət təriflərini və əlavə yükü əhatə edir.',
|
||||||
"context.breakdown.system": "Sistem",
|
"context.breakdown.system": "Sistem",
|
||||||
@@ -555,8 +550,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Digər",
|
"context.breakdown.other": "Digər",
|
||||||
"context.systemPrompt.title": "Sistem promptu",
|
"context.systemPrompt.title": "Sistem promptu",
|
||||||
"context.rawMessages.title": "Xam mesajlar",
|
"context.rawMessages.title": "Xam mesajlar",
|
||||||
"context.export.session": "Sessiyanı ixrac et",
|
|
||||||
|
|
||||||
"context.stats.session": "Sessiya",
|
"context.stats.session": "Sessiya",
|
||||||
"context.stats.messages": "Mesajlar",
|
"context.stats.messages": "Mesajlar",
|
||||||
"context.stats.provider": "Provayder",
|
"context.stats.provider": "Provayder",
|
||||||
@@ -623,11 +616,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Sessiyanın paylaşımı uğurla dayandırıldı!",
|
"toast.session.unshare.success.description": "Sessiyanın paylaşımı uğurla dayandırıldı!",
|
||||||
"toast.session.unshare.failed.title": "Sessiyanın paylaşımı dayandırıla bilmədi",
|
"toast.session.unshare.failed.title": "Sessiyanın paylaşımı dayandırıla bilmədi",
|
||||||
"toast.session.unshare.failed.description": "Sessiyanın paylaşımını dayandırarkən xəta baş verdi",
|
"toast.session.unshare.failed.description": "Sessiyanın paylaşımını dayandırarkən xəta baş verdi",
|
||||||
"toast.session.export.success.title": "Sessiya ixrac edildi",
|
|
||||||
"toast.session.export.success.description": "Sessiya {{filename}} faylına saxlanıldı",
|
|
||||||
"toast.session.export.failed.title": "Sessiya ixrac edilə bilmədi",
|
|
||||||
"toast.session.export.failed.description": "Sessiyanı ixrac edərkən xəta baş verdi",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}} üçün sessiyalar yüklənə bilmədi",
|
"toast.session.listFailed.title": "{{project}} üçün sessiyalar yüklənə bilmədi",
|
||||||
"toast.project.reloadFailed.title": "{{project}} yenidən yüklənə bilmədi",
|
"toast.project.reloadFailed.title": "{{project}} yenidən yüklənə bilmədi",
|
||||||
"toast.update.title": "Yeniləmə mövcuddur",
|
"toast.update.title": "Yeniləmə mövcuddur",
|
||||||
@@ -844,7 +832,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Daha çox seçim",
|
"common.moreOptions": "Daha çox seçim",
|
||||||
"common.learnMore": "Ətraflı öyrən",
|
"common.learnMore": "Ətraflı öyrən",
|
||||||
"common.rename": "Adını dəyiş",
|
"common.rename": "Adını dəyiş",
|
||||||
"common.export": "İxrac et",
|
|
||||||
"common.reset": "Sıfırla",
|
"common.reset": "Sıfırla",
|
||||||
"common.archive": "Arxivlə",
|
"common.archive": "Arxivlə",
|
||||||
"common.delete": "Sil",
|
"common.delete": "Sil",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -186,9 +186,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Compartilhar esta sessão e copiar a URL para a área de transferência",
|
"command.session.share.description": "Compartilhar esta sessão e copiar a URL para a área de transferência",
|
||||||
"command.session.unshare": "Parar de compartilhar sessão",
|
"command.session.unshare": "Parar de compartilhar sessão",
|
||||||
"command.session.unshare.description": "Parar de compartilhar esta sessão",
|
"command.session.unshare.description": "Parar de compartilhar esta sessão",
|
||||||
"command.session.export": "Exportar sessão",
|
|
||||||
"command.session.export.description": "Exportar a transcrição completa da sessão como JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Buscar arquivos, comandos e sessões",
|
"palette.search.placeholder": "Buscar arquivos, comandos e sessões",
|
||||||
"palette.search.placeholder.home": "Buscar comandos e sessões",
|
"palette.search.placeholder.home": "Buscar comandos e sessões",
|
||||||
"palette.empty": "Nenhum resultado encontrado",
|
"palette.empty": "Nenhum resultado encontrado",
|
||||||
@@ -537,8 +534,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup": "Script de inicialização do espaço de trabalho",
|
"dialog.project.edit.worktree.startup": "Script de inicialização do espaço de trabalho",
|
||||||
"dialog.project.edit.worktree.startup.description": "Executa após criar um novo espaço de trabalho (worktree).",
|
"dialog.project.edit.worktree.startup.description": "Executa após criar um novo espaço de trabalho (worktree).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "Ex.: bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "Ex.: bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Não mostrar novamente",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Detalhamento do contexto",
|
"context.breakdown.title": "Detalhamento do contexto",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Detalhamento aproximado dos tokens de entrada. "Outros" inclui definições de ferramentas e sobrecarga.',
|
'Detalhamento aproximado dos tokens de entrada. "Outros" inclui definições de ferramentas e sobrecarga.',
|
||||||
@@ -549,8 +544,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Outros",
|
"context.breakdown.other": "Outros",
|
||||||
"context.systemPrompt.title": "Prompt do sistema",
|
"context.systemPrompt.title": "Prompt do sistema",
|
||||||
"context.rawMessages.title": "Mensagens brutas",
|
"context.rawMessages.title": "Mensagens brutas",
|
||||||
"context.export.session": "Exportar sessão",
|
|
||||||
|
|
||||||
"context.stats.session": "Sessão",
|
"context.stats.session": "Sessão",
|
||||||
"context.stats.messages": "Mensagens",
|
"context.stats.messages": "Mensagens",
|
||||||
"context.stats.provider": "Provedor",
|
"context.stats.provider": "Provedor",
|
||||||
@@ -617,11 +610,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Sessão deixou de ser compartilhada com sucesso!",
|
"toast.session.unshare.success.description": "Sessão deixou de ser compartilhada com sucesso!",
|
||||||
"toast.session.unshare.failed.title": "Falha ao parar de compartilhar sessão",
|
"toast.session.unshare.failed.title": "Falha ao parar de compartilhar sessão",
|
||||||
"toast.session.unshare.failed.description": "Ocorreu um erro ao parar de compartilhar a sessão",
|
"toast.session.unshare.failed.description": "Ocorreu um erro ao parar de compartilhar a sessão",
|
||||||
"toast.session.export.success.title": "Sessão exportada",
|
|
||||||
"toast.session.export.success.description": "Sessão salva em {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Falha ao exportar sessão",
|
|
||||||
"toast.session.export.failed.description": "Ocorreu um erro ao exportar a sessão",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Falha ao carregar sessões para {{project}}",
|
"toast.session.listFailed.title": "Falha ao carregar sessões para {{project}}",
|
||||||
"toast.update.title": "Atualização disponível",
|
"toast.update.title": "Atualização disponível",
|
||||||
"toast.update.description": "Uma nova versão do OpenCode ({{version}}) está disponível para instalação.",
|
"toast.update.description": "Uma nova versão do OpenCode ({{version}}) está disponível para instalação.",
|
||||||
@@ -808,7 +796,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Mais opções",
|
"common.moreOptions": "Mais opções",
|
||||||
"common.learnMore": "Saiba mais",
|
"common.learnMore": "Saiba mais",
|
||||||
"common.rename": "Renomear",
|
"common.rename": "Renomear",
|
||||||
"common.export": "Exportar",
|
|
||||||
"common.reset": "Redefinir",
|
"common.reset": "Redefinir",
|
||||||
"common.archive": "Arquivar",
|
"common.archive": "Arquivar",
|
||||||
"common.delete": "Excluir",
|
"common.delete": "Excluir",
|
||||||
|
|||||||
@@ -193,9 +193,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Ukini dijeljenje sesije",
|
"command.session.unshare": "Ukini dijeljenje sesije",
|
||||||
"command.session.unshare.description": "Zaustavi dijeljenje ove sesije",
|
"command.session.unshare.description": "Zaustavi dijeljenje ove sesije",
|
||||||
|
|
||||||
"command.session.export": "Izvezi sesiju",
|
|
||||||
"command.session.export.description": "Izvezi cijeli zapis sesije u JSON formatu",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Pretraži datoteke, komande i sesije",
|
"palette.search.placeholder": "Pretraži datoteke, komande i sesije",
|
||||||
"palette.search.placeholder.home": "Pretraži komande i sesije",
|
"palette.search.placeholder.home": "Pretraži komande i sesije",
|
||||||
"palette.empty": "Nema rezultata",
|
"palette.empty": "Nema rezultata",
|
||||||
@@ -568,8 +565,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description": "Pokreće se nakon kreiranja novog radnog prostora (worktree).",
|
"dialog.project.edit.worktree.startup.description": "Pokreće se nakon kreiranja novog radnog prostora (worktree).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "npr. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "npr. bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "Nemoj više prikazivati",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Razlaganje konteksta",
|
"context.breakdown.title": "Razlaganje konteksta",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Približna raspodjela ulaznih tokena. "Ostalo" uključuje definicije alata i dodatno opterećenje.',
|
'Približna raspodjela ulaznih tokena. "Ostalo" uključuje definicije alata i dodatno opterećenje.',
|
||||||
@@ -582,8 +577,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Sistemski prompt",
|
"context.systemPrompt.title": "Sistemski prompt",
|
||||||
"context.rawMessages.title": "Sirove poruke",
|
"context.rawMessages.title": "Sirove poruke",
|
||||||
|
|
||||||
"context.export.session": "Izvezi sesiju",
|
|
||||||
|
|
||||||
"context.stats.session": "Sesija",
|
"context.stats.session": "Sesija",
|
||||||
"context.stats.messages": "Poruke",
|
"context.stats.messages": "Poruke",
|
||||||
"context.stats.provider": "Provajder",
|
"context.stats.provider": "Provajder",
|
||||||
@@ -662,11 +655,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Neuspjelo ukidanje dijeljenja",
|
"toast.session.unshare.failed.title": "Neuspjelo ukidanje dijeljenja",
|
||||||
"toast.session.unshare.failed.description": "Došlo je do greške prilikom ukidanja dijeljenja",
|
"toast.session.unshare.failed.description": "Došlo je do greške prilikom ukidanja dijeljenja",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Sesija izvezena",
|
|
||||||
"toast.session.export.success.description": "Sesija je sačuvana kao {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Izvoz sesije nije uspio",
|
|
||||||
"toast.session.export.failed.description": "Došlo je do greške prilikom izvoza sesije",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Neuspjelo učitavanje sesija za {{project}}",
|
"toast.session.listFailed.title": "Neuspjelo učitavanje sesija za {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "Dostupno ažuriranje",
|
"toast.update.title": "Dostupno ažuriranje",
|
||||||
@@ -868,7 +856,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Više opcija",
|
"common.moreOptions": "Više opcija",
|
||||||
"common.learnMore": "Saznaj više",
|
"common.learnMore": "Saznaj više",
|
||||||
"common.rename": "Preimenuj",
|
"common.rename": "Preimenuj",
|
||||||
"common.export": "Izvezi",
|
|
||||||
"common.reset": "Vrati na početno stanje",
|
"common.reset": "Vrati na početno stanje",
|
||||||
"common.archive": "Arhiviraj",
|
"common.archive": "Arhiviraj",
|
||||||
"common.delete": "Izbriši",
|
"common.delete": "Izbriši",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -92,9 +92,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Stop deling af session",
|
"command.session.unshare": "Stop deling af session",
|
||||||
"command.session.unshare.description": "Stop med at dele denne session",
|
"command.session.unshare.description": "Stop med at dele denne session",
|
||||||
|
|
||||||
"command.session.export": "Eksportér session",
|
|
||||||
"command.session.export.description": "Eksportér hele sessionsudskriften som JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Søg i filer, kommandoer og sessioner",
|
"palette.search.placeholder": "Søg i filer, kommandoer og sessioner",
|
||||||
"palette.search.placeholder.home": "Søg i kommandoer og sessioner",
|
"palette.search.placeholder.home": "Søg i kommandoer og sessioner",
|
||||||
"palette.empty": "Ingen resultater fundet",
|
"palette.empty": "Ingen resultater fundet",
|
||||||
@@ -449,8 +446,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup": "Opstartsscript for arbejdsområde",
|
"dialog.project.edit.worktree.startup": "Opstartsscript for arbejdsområde",
|
||||||
"dialog.project.edit.worktree.startup.description": "Køres efter oprettelse af et nyt arbejdsområde (worktree).",
|
"dialog.project.edit.worktree.startup.description": "Køres efter oprettelse af et nyt arbejdsområde (worktree).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "f.eks. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "f.eks. bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Vis ikke igen",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontekstfordeling",
|
"context.breakdown.title": "Kontekstfordeling",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Omtrentlig fordeling af input-tokens. "Andre" inkluderer værktøjsdefinitioner og overhead.',
|
'Omtrentlig fordeling af input-tokens. "Andre" inkluderer værktøjsdefinitioner og overhead.',
|
||||||
@@ -463,8 +458,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Systemprompt",
|
"context.systemPrompt.title": "Systemprompt",
|
||||||
"context.rawMessages.title": "Rå beskeder",
|
"context.rawMessages.title": "Rå beskeder",
|
||||||
|
|
||||||
"context.export.session": "Eksportér session",
|
|
||||||
|
|
||||||
"context.stats.session": "Session",
|
"context.stats.session": "Session",
|
||||||
"context.stats.messages": "Beskeder",
|
"context.stats.messages": "Beskeder",
|
||||||
"context.stats.provider": "Udbyder",
|
"context.stats.provider": "Udbyder",
|
||||||
@@ -542,11 +535,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Kunne ikke stoppe deling af session",
|
"toast.session.unshare.failed.title": "Kunne ikke stoppe deling af session",
|
||||||
"toast.session.unshare.failed.description": "Der opstod en fejl under stop af sessionsdeling",
|
"toast.session.unshare.failed.description": "Der opstod en fejl under stop af sessionsdeling",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Session eksporteret",
|
|
||||||
"toast.session.export.success.description": "Sessionen blev gemt i {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Kunne ikke eksportere session",
|
|
||||||
"toast.session.export.failed.description": "Der opstod en fejl under eksport af sessionen",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Kunne ikke indlæse sessioner for {{project}}",
|
"toast.session.listFailed.title": "Kunne ikke indlæse sessioner for {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "Opdatering tilgængelig",
|
"toast.update.title": "Opdatering tilgængelig",
|
||||||
@@ -745,7 +733,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Flere muligheder",
|
"common.moreOptions": "Flere muligheder",
|
||||||
"common.learnMore": "Lær mere",
|
"common.learnMore": "Lær mere",
|
||||||
"common.rename": "Omdøb",
|
"common.rename": "Omdøb",
|
||||||
"common.export": "Eksportér",
|
|
||||||
"common.reset": "Nulstil",
|
"common.reset": "Nulstil",
|
||||||
"common.archive": "Arkivér",
|
"common.archive": "Arkivér",
|
||||||
"common.delete": "Slet",
|
"common.delete": "Slet",
|
||||||
|
|||||||
@@ -89,9 +89,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Diese Sitzung teilen und URL in die Zwischenablage kopieren",
|
"command.session.share.description": "Diese Sitzung teilen und URL in die Zwischenablage kopieren",
|
||||||
"command.session.unshare": "Teilen der Sitzung aufheben",
|
"command.session.unshare": "Teilen der Sitzung aufheben",
|
||||||
"command.session.unshare.description": "Teilen dieser Sitzung beenden",
|
"command.session.unshare.description": "Teilen dieser Sitzung beenden",
|
||||||
"command.session.export": "Sitzung exportieren",
|
|
||||||
"command.session.export.description": "Das vollständige Transkript der Sitzung als JSON exportieren",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Dateien, Befehle und Sitzungen durchsuchen",
|
"palette.search.placeholder": "Dateien, Befehle und Sitzungen durchsuchen",
|
||||||
"palette.search.placeholder.home": "Befehle und Sitzungen durchsuchen",
|
"palette.search.placeholder.home": "Befehle und Sitzungen durchsuchen",
|
||||||
"palette.empty": "Keine Ergebnisse gefunden",
|
"palette.empty": "Keine Ergebnisse gefunden",
|
||||||
@@ -428,8 +425,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description":
|
"dialog.project.edit.worktree.startup.description":
|
||||||
"Wird nach dem Erstellen eines neuen Arbeitsbereichs (Worktree) ausgeführt.",
|
"Wird nach dem Erstellen eines neuen Arbeitsbereichs (Worktree) ausgeführt.",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "z. B. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "z. B. bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Nicht mehr anzeigen",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontext-Aufschlüsselung",
|
"context.breakdown.title": "Kontext-Aufschlüsselung",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Ungefähre Aufschlüsselung der Eingabe-Token. "Andere" beinhaltet Werkzeugdefinitionen und Overhead.',
|
'Ungefähre Aufschlüsselung der Eingabe-Token. "Andere" beinhaltet Werkzeugdefinitionen und Overhead.',
|
||||||
@@ -440,8 +435,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Andere",
|
"context.breakdown.other": "Andere",
|
||||||
"context.systemPrompt.title": "System-Prompt",
|
"context.systemPrompt.title": "System-Prompt",
|
||||||
"context.rawMessages.title": "Rohdaten der Nachrichten",
|
"context.rawMessages.title": "Rohdaten der Nachrichten",
|
||||||
"context.export.session": "Sitzung exportieren",
|
|
||||||
|
|
||||||
"context.stats.session": "Sitzung",
|
"context.stats.session": "Sitzung",
|
||||||
"context.stats.messages": "Nachrichten",
|
"context.stats.messages": "Nachrichten",
|
||||||
"context.stats.provider": "Anbieter",
|
"context.stats.provider": "Anbieter",
|
||||||
@@ -508,11 +501,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Teilen der Sitzung erfolgreich aufgehoben!",
|
"toast.session.unshare.success.description": "Teilen der Sitzung erfolgreich aufgehoben!",
|
||||||
"toast.session.unshare.failed.title": "Aufheben des Teilens fehlgeschlagen",
|
"toast.session.unshare.failed.title": "Aufheben des Teilens fehlgeschlagen",
|
||||||
"toast.session.unshare.failed.description": "Beim Aufheben des Teilens ist ein Fehler aufgetreten",
|
"toast.session.unshare.failed.description": "Beim Aufheben des Teilens ist ein Fehler aufgetreten",
|
||||||
"toast.session.export.success.title": "Sitzung exportiert",
|
|
||||||
"toast.session.export.success.description": "Sitzung unter {{filename}} gespeichert",
|
|
||||||
"toast.session.export.failed.title": "Sitzung konnte nicht exportiert werden",
|
|
||||||
"toast.session.export.failed.description": "Beim Exportieren der Sitzung ist ein Fehler aufgetreten",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Sitzungen für {{project}} konnten nicht geladen werden",
|
"toast.session.listFailed.title": "Sitzungen für {{project}} konnten nicht geladen werden",
|
||||||
"toast.update.title": "Update verfügbar",
|
"toast.update.title": "Update verfügbar",
|
||||||
"toast.update.description": "Eine neue Version von OpenCode ({{version}}) ist zur Installation verfügbar.",
|
"toast.update.description": "Eine neue Version von OpenCode ({{version}}) ist zur Installation verfügbar.",
|
||||||
@@ -698,7 +686,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Weitere Optionen",
|
"common.moreOptions": "Weitere Optionen",
|
||||||
"common.learnMore": "Mehr erfahren",
|
"common.learnMore": "Mehr erfahren",
|
||||||
"common.rename": "Umbenennen",
|
"common.rename": "Umbenennen",
|
||||||
"common.export": "Exportieren",
|
|
||||||
"common.reset": "Zurücksetzen",
|
"common.reset": "Zurücksetzen",
|
||||||
"common.archive": "Archivieren",
|
"common.archive": "Archivieren",
|
||||||
"common.delete": "Löschen",
|
"common.delete": "Löschen",
|
||||||
|
|||||||
@@ -3,83 +3,12 @@ import {
|
|||||||
createDesktopNativeBundle,
|
createDesktopNativeBundle,
|
||||||
DESKTOP_NATIVE_ENGLISH,
|
DESKTOP_NATIVE_ENGLISH,
|
||||||
DESKTOP_NATIVE_KEYS,
|
DESKTOP_NATIVE_KEYS,
|
||||||
DESKTOP_NATIVE_LABELS,
|
|
||||||
DESKTOP_NATIVE_LOCALES,
|
|
||||||
DESKTOP_NATIVE_LOCALE_TAGS,
|
|
||||||
detectDesktopNativeLocale,
|
|
||||||
DESKTOP_NATIVE_MAX_PAYLOAD_BYTES,
|
DESKTOP_NATIVE_MAX_PAYLOAD_BYTES,
|
||||||
formatDesktopNativeMessage,
|
formatDesktopNativeMessage,
|
||||||
parseDesktopNativeBundle,
|
parseDesktopNativeBundle,
|
||||||
} from "./desktop-native"
|
} from "./desktop-native"
|
||||||
|
|
||||||
describe("desktop native translations", () => {
|
describe("desktop native translations", () => {
|
||||||
test("uses native language names independent of the active locale", () => {
|
|
||||||
expect(DESKTOP_NATIVE_LOCALES.map((locale) => DESKTOP_NATIVE_LABELS[locale])).toEqual([
|
|
||||||
"English",
|
|
||||||
"简体中文",
|
|
||||||
"繁體中文",
|
|
||||||
"한국어",
|
|
||||||
"Deutsch",
|
|
||||||
"Español",
|
|
||||||
"Français",
|
|
||||||
"Dansk",
|
|
||||||
"日本語",
|
|
||||||
"Polski",
|
|
||||||
"Русский",
|
|
||||||
"Українська",
|
|
||||||
"Bosanski",
|
|
||||||
"العربية",
|
|
||||||
"Norsk",
|
|
||||||
"Português (Brasil)",
|
|
||||||
"ไทย",
|
|
||||||
"Türkçe",
|
|
||||||
"हिन्दी",
|
|
||||||
"Nederlands",
|
|
||||||
"Bahasa Indonesia",
|
|
||||||
"Tiếng Việt",
|
|
||||||
"Italiano",
|
|
||||||
"اردو",
|
|
||||||
"پنجابی",
|
|
||||||
"Azərbaycanca",
|
|
||||||
"Suomi",
|
|
||||||
"Svenska",
|
|
||||||
"አማርኛ",
|
|
||||||
"Български",
|
|
||||||
"বাংলা",
|
|
||||||
"Català",
|
|
||||||
"Čeština",
|
|
||||||
"ދިވެހި",
|
|
||||||
"རྫོང་ཁ",
|
|
||||||
"Ελληνικά",
|
|
||||||
"Eesti",
|
|
||||||
"فارسی",
|
|
||||||
"Føroyskt",
|
|
||||||
"Hrvatski",
|
|
||||||
"Magyar",
|
|
||||||
"Հայերեն",
|
|
||||||
"Íslenska",
|
|
||||||
"ქართული",
|
|
||||||
"ខ្មែរ",
|
|
||||||
"ລາວ",
|
|
||||||
"Lietuvių",
|
|
||||||
"Latviešu",
|
|
||||||
"Македонски",
|
|
||||||
"Монгол",
|
|
||||||
"Bahasa Melayu",
|
|
||||||
"မြန်မာ",
|
|
||||||
"नेपाली",
|
|
||||||
"Română",
|
|
||||||
"සිංහල",
|
|
||||||
"Slovenčina",
|
|
||||||
"Slovenščina",
|
|
||||||
"Shqip",
|
|
||||||
"Српски",
|
|
||||||
"Тоҷикӣ",
|
|
||||||
"Türkmençe",
|
|
||||||
"Oʻzbekcha",
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
test("accepts the exact typed bundle", () => {
|
test("accepts the exact typed bundle", () => {
|
||||||
const bundle = createDesktopNativeBundle("en", (key) => DESKTOP_NATIVE_ENGLISH[key])
|
const bundle = createDesktopNativeBundle("en", (key) => DESKTOP_NATIVE_ENGLISH[key])
|
||||||
expect(parseDesktopNativeBundle(bundle)).toEqual(bundle)
|
expect(parseDesktopNativeBundle(bundle)).toEqual(bundle)
|
||||||
@@ -110,42 +39,3 @@ describe("desktop native translations", () => {
|
|||||||
expect(formatDesktopNativeMessage("{{known}} {{unknown}}", { known: "yes" })).toBe("yes {{unknown}}")
|
expect(formatDesktopNativeMessage("{{known}} {{unknown}}", { known: "yes" })).toBe("yes {{unknown}}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("desktop native locale detection", () => {
|
|
||||||
test("follows preference order and skips invalid or unsupported tags", () => {
|
|
||||||
expect(detectDesktopNativeLocale(["not_a_locale", "fr-FR"])).toBe("fr")
|
|
||||||
expect(detectDesktopNativeLocale(["eo", "de-DE"])).toBe("de")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("uses Unicode likely subtags for script-sensitive bundles", () => {
|
|
||||||
expect(detectDesktopNativeLocale(["zh-TW"])).toBe("zht")
|
|
||||||
expect(detectDesktopNativeLocale(["zh-SG"])).toBe("zh")
|
|
||||||
expect(detectDesktopNativeLocale(["pa-PK"])).toBe("pa")
|
|
||||||
expect(detectDesktopNativeLocale(["pa-IN", "fr"])).toBe("fr")
|
|
||||||
expect(detectDesktopNativeLocale(["az-Cyrl", "de"])).toBe("de")
|
|
||||||
expect(detectDesktopNativeLocale(["sr-Cyrl"])).toBe("sr")
|
|
||||||
expect(detectDesktopNativeLocale(["sr-Latn", "en"])).toBe("en")
|
|
||||||
expect(detectDesktopNativeLocale(["uz-Latn"])).toBe("uz")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("recognizes Norwegian language tags", () => {
|
|
||||||
expect(detectDesktopNativeLocale(["no"])).toBe("no")
|
|
||||||
expect(detectDesktopNativeLocale(["nb-NO"])).toBe("no")
|
|
||||||
expect(detectDesktopNativeLocale(["nn-NO"])).toBe("no")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("desktop native ICU data", () => {
|
|
||||||
test("accepts every locale in standard Intl formatters", () => {
|
|
||||||
for (const locale of DESKTOP_NATIVE_LOCALES) {
|
|
||||||
const tag = DESKTOP_NATIVE_LOCALE_TAGS[locale]
|
|
||||||
expect(() => new Intl.Locale(tag), `${locale} locale`).not.toThrow()
|
|
||||||
expect(() => new Intl.NumberFormat(tag), `${locale} number`).not.toThrow()
|
|
||||||
expect(() => new Intl.DateTimeFormat(tag), `${locale} date`).not.toThrow()
|
|
||||||
expect(() => new Intl.PluralRules(tag), `${locale} plural`).not.toThrow()
|
|
||||||
expect(() => new Intl.ListFormat(tag), `${locale} list`).not.toThrow()
|
|
||||||
expect(() => new Intl.DisplayNames(tag, { type: "language" }), `${locale} names`).not.toThrow()
|
|
||||||
expect(() => new Intl.Segmenter(tag), `${locale} segmenter`).not.toThrow()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -27,200 +27,10 @@ export const DESKTOP_NATIVE_LOCALES = [
|
|||||||
"az",
|
"az",
|
||||||
"fi",
|
"fi",
|
||||||
"sv",
|
"sv",
|
||||||
"am",
|
|
||||||
"bg",
|
|
||||||
"bn",
|
|
||||||
"ca",
|
|
||||||
"cs",
|
|
||||||
"dv",
|
|
||||||
"dz",
|
|
||||||
"el",
|
|
||||||
"et",
|
|
||||||
"fa",
|
|
||||||
"fo",
|
|
||||||
"hr",
|
|
||||||
"hu",
|
|
||||||
"hy",
|
|
||||||
"is",
|
|
||||||
"ka",
|
|
||||||
"km",
|
|
||||||
"lo",
|
|
||||||
"lt",
|
|
||||||
"lv",
|
|
||||||
"mk",
|
|
||||||
"mn",
|
|
||||||
"ms",
|
|
||||||
"my",
|
|
||||||
"ne",
|
|
||||||
"ro",
|
|
||||||
"si",
|
|
||||||
"sk",
|
|
||||||
"sl",
|
|
||||||
"sq",
|
|
||||||
"sr",
|
|
||||||
"tg",
|
|
||||||
"tk",
|
|
||||||
"uz",
|
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type DesktopNativeLocale = (typeof DESKTOP_NATIVE_LOCALES)[number]
|
export type DesktopNativeLocale = (typeof DESKTOP_NATIVE_LOCALES)[number]
|
||||||
|
|
||||||
export const DESKTOP_NATIVE_LABELS: Record<DesktopNativeLocale, string> = {
|
|
||||||
en: "English",
|
|
||||||
zh: "简体中文",
|
|
||||||
zht: "繁體中文",
|
|
||||||
ko: "한국어",
|
|
||||||
de: "Deutsch",
|
|
||||||
es: "Español",
|
|
||||||
fr: "Français",
|
|
||||||
da: "Dansk",
|
|
||||||
ja: "日本語",
|
|
||||||
pl: "Polski",
|
|
||||||
ru: "Русский",
|
|
||||||
uk: "Українська",
|
|
||||||
bs: "Bosanski",
|
|
||||||
ar: "العربية",
|
|
||||||
no: "Norsk",
|
|
||||||
br: "Português (Brasil)",
|
|
||||||
th: "ไทย",
|
|
||||||
tr: "Türkçe",
|
|
||||||
hi: "हिन्दी",
|
|
||||||
nl: "Nederlands",
|
|
||||||
id: "Bahasa Indonesia",
|
|
||||||
vi: "Tiếng Việt",
|
|
||||||
it: "Italiano",
|
|
||||||
ur: "اردو",
|
|
||||||
pa: "پنجابی",
|
|
||||||
az: "Azərbaycanca",
|
|
||||||
fi: "Suomi",
|
|
||||||
sv: "Svenska",
|
|
||||||
am: "አማርኛ",
|
|
||||||
bg: "Български",
|
|
||||||
bn: "বাংলা",
|
|
||||||
ca: "Català",
|
|
||||||
cs: "Čeština",
|
|
||||||
dv: "ދިވެހި",
|
|
||||||
dz: "རྫོང་ཁ",
|
|
||||||
el: "Ελληνικά",
|
|
||||||
et: "Eesti",
|
|
||||||
fa: "فارسی",
|
|
||||||
fo: "Føroyskt",
|
|
||||||
hr: "Hrvatski",
|
|
||||||
hu: "Magyar",
|
|
||||||
hy: "Հայերեն",
|
|
||||||
is: "Íslenska",
|
|
||||||
ka: "ქართული",
|
|
||||||
km: "ខ្មែរ",
|
|
||||||
lo: "ລາວ",
|
|
||||||
lt: "Lietuvių",
|
|
||||||
lv: "Latviešu",
|
|
||||||
mk: "Македонски",
|
|
||||||
mn: "Монгол",
|
|
||||||
ms: "Bahasa Melayu",
|
|
||||||
my: "မြန်မာ",
|
|
||||||
ne: "नेपाली",
|
|
||||||
ro: "Română",
|
|
||||||
si: "සිංහල",
|
|
||||||
sk: "Slovenčina",
|
|
||||||
sl: "Slovenščina",
|
|
||||||
sq: "Shqip",
|
|
||||||
sr: "Српски",
|
|
||||||
tg: "Тоҷикӣ",
|
|
||||||
tk: "Türkmençe",
|
|
||||||
uz: "Oʻzbekcha",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DESKTOP_NATIVE_LOCALE_TAGS: Record<DesktopNativeLocale, string> = {
|
|
||||||
en: "en",
|
|
||||||
zh: "zh-Hans",
|
|
||||||
zht: "zh-Hant",
|
|
||||||
ko: "ko",
|
|
||||||
de: "de",
|
|
||||||
es: "es",
|
|
||||||
fr: "fr",
|
|
||||||
da: "da",
|
|
||||||
ja: "ja",
|
|
||||||
pl: "pl",
|
|
||||||
ru: "ru",
|
|
||||||
uk: "uk",
|
|
||||||
bs: "bs",
|
|
||||||
ar: "ar",
|
|
||||||
no: "nb-NO",
|
|
||||||
br: "pt-BR",
|
|
||||||
th: "th",
|
|
||||||
tr: "tr",
|
|
||||||
hi: "hi-IN",
|
|
||||||
nl: "nl-NL",
|
|
||||||
id: "id-ID",
|
|
||||||
vi: "vi-VN",
|
|
||||||
it: "it-IT",
|
|
||||||
ur: "ur-PK",
|
|
||||||
pa: "pa-Arab-PK",
|
|
||||||
az: "az-Latn-AZ",
|
|
||||||
fi: "fi-FI",
|
|
||||||
sv: "sv-SE",
|
|
||||||
am: "am-ET",
|
|
||||||
bg: "bg-BG",
|
|
||||||
bn: "bn-BD",
|
|
||||||
ca: "ca-AD",
|
|
||||||
cs: "cs-CZ",
|
|
||||||
dv: "dv-MV",
|
|
||||||
dz: "dz-BT",
|
|
||||||
el: "el-GR",
|
|
||||||
et: "et-EE",
|
|
||||||
fa: "fa-IR",
|
|
||||||
fo: "fo-FO",
|
|
||||||
hr: "hr-HR",
|
|
||||||
hu: "hu-HU",
|
|
||||||
hy: "hy-AM",
|
|
||||||
is: "is-IS",
|
|
||||||
ka: "ka-GE",
|
|
||||||
km: "km-KH",
|
|
||||||
lo: "lo-LA",
|
|
||||||
lt: "lt-LT",
|
|
||||||
lv: "lv-LV",
|
|
||||||
mk: "mk-MK",
|
|
||||||
mn: "mn-MN",
|
|
||||||
ms: "ms-MY",
|
|
||||||
my: "my-MM",
|
|
||||||
ne: "ne-NP",
|
|
||||||
ro: "ro-RO",
|
|
||||||
si: "si-LK",
|
|
||||||
sk: "sk-SK",
|
|
||||||
sl: "sl-SI",
|
|
||||||
sq: "sq-AL",
|
|
||||||
sr: "sr-Cyrl-RS",
|
|
||||||
tg: "tg-Cyrl-TJ",
|
|
||||||
tk: "tk-Latn-TM",
|
|
||||||
uz: "uz-Latn-UZ",
|
|
||||||
}
|
|
||||||
|
|
||||||
export function detectDesktopNativeLocale(languages: readonly string[]): DesktopNativeLocale {
|
|
||||||
for (const language of languages) {
|
|
||||||
const source = locale(language)
|
|
||||||
if (!source) continue
|
|
||||||
if (["no", "nb", "nn"].includes(source.language)) return "no"
|
|
||||||
const match = DESKTOP_NATIVE_LOCALES.find((candidate) => {
|
|
||||||
const target = locale(DESKTOP_NATIVE_LOCALE_TAGS[candidate])
|
|
||||||
return target?.language === source.language && target.script === source.script
|
|
||||||
})
|
|
||||||
if (match) return match
|
|
||||||
}
|
|
||||||
return "en"
|
|
||||||
}
|
|
||||||
|
|
||||||
export function desktopNativePluralCategories(locale: DesktopNativeLocale) {
|
|
||||||
return new Intl.PluralRules(DESKTOP_NATIVE_LOCALE_TAGS[locale]).resolvedOptions().pluralCategories
|
|
||||||
}
|
|
||||||
|
|
||||||
function locale(value: string) {
|
|
||||||
try {
|
|
||||||
return new Intl.Locale(value).maximize()
|
|
||||||
} catch {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DESKTOP_NATIVE_ENGLISH = {
|
export const DESKTOP_NATIVE_ENGLISH = {
|
||||||
"desktop.menu.app": "OpenCode",
|
"desktop.menu.app": "OpenCode",
|
||||||
"desktop.menu.file": "File",
|
"desktop.menu.file": "File",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -95,8 +95,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Share this session and copy the URL to clipboard",
|
"command.session.share.description": "Share this session and copy the URL to clipboard",
|
||||||
"command.session.unshare": "Unshare session",
|
"command.session.unshare": "Unshare session",
|
||||||
"command.session.unshare.description": "Stop sharing this session",
|
"command.session.unshare.description": "Stop sharing this session",
|
||||||
"command.session.export": "Export session",
|
|
||||||
"command.session.export.description": "Export the full session transcript as JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Search files, commands, and sessions",
|
"palette.search.placeholder": "Search files, commands, and sessions",
|
||||||
"palette.search.placeholder.home": "Search commands and sessions",
|
"palette.search.placeholder.home": "Search commands and sessions",
|
||||||
@@ -480,7 +478,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Next",
|
"dialog.releaseNotes.action.next": "Next",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Don't show these in the future",
|
"dialog.releaseNotes.action.hideFuture": "Don't show these in the future",
|
||||||
"dialog.releaseNotes.media.alt": "Release preview",
|
"dialog.releaseNotes.media.alt": "Release preview",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Don't show again",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Context Breakdown",
|
"context.breakdown.title": "Context Breakdown",
|
||||||
"context.breakdown.note": 'Approximate breakdown of input tokens. "Other" includes tool definitions and overhead.',
|
"context.breakdown.note": 'Approximate breakdown of input tokens. "Other" includes tool definitions and overhead.',
|
||||||
@@ -492,7 +489,6 @@ export const dict = {
|
|||||||
|
|
||||||
"context.systemPrompt.title": "System Prompt",
|
"context.systemPrompt.title": "System Prompt",
|
||||||
"context.rawMessages.title": "Raw messages",
|
"context.rawMessages.title": "Raw messages",
|
||||||
"context.export.session": "Export session",
|
|
||||||
|
|
||||||
"context.stats.session": "Session",
|
"context.stats.session": "Session",
|
||||||
"context.stats.messages": "Messages",
|
"context.stats.messages": "Messages",
|
||||||
@@ -572,11 +568,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Failed to unshare session",
|
"toast.session.unshare.failed.title": "Failed to unshare session",
|
||||||
"toast.session.unshare.failed.description": "An error occurred while unsharing the session",
|
"toast.session.unshare.failed.description": "An error occurred while unsharing the session",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Session exported",
|
|
||||||
"toast.session.export.success.description": "Saved session to {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Failed to export session",
|
|
||||||
"toast.session.export.failed.description": "An error occurred while exporting the session",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Failed to load sessions for {{project}}",
|
"toast.session.listFailed.title": "Failed to load sessions for {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Failed to reload {{project}}",
|
"toast.project.reloadFailed.title": "Failed to reload {{project}}",
|
||||||
|
|
||||||
@@ -811,7 +802,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "More options",
|
"common.moreOptions": "More options",
|
||||||
"common.learnMore": "Learn more",
|
"common.learnMore": "Learn more",
|
||||||
"common.rename": "Rename",
|
"common.rename": "Rename",
|
||||||
"common.export": "Export",
|
|
||||||
"common.reset": "Reset",
|
"common.reset": "Reset",
|
||||||
"common.archive": "Archive",
|
"common.archive": "Archive",
|
||||||
"common.delete": "Delete",
|
"common.delete": "Delete",
|
||||||
|
|||||||
@@ -193,9 +193,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Dejar de compartir sesión",
|
"command.session.unshare": "Dejar de compartir sesión",
|
||||||
"command.session.unshare.description": "Dejar de compartir esta sesión",
|
"command.session.unshare.description": "Dejar de compartir esta sesión",
|
||||||
|
|
||||||
"command.session.export": "Exportar sesión",
|
|
||||||
"command.session.export.description": "Exportar la transcripción completa de la sesión como JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Buscar archivos, comandos y sesiones",
|
"palette.search.placeholder": "Buscar archivos, comandos y sesiones",
|
||||||
"palette.search.placeholder.home": "Buscar comandos y sesiones",
|
"palette.search.placeholder.home": "Buscar comandos y sesiones",
|
||||||
"palette.empty": "No se encontraron resultados",
|
"palette.empty": "No se encontraron resultados",
|
||||||
@@ -570,8 +567,6 @@ export const dict = {
|
|||||||
"Se ejecuta después de crear un nuevo espacio de trabajo (árbol de trabajo).",
|
"Se ejecuta después de crear un nuevo espacio de trabajo (árbol de trabajo).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "p. ej. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "p. ej. bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "No volver a mostrar",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Desglose del contexto",
|
"context.breakdown.title": "Desglose del contexto",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Desglose aproximado de tokens de entrada. "Otro" incluye definiciones de herramientas y sobrecarga.',
|
'Desglose aproximado de tokens de entrada. "Otro" incluye definiciones de herramientas y sobrecarga.',
|
||||||
@@ -584,8 +579,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Prompt del sistema",
|
"context.systemPrompt.title": "Prompt del sistema",
|
||||||
"context.rawMessages.title": "Mensajes en bruto",
|
"context.rawMessages.title": "Mensajes en bruto",
|
||||||
|
|
||||||
"context.export.session": "Exportar sesión",
|
|
||||||
|
|
||||||
"context.stats.session": "Sesión",
|
"context.stats.session": "Sesión",
|
||||||
"context.stats.messages": "Mensajes",
|
"context.stats.messages": "Mensajes",
|
||||||
"context.stats.provider": "Proveedor",
|
"context.stats.provider": "Proveedor",
|
||||||
@@ -664,11 +657,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Fallo al dejar de compartir sesión",
|
"toast.session.unshare.failed.title": "Fallo al dejar de compartir sesión",
|
||||||
"toast.session.unshare.failed.description": "Ocurrió un error al dejar de compartir la sesión",
|
"toast.session.unshare.failed.description": "Ocurrió un error al dejar de compartir la sesión",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Sesión exportada",
|
|
||||||
"toast.session.export.success.description": "Sesión guardada en {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "No se pudo exportar la sesión",
|
|
||||||
"toast.session.export.failed.description": "Se produjo un error al exportar la sesión",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Fallo al cargar sesiones para {{project}}",
|
"toast.session.listFailed.title": "Fallo al cargar sesiones para {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "Actualización disponible",
|
"toast.update.title": "Actualización disponible",
|
||||||
@@ -873,7 +861,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Más opciones",
|
"common.moreOptions": "Más opciones",
|
||||||
"common.learnMore": "Más información",
|
"common.learnMore": "Más información",
|
||||||
"common.rename": "Renombrar",
|
"common.rename": "Renombrar",
|
||||||
"common.export": "Exportar",
|
|
||||||
"common.reset": "Restablecer",
|
"common.reset": "Restablecer",
|
||||||
"common.archive": "Archivar",
|
"common.archive": "Archivar",
|
||||||
"common.delete": "Eliminar",
|
"common.delete": "Eliminar",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -85,9 +85,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Jaa tämä istunto ja kopioi URL-osoite leikepöydälle",
|
"command.session.share.description": "Jaa tämä istunto ja kopioi URL-osoite leikepöydälle",
|
||||||
"command.session.unshare": "Peru istunnon jakaminen",
|
"command.session.unshare": "Peru istunnon jakaminen",
|
||||||
"command.session.unshare.description": "Lopeta tämän istunnon jakaminen",
|
"command.session.unshare.description": "Lopeta tämän istunnon jakaminen",
|
||||||
"command.session.export": "Vie istunto",
|
|
||||||
"command.session.export.description": "Vie istunnon koko transkriptio JSON-muodossa",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Hae tiedostoja, komentoja ja istuntoja",
|
"palette.search.placeholder": "Hae tiedostoja, komentoja ja istuntoja",
|
||||||
"palette.search.placeholder.home": "Hae komentoja ja istuntoja",
|
"palette.search.placeholder.home": "Hae komentoja ja istuntoja",
|
||||||
"palette.empty": "Tuloksia ei löytynyt",
|
"palette.empty": "Tuloksia ei löytynyt",
|
||||||
@@ -432,8 +429,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Seuraava",
|
"dialog.releaseNotes.action.next": "Seuraava",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Älä näytä näitä jatkossa",
|
"dialog.releaseNotes.action.hideFuture": "Älä näytä näitä jatkossa",
|
||||||
"dialog.releaseNotes.media.alt": "Julkaisun esikatselu",
|
"dialog.releaseNotes.media.alt": "Julkaisun esikatselu",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Älä näytä uudelleen",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontekstin erittely",
|
"context.breakdown.title": "Kontekstin erittely",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Syötetokenien arvioitu jakautuminen. "Muut" sisältää työkalumäärittelyt ja muun oheissisällön.',
|
'Syötetokenien arvioitu jakautuminen. "Muut" sisältää työkalumäärittelyt ja muun oheissisällön.',
|
||||||
@@ -444,8 +439,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Muut",
|
"context.breakdown.other": "Muut",
|
||||||
"context.systemPrompt.title": "Järjestelmäkehote",
|
"context.systemPrompt.title": "Järjestelmäkehote",
|
||||||
"context.rawMessages.title": "Raakaviestit",
|
"context.rawMessages.title": "Raakaviestit",
|
||||||
"context.export.session": "Vie istunto",
|
|
||||||
|
|
||||||
"context.stats.session": "Istunto",
|
"context.stats.session": "Istunto",
|
||||||
"context.stats.messages": "Viestit",
|
"context.stats.messages": "Viestit",
|
||||||
"context.stats.provider": "Palveluntarjoaja",
|
"context.stats.provider": "Palveluntarjoaja",
|
||||||
@@ -512,11 +505,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Istunnon jakaminen peruutettu onnistuneesti!",
|
"toast.session.unshare.success.description": "Istunnon jakaminen peruutettu onnistuneesti!",
|
||||||
"toast.session.unshare.failed.title": "Istunnon jakamisen peruuttaminen epäonnistui",
|
"toast.session.unshare.failed.title": "Istunnon jakamisen peruuttaminen epäonnistui",
|
||||||
"toast.session.unshare.failed.description": "Virhe peruttaessa istunnon jakamista",
|
"toast.session.unshare.failed.description": "Virhe peruttaessa istunnon jakamista",
|
||||||
"toast.session.export.success.title": "Istunto viety",
|
|
||||||
"toast.session.export.success.description": "Istunto tallennettu tiedostoon {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Istunnon vieminen epäonnistui",
|
|
||||||
"toast.session.export.failed.description": "Istuntoa vietäessä tapahtui virhe",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Projektin {{project}} istuntojen lataaminen epäonnistui",
|
"toast.session.listFailed.title": "Projektin {{project}} istuntojen lataaminen epäonnistui",
|
||||||
"toast.project.reloadFailed.title": "Projektin {{project}} lataaminen uudelleen epäonnistui",
|
"toast.project.reloadFailed.title": "Projektin {{project}} lataaminen uudelleen epäonnistui",
|
||||||
"toast.update.title": "Päivitys saatavilla",
|
"toast.update.title": "Päivitys saatavilla",
|
||||||
@@ -734,7 +722,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Lisää vaihtoehtoja",
|
"common.moreOptions": "Lisää vaihtoehtoja",
|
||||||
"common.learnMore": "Lue lisää",
|
"common.learnMore": "Lue lisää",
|
||||||
"common.rename": "Nimeä uudelleen",
|
"common.rename": "Nimeä uudelleen",
|
||||||
"common.export": "Vie",
|
|
||||||
"common.reset": "Palauta",
|
"common.reset": "Palauta",
|
||||||
"common.archive": "Arkistoi",
|
"common.archive": "Arkistoi",
|
||||||
"common.delete": "Poista",
|
"common.delete": "Poista",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -186,9 +186,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Partager cette session et copier l'URL dans le presse-papiers",
|
"command.session.share.description": "Partager cette session et copier l'URL dans le presse-papiers",
|
||||||
"command.session.unshare": "Ne plus partager la session",
|
"command.session.unshare": "Ne plus partager la session",
|
||||||
"command.session.unshare.description": "Arrêter de partager cette session",
|
"command.session.unshare.description": "Arrêter de partager cette session",
|
||||||
"command.session.export": "Exporter la session",
|
|
||||||
"command.session.export.description": "Exporter la transcription intégrale de la session au format JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Rechercher des fichiers, des commandes et des sessions",
|
"palette.search.placeholder": "Rechercher des fichiers, des commandes et des sessions",
|
||||||
"palette.search.placeholder.home": "Rechercher des commandes et des sessions",
|
"palette.search.placeholder.home": "Rechercher des commandes et des sessions",
|
||||||
"palette.empty": "Aucun résultat trouvé",
|
"palette.empty": "Aucun résultat trouvé",
|
||||||
@@ -543,8 +540,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description":
|
"dialog.project.edit.worktree.startup.description":
|
||||||
"S'exécute après la création d'un nouvel espace de travail (arbre de travail).",
|
"S'exécute après la création d'un nouvel espace de travail (arbre de travail).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "p. ex. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "p. ex. bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Ne plus afficher",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Répartition du contexte",
|
"context.breakdown.title": "Répartition du contexte",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
"Répartition approximative des jetons d'entrée. \"Autre\" inclut les définitions d'outils et les données annexes.",
|
"Répartition approximative des jetons d'entrée. \"Autre\" inclut les définitions d'outils et les données annexes.",
|
||||||
@@ -555,8 +550,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Autre",
|
"context.breakdown.other": "Autre",
|
||||||
"context.systemPrompt.title": "Invite système",
|
"context.systemPrompt.title": "Invite système",
|
||||||
"context.rawMessages.title": "Messages bruts",
|
"context.rawMessages.title": "Messages bruts",
|
||||||
"context.export.session": "Exporter la session",
|
|
||||||
|
|
||||||
"context.stats.session": "Session",
|
"context.stats.session": "Session",
|
||||||
"context.stats.messages": "Messages",
|
"context.stats.messages": "Messages",
|
||||||
"context.stats.provider": "Fournisseur",
|
"context.stats.provider": "Fournisseur",
|
||||||
@@ -624,11 +617,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Échec de la désactivation du partage",
|
"toast.session.unshare.failed.title": "Échec de la désactivation du partage",
|
||||||
"toast.session.unshare.failed.description":
|
"toast.session.unshare.failed.description":
|
||||||
"Une erreur s'est produite lors de la désactivation du partage de la session",
|
"Une erreur s'est produite lors de la désactivation du partage de la session",
|
||||||
"toast.session.export.success.title": "Session exportée",
|
|
||||||
"toast.session.export.success.description": "Session enregistrée dans {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Échec de l’exportation de la session",
|
|
||||||
"toast.session.export.failed.description": "Une erreur s’est produite lors de l’exportation de la session",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Échec du chargement des sessions pour {{project}}",
|
"toast.session.listFailed.title": "Échec du chargement des sessions pour {{project}}",
|
||||||
"toast.update.title": "Mise à jour disponible",
|
"toast.update.title": "Mise à jour disponible",
|
||||||
"toast.update.description":
|
"toast.update.description":
|
||||||
@@ -811,7 +799,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Plus d'options",
|
"common.moreOptions": "Plus d'options",
|
||||||
"common.learnMore": "En savoir plus",
|
"common.learnMore": "En savoir plus",
|
||||||
"common.rename": "Renommer",
|
"common.rename": "Renommer",
|
||||||
"common.export": "Exporter",
|
|
||||||
"common.reset": "Réinitialiser",
|
"common.reset": "Réinitialiser",
|
||||||
"common.archive": "Archiver",
|
"common.archive": "Archiver",
|
||||||
"common.delete": "Supprimer",
|
"common.delete": "Supprimer",
|
||||||
|
|||||||
@@ -185,9 +185,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "इस सेशन को साझा करें और URL को क्लिपबोर्ड पर कॉपी करें",
|
"command.session.share.description": "इस सेशन को साझा करें और URL को क्लिपबोर्ड पर कॉपी करें",
|
||||||
"command.session.unshare": "सेशन साझा करना बंद करें",
|
"command.session.unshare": "सेशन साझा करना बंद करें",
|
||||||
"command.session.unshare.description": "इस सेशन को साझा करना बंद करें",
|
"command.session.unshare.description": "इस सेशन को साझा करना बंद करें",
|
||||||
"command.session.export": "सेशन निर्यात करें",
|
|
||||||
"command.session.export.description": "सेशन की पूरी ट्रांसक्रिप्ट को JSON के रूप में निर्यात करें",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "फ़ाइलें, कमांड और सेशन खोजें",
|
"palette.search.placeholder": "फ़ाइलें, कमांड और सेशन खोजें",
|
||||||
"palette.search.placeholder.home": "कमांड और सेशन खोजें",
|
"palette.search.placeholder.home": "कमांड और सेशन खोजें",
|
||||||
"palette.empty": "कोई परिणाम नहीं मिला",
|
"palette.empty": "कोई परिणाम नहीं मिला",
|
||||||
@@ -546,8 +543,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "अगला",
|
"dialog.releaseNotes.action.next": "अगला",
|
||||||
"dialog.releaseNotes.action.hideFuture": "भविष्य में इन्हें न दिखाएँ",
|
"dialog.releaseNotes.action.hideFuture": "भविष्य में इन्हें न दिखाएँ",
|
||||||
"dialog.releaseNotes.media.alt": "रिलीज़ पूर्वावलोकन",
|
"dialog.releaseNotes.media.alt": "रिलीज़ पूर्वावलोकन",
|
||||||
"dialog.usageExceeded.dontShowAgain": "फिर से न दिखाएँ",
|
|
||||||
|
|
||||||
"context.breakdown.title": "कॉन्टेक्स्ट ब्रेकडाउन",
|
"context.breakdown.title": "कॉन्टेक्स्ट ब्रेकडाउन",
|
||||||
"context.breakdown.note": 'इनपुट टोकन का अनुमानित विभाजन। "अन्य" में टूल की परिभाषाएँ और अतिरिक्त खर्च शामिल हैं।',
|
"context.breakdown.note": 'इनपुट टोकन का अनुमानित विभाजन। "अन्य" में टूल की परिभाषाएँ और अतिरिक्त खर्च शामिल हैं।',
|
||||||
"context.breakdown.system": "सिस्टम",
|
"context.breakdown.system": "सिस्टम",
|
||||||
@@ -557,8 +552,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "अन्य",
|
"context.breakdown.other": "अन्य",
|
||||||
"context.systemPrompt.title": "सिस्टम प्रॉम्प्ट",
|
"context.systemPrompt.title": "सिस्टम प्रॉम्प्ट",
|
||||||
"context.rawMessages.title": "मूल संदेश",
|
"context.rawMessages.title": "मूल संदेश",
|
||||||
"context.export.session": "सेशन निर्यात करें",
|
|
||||||
|
|
||||||
"context.stats.session": "सेशन",
|
"context.stats.session": "सेशन",
|
||||||
"context.stats.messages": "संदेश",
|
"context.stats.messages": "संदेश",
|
||||||
"context.stats.provider": "प्रोवाइडर",
|
"context.stats.provider": "प्रोवाइडर",
|
||||||
@@ -625,11 +618,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "सेशन सफलतापूर्वक अनशेयर किया गया!",
|
"toast.session.unshare.success.description": "सेशन सफलतापूर्वक अनशेयर किया गया!",
|
||||||
"toast.session.unshare.failed.title": "सेशन को अनशेयर करने में विफल",
|
"toast.session.unshare.failed.title": "सेशन को अनशेयर करने में विफल",
|
||||||
"toast.session.unshare.failed.description": "सेशन को अनशेयर करते समय एक त्रुटि उत्पन्न हुई",
|
"toast.session.unshare.failed.description": "सेशन को अनशेयर करते समय एक त्रुटि उत्पन्न हुई",
|
||||||
"toast.session.export.success.title": "सेशन निर्यात किया गया",
|
|
||||||
"toast.session.export.success.description": "सेशन को {{filename}} में सहेजा गया",
|
|
||||||
"toast.session.export.failed.title": "सेशन निर्यात करने में विफल",
|
|
||||||
"toast.session.export.failed.description": "सेशन निर्यात करते समय एक त्रुटि हुई",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}} के लिए सेशन लोड करने में विफल",
|
"toast.session.listFailed.title": "{{project}} के लिए सेशन लोड करने में विफल",
|
||||||
"toast.project.reloadFailed.title": "{{project}} को पुनः लोड करने में विफल",
|
"toast.project.reloadFailed.title": "{{project}} को पुनः लोड करने में विफल",
|
||||||
"toast.update.title": "उपलब्ध अद्यतन",
|
"toast.update.title": "उपलब्ध अद्यतन",
|
||||||
@@ -845,7 +833,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "अधिक विकल्प",
|
"common.moreOptions": "अधिक विकल्प",
|
||||||
"common.learnMore": "और अधिक जानें",
|
"common.learnMore": "और अधिक जानें",
|
||||||
"common.rename": "नाम बदलें",
|
"common.rename": "नाम बदलें",
|
||||||
"common.export": "निर्यात करें",
|
|
||||||
"common.reset": "रीसेट करें",
|
"common.reset": "रीसेट करें",
|
||||||
"common.archive": "संग्रहित करें",
|
"common.archive": "संग्रहित करें",
|
||||||
"common.delete": "हटाएँ",
|
"common.delete": "हटाएँ",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -193,9 +193,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Hentikan berbagi",
|
"command.session.unshare": "Hentikan berbagi",
|
||||||
"command.session.unshare.description": "Hentikan berbagi sesi ini",
|
"command.session.unshare.description": "Hentikan berbagi sesi ini",
|
||||||
|
|
||||||
"command.session.export": "Ekspor sesi",
|
|
||||||
"command.session.export.description": "Ekspor transkrip sesi lengkap sebagai JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Cari berkas, perintah, dan sesi",
|
"palette.search.placeholder": "Cari berkas, perintah, dan sesi",
|
||||||
"palette.search.placeholder.home": "Cari perintah dan sesi",
|
"palette.search.placeholder.home": "Cari perintah dan sesi",
|
||||||
"palette.empty": "Hasil tidak ditemukan",
|
"palette.empty": "Hasil tidak ditemukan",
|
||||||
@@ -579,8 +576,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.hideFuture": "Jangan tampilkan ini di masa depan",
|
"dialog.releaseNotes.action.hideFuture": "Jangan tampilkan ini di masa depan",
|
||||||
"dialog.releaseNotes.media.alt": "Pratinjau rilis",
|
"dialog.releaseNotes.media.alt": "Pratinjau rilis",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "Jangan tampilkan lagi",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Rincian Konteks",
|
"context.breakdown.title": "Rincian Konteks",
|
||||||
"context.breakdown.note": 'Perkiraan rincian token masukan. "Lainnya" mencakup definisi alat dan beban tambahan.',
|
"context.breakdown.note": 'Perkiraan rincian token masukan. "Lainnya" mencakup definisi alat dan beban tambahan.',
|
||||||
"context.breakdown.system": "Sistem",
|
"context.breakdown.system": "Sistem",
|
||||||
@@ -592,8 +587,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Prompt Sistem",
|
"context.systemPrompt.title": "Prompt Sistem",
|
||||||
"context.rawMessages.title": "Pesan mentah",
|
"context.rawMessages.title": "Pesan mentah",
|
||||||
|
|
||||||
"context.export.session": "Ekspor sesi",
|
|
||||||
|
|
||||||
"context.stats.session": "Sesi",
|
"context.stats.session": "Sesi",
|
||||||
"context.stats.messages": "Pesan",
|
"context.stats.messages": "Pesan",
|
||||||
"context.stats.provider": "Penyedia",
|
"context.stats.provider": "Penyedia",
|
||||||
@@ -671,11 +664,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Gagal menghentikan berbagi sesi",
|
"toast.session.unshare.failed.title": "Gagal menghentikan berbagi sesi",
|
||||||
"toast.session.unshare.failed.description": "Terjadi kesalahan saat menghentikan berbagi sesi",
|
"toast.session.unshare.failed.description": "Terjadi kesalahan saat menghentikan berbagi sesi",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Sesi diekspor",
|
|
||||||
"toast.session.export.success.description": "Sesi disimpan ke {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Gagal mengekspor sesi",
|
|
||||||
"toast.session.export.failed.description": "Terjadi kesalahan saat mengekspor sesi",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Gagal memuat sesi untuk {{project}}",
|
"toast.session.listFailed.title": "Gagal memuat sesi untuk {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Gagal memuat ulang {{project}}",
|
"toast.project.reloadFailed.title": "Gagal memuat ulang {{project}}",
|
||||||
|
|
||||||
@@ -909,7 +897,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Opsi lainnya",
|
"common.moreOptions": "Opsi lainnya",
|
||||||
"common.learnMore": "Pelajari lebih lanjut",
|
"common.learnMore": "Pelajari lebih lanjut",
|
||||||
"common.rename": "Ganti nama",
|
"common.rename": "Ganti nama",
|
||||||
"common.export": "Ekspor",
|
|
||||||
"common.reset": "Atur ulang",
|
"common.reset": "Atur ulang",
|
||||||
"common.archive": "Arsipkan",
|
"common.archive": "Arsipkan",
|
||||||
"common.delete": "Hapus",
|
"common.delete": "Hapus",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -86,9 +86,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Condividi questa sessione e copia l'URL negli appunti",
|
"command.session.share.description": "Condividi questa sessione e copia l'URL negli appunti",
|
||||||
"command.session.unshare": "Annulla condivisione sessione",
|
"command.session.unshare": "Annulla condivisione sessione",
|
||||||
"command.session.unshare.description": "Interrompi la condivisione di questa sessione",
|
"command.session.unshare.description": "Interrompi la condivisione di questa sessione",
|
||||||
"command.session.export": "Esporta sessione",
|
|
||||||
"command.session.export.description": "Esporta la trascrizione completa della sessione in formato JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Cerca file, comandi e sessioni",
|
"palette.search.placeholder": "Cerca file, comandi e sessioni",
|
||||||
"palette.search.placeholder.home": "Cerca comandi e sessioni",
|
"palette.search.placeholder.home": "Cerca comandi e sessioni",
|
||||||
"palette.empty": "Nessun risultato trovato",
|
"palette.empty": "Nessun risultato trovato",
|
||||||
@@ -450,8 +447,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Avanti",
|
"dialog.releaseNotes.action.next": "Avanti",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Non mostrarli in futuro",
|
"dialog.releaseNotes.action.hideFuture": "Non mostrarli in futuro",
|
||||||
"dialog.releaseNotes.media.alt": "Anteprima delle novità",
|
"dialog.releaseNotes.media.alt": "Anteprima delle novità",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Non mostrare più",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Ripartizione del contesto",
|
"context.breakdown.title": "Ripartizione del contesto",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Ripartizione approssimativa dei token di input. "Altro" include le definizioni degli strumenti e i dati aggiuntivi.',
|
'Ripartizione approssimativa dei token di input. "Altro" include le definizioni degli strumenti e i dati aggiuntivi.',
|
||||||
@@ -462,8 +457,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Altro",
|
"context.breakdown.other": "Altro",
|
||||||
"context.systemPrompt.title": "Prompt di sistema",
|
"context.systemPrompt.title": "Prompt di sistema",
|
||||||
"context.rawMessages.title": "Messaggi non elaborati",
|
"context.rawMessages.title": "Messaggi non elaborati",
|
||||||
"context.export.session": "Esporta sessione",
|
|
||||||
|
|
||||||
"context.stats.session": "Sessione",
|
"context.stats.session": "Sessione",
|
||||||
"context.stats.messages": "Messaggi",
|
"context.stats.messages": "Messaggi",
|
||||||
"context.stats.provider": "Provider",
|
"context.stats.provider": "Provider",
|
||||||
@@ -531,11 +524,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Impossibile annullare la condivisione della sessione",
|
"toast.session.unshare.failed.title": "Impossibile annullare la condivisione della sessione",
|
||||||
"toast.session.unshare.failed.description":
|
"toast.session.unshare.failed.description":
|
||||||
"Si è verificato un errore durante l'annullamento della condivisione della sessione",
|
"Si è verificato un errore durante l'annullamento della condivisione della sessione",
|
||||||
"toast.session.export.success.title": "Sessione esportata",
|
|
||||||
"toast.session.export.success.description": "Sessione salvata in {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Impossibile esportare la sessione",
|
|
||||||
"toast.session.export.failed.description": "Si è verificato un errore durante l’esportazione della sessione",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Impossibile caricare le sessioni per {{project}}",
|
"toast.session.listFailed.title": "Impossibile caricare le sessioni per {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Impossibile ricaricare {{project}}",
|
"toast.project.reloadFailed.title": "Impossibile ricaricare {{project}}",
|
||||||
"toast.update.title": "Aggiornamento disponibile",
|
"toast.update.title": "Aggiornamento disponibile",
|
||||||
@@ -755,7 +743,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Altre opzioni",
|
"common.moreOptions": "Altre opzioni",
|
||||||
"common.learnMore": "Saperne di più",
|
"common.learnMore": "Saperne di più",
|
||||||
"common.rename": "Rinomina",
|
"common.rename": "Rinomina",
|
||||||
"common.export": "Esporta",
|
|
||||||
"common.reset": "Ripristina",
|
"common.reset": "Ripristina",
|
||||||
"common.archive": "Archivia",
|
"common.archive": "Archivia",
|
||||||
"common.delete": "Elimina",
|
"common.delete": "Elimina",
|
||||||
|
|||||||
@@ -184,9 +184,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "このセッションを共有しURLをクリップボードにコピー",
|
"command.session.share.description": "このセッションを共有しURLをクリップボードにコピー",
|
||||||
"command.session.unshare": "セッションの共有を停止",
|
"command.session.unshare": "セッションの共有を停止",
|
||||||
"command.session.unshare.description": "このセッションの共有を停止",
|
"command.session.unshare.description": "このセッションの共有を停止",
|
||||||
"command.session.export": "セッションをエクスポート",
|
|
||||||
"command.session.export.description": "セッションの全記録を JSON としてエクスポート",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "ファイル、コマンド、セッションを検索",
|
"palette.search.placeholder": "ファイル、コマンド、セッションを検索",
|
||||||
"palette.search.placeholder.home": "コマンドとセッションを検索",
|
"palette.search.placeholder.home": "コマンドとセッションを検索",
|
||||||
"palette.empty": "結果が見つかりません",
|
"palette.empty": "結果が見つかりません",
|
||||||
@@ -536,8 +533,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description":
|
"dialog.project.edit.worktree.startup.description":
|
||||||
"新しいワークスペース (ワークツリー) を作成した後に実行されます。",
|
"新しいワークスペース (ワークツリー) を作成した後に実行されます。",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "例: bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "例: bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "今後表示しない",
|
|
||||||
|
|
||||||
"context.breakdown.title": "コンテキストの内訳",
|
"context.breakdown.title": "コンテキストの内訳",
|
||||||
"context.breakdown.note": '入力トークンのおおよその内訳です。"その他"にはツールの定義やオーバーヘッドが含まれます。',
|
"context.breakdown.note": '入力トークンのおおよその内訳です。"その他"にはツールの定義やオーバーヘッドが含まれます。',
|
||||||
"context.breakdown.system": "システム",
|
"context.breakdown.system": "システム",
|
||||||
@@ -547,8 +542,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "その他",
|
"context.breakdown.other": "その他",
|
||||||
"context.systemPrompt.title": "システムプロンプト",
|
"context.systemPrompt.title": "システムプロンプト",
|
||||||
"context.rawMessages.title": "生のメッセージ",
|
"context.rawMessages.title": "生のメッセージ",
|
||||||
"context.export.session": "セッションをエクスポート",
|
|
||||||
|
|
||||||
"context.stats.session": "セッション",
|
"context.stats.session": "セッション",
|
||||||
"context.stats.messages": "メッセージ",
|
"context.stats.messages": "メッセージ",
|
||||||
"context.stats.provider": "プロバイダー",
|
"context.stats.provider": "プロバイダー",
|
||||||
@@ -615,11 +608,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "セッションの共有解除に成功しました!",
|
"toast.session.unshare.success.description": "セッションの共有解除に成功しました!",
|
||||||
"toast.session.unshare.failed.title": "セッションの共有解除に失敗しました",
|
"toast.session.unshare.failed.title": "セッションの共有解除に失敗しました",
|
||||||
"toast.session.unshare.failed.description": "セッションの共有解除中にエラーが発生しました",
|
"toast.session.unshare.failed.description": "セッションの共有解除中にエラーが発生しました",
|
||||||
"toast.session.export.success.title": "セッションをエクスポートしました",
|
|
||||||
"toast.session.export.success.description": "セッションを {{filename}} に保存しました",
|
|
||||||
"toast.session.export.failed.title": "セッションのエクスポートに失敗しました",
|
|
||||||
"toast.session.export.failed.description": "セッションのエクスポート中にエラーが発生しました",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}}のセッション読み込みに失敗しました",
|
"toast.session.listFailed.title": "{{project}}のセッション読み込みに失敗しました",
|
||||||
"toast.update.title": "アップデートが利用可能です",
|
"toast.update.title": "アップデートが利用可能です",
|
||||||
"toast.update.description": "OpenCodeの新しいバージョン ({{version}}) がインストール可能です。",
|
"toast.update.description": "OpenCodeの新しいバージョン ({{version}}) がインストール可能です。",
|
||||||
@@ -793,7 +781,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "その他のオプション",
|
"common.moreOptions": "その他のオプション",
|
||||||
"common.learnMore": "詳細",
|
"common.learnMore": "詳細",
|
||||||
"common.rename": "名前を変更",
|
"common.rename": "名前を変更",
|
||||||
"common.export": "エクスポート",
|
|
||||||
"common.reset": "リセット",
|
"common.reset": "リセット",
|
||||||
"common.archive": "アーカイブ",
|
"common.archive": "アーカイブ",
|
||||||
"common.delete": "削除",
|
"common.delete": "削除",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -81,9 +81,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "이 세션을 공유하고 URL을 클립보드에 복사",
|
"command.session.share.description": "이 세션을 공유하고 URL을 클립보드에 복사",
|
||||||
"command.session.unshare": "세션 공유 중지",
|
"command.session.unshare": "세션 공유 중지",
|
||||||
"command.session.unshare.description": "이 세션 공유 중지",
|
"command.session.unshare.description": "이 세션 공유 중지",
|
||||||
"command.session.export": "세션 내보내기",
|
|
||||||
"command.session.export.description": "전체 세션 기록을 JSON으로 내보내기",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "파일, 명령어 및 세션 검색",
|
"palette.search.placeholder": "파일, 명령어 및 세션 검색",
|
||||||
"palette.search.placeholder.home": "명령어 및 세션 검색",
|
"palette.search.placeholder.home": "명령어 및 세션 검색",
|
||||||
"palette.empty": "결과 없음",
|
"palette.empty": "결과 없음",
|
||||||
@@ -339,8 +336,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup": "작업 공간 시작 스크립트",
|
"dialog.project.edit.worktree.startup": "작업 공간 시작 스크립트",
|
||||||
"dialog.project.edit.worktree.startup.description": "새 작업 공간(작업 트리)을 만든 뒤 실행됩니다.",
|
"dialog.project.edit.worktree.startup.description": "새 작업 공간(작업 트리)을 만든 뒤 실행됩니다.",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "예: bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "예: bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "다시 표시하지 않기",
|
|
||||||
|
|
||||||
"context.breakdown.title": "컨텍스트 분석",
|
"context.breakdown.title": "컨텍스트 분석",
|
||||||
"context.breakdown.note": '입력 토큰의 대략적인 분석입니다. "기타"에는 도구 정의 및 오버헤드가 포함됩니다.',
|
"context.breakdown.note": '입력 토큰의 대략적인 분석입니다. "기타"에는 도구 정의 및 오버헤드가 포함됩니다.',
|
||||||
"context.breakdown.system": "시스템",
|
"context.breakdown.system": "시스템",
|
||||||
@@ -350,8 +345,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "기타",
|
"context.breakdown.other": "기타",
|
||||||
"context.systemPrompt.title": "시스템 프롬프트",
|
"context.systemPrompt.title": "시스템 프롬프트",
|
||||||
"context.rawMessages.title": "원시 메시지",
|
"context.rawMessages.title": "원시 메시지",
|
||||||
"context.export.session": "세션 내보내기",
|
|
||||||
|
|
||||||
"context.stats.session": "세션",
|
"context.stats.session": "세션",
|
||||||
"context.stats.messages": "메시지",
|
"context.stats.messages": "메시지",
|
||||||
"context.stats.provider": "공급자",
|
"context.stats.provider": "공급자",
|
||||||
@@ -417,11 +410,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "세션 공유가 성공적으로 해제되었습니다!",
|
"toast.session.unshare.success.description": "세션 공유가 성공적으로 해제되었습니다!",
|
||||||
"toast.session.unshare.failed.title": "세션 공유 해제 실패",
|
"toast.session.unshare.failed.title": "세션 공유 해제 실패",
|
||||||
"toast.session.unshare.failed.description": "세션 공유를 해제하는 동안 오류가 발생했습니다",
|
"toast.session.unshare.failed.description": "세션 공유를 해제하는 동안 오류가 발생했습니다",
|
||||||
"toast.session.export.success.title": "세션을 내보냈습니다",
|
|
||||||
"toast.session.export.success.description": "세션 저장 위치: {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "세션 내보내기 실패",
|
|
||||||
"toast.session.export.failed.description": "세션을 내보내는 동안 오류가 발생했습니다",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}}에 대한 세션을 로드하지 못했습니다",
|
"toast.session.listFailed.title": "{{project}}에 대한 세션을 로드하지 못했습니다",
|
||||||
"toast.update.title": "업데이트 가능",
|
"toast.update.title": "업데이트 가능",
|
||||||
"toast.update.description": "OpenCode의 새 버전({{version}})을 설치할 수 있습니다.",
|
"toast.update.description": "OpenCode의 새 버전({{version}})을 설치할 수 있습니다.",
|
||||||
@@ -556,7 +544,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "더 많은 옵션",
|
"common.moreOptions": "더 많은 옵션",
|
||||||
"common.learnMore": "더 알아보기",
|
"common.learnMore": "더 알아보기",
|
||||||
"common.rename": "이름 바꾸기",
|
"common.rename": "이름 바꾸기",
|
||||||
"common.export": "내보내기",
|
|
||||||
"common.reset": "초기화",
|
"common.reset": "초기화",
|
||||||
"common.archive": "보관",
|
"common.archive": "보관",
|
||||||
"common.delete": "삭제",
|
"common.delete": "삭제",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -178,9 +178,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Deel deze sessie en kopieer de URL naar het klembord",
|
"command.session.share.description": "Deel deze sessie en kopieer de URL naar het klembord",
|
||||||
"command.session.unshare": "Sessie niet meer delen",
|
"command.session.unshare": "Sessie niet meer delen",
|
||||||
"command.session.unshare.description": "Stop met het delen van deze sessie",
|
"command.session.unshare.description": "Stop met het delen van deze sessie",
|
||||||
"command.session.export": "Sessie exporteren",
|
|
||||||
"command.session.export.description": "Het volledige sessietranscript exporteren als JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Zoek naar bestanden, opdrachten en sessies",
|
"palette.search.placeholder": "Zoek naar bestanden, opdrachten en sessies",
|
||||||
"palette.search.placeholder.home": "Opdrachten en sessies zoeken",
|
"palette.search.placeholder.home": "Opdrachten en sessies zoeken",
|
||||||
"palette.empty": "Geen resultaten gevonden",
|
"palette.empty": "Geen resultaten gevonden",
|
||||||
@@ -542,8 +539,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Volgende",
|
"dialog.releaseNotes.action.next": "Volgende",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Laat deze in de toekomst niet zien",
|
"dialog.releaseNotes.action.hideFuture": "Laat deze in de toekomst niet zien",
|
||||||
"dialog.releaseNotes.media.alt": "Releasevoorbeeld",
|
"dialog.releaseNotes.media.alt": "Releasevoorbeeld",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Niet meer weergeven",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Contextanalyse",
|
"context.breakdown.title": "Contextanalyse",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Geschatte uitsplitsing van invoertokens. "Overig" omvat gereedschapsdefinities en overhead.',
|
'Geschatte uitsplitsing van invoertokens. "Overig" omvat gereedschapsdefinities en overhead.',
|
||||||
@@ -554,8 +549,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Overig",
|
"context.breakdown.other": "Overig",
|
||||||
"context.systemPrompt.title": "Systeemprompt",
|
"context.systemPrompt.title": "Systeemprompt",
|
||||||
"context.rawMessages.title": "Ruwe berichten",
|
"context.rawMessages.title": "Ruwe berichten",
|
||||||
"context.export.session": "Sessie exporteren",
|
|
||||||
|
|
||||||
"context.stats.session": "Sessie",
|
"context.stats.session": "Sessie",
|
||||||
"context.stats.messages": "Berichten",
|
"context.stats.messages": "Berichten",
|
||||||
"context.stats.provider": "Aanbieder",
|
"context.stats.provider": "Aanbieder",
|
||||||
@@ -623,11 +616,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Kan het delen van de sessie niet ongedaan maken",
|
"toast.session.unshare.failed.title": "Kan het delen van de sessie niet ongedaan maken",
|
||||||
"toast.session.unshare.failed.description":
|
"toast.session.unshare.failed.description":
|
||||||
"Er is een fout opgetreden bij het ongedaan maken van het delen van de sessie",
|
"Er is een fout opgetreden bij het ongedaan maken van het delen van de sessie",
|
||||||
"toast.session.export.success.title": "Sessie geëxporteerd",
|
|
||||||
"toast.session.export.success.description": "Sessie opgeslagen in {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Kan sessie niet exporteren",
|
|
||||||
"toast.session.export.failed.description": "Er is een fout opgetreden tijdens het exporteren van de sessie",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Kan sessies voor {{project}} niet laden",
|
"toast.session.listFailed.title": "Kan sessies voor {{project}} niet laden",
|
||||||
"toast.project.reloadFailed.title": "Kan {{project}} niet opnieuw laden",
|
"toast.project.reloadFailed.title": "Kan {{project}} niet opnieuw laden",
|
||||||
"toast.update.title": "Update beschikbaar",
|
"toast.update.title": "Update beschikbaar",
|
||||||
@@ -844,7 +832,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Meer opties",
|
"common.moreOptions": "Meer opties",
|
||||||
"common.learnMore": "Meer informatie",
|
"common.learnMore": "Meer informatie",
|
||||||
"common.rename": "Hernoemen",
|
"common.rename": "Hernoemen",
|
||||||
"common.export": "Exporteren",
|
|
||||||
"common.reset": "Opnieuw instellen",
|
"common.reset": "Opnieuw instellen",
|
||||||
"common.archive": "Archiveren",
|
"common.archive": "Archiveren",
|
||||||
"common.delete": "Verwijderen",
|
"common.delete": "Verwijderen",
|
||||||
|
|||||||
@@ -191,9 +191,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Slutt å dele sesjon",
|
"command.session.unshare": "Slutt å dele sesjon",
|
||||||
"command.session.unshare.description": "Slutt å dele denne sesjonen",
|
"command.session.unshare.description": "Slutt å dele denne sesjonen",
|
||||||
|
|
||||||
"command.session.export": "Eksporter sesjon",
|
|
||||||
"command.session.export.description": "Eksporter hele sesjonsutskriften som JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Søk i filer, kommandoer og sesjoner",
|
"palette.search.placeholder": "Søk i filer, kommandoer og sesjoner",
|
||||||
"palette.search.placeholder.home": "Søk i kommandoer og sesjoner",
|
"palette.search.placeholder.home": "Søk i kommandoer og sesjoner",
|
||||||
"palette.empty": "Ingen resultater funnet",
|
"palette.empty": "Ingen resultater funnet",
|
||||||
@@ -473,8 +470,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description": "Kjører etter at et nytt arbeidsområde (worktree) er opprettet.",
|
"dialog.project.edit.worktree.startup.description": "Kjører etter at et nytt arbeidsområde (worktree) er opprettet.",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "f.eks. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "f.eks. bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "Ikke vis igjen",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontekstfordeling",
|
"context.breakdown.title": "Kontekstfordeling",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Omtrentlig fordeling av inndatatokener. "Annet" inkluderer verktøydefinisjoner og overhead.',
|
'Omtrentlig fordeling av inndatatokener. "Annet" inkluderer verktøydefinisjoner og overhead.',
|
||||||
@@ -487,8 +482,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Systemprompt",
|
"context.systemPrompt.title": "Systemprompt",
|
||||||
"context.rawMessages.title": "Rå meldinger",
|
"context.rawMessages.title": "Rå meldinger",
|
||||||
|
|
||||||
"context.export.session": "Eksporter sesjon",
|
|
||||||
|
|
||||||
"context.stats.session": "Sesjon",
|
"context.stats.session": "Sesjon",
|
||||||
"context.stats.messages": "Meldinger",
|
"context.stats.messages": "Meldinger",
|
||||||
"context.stats.provider": "Leverandør",
|
"context.stats.provider": "Leverandør",
|
||||||
@@ -566,11 +559,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Kunne ikke stoppe deling av sesjon",
|
"toast.session.unshare.failed.title": "Kunne ikke stoppe deling av sesjon",
|
||||||
"toast.session.unshare.failed.description": "Det oppstod en feil da delingen av sesjonen skulle stoppes",
|
"toast.session.unshare.failed.description": "Det oppstod en feil da delingen av sesjonen skulle stoppes",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Sesjon eksportert",
|
|
||||||
"toast.session.export.success.description": "Sesjonen ble lagret i {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Kunne ikke eksportere sesjon",
|
|
||||||
"toast.session.export.failed.description": "Det oppstod en feil under eksport av sesjonen",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Kunne ikke laste sesjoner for {{project}}",
|
"toast.session.listFailed.title": "Kunne ikke laste sesjoner for {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "Oppdatering tilgjengelig",
|
"toast.update.title": "Oppdatering tilgjengelig",
|
||||||
@@ -733,7 +721,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Flere alternativer",
|
"common.moreOptions": "Flere alternativer",
|
||||||
"common.learnMore": "Lær mer",
|
"common.learnMore": "Lær mer",
|
||||||
"common.rename": "Gi nytt navn",
|
"common.rename": "Gi nytt navn",
|
||||||
"common.export": "Eksporter",
|
|
||||||
"common.reset": "Tilbakestill",
|
"common.reset": "Tilbakestill",
|
||||||
"common.archive": "Arkiver",
|
"common.archive": "Arkiver",
|
||||||
"common.delete": "Slett",
|
"common.delete": "Slett",
|
||||||
|
|||||||
@@ -184,9 +184,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "اس سیشن نو شیئر کرو تے URL نو کلپ بورڈ تے کاپی کرو",
|
"command.session.share.description": "اس سیشن نو شیئر کرو تے URL نو کلپ بورڈ تے کاپی کرو",
|
||||||
"command.session.unshare": "سیشن شیئر کرنا بند کرو",
|
"command.session.unshare": "سیشن شیئر کرنا بند کرو",
|
||||||
"command.session.unshare.description": "اس سیشن نو شیئر کرنا بند کرو",
|
"command.session.unshare.description": "اس سیشن نو شیئر کرنا بند کرو",
|
||||||
"command.session.export": "سیشن برآمد کرو",
|
|
||||||
"command.session.export.description": "سیشن دی پوری نقل JSON دی شکل وچ برآمد کرو",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "فائلاں، کمانڈز، تے سیشنز تلاش کرو",
|
"palette.search.placeholder": "فائلاں، کمانڈز، تے سیشنز تلاش کرو",
|
||||||
"palette.search.placeholder.home": "سرچ کمانڈز تے سیشنز",
|
"palette.search.placeholder.home": "سرچ کمانڈز تے سیشنز",
|
||||||
"palette.empty": "کوئی نتیجہ نئیں ملیا",
|
"palette.empty": "کوئی نتیجہ نئیں ملیا",
|
||||||
@@ -547,8 +544,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "اگلا",
|
"dialog.releaseNotes.action.next": "اگلا",
|
||||||
"dialog.releaseNotes.action.hideFuture": "ایہہ اگوں نہ وکھاؤ",
|
"dialog.releaseNotes.action.hideFuture": "ایہہ اگوں نہ وکھاؤ",
|
||||||
"dialog.releaseNotes.media.alt": "ریلیز پیش نظارہ",
|
"dialog.releaseNotes.media.alt": "ریلیز پیش نظارہ",
|
||||||
"dialog.usageExceeded.dontShowAgain": "دوبارہ نہ وکھاؤ",
|
|
||||||
|
|
||||||
"context.breakdown.title": "کانٹیکسٹ دی ونڈ",
|
"context.breakdown.title": "کانٹیکسٹ دی ونڈ",
|
||||||
"context.breakdown.note": 'ان پٹ ٹوکناں دی لگ بھگ ونڈ۔ "ہور" وچ ٹول دیاں تعریفاں تے وادھو خرچ شامل نیں۔',
|
"context.breakdown.note": 'ان پٹ ٹوکناں دی لگ بھگ ونڈ۔ "ہور" وچ ٹول دیاں تعریفاں تے وادھو خرچ شامل نیں۔',
|
||||||
"context.breakdown.system": "نظام",
|
"context.breakdown.system": "نظام",
|
||||||
@@ -558,8 +553,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "ہور",
|
"context.breakdown.other": "ہور",
|
||||||
"context.systemPrompt.title": "سسٹم پرامپٹ",
|
"context.systemPrompt.title": "سسٹم پرامپٹ",
|
||||||
"context.rawMessages.title": "خام سنیہے",
|
"context.rawMessages.title": "خام سنیہے",
|
||||||
"context.export.session": "سیشن برآمد کرو",
|
|
||||||
|
|
||||||
"context.stats.session": "سیشن",
|
"context.stats.session": "سیشن",
|
||||||
"context.stats.messages": "سنیہے",
|
"context.stats.messages": "سنیہے",
|
||||||
"context.stats.provider": "پرووائیڈر",
|
"context.stats.provider": "پرووائیڈر",
|
||||||
@@ -626,11 +619,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "سیشن دا شیئر کامیابی نال بند ہو گیا!",
|
"toast.session.unshare.success.description": "سیشن دا شیئر کامیابی نال بند ہو گیا!",
|
||||||
"toast.session.unshare.failed.title": "سیشن ان شیئر کرن چ ناکام رہیا",
|
"toast.session.unshare.failed.title": "سیشن ان شیئر کرن چ ناکام رہیا",
|
||||||
"toast.session.unshare.failed.description": "سیشن ان شیئر کردے ویلے کوئی غلطی ہو گئی",
|
"toast.session.unshare.failed.description": "سیشن ان شیئر کردے ویلے کوئی غلطی ہو گئی",
|
||||||
"toast.session.export.success.title": "سیشن برآمد ہو گیا",
|
|
||||||
"toast.session.export.success.description": "سیشن نوں \u2068{{filename}}\u2069 وچ محفوظ کر دتا گیا",
|
|
||||||
"toast.session.export.failed.title": "سیشن برآمد کرن چ ناکامی ہوئی",
|
|
||||||
"toast.session.export.failed.description": "سیشن برآمد کردے ویلے اک غلطی ہو گئی",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}} لئی سیشن لوڈ کرن چ ناکام رہیا",
|
"toast.session.listFailed.title": "{{project}} لئی سیشن لوڈ کرن چ ناکام رہیا",
|
||||||
"toast.project.reloadFailed.title": "{{project}} دوبارہ لوڈ نئیں ہو سکیا",
|
"toast.project.reloadFailed.title": "{{project}} دوبارہ لوڈ نئیں ہو سکیا",
|
||||||
"toast.update.title": "اپ ڈیٹ دستیاب اے",
|
"toast.update.title": "اپ ڈیٹ دستیاب اے",
|
||||||
@@ -843,7 +831,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "ہور اختیارات",
|
"common.moreOptions": "ہور اختیارات",
|
||||||
"common.learnMore": "ہور جانو",
|
"common.learnMore": "ہور جانو",
|
||||||
"common.rename": "ناں بدلو",
|
"common.rename": "ناں بدلو",
|
||||||
"common.export": "برآمد کرو",
|
|
||||||
"common.reset": "ری سیٹ کرو",
|
"common.reset": "ری سیٹ کرو",
|
||||||
"common.archive": "آرکائیو کرو",
|
"common.archive": "آرکائیو کرو",
|
||||||
"common.delete": "مکاؤ",
|
"common.delete": "مکاؤ",
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { desktopNativePluralCategories } from "./desktop-native"
|
|
||||||
|
|
||||||
const appLocales = [
|
const appLocales = [
|
||||||
"ar",
|
"ar",
|
||||||
@@ -29,51 +28,19 @@ const appLocales = [
|
|||||||
"az",
|
"az",
|
||||||
"fi",
|
"fi",
|
||||||
"sv",
|
"sv",
|
||||||
"am",
|
|
||||||
"bg",
|
|
||||||
"bn",
|
|
||||||
"ca",
|
|
||||||
"cs",
|
|
||||||
"dv",
|
|
||||||
"dz",
|
|
||||||
"el",
|
|
||||||
"et",
|
|
||||||
"fa",
|
|
||||||
"fo",
|
|
||||||
"hr",
|
|
||||||
"hu",
|
|
||||||
"hy",
|
|
||||||
"is",
|
|
||||||
"ka",
|
|
||||||
"km",
|
|
||||||
"lo",
|
|
||||||
"lt",
|
|
||||||
"lv",
|
|
||||||
"mk",
|
|
||||||
"mn",
|
|
||||||
"ms",
|
|
||||||
"my",
|
|
||||||
"ne",
|
|
||||||
"ro",
|
|
||||||
"si",
|
|
||||||
"sk",
|
|
||||||
"sl",
|
|
||||||
"sq",
|
|
||||||
"sr",
|
|
||||||
"tg",
|
|
||||||
"tk",
|
|
||||||
"uz",
|
|
||||||
] as const
|
] as const
|
||||||
const desktopLocales = appLocales
|
const desktopLocales = appLocales
|
||||||
const pluralCategories = new Map(
|
const pluralCategories: Partial<Record<(typeof appLocales)[number], readonly string[]>> = {
|
||||||
appLocales.map(
|
ar: ["zero", "two", "few", "many"],
|
||||||
(locale) =>
|
br: ["many"],
|
||||||
[
|
bs: ["few"],
|
||||||
locale,
|
es: ["many"],
|
||||||
desktopNativePluralCategories(locale).filter((category) => category !== "one" && category !== "other"),
|
fr: ["many"],
|
||||||
] as const,
|
it: ["many"],
|
||||||
),
|
pl: ["few", "many"],
|
||||||
)
|
ru: ["few", "many"],
|
||||||
|
uk: ["few", "many"],
|
||||||
|
}
|
||||||
|
|
||||||
const domains = [
|
const domains = [
|
||||||
{
|
{
|
||||||
@@ -96,7 +63,7 @@ const domains = [
|
|||||||
},
|
},
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
describe("i18n parity", () => {
|
describe.skipIf(!!process.env.CI)("i18n parity", () => {
|
||||||
test("non-English locales have every English key and required plural variants", async () => {
|
test("non-English locales have every English key and required plural variants", async () => {
|
||||||
for (const domain of domains) {
|
for (const domain of domains) {
|
||||||
const source = await dictionary(domain.source)
|
const source = await dictionary(domain.source)
|
||||||
@@ -107,7 +74,7 @@ describe("i18n parity", () => {
|
|||||||
.filter((key) => !Object.hasOwn(source, key))
|
.filter((key) => !Object.hasOwn(source, key))
|
||||||
.sort()
|
.sort()
|
||||||
const expected = pluralFamilies(source)
|
const expected = pluralFamilies(source)
|
||||||
.flatMap((key) => (pluralCategories.get(locale) ?? []).map((category) => `${key}.${category}`))
|
.flatMap((key) => (pluralCategories[locale] ?? []).map((category) => `${key}.${category}`))
|
||||||
.sort()
|
.sort()
|
||||||
expect({ domain: domain.name, locale, missing, extra }).toEqual({
|
expect({ domain: domain.name, locale, missing, extra }).toEqual({
|
||||||
domain: domain.name,
|
domain: domain.name,
|
||||||
@@ -128,7 +95,7 @@ describe("i18n parity", () => {
|
|||||||
(key) => Object.hasOwn(target, key) && placeholders(source[key]).join() !== placeholders(target[key]).join(),
|
(key) => Object.hasOwn(target, key) && placeholders(source[key]).join() !== placeholders(target[key]).join(),
|
||||||
)
|
)
|
||||||
const pluralMismatched = pluralFamilies(source).flatMap((key) =>
|
const pluralMismatched = pluralFamilies(source).flatMap((key) =>
|
||||||
(pluralCategories.get(locale) ?? [])
|
(pluralCategories[locale] ?? [])
|
||||||
.map((category) => `${key}.${category}`)
|
.map((category) => `${key}.${category}`)
|
||||||
.filter((variant) => placeholders(source[`${key}.other`]).join() !== placeholders(target[variant]).join()),
|
.filter((variant) => placeholders(source[`${key}.other`]).join() !== placeholders(target[variant]).join()),
|
||||||
)
|
)
|
||||||
@@ -177,12 +144,12 @@ describe("i18n plural parity", () => {
|
|||||||
for (const locale of domain.locales) {
|
for (const locale of domain.locales) {
|
||||||
const target = await dictionary(domain.target(locale))
|
const target = await dictionary(domain.target(locale))
|
||||||
const missing = families.flatMap((key) =>
|
const missing = families.flatMap((key) =>
|
||||||
(pluralCategories.get(locale) ?? [])
|
(pluralCategories[locale] ?? [])
|
||||||
.map((category) => `${key}.${category}`)
|
.map((category) => `${key}.${category}`)
|
||||||
.filter((variant) => !Object.hasOwn(target, variant)),
|
.filter((variant) => !Object.hasOwn(target, variant)),
|
||||||
)
|
)
|
||||||
const mismatched = families.flatMap((key) =>
|
const mismatched = families.flatMap((key) =>
|
||||||
(pluralCategories.get(locale) ?? [])
|
(pluralCategories[locale] ?? [])
|
||||||
.map((category) => `${key}.${category}`)
|
.map((category) => `${key}.${category}`)
|
||||||
.filter(
|
.filter(
|
||||||
(variant) =>
|
(variant) =>
|
||||||
|
|||||||
@@ -185,9 +185,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Udostępnij tę sesję i skopiuj adres URL do schowka",
|
"command.session.share.description": "Udostępnij tę sesję i skopiuj adres URL do schowka",
|
||||||
"command.session.unshare": "Przestań udostępniać sesję",
|
"command.session.unshare": "Przestań udostępniać sesję",
|
||||||
"command.session.unshare.description": "Zatrzymaj udostępnianie tej sesji",
|
"command.session.unshare.description": "Zatrzymaj udostępnianie tej sesji",
|
||||||
"command.session.export": "Eksportuj sesję",
|
|
||||||
"command.session.export.description": "Eksportuj pełny zapis sesji w formacie JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Szukaj plików, poleceń i sesji",
|
"palette.search.placeholder": "Szukaj plików, poleceń i sesji",
|
||||||
"palette.search.placeholder.home": "Szukaj poleceń i sesji",
|
"palette.search.placeholder.home": "Szukaj poleceń i sesji",
|
||||||
"palette.empty": "Brak wyników",
|
"palette.empty": "Brak wyników",
|
||||||
@@ -538,8 +535,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description":
|
"dialog.project.edit.worktree.startup.description":
|
||||||
"Uruchamiany po utworzeniu nowej przestrzeni roboczej (worktree).",
|
"Uruchamiany po utworzeniu nowej przestrzeni roboczej (worktree).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "np. bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "np. bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Nie pokazuj ponownie",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Podział kontekstu",
|
"context.breakdown.title": "Podział kontekstu",
|
||||||
"context.breakdown.note": 'Przybliżony podział tokenów wejściowych. "Inne" obejmuje definicje narzędzi i narzut.',
|
"context.breakdown.note": 'Przybliżony podział tokenów wejściowych. "Inne" obejmuje definicje narzędzi i narzut.',
|
||||||
"context.breakdown.system": "System",
|
"context.breakdown.system": "System",
|
||||||
@@ -549,8 +544,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Inne",
|
"context.breakdown.other": "Inne",
|
||||||
"context.systemPrompt.title": "Prompt systemowy",
|
"context.systemPrompt.title": "Prompt systemowy",
|
||||||
"context.rawMessages.title": "Surowe wiadomości",
|
"context.rawMessages.title": "Surowe wiadomości",
|
||||||
"context.export.session": "Eksportuj sesję",
|
|
||||||
|
|
||||||
"context.stats.session": "Sesja",
|
"context.stats.session": "Sesja",
|
||||||
"context.stats.messages": "Wiadomości",
|
"context.stats.messages": "Wiadomości",
|
||||||
"context.stats.provider": "Dostawca",
|
"context.stats.provider": "Dostawca",
|
||||||
@@ -617,11 +610,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Udostępnianie sesji zostało pomyślnie zatrzymane!",
|
"toast.session.unshare.success.description": "Udostępnianie sesji zostało pomyślnie zatrzymane!",
|
||||||
"toast.session.unshare.failed.title": "Nie udało się zatrzymać udostępniania sesji",
|
"toast.session.unshare.failed.title": "Nie udało się zatrzymać udostępniania sesji",
|
||||||
"toast.session.unshare.failed.description": "Wystąpił błąd podczas zatrzymywania udostępniania sesji",
|
"toast.session.unshare.failed.description": "Wystąpił błąd podczas zatrzymywania udostępniania sesji",
|
||||||
"toast.session.export.success.title": "Sesja wyeksportowana",
|
|
||||||
"toast.session.export.success.description": "Sesję zapisano jako {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Nie udało się wyeksportować sesji",
|
|
||||||
"toast.session.export.failed.description": "Wystąpił błąd podczas eksportowania sesji",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Nie udało się załadować sesji dla {{project}}",
|
"toast.session.listFailed.title": "Nie udało się załadować sesji dla {{project}}",
|
||||||
"toast.update.title": "Dostępna aktualizacja",
|
"toast.update.title": "Dostępna aktualizacja",
|
||||||
"toast.update.description": "Nowa wersja OpenCode ({{version}}) jest teraz dostępna do instalacji.",
|
"toast.update.description": "Nowa wersja OpenCode ({{version}}) jest teraz dostępna do instalacji.",
|
||||||
@@ -809,7 +797,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Więcej opcji",
|
"common.moreOptions": "Więcej opcji",
|
||||||
"common.learnMore": "Dowiedz się więcej",
|
"common.learnMore": "Dowiedz się więcej",
|
||||||
"common.rename": "Zmień nazwę",
|
"common.rename": "Zmień nazwę",
|
||||||
"common.export": "Eksportuj",
|
|
||||||
"common.reset": "Resetuj",
|
"common.reset": "Resetuj",
|
||||||
"common.archive": "Archiwizuj",
|
"common.archive": "Archiwizuj",
|
||||||
"common.delete": "Usuń",
|
"common.delete": "Usuń",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -192,9 +192,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Отменить публикацию",
|
"command.session.unshare": "Отменить публикацию",
|
||||||
"command.session.unshare.description": "Прекратить публикацию сессии",
|
"command.session.unshare.description": "Прекратить публикацию сессии",
|
||||||
|
|
||||||
"command.session.export": "Экспортировать сессию",
|
|
||||||
"command.session.export.description": "Экспортировать полную историю сессии в формате JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Поиск файлов, команд и сессий",
|
"palette.search.placeholder": "Поиск файлов, команд и сессий",
|
||||||
"palette.search.placeholder.home": "Поиск команд и сессий",
|
"palette.search.placeholder.home": "Поиск команд и сессий",
|
||||||
"palette.empty": "Ничего не найдено",
|
"palette.empty": "Ничего не найдено",
|
||||||
@@ -567,8 +564,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description":
|
"dialog.project.edit.worktree.startup.description":
|
||||||
"Запускается после создания нового рабочего пространства (worktree).",
|
"Запускается после создания нового рабочего пространства (worktree).",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "например, bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "например, bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Больше не показывать",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Разбивка контекста",
|
"context.breakdown.title": "Разбивка контекста",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Приблизительная разбивка входных токенов. "Другое" включает определения инструментов и накладные расходы.',
|
'Приблизительная разбивка входных токенов. "Другое" включает определения инструментов и накладные расходы.',
|
||||||
@@ -581,8 +576,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Системный промпт",
|
"context.systemPrompt.title": "Системный промпт",
|
||||||
"context.rawMessages.title": "Исходные сообщения",
|
"context.rawMessages.title": "Исходные сообщения",
|
||||||
|
|
||||||
"context.export.session": "Экспортировать сессию",
|
|
||||||
|
|
||||||
"context.stats.session": "Сессия",
|
"context.stats.session": "Сессия",
|
||||||
"context.stats.messages": "Сообщения",
|
"context.stats.messages": "Сообщения",
|
||||||
"context.stats.provider": "Провайдер",
|
"context.stats.provider": "Провайдер",
|
||||||
@@ -660,11 +653,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Не удалось отменить публикацию",
|
"toast.session.unshare.failed.title": "Не удалось отменить публикацию",
|
||||||
"toast.session.unshare.failed.description": "Произошла ошибка при отмене публикации",
|
"toast.session.unshare.failed.description": "Произошла ошибка при отмене публикации",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Сессия экспортирована",
|
|
||||||
"toast.session.export.success.description": "Сессия сохранена в файл {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Не удалось экспортировать сессию",
|
|
||||||
"toast.session.export.failed.description": "Произошла ошибка при экспорте сессии",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Не удалось загрузить сессии для {{project}}",
|
"toast.session.listFailed.title": "Не удалось загрузить сессии для {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "Доступно обновление",
|
"toast.update.title": "Доступно обновление",
|
||||||
@@ -870,7 +858,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Дополнительные опции",
|
"common.moreOptions": "Дополнительные опции",
|
||||||
"common.learnMore": "Подробнее",
|
"common.learnMore": "Подробнее",
|
||||||
"common.rename": "Переименовать",
|
"common.rename": "Переименовать",
|
||||||
"common.export": "Экспортировать",
|
|
||||||
"common.reset": "Сбросить",
|
"common.reset": "Сбросить",
|
||||||
"common.archive": "Архивировать",
|
"common.archive": "Архивировать",
|
||||||
"common.delete": "Удалить",
|
"common.delete": "Удалить",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -179,9 +179,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Dela den här sessionen och kopiera URL:en till urklipp",
|
"command.session.share.description": "Dela den här sessionen och kopiera URL:en till urklipp",
|
||||||
"command.session.unshare": "Sluta dela session",
|
"command.session.unshare": "Sluta dela session",
|
||||||
"command.session.unshare.description": "Sluta dela den här sessionen",
|
"command.session.unshare.description": "Sluta dela den här sessionen",
|
||||||
"command.session.export": "Exportera session",
|
|
||||||
"command.session.export.description": "Exportera hela sessionsutskriften som JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Sök efter filer, kommandon och sessioner",
|
"palette.search.placeholder": "Sök efter filer, kommandon och sessioner",
|
||||||
"palette.search.placeholder.home": "Sök bland kommandon och sessioner",
|
"palette.search.placeholder.home": "Sök bland kommandon och sessioner",
|
||||||
"palette.empty": "Inga resultat hittades",
|
"palette.empty": "Inga resultat hittades",
|
||||||
@@ -541,8 +538,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Nästa",
|
"dialog.releaseNotes.action.next": "Nästa",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Visa inte dessa i framtiden",
|
"dialog.releaseNotes.action.hideFuture": "Visa inte dessa i framtiden",
|
||||||
"dialog.releaseNotes.media.alt": "Förhandsvisning av version",
|
"dialog.releaseNotes.media.alt": "Förhandsvisning av version",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Visa inte igen",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Kontextfördelning",
|
"context.breakdown.title": "Kontextfördelning",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Ungefärlig uppdelning av inmatningstokens. "Övrigt" inkluderar verktygsdefinitioner och overhead.',
|
'Ungefärlig uppdelning av inmatningstokens. "Övrigt" inkluderar verktygsdefinitioner och overhead.',
|
||||||
@@ -553,8 +548,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Övrigt",
|
"context.breakdown.other": "Övrigt",
|
||||||
"context.systemPrompt.title": "Systemprompt",
|
"context.systemPrompt.title": "Systemprompt",
|
||||||
"context.rawMessages.title": "Råmeddelanden",
|
"context.rawMessages.title": "Råmeddelanden",
|
||||||
"context.export.session": "Exportera session",
|
|
||||||
|
|
||||||
"context.stats.session": "Session",
|
"context.stats.session": "Session",
|
||||||
"context.stats.messages": "Meddelanden",
|
"context.stats.messages": "Meddelanden",
|
||||||
"context.stats.provider": "Leverantör",
|
"context.stats.provider": "Leverantör",
|
||||||
@@ -621,11 +614,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Delningen av sessionen har avslutats!",
|
"toast.session.unshare.success.description": "Delningen av sessionen har avslutats!",
|
||||||
"toast.session.unshare.failed.title": "Det gick inte att avsluta delningen",
|
"toast.session.unshare.failed.title": "Det gick inte att avsluta delningen",
|
||||||
"toast.session.unshare.failed.description": "Ett fel uppstod när delningen skulle avslutas",
|
"toast.session.unshare.failed.description": "Ett fel uppstod när delningen skulle avslutas",
|
||||||
"toast.session.export.success.title": "Session exporterad",
|
|
||||||
"toast.session.export.success.description": "Sessionen sparades i {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Det gick inte att exportera sessionen",
|
|
||||||
"toast.session.export.failed.description": "Ett fel uppstod när sessionen exporterades",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Det gick inte att läsa in sessioner för {{project}}",
|
"toast.session.listFailed.title": "Det gick inte att läsa in sessioner för {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Det gick inte att ladda om {{project}}",
|
"toast.project.reloadFailed.title": "Det gick inte att ladda om {{project}}",
|
||||||
"toast.update.title": "Uppdatering tillgänglig",
|
"toast.update.title": "Uppdatering tillgänglig",
|
||||||
@@ -840,7 +828,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Fler alternativ",
|
"common.moreOptions": "Fler alternativ",
|
||||||
"common.learnMore": "Läs mer",
|
"common.learnMore": "Läs mer",
|
||||||
"common.rename": "Byt namn",
|
"common.rename": "Byt namn",
|
||||||
"common.export": "Exportera",
|
|
||||||
"common.reset": "Återställ",
|
"common.reset": "Återställ",
|
||||||
"common.archive": "Arkivera",
|
"common.archive": "Arkivera",
|
||||||
"common.delete": "Radera",
|
"common.delete": "Radera",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -191,9 +191,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "ยกเลิกการแชร์เซสชัน",
|
"command.session.unshare": "ยกเลิกการแชร์เซสชัน",
|
||||||
"command.session.unshare.description": "หยุดการแชร์เซสชันนี้",
|
"command.session.unshare.description": "หยุดการแชร์เซสชันนี้",
|
||||||
|
|
||||||
"command.session.export": "ส่งออกเซสชัน",
|
|
||||||
"command.session.export.description": "ส่งออกบันทึกทั้งหมดของเซสชันเป็น JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "ค้นหาไฟล์ คำสั่ง และเซสชัน",
|
"palette.search.placeholder": "ค้นหาไฟล์ คำสั่ง และเซสชัน",
|
||||||
"palette.search.placeholder.home": "ค้นหาคำสั่งและเซสชัน",
|
"palette.search.placeholder.home": "ค้นหาคำสั่งและเซสชัน",
|
||||||
"palette.empty": "ไม่พบผลลัพธ์",
|
"palette.empty": "ไม่พบผลลัพธ์",
|
||||||
@@ -564,8 +561,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description": "ทำงานหลังจากสร้างพื้นที่ทำงานใหม่ (worktree)",
|
"dialog.project.edit.worktree.startup.description": "ทำงานหลังจากสร้างพื้นที่ทำงานใหม่ (worktree)",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "เช่น bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "เช่น bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "ไม่ต้องแสดงอีก",
|
|
||||||
|
|
||||||
"context.breakdown.title": "การแบ่งบริบท",
|
"context.breakdown.title": "การแบ่งบริบท",
|
||||||
"context.breakdown.note": 'การแบ่งโดยประมาณของโทเค็นนำเข้า "อื่น ๆ" รวมถึงคำนิยามเครื่องมือและโอเวอร์เฮด',
|
"context.breakdown.note": 'การแบ่งโดยประมาณของโทเค็นนำเข้า "อื่น ๆ" รวมถึงคำนิยามเครื่องมือและโอเวอร์เฮด',
|
||||||
"context.breakdown.system": "ระบบ",
|
"context.breakdown.system": "ระบบ",
|
||||||
@@ -577,8 +572,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "พรอมต์ระบบ",
|
"context.systemPrompt.title": "พรอมต์ระบบ",
|
||||||
"context.rawMessages.title": "ข้อความดิบ",
|
"context.rawMessages.title": "ข้อความดิบ",
|
||||||
|
|
||||||
"context.export.session": "ส่งออกเซสชัน",
|
|
||||||
|
|
||||||
"context.stats.session": "เซสชัน",
|
"context.stats.session": "เซสชัน",
|
||||||
"context.stats.messages": "ข้อความ",
|
"context.stats.messages": "ข้อความ",
|
||||||
"context.stats.provider": "ผู้ให้บริการ",
|
"context.stats.provider": "ผู้ให้บริการ",
|
||||||
@@ -657,11 +650,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "ไม่สามารถยกเลิกการแชร์เซสชัน",
|
"toast.session.unshare.failed.title": "ไม่สามารถยกเลิกการแชร์เซสชัน",
|
||||||
"toast.session.unshare.failed.description": "เกิดข้อผิดพลาดระหว่างการยกเลิกการแชร์เซสชัน",
|
"toast.session.unshare.failed.description": "เกิดข้อผิดพลาดระหว่างการยกเลิกการแชร์เซสชัน",
|
||||||
|
|
||||||
"toast.session.export.success.title": "ส่งออกเซสชันแล้ว",
|
|
||||||
"toast.session.export.success.description": "บันทึกเซสชันไปยัง {{filename}} แล้ว",
|
|
||||||
"toast.session.export.failed.title": "ไม่สามารถส่งออกเซสชัน",
|
|
||||||
"toast.session.export.failed.description": "เกิดข้อผิดพลาดขณะส่งออกเซสชัน",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "ไม่สามารถโหลดเซสชันสำหรับ {{project}}",
|
"toast.session.listFailed.title": "ไม่สามารถโหลดเซสชันสำหรับ {{project}}",
|
||||||
|
|
||||||
"toast.update.title": "มีการอัปเดต",
|
"toast.update.title": "มีการอัปเดต",
|
||||||
@@ -855,7 +843,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "ตัวเลือกเพิ่มเติม",
|
"common.moreOptions": "ตัวเลือกเพิ่มเติม",
|
||||||
"common.learnMore": "เรียนรู้เพิ่มเติม",
|
"common.learnMore": "เรียนรู้เพิ่มเติม",
|
||||||
"common.rename": "เปลี่ยนชื่อ",
|
"common.rename": "เปลี่ยนชื่อ",
|
||||||
"common.export": "ส่งออก",
|
|
||||||
"common.reset": "รีเซ็ต",
|
"common.reset": "รีเซ็ต",
|
||||||
"common.archive": "จัดเก็บ",
|
"common.archive": "จัดเก็บ",
|
||||||
"common.delete": "ลบ",
|
"common.delete": "ลบ",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -197,9 +197,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Paylaşımı kaldır",
|
"command.session.unshare": "Paylaşımı kaldır",
|
||||||
"command.session.unshare.description": "Bu oturumun paylaşımını durdur",
|
"command.session.unshare.description": "Bu oturumun paylaşımını durdur",
|
||||||
|
|
||||||
"command.session.export": "Oturumu dışa aktar",
|
|
||||||
"command.session.export.description": "Oturumun tam dökümünü JSON olarak dışa aktar",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Dosya, komut ve oturum ara",
|
"palette.search.placeholder": "Dosya, komut ve oturum ara",
|
||||||
"palette.search.placeholder.home": "Komut ve oturum ara",
|
"palette.search.placeholder.home": "Komut ve oturum ara",
|
||||||
"palette.empty": "Sonuç bulunamadı",
|
"palette.empty": "Sonuç bulunamadı",
|
||||||
@@ -572,8 +569,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description": "Yeni bir çalışma alanı (worktree) oluşturduktan sonra çalışır.",
|
"dialog.project.edit.worktree.startup.description": "Yeni bir çalışma alanı (worktree) oluşturduktan sonra çalışır.",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "örneğin bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "örneğin bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "Bir daha gösterme",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Bağlam Dökümü",
|
"context.breakdown.title": "Bağlam Dökümü",
|
||||||
"context.breakdown.note": 'Girdi tokenlerinin yaklaşık dökümü. "Diğer" araç tanımları ve ek yükleri içerir.',
|
"context.breakdown.note": 'Girdi tokenlerinin yaklaşık dökümü. "Diğer" araç tanımları ve ek yükleri içerir.',
|
||||||
"context.breakdown.system": "Sistem",
|
"context.breakdown.system": "Sistem",
|
||||||
@@ -585,8 +580,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Sistem İstemi",
|
"context.systemPrompt.title": "Sistem İstemi",
|
||||||
"context.rawMessages.title": "Ham mesajlar",
|
"context.rawMessages.title": "Ham mesajlar",
|
||||||
|
|
||||||
"context.export.session": "Oturumu dışa aktar",
|
|
||||||
|
|
||||||
"context.stats.session": "Oturum",
|
"context.stats.session": "Oturum",
|
||||||
"context.stats.messages": "Mesajlar",
|
"context.stats.messages": "Mesajlar",
|
||||||
"context.stats.provider": "Sağlayıcı",
|
"context.stats.provider": "Sağlayıcı",
|
||||||
@@ -665,11 +658,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Oturum paylaşımı kaldırılamadı",
|
"toast.session.unshare.failed.title": "Oturum paylaşımı kaldırılamadı",
|
||||||
"toast.session.unshare.failed.description": "Oturum paylaşımı kaldırılırken bir hata oluştu",
|
"toast.session.unshare.failed.description": "Oturum paylaşımı kaldırılırken bir hata oluştu",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Oturum dışa aktarıldı",
|
|
||||||
"toast.session.export.success.description": "Oturum {{filename}} dosyasına kaydedildi",
|
|
||||||
"toast.session.export.failed.title": "Oturum dışa aktarılamadı",
|
|
||||||
"toast.session.export.failed.description": "Oturum dışa aktarılırken bir hata oluştu",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}} için oturumlar yüklenemedi",
|
"toast.session.listFailed.title": "{{project}} için oturumlar yüklenemedi",
|
||||||
|
|
||||||
"toast.update.title": "Güncelleme mevcut",
|
"toast.update.title": "Güncelleme mevcut",
|
||||||
@@ -873,7 +861,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Daha fazla seçenek",
|
"common.moreOptions": "Daha fazla seçenek",
|
||||||
"common.learnMore": "Daha fazla bilgi",
|
"common.learnMore": "Daha fazla bilgi",
|
||||||
"common.rename": "Yeniden adlandır",
|
"common.rename": "Yeniden adlandır",
|
||||||
"common.export": "Dışa aktar",
|
|
||||||
"common.reset": "Sıfırla",
|
"common.reset": "Sıfırla",
|
||||||
"common.archive": "Arşivle",
|
"common.archive": "Arşivle",
|
||||||
"common.delete": "Sil",
|
"common.delete": "Sil",
|
||||||
|
|||||||
@@ -193,9 +193,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "Припинити поширення сесії",
|
"command.session.unshare": "Припинити поширення сесії",
|
||||||
"command.session.unshare.description": "Припинити поширення цієї сесії",
|
"command.session.unshare.description": "Припинити поширення цієї сесії",
|
||||||
|
|
||||||
"command.session.export": "Експортувати сесію",
|
|
||||||
"command.session.export.description": "Експортувати повну історію сесії у форматі JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Пошук файлів, команд і сесій",
|
"palette.search.placeholder": "Пошук файлів, команд і сесій",
|
||||||
"palette.search.placeholder.home": "Пошук команд і сесій",
|
"palette.search.placeholder.home": "Пошук команд і сесій",
|
||||||
"palette.empty": "Результатів не знайдено",
|
"palette.empty": "Результатів не знайдено",
|
||||||
@@ -581,8 +578,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.hideFuture": "Не показувати це в майбутньому",
|
"dialog.releaseNotes.action.hideFuture": "Не показувати це в майбутньому",
|
||||||
"dialog.releaseNotes.media.alt": "Попередній перегляд релізу",
|
"dialog.releaseNotes.media.alt": "Попередній перегляд релізу",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "Більше не показувати",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Розподіл контексту",
|
"context.breakdown.title": "Розподіл контексту",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Приблизний розподіл вхідних токенів. "Інше" включає визначення інструментів і накладні витрати.',
|
'Приблизний розподіл вхідних токенів. "Інше" включає визначення інструментів і накладні витрати.',
|
||||||
@@ -595,8 +590,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "Системний запит",
|
"context.systemPrompt.title": "Системний запит",
|
||||||
"context.rawMessages.title": "Необроблені повідомлення",
|
"context.rawMessages.title": "Необроблені повідомлення",
|
||||||
|
|
||||||
"context.export.session": "Експортувати сесію",
|
|
||||||
|
|
||||||
"context.stats.session": "Сесія",
|
"context.stats.session": "Сесія",
|
||||||
"context.stats.messages": "Повідомлення",
|
"context.stats.messages": "Повідомлення",
|
||||||
"context.stats.provider": "Провайдер",
|
"context.stats.provider": "Провайдер",
|
||||||
@@ -675,11 +668,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "Не вдалося припинити поширення сесії",
|
"toast.session.unshare.failed.title": "Не вдалося припинити поширення сесії",
|
||||||
"toast.session.unshare.failed.description": "Під час припинення поширення сесії сталася помилка",
|
"toast.session.unshare.failed.description": "Під час припинення поширення сесії сталася помилка",
|
||||||
|
|
||||||
"toast.session.export.success.title": "Сесію експортовано",
|
|
||||||
"toast.session.export.success.description": "Сесію збережено у файл {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Не вдалося експортувати сесію",
|
|
||||||
"toast.session.export.failed.description": "Під час експортування сесії сталася помилка",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Не вдалося завантажити сесії для {{project}}",
|
"toast.session.listFailed.title": "Не вдалося завантажити сесії для {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Не вдалося перезавантажити {{project}}",
|
"toast.project.reloadFailed.title": "Не вдалося перезавантажити {{project}}",
|
||||||
|
|
||||||
@@ -922,7 +910,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Більше параметрів",
|
"common.moreOptions": "Більше параметрів",
|
||||||
"common.learnMore": "Дізнатися більше",
|
"common.learnMore": "Дізнатися більше",
|
||||||
"common.rename": "Перейменувати",
|
"common.rename": "Перейменувати",
|
||||||
"common.export": "Експортувати",
|
|
||||||
"common.reset": "Скинути",
|
"common.reset": "Скинути",
|
||||||
"common.archive": "Архівувати",
|
"common.archive": "Архівувати",
|
||||||
"common.delete": "Видалити",
|
"common.delete": "Видалити",
|
||||||
|
|||||||
@@ -186,9 +186,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "اس سیشن کا اشتراک کریں اور URL کو کلپ بورڈ میں کاپی کریں۔",
|
"command.session.share.description": "اس سیشن کا اشتراک کریں اور URL کو کلپ بورڈ میں کاپی کریں۔",
|
||||||
"command.session.unshare": "سیشن کا اشتراک ختم کریں۔",
|
"command.session.unshare": "سیشن کا اشتراک ختم کریں۔",
|
||||||
"command.session.unshare.description": "اس سیشن کا اشتراک کرنا بند کریں۔",
|
"command.session.unshare.description": "اس سیشن کا اشتراک کرنا بند کریں۔",
|
||||||
"command.session.export": "سیشن برآمد کریں",
|
|
||||||
"command.session.export.description": "سیشن کی مکمل نقل JSON کی صورت میں برآمد کریں",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "فائلیں، کمانڈز اور سیشنز تلاش کریں۔",
|
"palette.search.placeholder": "فائلیں، کمانڈز اور سیشنز تلاش کریں۔",
|
||||||
"palette.search.placeholder.home": "کمانڈز اور سیشن تلاش کریں۔",
|
"palette.search.placeholder.home": "کمانڈز اور سیشن تلاش کریں۔",
|
||||||
"palette.empty": "کوئی نتیجہ نہیں ملا",
|
"palette.empty": "کوئی نتیجہ نہیں ملا",
|
||||||
@@ -549,8 +546,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "اگلا",
|
"dialog.releaseNotes.action.next": "اگلا",
|
||||||
"dialog.releaseNotes.action.hideFuture": "مستقبل میں یہ نہ دکھائیں۔",
|
"dialog.releaseNotes.action.hideFuture": "مستقبل میں یہ نہ دکھائیں۔",
|
||||||
"dialog.releaseNotes.media.alt": "ریلیز کا پیش منظر",
|
"dialog.releaseNotes.media.alt": "ریلیز کا پیش منظر",
|
||||||
"dialog.usageExceeded.dontShowAgain": "دوبارہ نہ دکھائیں",
|
|
||||||
|
|
||||||
"context.breakdown.title": "سیاق و سباق کی تفصیل",
|
"context.breakdown.title": "سیاق و سباق کی تفصیل",
|
||||||
"context.breakdown.note": 'ان پٹ ٹوکنز کی تخمینی تقسیم۔ "دیگر" میں ٹول کی تعریفیں اور اضافی بوجھ شامل ہیں۔',
|
"context.breakdown.note": 'ان پٹ ٹوکنز کی تخمینی تقسیم۔ "دیگر" میں ٹول کی تعریفیں اور اضافی بوجھ شامل ہیں۔',
|
||||||
"context.breakdown.system": "سسٹم",
|
"context.breakdown.system": "سسٹم",
|
||||||
@@ -560,8 +555,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "دیگر",
|
"context.breakdown.other": "دیگر",
|
||||||
"context.systemPrompt.title": "سسٹم پرامپٹ",
|
"context.systemPrompt.title": "سسٹم پرامپٹ",
|
||||||
"context.rawMessages.title": "خام پیغامات",
|
"context.rawMessages.title": "خام پیغامات",
|
||||||
"context.export.session": "سیشن برآمد کریں",
|
|
||||||
|
|
||||||
"context.stats.session": "سیشن",
|
"context.stats.session": "سیشن",
|
||||||
"context.stats.messages": "پیغامات",
|
"context.stats.messages": "پیغامات",
|
||||||
"context.stats.provider": "فراہم کنندہ",
|
"context.stats.provider": "فراہم کنندہ",
|
||||||
@@ -628,11 +621,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "سیشن کا اشتراک کامیابی سے ختم ہو گیا!",
|
"toast.session.unshare.success.description": "سیشن کا اشتراک کامیابی سے ختم ہو گیا!",
|
||||||
"toast.session.unshare.failed.title": "سیشن کا اشتراک ختم کرنے میں ناکام",
|
"toast.session.unshare.failed.title": "سیشن کا اشتراک ختم کرنے میں ناکام",
|
||||||
"toast.session.unshare.failed.description": "سیشن کا اشتراک ختم کرتے وقت ایک خرابی پیش آگئی",
|
"toast.session.unshare.failed.description": "سیشن کا اشتراک ختم کرتے وقت ایک خرابی پیش آگئی",
|
||||||
"toast.session.export.success.title": "سیشن برآمد کر دیا گیا",
|
|
||||||
"toast.session.export.success.description": "سیشن کو \u2068{{filename}}\u2069 میں محفوظ کر دیا گیا",
|
|
||||||
"toast.session.export.failed.title": "سیشن برآمد کرنے میں ناکام",
|
|
||||||
"toast.session.export.failed.description": "سیشن برآمد کرتے وقت ایک خرابی پیش آ گئی",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "{{project}} کے لیے سیشن لوڈ کرنے میں ناکام",
|
"toast.session.listFailed.title": "{{project}} کے لیے سیشن لوڈ کرنے میں ناکام",
|
||||||
"toast.project.reloadFailed.title": "{{project}} کو دوبارہ لوڈ کرنے میں ناکام",
|
"toast.project.reloadFailed.title": "{{project}} کو دوبارہ لوڈ کرنے میں ناکام",
|
||||||
"toast.update.title": "اپ ڈیٹ دستیاب ہے۔",
|
"toast.update.title": "اپ ڈیٹ دستیاب ہے۔",
|
||||||
@@ -846,7 +834,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "مزید اختیارات",
|
"common.moreOptions": "مزید اختیارات",
|
||||||
"common.learnMore": "مزید جانیں",
|
"common.learnMore": "مزید جانیں",
|
||||||
"common.rename": "نام تبدیل کریں۔",
|
"common.rename": "نام تبدیل کریں۔",
|
||||||
"common.export": "برآمد کریں",
|
|
||||||
"common.reset": "دوبارہ ترتیب دیں۔",
|
"common.reset": "دوبارہ ترتیب دیں۔",
|
||||||
"common.archive": "آرکائیو کریں",
|
"common.archive": "آرکائیو کریں",
|
||||||
"common.delete": "حذف کریں۔",
|
"common.delete": "حذف کریں۔",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -185,9 +185,6 @@ export const dict = {
|
|||||||
"command.session.share.description": "Chia sẻ phiên này và sao chép URL vào bảng tạm",
|
"command.session.share.description": "Chia sẻ phiên này và sao chép URL vào bảng tạm",
|
||||||
"command.session.unshare": "Ngừng chia sẻ phiên",
|
"command.session.unshare": "Ngừng chia sẻ phiên",
|
||||||
"command.session.unshare.description": "Dừng chia sẻ phiên này",
|
"command.session.unshare.description": "Dừng chia sẻ phiên này",
|
||||||
"command.session.export": "Xuất phiên",
|
|
||||||
"command.session.export.description": "Xuất toàn bộ bản ghi phiên dưới dạng JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "Tìm kiếm tệp, lệnh và phiên",
|
"palette.search.placeholder": "Tìm kiếm tệp, lệnh và phiên",
|
||||||
"palette.search.placeholder.home": "Tìm kiếm lệnh và phiên",
|
"palette.search.placeholder.home": "Tìm kiếm lệnh và phiên",
|
||||||
"palette.empty": "Không tìm thấy kết quả nào",
|
"palette.empty": "Không tìm thấy kết quả nào",
|
||||||
@@ -546,8 +543,6 @@ export const dict = {
|
|||||||
"dialog.releaseNotes.action.next": "Tiếp theo",
|
"dialog.releaseNotes.action.next": "Tiếp theo",
|
||||||
"dialog.releaseNotes.action.hideFuture": "Không hiển thị lại",
|
"dialog.releaseNotes.action.hideFuture": "Không hiển thị lại",
|
||||||
"dialog.releaseNotes.media.alt": "Xem trước bản phát hành",
|
"dialog.releaseNotes.media.alt": "Xem trước bản phát hành",
|
||||||
"dialog.usageExceeded.dontShowAgain": "Không hiển thị lại",
|
|
||||||
|
|
||||||
"context.breakdown.title": "Phân tích ngữ cảnh",
|
"context.breakdown.title": "Phân tích ngữ cảnh",
|
||||||
"context.breakdown.note":
|
"context.breakdown.note":
|
||||||
'Phân tích gần đúng của token đầu vào. "Khác" bao gồm các định nghĩa công cụ và chi phí chung.',
|
'Phân tích gần đúng của token đầu vào. "Khác" bao gồm các định nghĩa công cụ và chi phí chung.',
|
||||||
@@ -558,8 +553,6 @@ export const dict = {
|
|||||||
"context.breakdown.other": "Khác",
|
"context.breakdown.other": "Khác",
|
||||||
"context.systemPrompt.title": "Lời nhắc hệ thống",
|
"context.systemPrompt.title": "Lời nhắc hệ thống",
|
||||||
"context.rawMessages.title": "Tin nhắn thô",
|
"context.rawMessages.title": "Tin nhắn thô",
|
||||||
"context.export.session": "Xuất phiên",
|
|
||||||
|
|
||||||
"context.stats.session": "Phiên",
|
"context.stats.session": "Phiên",
|
||||||
"context.stats.messages": "Tin nhắn",
|
"context.stats.messages": "Tin nhắn",
|
||||||
"context.stats.provider": "Nhà cung cấp",
|
"context.stats.provider": "Nhà cung cấp",
|
||||||
@@ -626,11 +619,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "Đã hủy chia sẻ phiên thành công!",
|
"toast.session.unshare.success.description": "Đã hủy chia sẻ phiên thành công!",
|
||||||
"toast.session.unshare.failed.title": "Không hủy chia sẻ được phiên",
|
"toast.session.unshare.failed.title": "Không hủy chia sẻ được phiên",
|
||||||
"toast.session.unshare.failed.description": "Đã xảy ra lỗi khi hủy chia sẻ phiên",
|
"toast.session.unshare.failed.description": "Đã xảy ra lỗi khi hủy chia sẻ phiên",
|
||||||
"toast.session.export.success.title": "Đã xuất phiên",
|
|
||||||
"toast.session.export.success.description": "Đã lưu phiên vào {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "Không thể xuất phiên",
|
|
||||||
"toast.session.export.failed.description": "Đã xảy ra lỗi khi xuất phiên",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "Không thể tải phiên cho {{project}}",
|
"toast.session.listFailed.title": "Không thể tải phiên cho {{project}}",
|
||||||
"toast.project.reloadFailed.title": "Không thể tải lại {{project}}",
|
"toast.project.reloadFailed.title": "Không thể tải lại {{project}}",
|
||||||
"toast.update.title": "Đã có bản cập nhật",
|
"toast.update.title": "Đã có bản cập nhật",
|
||||||
@@ -846,7 +834,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "Nhiều lựa chọn hơn",
|
"common.moreOptions": "Nhiều lựa chọn hơn",
|
||||||
"common.learnMore": "Tìm hiểu thêm",
|
"common.learnMore": "Tìm hiểu thêm",
|
||||||
"common.rename": "Đổi tên",
|
"common.rename": "Đổi tên",
|
||||||
"common.export": "Xuất",
|
|
||||||
"common.reset": "Đặt lại",
|
"common.reset": "Đặt lại",
|
||||||
"common.archive": "Lưu trữ",
|
"common.archive": "Lưu trữ",
|
||||||
"common.delete": "Xóa",
|
"common.delete": "Xóa",
|
||||||
|
|||||||
@@ -218,9 +218,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "取消分享会话",
|
"command.session.unshare": "取消分享会话",
|
||||||
"command.session.unshare.description": "停止分享此会话",
|
"command.session.unshare.description": "停止分享此会话",
|
||||||
|
|
||||||
"command.session.export": "导出会话",
|
|
||||||
"command.session.export.description": "将完整会话记录导出为 JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "搜索文件、命令和会话",
|
"palette.search.placeholder": "搜索文件、命令和会话",
|
||||||
"palette.search.placeholder.home": "搜索命令和会话",
|
"palette.search.placeholder.home": "搜索命令和会话",
|
||||||
"palette.empty": "未找到结果",
|
"palette.empty": "未找到结果",
|
||||||
@@ -580,10 +577,8 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup.description": "创建新工作区 (worktree) 后运行。",
|
"dialog.project.edit.worktree.startup.description": "创建新工作区 (worktree) 后运行。",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "例如 bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "例如 bun install",
|
||||||
|
|
||||||
"dialog.usageExceeded.dontShowAgain": "不再显示",
|
|
||||||
|
|
||||||
"context.breakdown.title": "上下文细分",
|
"context.breakdown.title": "上下文细分",
|
||||||
"context.breakdown.note": "输入词元的大致细分。“其他”包含工具定义和开销。",
|
"context.breakdown.note": "输入令牌的大致细分。“其他”包含工具定义和开销。",
|
||||||
"context.breakdown.system": "系统",
|
"context.breakdown.system": "系统",
|
||||||
"context.breakdown.user": "用户",
|
"context.breakdown.user": "用户",
|
||||||
"context.breakdown.assistant": "助手",
|
"context.breakdown.assistant": "助手",
|
||||||
@@ -591,25 +586,23 @@ export const dict = {
|
|||||||
"context.breakdown.other": "其他",
|
"context.breakdown.other": "其他",
|
||||||
"context.systemPrompt.title": "系统提示词",
|
"context.systemPrompt.title": "系统提示词",
|
||||||
"context.rawMessages.title": "原始消息",
|
"context.rawMessages.title": "原始消息",
|
||||||
"context.export.session": "导出会话",
|
|
||||||
|
|
||||||
"context.stats.session": "会话",
|
"context.stats.session": "会话",
|
||||||
"context.stats.messages": "消息数",
|
"context.stats.messages": "消息数",
|
||||||
"context.stats.provider": "提供商",
|
"context.stats.provider": "提供商",
|
||||||
"context.stats.model": "模型",
|
"context.stats.model": "模型",
|
||||||
"context.stats.limit": "上下文限制",
|
"context.stats.limit": "上下文限制",
|
||||||
"context.stats.totalTokens": "词元总数",
|
"context.stats.totalTokens": "令牌总数",
|
||||||
"context.stats.usage": "使用率",
|
"context.stats.usage": "使用率",
|
||||||
"context.stats.inputTokens": "输入词元",
|
"context.stats.inputTokens": "输入令牌",
|
||||||
"context.stats.outputTokens": "输出词元",
|
"context.stats.outputTokens": "输出令牌",
|
||||||
"context.stats.reasoningTokens": "推理词元",
|
"context.stats.reasoningTokens": "推理令牌",
|
||||||
"context.stats.cacheTokens": "缓存词元(读/写)",
|
"context.stats.cacheTokens": "缓存令牌(读/写)",
|
||||||
"context.stats.userMessages": "用户消息",
|
"context.stats.userMessages": "用户消息",
|
||||||
"context.stats.assistantMessages": "助手消息",
|
"context.stats.assistantMessages": "助手消息",
|
||||||
"context.stats.totalCost": "总成本",
|
"context.stats.totalCost": "总成本",
|
||||||
"context.stats.sessionCreated": "创建时间",
|
"context.stats.sessionCreated": "创建时间",
|
||||||
"context.stats.lastActivity": "最后活动",
|
"context.stats.lastActivity": "最后活动",
|
||||||
"context.usage.tokens": "词元数",
|
"context.usage.tokens": "令牌数",
|
||||||
"context.usage.usage": "使用率",
|
"context.usage.usage": "使用率",
|
||||||
"context.usage.cost": "成本",
|
"context.usage.cost": "成本",
|
||||||
"context.usage.clickToView": "点击查看上下文",
|
"context.usage.clickToView": "点击查看上下文",
|
||||||
@@ -661,11 +654,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.success.description": "会话已成功取消分享",
|
"toast.session.unshare.success.description": "会话已成功取消分享",
|
||||||
"toast.session.unshare.failed.title": "取消分享失败",
|
"toast.session.unshare.failed.title": "取消分享失败",
|
||||||
"toast.session.unshare.failed.description": "取消分享会话时发生错误",
|
"toast.session.unshare.failed.description": "取消分享会话时发生错误",
|
||||||
"toast.session.export.success.title": "会话已导出",
|
|
||||||
"toast.session.export.success.description": "已将会话保存到 {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "导出会话失败",
|
|
||||||
"toast.session.export.failed.description": "导出会话时发生错误",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "无法加载 {{project}} 的会话",
|
"toast.session.listFailed.title": "无法加载 {{project}} 的会话",
|
||||||
"toast.update.title": "有可用更新",
|
"toast.update.title": "有可用更新",
|
||||||
"toast.update.description": "OpenCode 有新版本 ({{version}}) 可安装。",
|
"toast.update.description": "OpenCode 有新版本 ({{version}}) 可安装。",
|
||||||
@@ -851,7 +839,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "更多选项",
|
"common.moreOptions": "更多选项",
|
||||||
"common.learnMore": "了解更多",
|
"common.learnMore": "了解更多",
|
||||||
"common.rename": "重命名",
|
"common.rename": "重命名",
|
||||||
"common.export": "导出",
|
|
||||||
"common.reset": "重置",
|
"common.reset": "重置",
|
||||||
"common.archive": "归档",
|
"common.archive": "归档",
|
||||||
"common.delete": "删除",
|
"common.delete": "删除",
|
||||||
|
|||||||
@@ -195,9 +195,6 @@ export const dict = {
|
|||||||
"command.session.unshare": "取消分享工作階段",
|
"command.session.unshare": "取消分享工作階段",
|
||||||
"command.session.unshare.description": "停止分享此工作階段",
|
"command.session.unshare.description": "停止分享此工作階段",
|
||||||
|
|
||||||
"command.session.export": "匯出工作階段",
|
|
||||||
"command.session.export.description": "將完整的工作階段記錄匯出為 JSON",
|
|
||||||
|
|
||||||
"palette.search.placeholder": "搜尋檔案、命令和工作階段",
|
"palette.search.placeholder": "搜尋檔案、命令和工作階段",
|
||||||
"palette.search.placeholder.home": "搜尋命令和工作階段",
|
"palette.search.placeholder.home": "搜尋命令和工作階段",
|
||||||
"palette.empty": "找不到結果",
|
"palette.empty": "找不到結果",
|
||||||
@@ -561,8 +558,6 @@ export const dict = {
|
|||||||
"dialog.project.edit.worktree.startup": "工作區啟動腳本",
|
"dialog.project.edit.worktree.startup": "工作區啟動腳本",
|
||||||
"dialog.project.edit.worktree.startup.description": "在建立新的工作區 (worktree) 後執行。",
|
"dialog.project.edit.worktree.startup.description": "在建立新的工作區 (worktree) 後執行。",
|
||||||
"dialog.project.edit.worktree.startup.placeholder": "例如 bun install",
|
"dialog.project.edit.worktree.startup.placeholder": "例如 bun install",
|
||||||
"dialog.usageExceeded.dontShowAgain": "不再顯示",
|
|
||||||
|
|
||||||
"context.breakdown.title": "上下文細分",
|
"context.breakdown.title": "上下文細分",
|
||||||
"context.breakdown.note": "輸入 token 的概略細分。「其他」包含工具定義和額外負擔。",
|
"context.breakdown.note": "輸入 token 的概略細分。「其他」包含工具定義和額外負擔。",
|
||||||
"context.breakdown.system": "系統",
|
"context.breakdown.system": "系統",
|
||||||
@@ -574,8 +569,6 @@ export const dict = {
|
|||||||
"context.systemPrompt.title": "系統提示詞",
|
"context.systemPrompt.title": "系統提示詞",
|
||||||
"context.rawMessages.title": "原始訊息",
|
"context.rawMessages.title": "原始訊息",
|
||||||
|
|
||||||
"context.export.session": "匯出工作階段",
|
|
||||||
|
|
||||||
"context.stats.session": "工作階段",
|
"context.stats.session": "工作階段",
|
||||||
"context.stats.messages": "訊息數",
|
"context.stats.messages": "訊息數",
|
||||||
"context.stats.provider": "提供者",
|
"context.stats.provider": "提供者",
|
||||||
@@ -653,11 +646,6 @@ export const dict = {
|
|||||||
"toast.session.unshare.failed.title": "取消分享失敗",
|
"toast.session.unshare.failed.title": "取消分享失敗",
|
||||||
"toast.session.unshare.failed.description": "取消分享工作階段時發生錯誤",
|
"toast.session.unshare.failed.description": "取消分享工作階段時發生錯誤",
|
||||||
|
|
||||||
"toast.session.export.success.title": "工作階段已匯出",
|
|
||||||
"toast.session.export.success.description": "已將工作階段儲存至 {{filename}}",
|
|
||||||
"toast.session.export.failed.title": "匯出工作階段失敗",
|
|
||||||
"toast.session.export.failed.description": "匯出工作階段時發生錯誤",
|
|
||||||
|
|
||||||
"toast.session.listFailed.title": "無法載入 {{project}} 的工作階段",
|
"toast.session.listFailed.title": "無法載入 {{project}} 的工作階段",
|
||||||
|
|
||||||
"toast.update.title": "有可用更新",
|
"toast.update.title": "有可用更新",
|
||||||
@@ -848,7 +836,6 @@ export const dict = {
|
|||||||
"common.moreOptions": "更多選項",
|
"common.moreOptions": "更多選項",
|
||||||
"common.learnMore": "深入了解",
|
"common.learnMore": "深入了解",
|
||||||
"common.rename": "重新命名",
|
"common.rename": "重新命名",
|
||||||
"common.export": "匯出",
|
|
||||||
"common.reset": "重設",
|
"common.reset": "重設",
|
||||||
"common.archive": "封存",
|
"common.archive": "封存",
|
||||||
"common.delete": "刪除",
|
"common.delete": "刪除",
|
||||||
|
|||||||
@@ -90,20 +90,7 @@ export function createHomeController() {
|
|||||||
const directory = directories[0]
|
const directory = directories[0]
|
||||||
if (!directory) return
|
if (!directory) return
|
||||||
const ctx = global.ensureServerCtx(conn)
|
const ctx = global.ensureServerCtx(conn)
|
||||||
directories.forEach((item) => {
|
directories.forEach((item) => ctx.projects.open(item))
|
||||||
if (ctx.projects.list().some((project) => project.worktree === item)) return
|
|
||||||
const location = { directory: item }
|
|
||||||
void ctx.sdk.api.file
|
|
||||||
.list({ path: ".", location })
|
|
||||||
.then(async (files) => {
|
|
||||||
if (files.data.length > 0) return ctx.sdk.api.project.current({ location })
|
|
||||||
const result = await ctx.sdk.client.project.initGit({ directory: item })
|
|
||||||
return result.data ?? ctx.sdk.api.project.current({ location })
|
|
||||||
})
|
|
||||||
.then((project) => ctx.sync.child(item, { bootstrap: false })[1]("project", project.id))
|
|
||||||
.catch(() => undefined)
|
|
||||||
ctx.projects.open(item)
|
|
||||||
})
|
|
||||||
ctx.projects.touch(directory)
|
ctx.projects.touch(directory)
|
||||||
setSelection({ server: ServerConnection.key(conn), directory })
|
setSelection({ server: ServerConnection.key(conn), directory })
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -475,10 +475,6 @@ function HomeProjectRow(
|
|||||||
ref={sortable.ref}
|
ref={sortable.ref}
|
||||||
class="group/project relative flex h-7 min-w-0 items-center rounded-[6px]"
|
class="group/project relative flex h-7 min-w-0 items-center rounded-[6px]"
|
||||||
classList={{ "z-10": sortable.isDragSource() }}
|
classList={{ "z-10": sortable.isDragSource() }}
|
||||||
onContextMenu={(event) => {
|
|
||||||
event.preventDefault()
|
|
||||||
props.onSetContextMenuOpen(contextMenuID(), true)
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<HomeProjectNavButton
|
<HomeProjectNavButton
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import type { LocalProject } from "@/context/layout"
|
|||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { ServerConnection } from "@/context/server"
|
import { ServerConnection } from "@/context/server"
|
||||||
import { sessionHasOpenTab, useTabs } from "@/context/tabs"
|
import { sessionHasOpenTab, useTabs } from "@/context/tabs"
|
||||||
import { compareSessionTime, displayName, errorMessage, projectForSession } from "@/pages/layout/helpers"
|
import { displayName, errorMessage, projectForSession } from "@/pages/layout/helpers"
|
||||||
import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state"
|
import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state"
|
||||||
import { pathKey } from "@/utils/path-key"
|
import { pathKey } from "@/utils/path-key"
|
||||||
import { showToast } from "@/utils/toast"
|
import { showToast } from "@/utils/toast"
|
||||||
@@ -254,7 +254,7 @@ function buildHomeSessionRecords(input: {
|
|||||||
const directories = new Set(input.projectDirectories().map(pathKey))
|
const directories = new Set(input.projectDirectories().map(pathKey))
|
||||||
const sessions = input.sessions().filter((session) => directories.has(pathKey(session.directory)))
|
const sessions = input.sessions().filter((session) => directories.has(pathKey(session.directory)))
|
||||||
return [...new Map(sessions.map((session) => [session.id, session] as const)).values()]
|
return [...new Map(sessions.map((session) => [session.id, session] as const)).values()]
|
||||||
.sort(compareSessionTime)
|
.sort((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created))
|
||||||
.flatMap((session) => {
|
.flatMap((session) => {
|
||||||
const directory = pathKey(session.directory)
|
const directory = pathKey(session.directory)
|
||||||
const project =
|
const project =
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import { type Session } from "@opencode-ai/sdk/v2/client"
|
|||||||
import {
|
import {
|
||||||
childSessionOnPath,
|
childSessionOnPath,
|
||||||
closeHomeProject,
|
closeHomeProject,
|
||||||
compareSessionTime,
|
|
||||||
displayName,
|
displayName,
|
||||||
effectiveWorkspaceOrder,
|
effectiveWorkspaceOrder,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
@@ -19,7 +18,6 @@ import {
|
|||||||
homeProjectDirectories,
|
homeProjectDirectories,
|
||||||
homeSessionServerStatus,
|
homeSessionServerStatus,
|
||||||
latestRootSession,
|
latestRootSession,
|
||||||
sortedRootSessions,
|
|
||||||
toggleHomeProjectSelection,
|
toggleHomeProjectSelection,
|
||||||
} from "./helpers"
|
} from "./helpers"
|
||||||
import { pathKey } from "@/utils/path-key"
|
import { pathKey } from "@/utils/path-key"
|
||||||
@@ -155,30 +153,6 @@ describe("layout workspace helpers", () => {
|
|||||||
expect(result?.id).toBe("workspace")
|
expect(result?.id).toBe("workspace")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("sorts recent sessions by persisted update time instead of id", () => {
|
|
||||||
const result = sortedRootSessions(
|
|
||||||
{
|
|
||||||
path: { directory: "/workspace" },
|
|
||||||
session: [
|
|
||||||
session({ id: "ses_z", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
|
|
||||||
session({ id: "ses_a", directory: "/workspace", time: { created: 1, updated: 3, archived: undefined } }),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
3,
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(result.map((item) => item.id)).toEqual(["ses_a", "ses_z"])
|
|
||||||
})
|
|
||||||
|
|
||||||
test("uses id only to break equal session timestamps", () => {
|
|
||||||
const sessions = [
|
|
||||||
session({ id: "ses_z", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
|
|
||||||
session({ id: "ses_a", directory: "/workspace", time: { created: 1, updated: 2, archived: undefined } }),
|
|
||||||
]
|
|
||||||
|
|
||||||
expect(sessions.sort(compareSessionTime).map((item) => item.id)).toEqual(["ses_a", "ses_z"])
|
|
||||||
})
|
|
||||||
|
|
||||||
test("detects project permissions with a filter", () => {
|
test("detects project permissions with a filter", () => {
|
||||||
const result = hasProjectPermissions(
|
const result = hasProjectPermissions(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,10 +9,18 @@ type SessionStore = {
|
|||||||
path: { directory: string }
|
path: { directory: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function compareSessionTime(a: Session, b: Session) {
|
function sortSessions(now: number) {
|
||||||
const updated = (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)
|
const oneMinuteAgo = now - 60 * 1000
|
||||||
if (updated !== 0) return updated
|
return (a: Session, b: Session) => {
|
||||||
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0
|
const aUpdated = a.time.updated ?? a.time.created
|
||||||
|
const bUpdated = b.time.updated ?? b.time.created
|
||||||
|
const aRecent = aUpdated > oneMinuteAgo
|
||||||
|
const bRecent = bUpdated > oneMinuteAgo
|
||||||
|
if (aRecent && bRecent) return a.id < b.id ? -1 : a.id > b.id ? 1 : 0
|
||||||
|
if (aRecent && !bRecent) return -1
|
||||||
|
if (!aRecent && bRecent) return 1
|
||||||
|
return bUpdated - aUpdated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRootVisibleSession = (session: Session, directory: string) =>
|
const isRootVisibleSession = (session: Session, directory: string) =>
|
||||||
@@ -21,10 +29,10 @@ const isRootVisibleSession = (session: Session, directory: string) =>
|
|||||||
export const roots = (store: SessionStore) =>
|
export const roots = (store: SessionStore) =>
|
||||||
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
(store.session ?? []).filter((session) => isRootVisibleSession(session, store.path.directory))
|
||||||
|
|
||||||
export const sortedRootSessions = (store: SessionStore, _now: number) => roots(store).sort(compareSessionTime)
|
export const sortedRootSessions = (store: SessionStore, now: number) => roots(store).sort(sortSessions(now))
|
||||||
|
|
||||||
export const latestRootSession = (stores: SessionStore[], _now: number) =>
|
export const latestRootSession = (stores: SessionStore[], now: number) =>
|
||||||
stores.flatMap(roots).sort(compareSessionTime)[0]
|
stores.flatMap(roots).sort(sortSessions(now))[0]
|
||||||
|
|
||||||
export function hasProjectPermissions<T>(
|
export function hasProjectPermissions<T>(
|
||||||
request: Record<string, T[] | undefined> | undefined,
|
request: Record<string, T[] | undefined> | undefined,
|
||||||
|
|||||||
@@ -1851,9 +1851,7 @@ export default function Page() {
|
|||||||
|
|
||||||
const session = sdk().api.session
|
const session = sdk().api.session
|
||||||
const target = sync()
|
const target = sync()
|
||||||
const index = userMessages().findIndex((item) => item.id === id)
|
const next = userMessages().find((item) => item.id > id)
|
||||||
if (index < 0) return
|
|
||||||
const next = userMessages()[index + 1]
|
|
||||||
const last = target.session.get(sessionID)?.revert
|
const last = target.session.get(sessionID)?.revert
|
||||||
|
|
||||||
await runPromptRollbackMutation({
|
await runPromptRollbackMutation({
|
||||||
@@ -1893,10 +1891,8 @@ export default function Page() {
|
|||||||
const rolled = createMemo(() => {
|
const rolled = createMemo(() => {
|
||||||
const id = revertMessageID()
|
const id = revertMessageID()
|
||||||
if (!id) return []
|
if (!id) return []
|
||||||
const index = userMessages().findIndex((item) => item.id === id)
|
|
||||||
if (index < 0) return []
|
|
||||||
return userMessages()
|
return userMessages()
|
||||||
.slice(index)
|
.filter((item) => item.id >= id)
|
||||||
.map((item) => ({ id: item.id, text: line(item.id) }))
|
.map((item) => ({ id: item.id, text: line(item.id) }))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ import type {
|
|||||||
UserMessage,
|
UserMessage,
|
||||||
} from "@opencode-ai/sdk/v2"
|
} from "@opencode-ai/sdk/v2"
|
||||||
import { showToast } from "@/utils/toast"
|
import { showToast } from "@/utils/toast"
|
||||||
import { downloadSessionExport, fetchSessionExport, sessionExportFilename } from "@/utils/session-export"
|
|
||||||
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"
|
||||||
import { Popover as KobaltePopover } from "@kobalte/core/popover"
|
import { Popover as KobaltePopover } from "@kobalte/core/popover"
|
||||||
import { normalize } from "@opencode-ai/session-ui/session-diff"
|
import { normalize } from "@opencode-ai/session-ui/session-diff"
|
||||||
@@ -287,9 +286,7 @@ export function MessageTimeline(props: {
|
|||||||
const visible = new Set(props.userMessages.map((message) => message.id))
|
const visible = new Set(props.userMessages.map((message) => message.id))
|
||||||
const boundary = sessionMessages().find((message) => message.role === "user" && !visible.has(message.id))?.id
|
const boundary = sessionMessages().find((message) => message.role === "user" && !visible.has(message.id))?.id
|
||||||
const messages = sync().data.session_message[id] ?? []
|
const messages = sync().data.session_message[id] ?? []
|
||||||
if (!boundary) return messages
|
return boundary ? messages.filter((message) => message.id < boundary) : messages
|
||||||
const index = messages.findIndex((message) => message.id === boundary)
|
|
||||||
return index < 0 ? messages : messages.slice(0, index)
|
|
||||||
})
|
})
|
||||||
const info = createMemo(() => {
|
const info = createMemo(() => {
|
||||||
const id = sessionID()
|
const id = sessionID()
|
||||||
@@ -809,29 +806,6 @@ export function MessageTimeline(props: {
|
|||||||
navigate(`/${params.dir}/session`)
|
navigate(`/${params.dir}/session`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportSession = async (sessionID: string) => {
|
|
||||||
try {
|
|
||||||
const data = await fetchSessionExport({
|
|
||||||
sessionID,
|
|
||||||
client: sdk().client,
|
|
||||||
})
|
|
||||||
const filename = sessionExportFilename(data.info)
|
|
||||||
downloadSessionExport(filename, data)
|
|
||||||
showToast({
|
|
||||||
variant: "success",
|
|
||||||
icon: "circle-check",
|
|
||||||
title: language.t("toast.session.export.success.title"),
|
|
||||||
description: language.t("toast.session.export.success.description", { filename }),
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: language.t("toast.session.export.failed.title"),
|
|
||||||
description: err instanceof Error ? err.message : language.t("toast.session.export.failed.description"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const archiveSession = async (sessionID: string) => {
|
const archiveSession = async (sessionID: string) => {
|
||||||
const session = sync().session.get(sessionID)
|
const session = sync().session.get(sessionID)
|
||||||
if (!session) return
|
if (!session) return
|
||||||
@@ -1590,9 +1564,6 @@ export function MessageTimeline(props: {
|
|||||||
</DropdownMenu.ItemLabel>
|
</DropdownMenu.ItemLabel>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
</Show>
|
</Show>
|
||||||
<DropdownMenu.Item onSelect={() => exportSession(id)}>
|
|
||||||
<DropdownMenu.ItemLabel>{language.t("common.export")}</DropdownMenu.ItemLabel>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item onSelect={() => void archiveSession(id)}>
|
<DropdownMenu.Item onSelect={() => void archiveSession(id)}>
|
||||||
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
|
<DropdownMenu.ItemLabel>{language.t("common.archive")}</DropdownMenu.ItemLabel>
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
@@ -1664,9 +1635,6 @@ export function MessageTimeline(props: {
|
|||||||
{language.t("session.share.action.share")}...
|
{language.t("session.share.action.share")}...
|
||||||
</MenuV2.Item>
|
</MenuV2.Item>
|
||||||
</Show>
|
</Show>
|
||||||
<MenuV2.Item onSelect={() => exportSession(id)}>
|
|
||||||
{language.t("common.export")}...
|
|
||||||
</MenuV2.Item>
|
|
||||||
<MenuV2.Item onSelect={() => void archiveSession(id)}>
|
<MenuV2.Item onSelect={() => void archiveSession(id)}>
|
||||||
{language.t("common.archive")}
|
{language.t("common.archive")}
|
||||||
</MenuV2.Item>
|
</MenuV2.Item>
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ const assistant = (id: string) => ({ id, role: "assistant" }) as AssistantMessag
|
|||||||
|
|
||||||
describe("timeline model", () => {
|
describe("timeline model", () => {
|
||||||
test("selects users and applies the revert boundary", () => {
|
test("selects users and applies the revert boundary", () => {
|
||||||
const messages: Message[] = [user("msg_z"), assistant("msg_a"), user("msg_b"), user("msg_c")]
|
const messages: Message[] = [user("msg_1"), assistant("msg_2"), user("msg_3"), user("msg_5")]
|
||||||
const users = selectUserMessages(messages)
|
const users = selectUserMessages(messages)
|
||||||
|
|
||||||
expect(users.map((message) => message.id)).toEqual(["msg_z", "msg_b", "msg_c"])
|
expect(users.map((message) => message.id)).toEqual(["msg_1", "msg_3", "msg_5"])
|
||||||
expect(selectVisibleUserMessages(users, "msg_b").map((message) => message.id)).toEqual(["msg_z"])
|
expect(selectVisibleUserMessages(users, "msg_5").map((message) => message.id)).toEqual(["msg_1", "msg_3"])
|
||||||
expect(selectVisibleUserMessages(users)).toBe(users)
|
expect(selectVisibleUserMessages(users)).toBe(users)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -104,8 +104,7 @@ export function isTimelineReady(messages: Message[] | undefined, loading: boolea
|
|||||||
|
|
||||||
export function selectVisibleUserMessages(messages: UserMessage[], revertMessageID?: string) {
|
export function selectVisibleUserMessages(messages: UserMessage[], revertMessageID?: string) {
|
||||||
if (!revertMessageID) return messages
|
if (!revertMessageID) return messages
|
||||||
const boundary = messages.findIndex((message) => message.id === revertMessageID)
|
return messages.filter((message) => message.id < revertMessageID)
|
||||||
return boundary < 0 ? messages : messages.slice(0, boundary)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadOlderTimeline(input: {
|
export async function loadOlderTimeline(input: {
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ describe("current session timeline rows", () => {
|
|||||||
|
|
||||||
test("renders an optimistic user turn and thinking before the protocol message arrives", () => {
|
test("renders an optimistic user turn and thinking before the protocol message arrives", () => {
|
||||||
const source = [
|
const source = [
|
||||||
{ id: "msg_z", type: "user", text: "existing", time: { created: 1 } },
|
{ id: "msg_1", type: "user", text: "existing", time: { created: 1 } },
|
||||||
] satisfies SessionMessageInfo[]
|
] satisfies SessionMessageInfo[]
|
||||||
const normalized = normalizeSessionMessages("ses_1", source)
|
const normalized = normalizeSessionMessages("ses_1", source)
|
||||||
const optimistic = {
|
const optimistic = {
|
||||||
id: "msg_a",
|
id: "msg_2",
|
||||||
sessionID: "ses_1",
|
sessionID: "ses_1",
|
||||||
role: "user" as const,
|
role: "user" as const,
|
||||||
time: { created: 2 },
|
time: { created: 2 },
|
||||||
@@ -161,10 +161,10 @@ describe("current session timeline rows", () => {
|
|||||||
|
|
||||||
expect(result.activeMessageID).toBe(optimistic.id)
|
expect(result.activeMessageID).toBe(optimistic.id)
|
||||||
expect(result.rows.map(TimelineRow.key)).toEqual([
|
expect(result.rows.map(TimelineRow.key)).toEqual([
|
||||||
"user-message:msg_z",
|
"user-message:msg_1",
|
||||||
"turn-gap:msg_a",
|
"turn-gap:msg_2",
|
||||||
"user-message:msg_a",
|
"user-message:msg_2",
|
||||||
"thinking:msg_a",
|
"thinking:msg_2",
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { AssistantMessage, Part, SessionStatus, UserMessage } from "@opencode-ai
|
|||||||
import { groupParts, renderable, type PartGroup } from "@opencode-ai/session-ui/message-part"
|
import { groupParts, renderable, type PartGroup } from "@opencode-ai/session-ui/message-part"
|
||||||
import { TimelineRow, type SummaryDiff } from "./timeline-row"
|
import { TimelineRow, type SummaryDiff } from "./timeline-row"
|
||||||
import { uniqueSummaryDiffs } from "./summary-diffs"
|
import { uniqueSummaryDiffs } from "./summary-diffs"
|
||||||
import { compareMessages } from "@/utils/session-message"
|
|
||||||
|
|
||||||
export { TimelineRow, type SummaryDiff } from "./timeline-row"
|
export { TimelineRow, type SummaryDiff } from "./timeline-row"
|
||||||
|
|
||||||
@@ -72,12 +71,12 @@ export namespace Timeline {
|
|||||||
turns.push(turn)
|
turns.push(turn)
|
||||||
turnByUserID.set(user.id, turn)
|
turnByUserID.set(user.id, turn)
|
||||||
})
|
})
|
||||||
|
const latestUserMessageID = turns.at(-1)?.user.id
|
||||||
projectedUserMessages.forEach((user) => {
|
projectedUserMessages.forEach((user) => {
|
||||||
if (turnByUserID.has(user.id)) return
|
if (turnByUserID.has(user.id)) return
|
||||||
|
if (latestUserMessageID && user.id < latestUserMessageID) return
|
||||||
const turn = { user, assistants: [] }
|
const turn = { user, assistants: [] }
|
||||||
const index = turns.findIndex((item) => compareMessages(user, item.user) < 0)
|
turns.push(turn)
|
||||||
if (index < 0) turns.push(turn)
|
|
||||||
if (index >= 0) turns.splice(index, 0, turn)
|
|
||||||
turnByUserID.set(user.id, turn)
|
turnByUserID.set(user.id, turn)
|
||||||
})
|
})
|
||||||
const activeMessageID = turns.at(-1)?.user.id
|
const activeMessageID = turns.at(-1)?.user.id
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ import { useSettings } from "@/context/settings"
|
|||||||
import { useSync } from "@/context/sync"
|
import { useSync } from "@/context/sync"
|
||||||
import { useTerminal } from "@/context/terminal"
|
import { useTerminal } from "@/context/terminal"
|
||||||
import { showToast } from "@/utils/toast"
|
import { showToast } from "@/utils/toast"
|
||||||
import { downloadSessionExport, fetchSessionExport, sessionExportFilename } from "@/utils/session-export"
|
|
||||||
import { findLast } from "@opencode-ai/core/util/array"
|
import { findLast } from "@opencode-ai/core/util/array"
|
||||||
import { createSessionTabs } from "@/pages/session/helpers"
|
import { createSessionTabs } from "@/pages/session/helpers"
|
||||||
import { extractPromptFromParts } from "@/utils/prompt"
|
import { extractPromptFromParts } from "@/utils/prompt"
|
||||||
import { Message, Part, UserMessage } from "@opencode-ai/sdk/v2"
|
import { UserMessage } from "@opencode-ai/sdk/v2"
|
||||||
import { useSessionLayout } from "@/pages/session/session-layout"
|
import { useSessionLayout } from "@/pages/session/session-layout"
|
||||||
import { createSessionOwnership } from "./session-ownership"
|
import { createSessionOwnership } from "./session-ownership"
|
||||||
import { useLocal } from "@/context/local"
|
import { useLocal } from "@/context/local"
|
||||||
@@ -100,8 +99,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
const visibleUserMessages = () => {
|
const visibleUserMessages = () => {
|
||||||
const revert = info()?.revert?.messageID
|
const revert = info()?.revert?.messageID
|
||||||
if (!revert) return userMessages()
|
if (!revert) return userMessages()
|
||||||
const boundary = userMessages().findIndex((message) => message.id === revert)
|
return userMessages().filter((m) => m.id < revert)
|
||||||
return boundary < 0 ? userMessages() : userMessages().slice(0, boundary)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const showAllFiles = () => {
|
const showAllFiles = () => {
|
||||||
@@ -233,31 +231,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportSession = async () => {
|
|
||||||
const sessionID = params.id
|
|
||||||
if (!sessionID) return
|
|
||||||
try {
|
|
||||||
const data = await fetchSessionExport({
|
|
||||||
sessionID,
|
|
||||||
client: sdk().client,
|
|
||||||
})
|
|
||||||
const filename = sessionExportFilename(data.info)
|
|
||||||
downloadSessionExport(filename, data)
|
|
||||||
showToast({
|
|
||||||
variant: "success",
|
|
||||||
icon: "circle-check",
|
|
||||||
title: language.t("toast.session.export.success.title"),
|
|
||||||
description: language.t("toast.session.export.success.description", { filename }),
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
showToast({
|
|
||||||
variant: "error",
|
|
||||||
title: language.t("toast.session.export.failed.title"),
|
|
||||||
description: err instanceof Error ? err.message : language.t("toast.session.export.failed.description"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const openFile = () => {
|
const openFile = () => {
|
||||||
void openDialog(
|
void openDialog(
|
||||||
() => import("@/components/dialog-select-file"),
|
() => import("@/components/dialog-select-file"),
|
||||||
@@ -338,9 +311,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
const promptSession = prompt.capture()
|
const promptSession = prompt.capture()
|
||||||
const revert = info()?.revert?.messageID
|
const revert = info()?.revert?.messageID
|
||||||
const messages = userMessages()
|
const messages = userMessages()
|
||||||
const boundary = revert ? messages.findIndex((message) => message.id === revert) : messages.length
|
const message = findLast(messages, (x) => !revert || x.id < revert)
|
||||||
if (boundary < 0) return
|
|
||||||
const message = messages[boundary - 1]
|
|
||||||
if (!message) return
|
if (!message) return
|
||||||
const parts = sync().data.part[message.id]
|
const parts = sync().data.part[message.id]
|
||||||
|
|
||||||
@@ -355,7 +326,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
updatePrompt: (promptSession) => {
|
updatePrompt: (promptSession) => {
|
||||||
if (parts) promptSession.set(extractPromptFromParts(parts, { directory }))
|
if (parts) promptSession.set(extractPromptFromParts(parts, { directory }))
|
||||||
},
|
},
|
||||||
updateViewport: () => setActiveMessage(messages[boundary - 2]),
|
updateViewport: () => setActiveMessage(findLast(messages, (x) => x.id < message.id)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,16 +341,14 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
const revertMessageID = info()?.revert?.messageID
|
const revertMessageID = info()?.revert?.messageID
|
||||||
if (!revertMessageID) return
|
if (!revertMessageID) return
|
||||||
|
|
||||||
const boundary = messages.findIndex((message) => message.id === revertMessageID)
|
const next = messages.find((x) => x.id > revertMessageID)
|
||||||
if (boundary < 0) return
|
|
||||||
const next = messages[boundary + 1]
|
|
||||||
if (!next) {
|
if (!next) {
|
||||||
await runCommand({
|
await runCommand({
|
||||||
owner,
|
owner,
|
||||||
prompt: promptSession,
|
prompt: promptSession,
|
||||||
request: () => session.revert.clear({ sessionID }),
|
request: () => session.revert.clear({ sessionID }),
|
||||||
updatePrompt: (promptSession) => promptSession.reset(),
|
updatePrompt: (promptSession) => promptSession.reset(),
|
||||||
updateViewport: () => setActiveMessage(messages.at(-1)),
|
updateViewport: () => setActiveMessage(findLast(messages, (x) => x.id >= revertMessageID)),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -389,7 +358,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
prompt: promptSession,
|
prompt: promptSession,
|
||||||
request: () => session.revert.stage({ sessionID, messageID: next.id }),
|
request: () => session.revert.stage({ sessionID, messageID: next.id }),
|
||||||
updatePrompt: () => undefined,
|
updatePrompt: () => undefined,
|
||||||
updateViewport: () => setActiveMessage(messages[boundary]),
|
updateViewport: () => setActiveMessage(findLast(messages, (x) => x.id < next.id)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,14 +458,6 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
|
|||||||
disabled: !params.id || visibleUserMessages().length === 0,
|
disabled: !params.id || visibleUserMessages().length === 0,
|
||||||
onSelect: fork,
|
onSelect: fork,
|
||||||
}),
|
}),
|
||||||
sessionCommand({
|
|
||||||
id: "session.export",
|
|
||||||
title: language.t("command.session.export"),
|
|
||||||
description: language.t("command.session.export.description"),
|
|
||||||
slash: "export",
|
|
||||||
disabled: !params.id,
|
|
||||||
onSelect: exportSession,
|
|
||||||
}),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const fileCmds = () => {
|
const fileCmds = () => {
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
|
||||||
import { fetchSessionExport, sessionExportFilename } from "./session-export"
|
|
||||||
import type { Message, Part, Session } from "@opencode-ai/sdk/v2/client"
|
|
||||||
|
|
||||||
describe("sessionExportFilename", () => {
|
|
||||||
test("generates filename from title", () => {
|
|
||||||
expect(sessionExportFilename({ id: "ses_123", title: "Clone PR in worktree from fork" })).toBe(
|
|
||||||
"clone-pr-in-worktree-from-fork.json",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("generates filename from slug when title missing", () => {
|
|
||||||
expect(sessionExportFilename({ id: "ses_123", slug: "my-session-slug" })).toBe("my-session-slug.json")
|
|
||||||
})
|
|
||||||
|
|
||||||
test("falls back to id when title and slug are empty", () => {
|
|
||||||
expect(sessionExportFilename({ id: "ses_123" })).toBe("ses_123.json")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("fetchSessionExport", () => {
|
|
||||||
test("fetches full transcript from client", async () => {
|
|
||||||
const session = { id: "ses_1", title: "Test Session" } as Session
|
|
||||||
const msg = { id: "msg_1", role: "user" } as Message
|
|
||||||
const part = { id: "prt_1", type: "text", text: "hello" } as Part
|
|
||||||
const messages = [{ info: msg, parts: [part] }]
|
|
||||||
|
|
||||||
const client = {
|
|
||||||
session: {
|
|
||||||
get: async () => ({ data: session }),
|
|
||||||
messages: async () => ({ data: messages }),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await fetchSessionExport({
|
|
||||||
sessionID: "ses_1",
|
|
||||||
client,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
info: session,
|
|
||||||
messages,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test("throws when session not found", async () => {
|
|
||||||
const client = {
|
|
||||||
session: {
|
|
||||||
get: async () => ({ data: null }),
|
|
||||||
messages: async () => ({ data: [] }),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(
|
|
||||||
fetchSessionExport({
|
|
||||||
sessionID: "ses_missing",
|
|
||||||
client,
|
|
||||||
}),
|
|
||||||
).rejects.toThrow("Session not found: ses_missing")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import type { Message, Part, Session } from "@opencode-ai/sdk/v2/client"
|
|
||||||
|
|
||||||
// Matches the exact `{ info, messages: [{ info, parts }] }` structure produced by `opencode export` CLI
|
|
||||||
export type SessionExportData = {
|
|
||||||
info: Session
|
|
||||||
messages: {
|
|
||||||
info: Message
|
|
||||||
parts: Part[]
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SessionExportClient = {
|
|
||||||
session: {
|
|
||||||
get: (input: { sessionID: string }) => Promise<{ data?: Session | null }>
|
|
||||||
messages: (input: { sessionID: string }) => Promise<{ data?: SessionExportData["messages"] | null }>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function fetchSessionExport(input: {
|
|
||||||
sessionID: string
|
|
||||||
client: SessionExportClient
|
|
||||||
}): Promise<SessionExportData> {
|
|
||||||
const [sessionRes, messagesRes] = await Promise.all([
|
|
||||||
input.client.session.get({ sessionID: input.sessionID }),
|
|
||||||
input.client.session.messages({ sessionID: input.sessionID }),
|
|
||||||
])
|
|
||||||
|
|
||||||
if (!sessionRes?.data) {
|
|
||||||
throw new Error(`Session not found: ${input.sessionID}`)
|
|
||||||
}
|
|
||||||
if (!messagesRes?.data) {
|
|
||||||
throw new Error(`Failed to load messages for session: ${input.sessionID}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
info: sessionRes.data,
|
|
||||||
messages: messagesRes.data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sessionExportFilename(session: { id: string; title?: string; slug?: string }) {
|
|
||||||
const name = session.title || session.slug || session.id
|
|
||||||
const clean = name
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^a-z0-9_-]+/gi, "-")
|
|
||||||
.replace(/^-+|-+$/g, "")
|
|
||||||
return `${clean || session.id}.json`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function downloadSessionExport(filename: string, data: unknown) {
|
|
||||||
const json = JSON.stringify(data, null, 2)
|
|
||||||
const blob = new Blob([json], { type: "application/json" })
|
|
||||||
const url = URL.createObjectURL(blob)
|
|
||||||
const a = document.createElement("a")
|
|
||||||
a.href = url
|
|
||||||
a.download = filename
|
|
||||||
document.body.appendChild(a)
|
|
||||||
a.click()
|
|
||||||
document.body.removeChild(a)
|
|
||||||
URL.revokeObjectURL(url)
|
|
||||||
}
|
|
||||||
@@ -12,14 +12,6 @@ const emptyTokens = { input: 0, output: 0, reasoning: 0, cache: { read: 0, write
|
|||||||
const emptyModel: { id: string; providerID: string; variant?: string } = { id: "", providerID: "" }
|
const emptyModel: { id: string; providerID: string; variant?: string } = { id: "", providerID: "" }
|
||||||
const decodeToolInput = Schema.decodeUnknownOption(Schema.UnknownFromJsonString)
|
const decodeToolInput = Schema.decodeUnknownOption(Schema.UnknownFromJsonString)
|
||||||
|
|
||||||
export function compareMessages(a: Pick<Message, "id" | "time">, b: Pick<Message, "id" | "time">) {
|
|
||||||
const left = messageKey(a)
|
|
||||||
const right = messageKey(b)
|
|
||||||
return left < right ? -1 : left > right ? 1 : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
export const messageKey = (message: Pick<Message, "id" | "time">) => message.time.created + message.id
|
|
||||||
|
|
||||||
function record(value: unknown): value is Record<string, unknown> {
|
function record(value: unknown): value is Record<string, unknown> {
|
||||||
return !!value && typeof value === "object" && !Array.isArray(value)
|
return !!value && typeof value === "object" && !Array.isArray(value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/cli",
|
"name": "@opencode-ai/cli",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/codemode",
|
"name": "@opencode-ai/codemode",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"description": "Effect-native confined code execution over schema-described tools",
|
"description": "Effect-native confined code execution over schema-described tools",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.18.15",
|
"version": "1.18.13",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user