Compare commits

...
Author SHA1 Message Date
neriousy 2356e7bbad feat(server): gate external integration values by client API version
Clients now send x-opencode-api-version. Clients that send no header
(v2.0.24 and earlier) reject external integration methods, connections,
and credentials, so integration.list, integration.get, and credential.list
omit those values for them instead of failing the whole response.
2026-10-07 23:01:06 +00:00
Luke Parker 46c69bc35c fix(session-ui): show latest thinking summary heading while streaming (#53815) 2026-10-08 08:24:05 +10:00
Aiden Cline be19c7612f fix(core): drop early guarded plugin activation (#53819) 2026-10-07 17:12:45 -05:00
Simon Klee 162bc6922b test: stabilize asynchronous UI and plugin tests (#53818) 2026-10-07 22:01:55 +00:00
Filip 87a1ebcc97 feat(core): connect Azure through the Azure CLI as an external credential (#53794) 2026-10-07 23:10:18 +02:00
opencode-agent[bot] 2138bfd02a chore: update nix node_modules hashes 2026-10-07 21:04:54 +00:00
Luke Parker 98d57d0dd2 fix(app): focus search input when opening /model dialog (#53707) 2026-10-08 06:56:27 +10:00
Simon Klee fcad1319bf chore: upgrade opentui v0.5.16 (#53805) 2026-10-07 20:54:17 +00:00
Dax Raad e3419d47ee fix(cli): keep state on uninstall 2026-10-07 16:45:59 -04:00
Adam d016db856c feat(core): enforce skill integration policies 2026-10-07 15:39:27 -05:00
Adam 613ef8ba87 feat(core): enforce managed integration and tool policies (#53775) 2026-10-07 15:39:26 -05:00
Dax Raad b8d3c92985 fix(cli): keep data and config on uninstall 2026-10-07 16:34:39 -04:00
opencode-agent[bot]andnexxeln 8587f817cc fix(tui): separate queued prompt dock from composer (#53801)
Co-authored-by: nexxeln <95541290+nexxeln@users.noreply.github.com>
2026-10-08 01:45:54 +05:30
Simon Klee a98adc1ab0 fix(tui): stop dialogs reading stale transcript rows after resync (#53800) 2026-10-07 22:13:36 +02:00
Milosz JankiewiczandJaaneek 31bdd8e8f7 fix(core): only send png, jpeg and webp images to xAI (#53787)
Co-authored-by: Jaaneek <Jaaneek@users.noreply.github.com>
2026-10-07 21:46:09 +02:00
Frank cab7e2c242 docs(www): add Haiku 5.5 to V2 Go guide 2026-10-07 15:10:42 -04:00
Aiden Cline 56be008756 feat(core): add AWS profile setup for Bedrock (#53626) 2026-10-07 14:05:08 -05:00
Frank 554e7c2341 docs(www): add Haiku 5.5 to V2 model tables 2026-10-07 14:47:58 -04:00
opencode-agent[bot]andrekram1-node 5183ea45c3 fix(core): send Codex session headers with ChatGPT token sharing (#53767)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-10-07 11:32:57 -05:00
Dax 053e534e5a refactor(server): align pty connect preflight order (#53579) 2026-10-07 12:07:48 -04:00
opencode-agent[bot]andrekram1-node 8bd8960154 fix(ai): add missing OpenAI and Google service tiers (#53753)
Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
2026-10-07 11:06:50 -05:00
holny d5154fb74e fix(core): bypass gray-matter content cache when parsing frontmatter (#51245) 2026-10-07 11:05:37 -05:00
Aiden Cline 70c6c8cbc5 feat(integration): add declarative external connection method (#53672) 2026-10-07 11:03:24 -05:00
NamitandJames Long e2979039f1 fix(core): bump session time_updated on step lifecycle events (#49105)
Co-authored-by: James Long <longster@gmail.com>
2026-10-07 11:40:47 -04:00
opencode-agent[bot]andBrendonovich 119cb15d1d refactor(app): remove configurable default server (#53731)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 20:46:51 +08:00
opencode-agent[bot] e1b7299bc9 chore(core): refresh bundled models.dev snapshot 2026-10-07 12:22:51 +00:00
opencode-agent[bot]andBrendonovich 68aa4f8017 feat(app): show recent sessions in the empty command palette (#53727)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 10:58:35 +00:00
David HillandBrendonovich 69219470a2 feat(app): show recently closed tabs menu (#51973)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 10:24:51 +00:00
opencode-agent[bot]andBrendonovich 10b11ba946 fix(app): keep live terminals through transient connect failures (#52232)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 10:04:03 +00:00
opencode-agent[bot]andBrendonovich 2e3d3a735a fix(app): use filled clear icon in model and branch searches (#53511)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 17:12:10 +08:00
opencode-agent[bot]andBrendonovich f655e7b2b5 fix(app): wrap mobile project controls responsively (#50484)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 17:11:57 +08:00
opencode-agent[bot]andneriousy 6273bd7924 fix(core): stop sending API key metadata as request body (#53546)
Co-authored-by: neriousy <filip@anoma.ly>
2026-10-07 10:36:22 +02:00
Aiden Cline 34cf183c4c feat(ai): support between_tools thinking in Anthropic Messages (#53601) 2026-10-06 23:57:20 -05:00
opencode-agent[bot]andBrendonovich fd99516e51 fix(session-ui): keep Markdown text selectable (#53665)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-07 04:33:34 +00:00
Aiden Cline 1d610f90a0 fix(ui): support inline custom answers for string choice fields in connect (#53625) 2026-10-06 22:41:21 -05:00
Luke Parker eebe9d370f fix(app): handle one-time pairing links across the GUI (#53257) 2026-10-07 12:56:07 +10:00
Luke Parker a2b6005627 fix(desktop): delete old staged CLI versions (#53659) 2026-10-07 02:10:05 +00:00
Luke Parker a90ad8566d fix(cli): serve the embedded web UI brotli-compressed (#53645) 2026-10-07 11:35:20 +10:00
Luke Parker a7f3d570ae fix(cli): compress the embedded web UI at brotli's best quality (#53644) 2026-10-07 11:35:20 +10:00
Luke Parker 8b45c5674b fix(cli): embed the web UI as raw bytes instead of base64 strings (#53643) 2026-10-07 11:35:19 +10:00
Frank 56c2f432cc docs(www): sync Mistral Large 4 pricing and privacy 2026-10-06 21:27:39 -04:00
Kit Langton 74678c4677 feat(server): stream fs.read responses with HTTP Range support (#53088) 2026-10-06 18:24:55 -07:00
Aiden Cline 369aad308b feat(core): add external credential references (#53624) 2026-10-06 19:55:05 -05:00
opencode-agent[bot] d5cf9c2548 chore: update nix node_modules hashes 2026-10-07 00:40:27 +00:00
Luke Parker 9c51d84f8f feat(app): preview Word, Excel and PowerPoint files (#53305) 2026-10-07 00:31:01 +00:00
Aiden Cline 8b02c4ef04 fix(ai): drop empty unfinished reasoning items on replay (#53603) 2026-10-06 19:03:35 -05:00
Luke Parker e41256eb5a fix(desktop): fix browser bar review findings (#53627) 2026-10-07 09:50:13 +10:00
Daniel Chen d1749770c7 docs(www): add Exo Free to Console models (#53620) 2026-10-06 15:27:58 -07:00
Kit Langton 9ee97d87a2 fix(sdk): release completed embedded request signals (#53613) 2026-10-06 15:05:36 -07:00
59e5953443 fix(schema): expose effort-update and thinking-binding overrides on model compatibility (#52172)
Co-authored-by: argszero <argszero@users.noreply.github.com>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
2026-10-06 15:41:12 -05:00
Dax 4a0f273fa7 feat(cli): include every pairing address in QR codes (#53588) 2026-10-06 16:13:34 -04:00
Dax 36a38058fb feat(core): stop asking for external directory access by default (#53585) 2026-10-06 15:52:23 -04:00
Dax ccb5162714 fix(tui): match execute dialog to two-toned dialog layout (#53584) 2026-10-06 15:20:21 -04:00
opencode-agent[bot]andrekram1-node c2f87853c6 fix(core): drop tool name and namespace length caps (#53586)
Co-authored-by: rekram1-node <63023139+rekram1-node@users.noreply.github.com>
2026-10-06 14:15:40 -05:00
Shoubhit Dash ed0e7acecd fix(acp): reject a mismatched fork cwd and resolve overlapping provider IDs (#53534) 2026-10-06 22:49:59 +05:30
Adam de2cacdac8 fix(docs): redirect inference help link 2026-10-06 11:18:52 -05:00
opencode-agent[bot] 6bffe7932e chore(core): refresh bundled models.dev snapshot 2026-10-06 12:21:22 +00:00
Victor Navarro ba281e7f91 docs(console): add workspace, providers, and api docs (#53531) 2026-10-06 14:11:33 +02:00
Shoubhit Dash f17b15eaa5 fix(acp): tighten cwd, cancel, delete, and terminal auth handling (#53359) 2026-10-06 17:15:51 +05:30
Shoubhit Dash f6ae986549 fix(acp): report tool names and full-file diffs (#53360) 2026-10-06 17:12:27 +05:30
Shoubhit Dash fb72e25c06 fix(acp): wait for a cold location's plugins before the first catalog read (#53358) 2026-10-06 17:10:48 +05:30
opencode-agent[bot] 184890e429 chore: update nix node_modules hashes 2026-10-06 11:23:46 +00:00
opencode-agent[bot]andBrendonovich a7523ac4b7 fix(ui): render dollar math with marked-katex-extension (#53513)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
2026-10-06 19:13:35 +08:00
535 changed files with 16026 additions and 3082 deletions

No files matched your search

+31 -20
View File
@@ -506,6 +506,10 @@
"name": "@opencode/gui-extensions",
"version": "2.0.24",
"dependencies": {
"@betteroffice/docx": "0.4.3",
"@betteroffice/fonts": "0.4.0",
"@betteroffice/pptx": "0.2.0",
"@betteroffice/xlsx": "0.3.0",
"@dnd-kit/abstract": "0.5.0",
"@dnd-kit/dom": "0.5.0",
"@dnd-kit/solid": "0.5.0",
@@ -634,8 +638,8 @@
},
"peerDependencies": {
"@opencode/theme": "workspace:*",
"@opentui/core": ">=0.5.14",
"@opentui/solid": ">=0.5.14",
"@opentui/core": ">=0.5.16",
"@opentui/solid": ">=0.5.16",
"solid-js": ">=1.9.0",
},
"optionalPeers": [
@@ -969,6 +973,7 @@
"fuzzysort": "catalog:",
"katex": "0.16.47",
"marked": "catalog:",
"marked-katex-extension": "5.1.13",
"marked-shiki": "catalog:",
"motion": "12.34.5",
"remeda": "catalog:",
@@ -1151,9 +1156,9 @@
"@npmcli/arborist": "9.4.0",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.0.0-20250322224806",
"@opentui/core": "0.5.14",
"@opentui/keymap": "0.5.14",
"@opentui/solid": "0.5.14",
"@opentui/core": "0.5.16",
"@opentui/keymap": "0.5.16",
"@opentui/solid": "0.5.16",
"@pierre/diffs": "1.5.1",
"@playwright/test": "1.59.1",
"@sentry/solid": "10.71.0",
@@ -1633,6 +1638,14 @@
"@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
"@betteroffice/docx": ["@betteroffice/docx@0.4.3", "", { "peerDependencies": { "@betteroffice/fonts": "^0" }, "optionalPeers": ["@betteroffice/fonts"] }, "sha512-CEErXJH3iCsi2a61gTNkAofLCzSTcktLmp710gGhMwbBfOqwQ2yI7dRFBV3ElGa9JxkS03IfejvLX0sAvlTrUQ=="],
"@betteroffice/fonts": ["@betteroffice/fonts@0.4.0", "", { "peerDependencies": { "@betteroffice/fonts-cjk": "^0" }, "optionalPeers": ["@betteroffice/fonts-cjk"] }, "sha512-x1BVwYDAgY5R6TWI4t9NLguSiAEbH5GItN2ZlpBIFoRXTIJgjBsXd6sUxPGpexXOyY6KdhRjG8XvHjyAYxEGCw=="],
"@betteroffice/pptx": ["@betteroffice/pptx@0.2.0", "", {}, "sha512-pNPQ58tlA+pVibERbLdQNskvP7a0GIMf4jhkCU/gPp8043Ichf6gB3PSb4ra9sfqoIaWqOaZKCWyptovA2+Q0A=="],
"@betteroffice/xlsx": ["@betteroffice/xlsx@0.3.0", "", {}, "sha512-K2bHtdk/epAxsmvxJlIWBRndjP3ltQU0Oh3p4gcZd2n5/YgXglo3SmMYX4nQe8WEm/yvz91p+aIasKyXXQP9Wg=="],
"@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="],
"@brendonovich/vite-plugin-opencode": ["@brendonovich/vite-plugin-opencode@0.1.3", "", { "dependencies": { "@babel/core": "^7.29.0", "@opencode-ai/client": "0.0.0-beta-18050" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-iiIwlNoycOMUiaUzL1ZirLapCG3WY8cg9hSj4KgE/JYIWgqauoHikIlfUt7SdMqqGIkb4iZu6I1MxgDDJaRfBA=="],
@@ -2289,27 +2302,27 @@
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
"@opentui/core": ["@opentui/core@0.5.14", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.14", "@opentui/core-darwin-x64": "0.5.14", "@opentui/core-linux-arm64": "0.5.14", "@opentui/core-linux-arm64-musl": "0.5.14", "@opentui/core-linux-x64": "0.5.14", "@opentui/core-linux-x64-musl": "0.5.14", "@opentui/core-win32-arm64": "0.5.14", "@opentui/core-win32-x64": "0.5.14" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-tfQ+PWQyeBnYloB3diEcPqbILv14xemH5jjAEICfPuyNDtGBqrjhUtThrhbvFRuPMcj6IEeXrAk6VE8e91h0kg=="],
"@opentui/core": ["@opentui/core@0.5.16", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.16", "@opentui/core-darwin-x64": "0.5.16", "@opentui/core-linux-arm64": "0.5.16", "@opentui/core-linux-arm64-musl": "0.5.16", "@opentui/core-linux-x64": "0.5.16", "@opentui/core-linux-x64-musl": "0.5.16", "@opentui/core-win32-arm64": "0.5.16", "@opentui/core-win32-x64": "0.5.16" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-RDVip7Ih8Lg5tFkwTDGFqc0TXx8A+rRvm3UuDAqd9YayDx4fIsECBjSS8FDPLYvq5KP1gJB4oY8iGM8WgTbNqw=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.14", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wWmw41wRMBoI0lN9mgyzGRwYujwwfNkBP6jYM99k4Bx2XkeSZ3sCeu5bwX9vEJPYqjiBShbDhc0NnVSP7NwzVg=="],
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mbdp/A2KJOv7hI0b0ezqZx/5vh5G6LwhZnjRW4K3hNcoZM4yC55y/D+L8J960rT4o7QRB3cNXr3NSlnVi1btZA=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.14", "", { "os": "darwin", "cpu": "x64" }, "sha512-7smHKDH8IhUaBsgYuAClMl2mHWu+yjpMrtdw3wEvBVtCzKMrHi/TJ5PtydO+IfUzR3BXpVubdbR1irD8BTcR/w=="],
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-D1oA0VBitDHOYrg58GaxQQNAXJ1nSFwu2HQMZklL/LkrqZLX23K/oxgutH/GKvLsyRQNsIVfsXmGZ2LtGiGpxA=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-xH1hP+NaLySEJeZkl21NlkZBMddMfQ1jU8NeX1AEBc2GNBOvDXU4Ud/xw87SrAvU1xG9K7/9C4oy4AmIMEpVGg=="],
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-ghu4tKIR3wZMZ8Ih/VLeyyG/C7kQgAZuKoGKRSUPcVEF6Qr99yHhtIixBrBoFXfqVm63n5lGimS6KKqbdUQ1yA=="],
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.14", "", { "os": "linux", "cpu": "arm64" }, "sha512-mnBBAuTb92NiRLAjOD755tS8/tNQemDztbg9tMvoCT90G52FtVrRb31Ge6OrYqfm0c9DkZGhEBOhunsId/4zSA=="],
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-t1vppHpf6iR7k+JF6kQtcLKr11gIxm2nH1h9y3eawrG4NCXDQbOvn7XtC6KsT3I1iy0A2Yy+nM0heISziORZlQ=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.14", "", { "os": "linux", "cpu": "x64" }, "sha512-Hkk4kaDGMcn9bmJFJPW3/QOGGbPuWe3sCFV/CkiVb4+bCvcTm7EXQr4QTAA63BYy2dKE5bUFUi1zZlyeMkWpnA=="],
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.16", "", { "os": "linux", "cpu": "x64" }, "sha512-y63M7JrjfAQPUwTXogDGqBjS46DfC51LebBUQYVE01/N2F1inybD08qEfxUAFx/Omlf7CXef6liLDdRyTLaohw=="],
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.14", "", { "os": "linux", "cpu": "x64" }, "sha512-ngJ+U2grOGEteeQvZdAJNqn09M+At5mfWInauK5aS427bea1yLo+e6hor/CRmbn9SxEEF+SwoyekaOrLPWyU7w=="],
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.16", "", { "os": "linux", "cpu": "x64" }, "sha512-lQ1kRwFPBRElG2uFl0afWzpHyUwVEizbV2Ue1IA8DXH15sRCOd7KqeOltpzuKJYIyLey7vLF8SofAe8K1JNnTg=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.14", "", { "os": "win32", "cpu": "arm64" }, "sha512-T9kNqKXg2jysmTsyyZ1A8LBQotFBM+iPjzyRslxyexqrs8a1UcmxbApEo+COtxQuqukMTbvwyqEdAT8vcmxEkQ=="],
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-cML9+1tqEe+SaB5xlx9jKcYAIG15Eg9sImH/LYyMbm+al7dRBNy5IzdFCldXfwC50blM/goiyzLN1CjTo02vCQ=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.14", "", { "os": "win32", "cpu": "x64" }, "sha512-mqKSkab8VdMLSmMdocna7+BTyMoIutkVXOV9lfmPrBO2g7Np5c6c4SJ4QIVZqPvast11XyT0/7FfXOYLKAS72w=="],
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.16", "", { "os": "win32", "cpu": "x64" }, "sha512-1QZ9yHK9xTZBNXVgjPfbdQ94nfw0/KZic9XkuAsNBzUGTkYmfGKZSvPB1YKomBt/1lipRoCdMAnihlS/R7g5eg=="],
"@opentui/keymap": ["@opentui/keymap@0.5.14", "", { "dependencies": { "@opentui/core": "0.5.14" }, "peerDependencies": { "@opentui/react": "0.5.14", "@opentui/solid": "0.5.14", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-YGTAvRrpQTbRNV7GH0UxRuCSPxwnSooVdB+qPHHP+3ywc93+lhekljgP8dRivl32f3CiMqqm96Uj2PgwKxkC0Q=="],
"@opentui/keymap": ["@opentui/keymap@0.5.16", "", { "dependencies": { "@opentui/core": "0.5.16" }, "peerDependencies": { "@opentui/react": "0.5.16", "@opentui/solid": "0.5.16", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-W78sDuTHMjHa8NwYmoGx5Xy0ztcGsuzrUa/1d24jADj9JCYEJQjABnrWZBRSExsNjiFYV3SxeCKwAPhJli0M3g=="],
"@opentui/solid": ["@opentui/solid@0.5.14", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.14", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-bBRl34mZ0wFGhjHX6y1VNiZmJ3DSm2DVPm0PNSVDpvq9qxRHuywEPTCn/Lgte0C9450tgf11cDqcE3pR9cZwVA=="],
"@opentui/solid": ["@opentui/solid@0.5.16", "", { "dependencies": { "@babel/core": "7.29.7", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.16", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-gCULWG+HORd5IVydiCchlmULgY1PQccODJvJKDNYJHDmhwyg9/sNSFUxoYajEXLZ40pUIL8ENAK+6p34Z9m/JQ=="],
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
@@ -4607,6 +4620,8 @@
"marked": ["marked@18.0.11", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw=="],
"marked-katex-extension": ["marked-katex-extension@5.1.13", "", { "peerDependencies": { "katex": ">=0.16 <0.19", "marked": ">=4 <19" } }, "sha512-+6gVygGg5at9g+YsuIQZk7XcAc6Pg1P0grEJKEWvF7DAwceZ7ZIvU0fhQe6auUqSbnPmSjJxZuICdSCdbGaFRw=="],
"marked-shiki": ["marked-shiki@1.2.1", "", { "peerDependencies": { "marked": ">=7.0.0", "shiki": ">=1.0.0" } }, "sha512-yHxYQhPY5oYaIRnROn98foKhuClark7M373/VpLxiy5TrDu9Jd/LsMwo8w+U91Up4oDb9IXFrP0N1MFRz8W/DQ=="],
"marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="],
@@ -6277,8 +6292,6 @@
"@opentui/core/marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="],
"@opentui/solid/@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="],
"@opentui/solid/babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="],
"@oslojs/jwt/@oslojs/encoding": ["@oslojs/encoding@0.4.1", "", {}, "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q=="],
@@ -7169,8 +7182,6 @@
"@opentelemetry/instrumentation/@opentelemetry/api-logs/@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
"@opentui/solid/@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@oxc-resolver/binding-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
"@pierre/trees/react-dom/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
+3 -3
View File
@@ -1,7 +1,7 @@
{
"nodeModules": {
"x86_64-linux": "sha256-yGEhVYKrwrbGL76w4spbGIBGLTU0cA5F5OYdTmKaNwc=",
"aarch64-linux": "sha256-IwygJZ9nJTvqOKrulRYteqC1xqL8Fba1eRruNvmmen0=",
"aarch64-darwin": "sha256-3l0bkSPYw71M0g7fvtOwm8BXQxe1bNSnjc3tb1js434="
"x86_64-linux": "sha256-GHLheOh+zY847BpZ9G/vCfjPT7jUt8doODFOQP9REjw=",
"aarch64-linux": "sha256-+To0HYoZzNJ5Qd7y22/ZvljcxQbchGBvYaCPYhte2As=",
"aarch64-darwin": "sha256-KVGWrTpe8SB8PgKAyb+2FFRBvXLkJlJVsVTHa/bUhg0="
}
}
+3 -3
View File
@@ -53,9 +53,9 @@
"@octokit/rest": "22.0.0",
"@hono/standard-validator": "0.2.0",
"@hono/zod-validator": "0.4.2",
"@opentui/core": "0.5.14",
"@opentui/keymap": "0.5.14",
"@opentui/solid": "0.5.14",
"@opentui/core": "0.5.16",
"@opentui/keymap": "0.5.16",
"@opentui/solid": "0.5.16",
"@tanstack/solid-virtual": "3.13.37",
"@shikijs/stream": "4.4.3",
"@standard-schema/spec": "1.1.0",
@@ -285,7 +285,7 @@ const AnthropicThinkingEnabled = Schema.Struct({
...AnthropicThinkingFields,
})
const AnthropicThinkingAdaptive = Schema.Struct({ type: Schema.tag("adaptive"), ...AnthropicThinkingFields })
const AnthropicThinkingDisabled = Schema.Struct({ type: Schema.tag("disabled") })
const AnthropicThinkingDisabled = Schema.Struct({ type: Schema.Literals(["disabled", "between_tools"]) })
const AnthropicThinking = Schema.Union([AnthropicThinkingEnabled, AnthropicThinkingAdaptive, AnthropicThinkingDisabled])
type AnthropicThinking = typeof AnthropicThinking.Type
@@ -1001,18 +1001,21 @@ const lowerMessages = Effect.fnUntraced(function* (request: LLMRequest, breakpoi
// TODO: Move per-model capability heuristics (`supportsEffortUpdates`, `supportsNativeSystemUpdates`,
// `supportsThinkingBlockBinding`) into explicit model/provider `compatibility` metadata so the protocol
// only reads `request.model.compatibility`.
const isThinkingOff = Schema.is(AnthropicThinkingDisabled)
// Per-turn effort started with Claude Opus 5 and every Claude 5.1 model; later versions of any family inherit it.
const supportsEffortUpdates = (model: LLMRequest["model"]) => {
const override = model.compatibility?.supportsEffortUpdates
const supportsEffortUpdates = (request: LLMRequest) => {
if (isThinkingOff(request.providerOptions?.thinking)) return false
const override = request.model.compatibility?.supportsEffortUpdates
if (override !== undefined) return override
const version = claudeVersion(model.id)
const version = claudeVersion(request.model.id)
if (version === undefined) return false
if (version.family === "opus" && version.major >= 5) return true
return version.major > 5 || (version.major === 5 && version.minor >= 1)
}
const applyThinkingBindingDefault = (model: LLMRequest["model"], thinking: AnthropicThinking | undefined) => {
if (thinking?.type === "disabled") return thinking
if (isThinkingOff(thinking)) return thinking
if (!supportsThinkingBlockBinding(model)) return thinking
return {
...(thinking ?? { type: "adaptive" as const }),
@@ -1607,7 +1610,7 @@ export const protocol = Protocol.make({
}),
step,
},
supportsEffortUpdates: (request) => supportsEffortUpdates(request.model),
supportsEffortUpdates,
})
export const transport = <
@@ -1653,7 +1656,7 @@ function requiredBetaHeaders(body: Pick<AnthropicMessagesBody, "messages" | "con
betas.push("mid-conversation-output-config-2026-07-01")
const thinking = body.thinking
if (thinking && thinking.type !== "disabled" && thinking.block_binding) betas.push(THINKING_BINDING_BETA)
if (thinking && !isThinkingOff(thinking) && thinking.block_binding) betas.push(THINKING_BINDING_BETA)
return betas
}
@@ -476,7 +476,9 @@ const MIN_THINKING_BUDGET = 1_024
const isThinkingDisabled = Schema.is(
Schema.Struct({
additionalModelRequestFields: Schema.Struct({ thinking: Schema.Struct({ type: Schema.Literal("disabled") }) }),
additionalModelRequestFields: Schema.Struct({
thinking: Schema.Struct({ type: Schema.Literals(["disabled", "between_tools"]) }),
}),
}),
)
@@ -33,7 +33,7 @@ const Options = Schema.Struct({
store: lenient(Schema.Boolean),
thinkingLevel: lenient(ThinkingLevel),
thinkingSummaries: lenient(knownString<"auto" | "none">()),
serviceTier: lenient(knownString<"standard" | "flex" | "priority">()),
serviceTier: lenient(knownString<"standard" | "flex" | "priority" | "deferred">()),
})
export type OptionsInput = typeof Options.Encoded
export type ProviderOptionsInput = OptionsInput
@@ -507,6 +507,7 @@ const lowerReasoning = (part: ReasoningPart, providerMetadataKey: string): OpenR
typeof metadata.reasoningEncryptedContent === "string" || metadata.reasoningEncryptedContent === null
? metadata.reasoningEncryptedContent
: undefined
if (part.text.length === 0 && !encryptedContent) return undefined
return {
type: "reasoning",
...(id === undefined ? {} : { id }),
@@ -37,7 +37,8 @@ export const defaultChain = (options: DefaultChainOptions): Effect.Effect<Creden
Effect.tryPromise({
try: async () => {
const { fromNodeProviderChain } = await import("@aws-sdk/credential-providers")
const identity = await fromNodeProviderChain(options.profile === undefined ? {} : { profile: options.profile })()
// ignoreCache re-reads shared config and SSO token files, so `aws sso login` takes effect without a restart.
const identity = await fromNodeProviderChain({ ignoreCache: true, profile: options.profile })()
return {
region: options.region,
accessKeyId: identity.accessKeyId,
@@ -9,7 +9,8 @@ export type OpenAITextVerbosity = OpenResponsesOptions.TextVerbosity
// in lockstep with `openai-node/src/resources/responses/responses.ts`.
export const OpenAIResponseIncludables = OpenResponsesOptions.ResponseIncludables
export type OpenAIResponseIncludable = OpenResponsesOptions.ResponseIncludable
export const OpenAIServiceTiers = [...OpenResponsesOptions.ServiceTiers, "scale"] as const
// Mirrors OpenAI's `ServiceTier` union from the official SDK.
export const OpenAIServiceTiers = [...OpenResponsesOptions.ServiceTiers, "scale", "fast", "ultrafast"] as const
export type OpenAIServiceTier = (typeof OpenAIServiceTiers)[number] | (string & {})
export const OpenAIReasoningEffort = OpenResponsesOptions.ReasoningEffort
@@ -65,8 +65,8 @@ const messagesRoute = Route.make({
...AnthropicMessages.protocol,
// Mantle rejects mid-conversation `output_config` on Opus 5.0; support starts at 5.1+.
supportsEffortUpdates: (request) => {
const override = request.model.compatibility?.supportsEffortUpdates
if (override !== undefined) return override
if (!(AnthropicMessages.protocol.supportsEffortUpdates?.(request) ?? false)) return false
if (request.model.compatibility?.supportsEffortUpdates !== undefined) return true
const version = claudeVersion(request.model.id)
return version !== undefined && (version.major > 5 || (version.major === 5 && version.minor >= 1))
},
+16
View File
@@ -268,6 +268,22 @@ describe("Anthropic Messages effort updates", () => {
}),
)
it.effect("strips markers when thinking is disabled or between_tools", () =>
Effect.gen(function* () {
const sonnet = anthropic("claude-sonnet-5-5")
const betweenTools = yield* compileRequest(
LLM.request({
model: sonnet,
messages: conversation,
providerOptions: { thinking: { type: "between_tools" }, effort: "low" },
}),
)
expect(systemMessages(betweenTools.body)).toHaveLength(0)
expect(betweenTools.body.output_config).toEqual({ effort: "low" })
}),
)
it.effect("strips markers for Opus 5.0 on Bedrock Mantle Messages while lowering Opus 5.5", () =>
Effect.gen(function* () {
const mantle = AmazonBedrockMantle.configure({ apiKey: "test", region: "us-east-1" })
@@ -9,6 +9,7 @@ LLM.request({ model: selected, prompt: "Hello", providerOptions: { reasoningEffo
LLM.request({ model: selected, prompt: "Hello", providerOptions: { textVerbosity: "low" } })
LLM.request({ model: selected, prompt: "Hello", providerOptions: { textVerbosity: "verbose" } })
LLM.request({ model: selected, prompt: "Hello", providerOptions: { serviceTier: "scale" } })
LLM.request({ model: selected, prompt: "Hello", providerOptions: { serviceTier: "ultrafast" } })
LLM.request({ model: selected, prompt: "Hello", providerOptions: { serviceTier: "future-tier" } })
LLM.request({ model: chat, prompt: "Hello", providerOptions: { reasoningEffort: "max" } })
LLM.request({ model: chat, prompt: "Hello", providerOptions: { reasoningEffort: "experimental" } })
@@ -44,6 +44,7 @@ it.effect("preserves explicit thinking settings and combines required beta heade
Effect.gen(function* () {
for (const thinking of [
{ type: "disabled" },
{ type: "between_tools" },
{ type: "adaptive", block_binding: { prefix_mismatch_behavior: "error" } },
] as const) {
const request = LLM.request({
@@ -55,7 +56,7 @@ it.effect("preserves explicit thinking settings and combines required beta heade
const prepared = yield* AnthropicMessages.route.prepareTransport(compiled.body, request)
expect(compiled.body.thinking).toEqual(thinking)
expect(prepared.request.headers["anthropic-beta"]).toBe(
thinking.type === "disabled"
thinking.type === "disabled" || thinking.type === "between_tools"
? "interleaved-thinking-2025-05-14,compact-2026-01-12"
: "interleaved-thinking-2025-05-14,compact-2026-01-12,thinking-binding-controls-2026-08-01",
)
@@ -325,11 +325,13 @@ describe("OpenAI Responses route", () => {
}),
)
it.effect("passes through provider-defined service tiers", () =>
it.effect("passes through provider-defined and future service tiers", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(LLMRequest.update(request, { providerOptions: { serviceTier: "scale" } }))
for (const serviceTier of ["scale", "ultrafast", "future-tier"]) {
const prepared = yield* compileRequest(LLMRequest.update(request, { providerOptions: { serviceTier } }))
expect(prepared.body.service_tier).toBe("scale")
expect(prepared.body.service_tier).toBe(serviceTier)
}
}),
)
@@ -4011,6 +4013,46 @@ describe("OpenAI Responses route", () => {
}),
)
it.effect("drops empty reasoning items without summary or encrypted content", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(
LLM.request({
id: "req_reasoning_empty_shell",
model,
messages: [
Message.user("What changed?"),
Message.assistant([
{
type: "reasoning",
text: "",
providerMetadata: {
openai: {
itemId: "rs_6aa28a10c05cf9f566f44022:rs_01a08aeb51217b92a5b853a0cb5b20ca",
reasoningEncryptedContent: null,
},
},
},
{ type: "text", text: "The parser changed." },
]),
Message.user("Summarize it."),
],
providerOptions: { store: false },
}),
)
expect(prepared.body.input).toEqual([
{ type: "message", role: "user", content: [{ type: "input_text", text: "What changed?" }] },
{
type: "message",
role: "assistant",
status: "completed",
content: [{ type: "output_text", text: "The parser changed." }],
},
{ type: "message", role: "user", content: [{ type: "input_text", text: "Summarize it." }] },
])
}),
)
it.effect("assembles streamed function call input", () =>
Effect.gen(function* () {
const body = sseEvents(
@@ -282,13 +282,28 @@ story("restores the current URL each time the same submitted navigation is block
await address.press("Enter")
await expect(address).toHaveValue("https://blocked.example/")
await root.getByRole("button", { name: "Block navigation", exact: true }).click()
await expect(root.getByRole("alert")).toHaveText("Request failed")
await expect(root.getByRole("alert")).toHaveText("Only web pages can open here.")
await expect(address).toHaveValue("https://alpha.example/")
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
})
}
})
story("explains why a typed address cannot open instead of searching for it", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
for (const [typed, reason] of [
["ftp://example.com", "Only web pages can open here."],
["https://user:pass@example.com", "Addresses with a user name or password can't open here."],
]) {
await address.fill(typed)
await address.press("Enter")
await expect(root.getByRole("alert")).toHaveText(reason)
await expect(address).toHaveValue("https://alpha.example/")
}
})
story("shows a themed failure state for only the failed tab and allows retry", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
await root.getByRole("button", { name: "Failed page", exact: true }).click()
@@ -435,6 +450,9 @@ story("suggests visited pages and opens the first one that completes the typed a
const options = page.getByRole("option")
await expect(options).toHaveCount(1)
await expect(options.first()).toHaveAttribute("aria-selected", "true")
// Arrow keys that pick IME candidates leave the suggestions alone.
await address.dispatchEvent("keydown", { key: "ArrowDown", isComposing: true })
await expect(options.first()).toHaveAttribute("aria-selected", "true")
await address.press("Enter")
await expect(address).toHaveValue("http://localhost:5173/settings")
@@ -451,14 +469,39 @@ story("suggests visited pages and opens the first one that completes the typed a
story("lists recent pages on a blank tab and opens one", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
const address = root.getByRole("combobox", { name: "Browser address", exact: true })
await root.getByRole("button", { name: "Seed history", exact: true }).click()
await root.getByRole("button", { name: "Blank page", exact: true }).click()
await expect(root.getByText("Recent", { exact: true })).toBeVisible()
// The globe at the field's start belongs to the field: a click there focuses it.
await expect(address).not.toBeFocused()
await root.locator('[data-component="browser-address"]').click({ position: { x: 16, y: 14 } })
await expect(address).toBeFocused()
await address.blur()
await root.getByRole("button", { name: /^Settings - Preview/ }).click()
await expect(root.getByRole("combobox", { name: "Browser address", exact: true })).toHaveValue(
"http://localhost:5173/settings",
)
await expect(address).toHaveValue("http://localhost:5173/settings")
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
// The opened page owns the field afterwards: an edit that is never submitted shows its URL again.
await address.click()
await address.fill("unsubmitted")
await address.blur()
await expect(address).toHaveValue("http://localhost:5173/settings")
})
story("adds the whole page to the session and keeps the draft when the button is pressed again", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
const field = root.locator('[data-component="browser-address"]')
const add = root.getByRole("button", { name: "Add page to session", exact: true })
await field.hover()
await add.click()
const editor = root.locator('[data-slot="browser-comment-editor"] textarea')
await editor.fill("Check the header layout")
await field.hover()
await add.click()
await expect(editor).toHaveValue("Check the header layout")
await editor.press("Enter")
await expect(root.getByTestId("fixture-comments").getByRole("listitem")).toHaveText([/: Check the header layout$/])
})
story("focuses the address field when the page uses the address shortcut", async ({ page }) => {
@@ -478,12 +521,22 @@ story("shows the page's cookies in the site information and clears them", async
await expect(site).toContainText("0 cookies in use")
})
story("zooms the page from the browser options and shows its zoom", async ({ page }) => {
story("zooms the page from the browser options in view and keeps its zoom in the address field", async ({ page }) => {
const root = page.getByTestId("browser-pane-fixture")
await root.getByRole("button", { name: "Browser options", exact: true }).click()
const options = root.getByRole("button", { name: "Browser options", exact: true })
await options.click()
await page.getByRole("menuitem", { name: /^Zoom in/ }).click()
await expect(root.getByText("Zoom: 110", { exact: true })).toBeVisible()
// The menu covered the page with a still; it closes so the zoomed page shows at once.
await expect(page.getByRole("menu")).toBeHidden()
await expect(root.getByTestId("native-Alpha")).toHaveAttribute("data-visible", "true")
const zoom = root.getByRole("button", { name: "110%", exact: true })
await expect(zoom).toBeVisible()
await options.click()
await expect(page.getByRole("menuitem", { name: /^Reset zoom/ })).toContainText("110%")
await page.getByRole("menuitem", { name: /^Reset zoom/ }).click()
await page.keyboard.press("Escape")
await zoom.click()
await expect(root.getByText("Zoom: 100", { exact: true })).toBeVisible()
await expect(zoom).toBeHidden()
})
@@ -85,7 +85,7 @@ const router: Router = { routing: () => false, path: () => "/" }
const keybinds: Keybinds = { keybind: () => [], keys: (bind) => bind.split("+"), matches: () => false }
const servers: Servers = { list: () => [] }
const servers: Servers = { list: () => [], get: () => undefined }
const workspaces: Workspaces = { on: () => () => undefined }
@@ -348,6 +348,7 @@ function standIn(overrides: Partial<Interface>): Interface {
keybind: () => [],
matches: () => false,
servers: () => ["local"],
server: () => undefined,
...overrides,
}
}
@@ -38,6 +38,16 @@ test("home commands do not wait for session search", async ({ page }) => {
release.resolve()
})
test("lists recent sessions before a query is entered", async ({ page }) => {
const { dialog } = await openCommandPalette(page, true)
const session = dialog.getByRole("option", { name: /Palette fixture session/ })
await expect(dialog.getByText("Recent sessions", { exact: true })).toBeVisible()
await expect(session).toHaveAttribute("aria-selected", "false")
await session.click()
await expect(dialog).toHaveCount(0)
await expect(page.getByRole("heading", { name: paletteSession.title, exact: true })).toBeVisible()
})
test("appends search results without resetting the selected command", async ({ page }) => {
const { dialog, input } = await openCommandPalette(page)
const files = Promise.withResolvers<void>()
@@ -213,7 +213,18 @@ test("keeps a narrow session composer contained when invoking a built-in", async
await page.getByRole("menuitem", { name: "Commands" }).click()
await page.locator('[data-suggestion-id="model.choose"]').click()
const dialog = page.getByRole("dialog", { name: "Select model", exact: true })
const search = dialog.getByRole("searchbox", { name: "Search models", exact: true })
await expect(search).toBeFocused()
await expect(editor).toHaveText("keep me")
await page.keyboard.press("Escape")
await expect(dialog).toBeHidden()
await editor.fill("/model")
await expect(page.locator('[data-suggestion-id="model.choose"]')).toHaveAttribute("data-active", "")
await editor.press("Enter")
await expect(search).toBeFocused()
await expect(editor).toBeEmpty()
})
test("lists slash commands in their built-in order", async ({ page }) => {
+81 -1
View File
@@ -1,6 +1,8 @@
import { expect, test, type Page } from "@playwright/test"
import { holdRoute, seed, sessionHref } from "../utils/app"
import { holdRoute, NO_PROVIDER, project, REMOTE_SERVER, seed, sessionHref } from "../utils/app"
import { mockOpenCodeServer } from "../utils/mock-server"
import { fixture, mockStressTimeline } from "../utils/session-fixture"
import { mockRemoteServer } from "../utils/workspace"
import { expectAppVisible } from "../utils/waits"
test.use({ serviceWorkers: "block" })
@@ -85,8 +87,11 @@ test("Home shows loaded sessions before the location request resolves", async ({
test("Home and the directory picker load without newer browser APIs", async ({ page }) => {
await page.addInitScript(() => {
// Safari 16.6 has none of these APIs. Remove them before the web entry runs.
// SAFETY: `Partial` only makes the static method optional so `delete` type-checks; the target is the real global.
delete (Map as Partial<typeof Map>).groupBy
// SAFETY: as above, for the real global `Promise`.
delete (Promise as Partial<typeof Promise>).withResolvers
// SAFETY: as above, for the real global `Promise`.
delete (Promise as Partial<typeof Promise>).try
})
await openHome(page, { fileList: () => [] })
@@ -101,6 +106,81 @@ test("Home and the directory picker load without newer browser APIs", async ({ p
await expect(target).toBeVisible()
})
test("adding a project to a signed-out server re-pairs it, then continues at the paired address", async ({ page }) => {
// The saved address rejects the new token, so saving moves the server to the link's address.
const paired = "http://127.0.0.1:4098"
await mockRemoteServer(page, { name: "Remote", password: "old-password" })
await mockOpenCodeServer(page, {
server: paired,
directory: "/remote/paired",
project: project({ id: "proj_paired", directory: "/remote/paired" }),
provider: NO_PROVIDER,
sessions: [],
pageMessages: () => ({ items: [] }),
fileList: () => [],
password: "session-token",
pairing: { code: "one-time-code", token: "session-token" },
})
await openHome(page, { fileList: () => [] })
const remote = page.locator("[data-home-row]").filter({ hasText: "Remote" })
await expect(page.getByRole("button", { name: "Authenticate", exact: true })).toBeVisible()
await remote.getByRole("button", { name: "Add project", exact: true }).click()
const editor = page.getByRole("dialog", { name: "Edit server" })
await editor.getByLabel("Pairing link", { exact: true }).fill(`${paired}/auth/connect/one-time-code`)
await editor.getByRole("button", { name: "Save", exact: true }).click()
// The folder picker reads the paired address; the removed one would reject the request.
const picker = page.getByRole("dialog").filter({ has: page.getByRole("button", { name: "Select folder" }) })
await expect(picker.getByRole("button", { name: "Select folder", exact: true })).toBeEnabled()
await expect(picker.getByText("Unable to read this folder")).toHaveCount(0)
})
test("a server whose saved password changes works with the new password", async ({ page }) => {
const accepted = { password: "old-password" }
await mockOpenCodeServer(page, {
server: REMOTE_SERVER,
directory: "/remote/project",
project: project({ id: "proj_remote", directory: "/remote/project" }),
provider: NO_PROVIDER,
sessions: [],
pageMessages: () => ({ items: [] }),
fileList: () => [],
password: () => accepted.password,
})
// Saved with the password the server accepts until the test changes it.
await seed(page, {
storage: {
"opencode.global.dat:server": {
list: [{ type: "http", displayName: "Remote", http: { url: REMOTE_SERVER, password: "old-password" } }],
},
},
})
await openHome(page, { fileList: () => [] })
const remote = page.locator("[data-home-row]").filter({ hasText: "Remote" })
const picker = page.getByRole("dialog").filter({ has: page.getByRole("button", { name: "Select folder" }) })
// Use the server once, so its controller exists with the old password.
await remote.getByRole("button", { name: "Add project", exact: true }).click()
await expect(picker.getByRole("button", { name: "Select folder", exact: true })).toBeEnabled()
await picker.getByRole("button", { name: "Cancel", exact: true }).click()
await expect(picker).toHaveCount(0)
await remote.getByRole("button", { name: "More options", exact: true }).click()
await page.getByRole("menuitem", { name: "Edit", exact: true }).click()
const editor = page.getByRole("dialog", { name: "Edit server" })
await editor.getByPlaceholder("password").fill("new-password")
// The server now rejects the old password, as after `opencode service set password`.
accepted.password = "new-password"
await editor.getByRole("button", { name: "Save", exact: true }).click()
await expect(editor).toHaveCount(0)
// The picker reads the folder through the server's controller, which must use the saved password now.
await remote.getByRole("button", { name: "Add project", exact: true }).click()
await expect(picker.getByRole("button", { name: "Select folder", exact: true })).toBeEnabled()
await expect(picker.getByText("Unable to read this folder")).toHaveCount(0)
})
const recovery = "C:/OpenCode/Worktrees/project-menu-recovery"
const worktree =
+83 -3
View File
@@ -1,6 +1,7 @@
import { expect, test, type Page } from "@playwright/test"
import type { ConfigEntry, OpenCodeEvent, WorktreeDirectory } from "@opencode/client/promise"
import { NO_PROVIDER, REMOTE_SERVER, SERVER, holdRoute, project, session } from "../utils/app"
import { mockOpenCodeServer } from "../utils/mock-server"
import { mockRemoteServer, mockWorkspace, openSettings, type WorkspaceInput } from "../utils/workspace"
const directory = "C:/Projects/settings-demo"
@@ -463,7 +464,7 @@ test("worktrees follow inventory events, wait for session counts, and delete by
worktrees: () => inventory,
onWorktreeRemove: (body) => {
inventory.splice(
inventory.findIndex((item) => item.directory === (body as { directory: string }).directory),
inventory.findIndex((item) => item.directory === body.directory),
1,
)
},
@@ -499,6 +500,7 @@ test("worktrees follow inventory events, wait for session counts, and delete by
// Home never listed this session, so only the new worktree's directory read can show it.
view.sessions.push(session({ id: "ses_discovered", directory: discovered, title: "Discovered session", projectID }))
inventory.push({ directory: discovered, strategy: "git" })
// SAFETY: a worktree.updated event carries only the project ID, which is all the app reads from it.
await view.push([
{ id: "evt_settings_worktree_updated", created: Date.now(), type: "worktree.updated", data: { projectID } },
] as OpenCodeEvent[])
@@ -582,7 +584,9 @@ test.describe("worktrees prefetch", () => {
test("server Worktrees hover only prefetches metadata", async ({ page }) => {
const { settings } = await open(page)
const calls = { projects: 0, worktrees: [] as string[], refreshes: [] as string[] }
const calls = { projects: 0, worktrees: new Array<string>(), refreshes: new Array<string>() }
page.on("request", (request) => {
if (new URL(request.url()).pathname === "/api/worktree/refresh")
calls.refreshes.push(request.postDataJSON().projectID)
@@ -754,7 +758,9 @@ test("the add server dialog keeps focus above fullscreen settings", async ({ pag
await settings.getByRole("button", { name: "Add server" }).click()
const editor = page.getByRole("dialog", { name: "Add server" })
await expect(editor.getByPlaceholder("http://localhost:4096")).toBeFocused()
await expect(editor.getByLabel("Pairing link", { exact: true })).toBeFocused()
await expect(editor.getByPlaceholder("password")).toHaveCount(0)
await editor.getByRole("button", { name: "Use password", exact: true }).click()
await expect(editor.getByPlaceholder("username")).toHaveCount(0)
const name = editor.getByPlaceholder("Localhost", { exact: true })
await name.click()
@@ -766,6 +772,80 @@ test("the add server dialog keeps focus above fullscreen settings", async ({ pag
await expect(settings).toBeVisible()
})
test("the add server dialog pairs from a one-time link and explains a spent one", async ({ page }) => {
const paired = "http://127.0.0.1:4098"
await mockRemoteServer(page, { directory: "/remote/settings-demo" })
await mockOpenCodeServer(page, {
server: paired,
directory: "/remote/paired",
project: project({ id: "proj_paired", directory: "/remote/paired" }),
provider: NO_PROVIDER,
sessions: [],
pageMessages: () => ({ items: [] }),
password: "session-token",
pairing: { code: "one-time-code", token: "session-token" },
})
const { settings } = await open(page)
const link = `${paired}/auth/connect/one-time-code`
const addServer = async () => {
await settings.locator('[data-component="settings-nav-group-header"]').filter({ hasText: "Servers" }).hover()
await settings.getByRole("button", { name: "Add server" }).click()
const editor = page.getByRole("dialog", { name: "Add server" })
await editor.getByLabel("Pairing link", { exact: true }).fill(link)
await editor.getByRole("button", { name: "Add server", exact: true }).click()
return editor
}
const added = await addServer()
await expect(added).toBeHidden()
await expect(settings.getByText(paired, { exact: true })).toBeVisible()
await settings.getByRole("button", { name: "Back to settings" }).click()
const spent = await addServer()
await expect(spent.getByRole("alert")).toHaveText(
"This pairing link expired or was already used. Run opencode pair to get a new one.",
)
})
test("a pairing code with several addresses keeps the first one that works with its token", async ({ page }) => {
// Both addresses reach one server. The second spends the code first, so the first answers 401, and the token works on
// it as on every address of that server.
const first = "http://127.0.0.1:4098"
const second = "http://127.0.0.1:4099"
await mockRemoteServer(page, { directory: "/remote/settings-demo" })
for (const [server, pairing] of [
[first, { code: "spent-by-the-other-address", token: "session-token" }],
[second, { code: "one-time-code", token: "session-token" }],
] as const) {
await mockOpenCodeServer(page, {
server,
directory: "/remote/paired",
project: project({ id: "proj_paired", directory: "/remote/paired" }),
provider: NO_PROVIDER,
sessions: [],
pageMessages: () => ({ items: [] }),
password: "session-token",
pairing,
})
}
const { settings } = await open(page)
await settings.locator('[data-component="settings-nav-group-header"]').filter({ hasText: "Servers" }).hover()
await settings.getByRole("button", { name: "Add server" }).click()
const editor = page.getByRole("dialog", { name: "Add server" })
await editor
.getByLabel("Pairing link", { exact: true })
.fill(JSON.stringify({ code: "one-time-code", urls: [first, second] }))
await editor.getByRole("button", { name: "Add server", exact: true }).click()
await expect(editor).toBeHidden()
await expect(settings.getByText(first, { exact: true })).toBeVisible()
await expect(settings.getByText(second, { exact: true })).toHaveCount(0)
})
test("the tab layout preference switches to vertical tabs and survives reload", async ({ page }) => {
const { settings } = await open(page)
const layout = settings.locator('[data-action="settings-tab-layout"]')
@@ -106,6 +106,37 @@ for (const mount of ["cached", "explicit"] as const) {
})
}
test("reconnects the same terminal after a transient connection failure", async ({ page }) => {
const { pty } = await openSession(page, workspace)
let tickets = 0
await page.route(/\/api\/pty\/[^/]+\/connect-token/, (route) => {
if (route.request().method() === "OPTIONS") return route.fallback()
tickets += 1
if (tickets !== 2) return route.fallback()
return route.fulfill({
status: 503,
headers: { "access-control-allow-origin": "*" },
body: "Service Unavailable",
})
})
await page.keyboard.press("Control+Backquote")
const terminal = page.locator('[data-component="terminal"]')
await expect(terminal.locator("textarea")).toHaveCount(1)
await expect.poll(() => pty.sockets.length).toBe(1)
const id = pty.sockets[0]!.id
await terminal.evaluate((element) => element.setAttribute("data-connection-probe", "original"))
await pty.sockets[0]!.close(1011, "Temporary disconnection")
await expect.poll(() => tickets).toBe(3)
await expect.poll(() => pty.sockets.length).toBe(2)
expect(pty.sockets[1]!.id).toBe(id)
expect(pty.rejected).toEqual([])
await expect(terminal).toHaveAttribute("data-connection-probe", "original")
expect(pty.created.map((item) => item.id)).toEqual([id])
})
test("focuses a terminal created from the new-terminal button", async ({ page }) => {
const { editor } = await openSession(page, workspace)
const terminal = page.locator('[data-component="terminal"]')
+26 -18
View File
@@ -1,13 +1,14 @@
import { expect, test, type Page } from "@playwright/test"
import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises"
import { createServer, type ServerResponse } from "node:http"
import type { AddressInfo } from "node:net"
import { once } from "node:events"
import { createHash } from "node:crypto"
import { join, extname, relative, sep } from "node:path"
import { tmpdir } from "node:os"
import { fileURLToPath } from "node:url"
import { build } from "vite"
import { serviceWorker } from "../../vite.pwa"
import { onDemandAsset, serviceWorker } from "../../vite.pwa"
type Site = {
url: string
@@ -127,14 +128,14 @@ const fixture = test.extend<{ site: Site }, { builds: Record<string, Record<stri
const file = builds[state.version][path]
const types: Record<string, string> = {
".js": "text/javascript",
".html": "text/html",
".json": "application/json",
".wasm": "application/wasm",
}
const types = new Map([
[".js", "text/javascript"],
[".html", "text/html"],
[".json", "application/json"],
[".wasm", "application/wasm"],
])
response.setHeader("content-type", types[extname(path)] ?? "application/octet-stream")
response.setHeader("content-type", types.get(extname(path)) ?? "application/octet-stream")
if (file) return void response.end(file)
@@ -145,9 +146,8 @@ const fixture = test.extend<{ site: Site }, { builds: Record<string, Record<stri
server.listen(0, "127.0.0.1")
await once(server, "listening")
const address = server.address()
if (!address || typeof address === "string") throw new Error("Expected a TCP address")
// SAFETY: a server listening on a host and port reports an AddressInfo; only pipe servers report a string.
const address = server.address() as AddressInfo
try {
await use({
@@ -284,9 +284,11 @@ fixture(
await expect
.poll(() =>
replacement.evaluate(() => {
const registration = (self as unknown as { registration: ServiceWorkerRegistration }).registration
// This runs in the service worker, whose global scope holds its registration.
const registration =
"registration" in self && self.registration instanceof ServiceWorkerRegistration ? self.registration : undefined
return { waiting: !!registration.waiting, active: registration.active?.state }
return { waiting: !!registration?.waiting, active: registration?.active?.state }
}),
)
.toEqual({ waiting: false, active: "activated" })
@@ -378,15 +380,22 @@ fixture("does not substitute cached HTML for API or missing asset navigations",
expect(await asset?.text()).toBe("Not found")
})
test("the production build precaches every deployable file", async ({ page, context }) => {
test("the production build precaches every deployable file except on-demand Office assets", async ({
page,
context,
}) => {
const directory = new URL("../../dist/", import.meta.url)
const files = (await readdir(directory, { recursive: true, withFileTypes: true }))
const deployable = (await readdir(directory, { recursive: true, withFileTypes: true }))
.filter((entry) => entry.isFile())
.map((entry) => "/" + relative(fileURLToPath(directory), join(entry.parentPath, entry.name)).split(sep).join("/"))
.filter((path) => !path.endsWith(".map") && !["/_headers", "/_redirects", "/sw.js"].includes(path))
const files = deployable.filter((path) => !onDemandAsset(path))
expect(files.length).toBeGreaterThan(1)
// The Office engines ship but load on demand, so a build without them would make this exclusion vacuous.
expect(deployable.some((path) => path.endsWith(".wasm") && onDemandAsset(path))).toBe(true)
const server = createServer(async (request, response) => {
const path = new URL(request.url ?? "/", "http://localhost").pathname
@@ -411,9 +420,8 @@ test("the production build precaches every deployable file", async ({ page, cont
server.listen(0, "127.0.0.1")
await once(server, "listening")
const address = server.address()
if (!address || typeof address === "string") throw new Error("Expected a TCP address")
// SAFETY: a server listening on a host and port reports an AddressInfo; only pipe servers report a string.
const address = server.address() as AddressInfo
const url = `http://127.0.0.1:${address.port}`
try {
@@ -56,7 +56,6 @@ export function mount(input: { server: string; route: string; direction: Directi
return (
<AppInterface
servers={[server]}
defaultServer={ServerConnection.key(server)}
canonicalLocalServer={ServerConnection.key(server)}
router={(props) => <MemoryRouter {...props} history={history} />}
>
+12 -4
View File
@@ -63,6 +63,12 @@ export class MockShellNotFound extends Schema.TaggedError<MockShellNotFound>()("
message: Schema.String,
}) {}
// The server's error for an unknown PTY, or one owned by another workspace.
export class MockPtyNotFound extends Schema.TaggedError<MockPtyNotFound>()("PtyNotFoundError", {
ptyID: Schema.String,
message: Schema.String,
}) {}
// The server's error for a request without its password.
export class MockUnauthorized extends Schema.TaggedError<MockUnauthorized>()("UnauthorizedError", {
message: Schema.String,
@@ -75,6 +81,8 @@ export class MockUnsupported extends Schema.TaggedError<MockUnsupported>()("Mock
const Unsupported = MockUnsupported.pipe(HttpApiSchema.status(501))
const PtyMissing = [MockNotFound.pipe(HttpApiSchema.status(404)), MockPtyNotFound.pipe(HttpApiSchema.status(404))]
const Group = HttpApiGroup.make("mock")
.add(HttpApiEndpoint.get("info", "/api/info", { success: Json }))
.add(
@@ -242,7 +250,7 @@ const Group = HttpApiGroup.make("mock")
HttpApiEndpoint.get("ptyGet", "/api/pty/:ptyID", {
params: PtyParams,
success: Json,
error: MockNotFound.pipe(HttpApiSchema.status(404)),
error: PtyMissing,
}),
)
.add(
@@ -250,21 +258,21 @@ const Group = HttpApiGroup.make("mock")
params: PtyParams,
payload: Pty.UpdateInput,
success: Json,
error: MockNotFound.pipe(HttpApiSchema.status(404)),
error: PtyMissing,
}),
)
.add(
HttpApiEndpoint.delete("ptyRemove", "/api/pty/:ptyID", {
params: PtyParams,
success: NoContent,
error: MockNotFound.pipe(HttpApiSchema.status(404)),
error: PtyMissing,
}),
)
.add(
HttpApiEndpoint.post("ptyConnectToken", "/api/pty/:ptyID/connect-token", {
params: PtyParams,
success: Json,
error: MockNotFound.pipe(HttpApiSchema.status(404)),
error: PtyMissing,
}),
)
.add(
+38 -2
View File
@@ -11,6 +11,7 @@ import {
MockBadRequest,
MockInternal,
MockNotFound,
MockPtyNotFound,
MockShellNotFound,
MockUnauthorized,
MockUnsupported,
@@ -135,6 +136,8 @@ export interface MockServerConfig {
strictDirectory?: boolean
// Answers 401 UnauthorizedError unless a request carries this password; a function may change it mid-test.
password?: Resolvable<string>
// Serves GET /auth/connect/:code: `code` redeems once for `token` (send it as the password); others answer 401.
pairing?: { code: string; token: string }
}
export type MockPtyInfo = {
@@ -147,7 +150,14 @@ export type MockPtyInfo = {
pid: number
}
export type MockPtySocket = { id: string; url: URL; input: string[]; closed: boolean; send(data: string): void }
export type MockPtySocket = {
id: string
url: URL
input: string[]
closed: boolean
send(data: string): void
close(code: number, reason: string): Promise<void>
}
export type MockPty = {
list: MockPtyInfo[]
@@ -401,6 +411,29 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
})
})
if (config.pairing) {
const pairing = { ...config.pairing, redeemed: false }
await page.route(`${server}/auth/connect/*`, (route) => {
if (route.request().method() === "OPTIONS") return route.fulfill({ status: 204, headers: corsHeaders })
const code = decodeURIComponent(new URL(route.request().url()).pathname.split("/").at(-1) ?? "")
if (code !== pairing.code || pairing.redeemed) {
return route.fulfill({
status: 401,
headers: corsHeaders,
json: Schema.encodeSync(MockUnauthorized)(
new MockUnauthorized({ message: "Pairing link expired or already used" }),
),
})
}
pairing.redeemed = true
return route.fulfill({ headers: corsHeaders, json: { token: pairing.token } })
})
}
if (config.pty) {
const host = new URL(server).host
await page.routeWebSocket(
@@ -422,6 +455,7 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) {
input: [],
closed: false,
send: (data) => ws.send(data),
close: (code, reason) => ws.close({ code, reason }),
}
ws.onMessage((message) => socket.input.push(message.toString()))
@@ -672,7 +706,9 @@ function mockHandlers(
const directory = requestDirectory(config, request)
const found = state.pty.find(id, directory)
return found ? Effect.succeed(found) : Effect.fail(new MockNotFound({ message: "PTY not found" }))
return found
? Effect.succeed(found)
: Effect.fail(new MockPtyNotFound({ ptyID: id, message: `PTY not found: ${id}` }))
}),
),
)
@@ -241,11 +241,7 @@ export function mount(input: {
return (
<Show when={extensions.ready()}>
<AppInterface
servers={servers()}
defaultServer={ServerConnection.Key.make("sidecar")}
router={(props) => <MemoryRouter {...props} history={history} />}
/>
<AppInterface servers={servers()} router={(props) => <MemoryRouter {...props} history={history} />} />
</Show>
)
}
@@ -4,7 +4,6 @@ import { render } from "solid-js/web"
import type { Bridge } from "@opencode/gui-extensions/sdk/bridge"
import { AppBaseProviders, AppInterface } from "../../src/app"
import { PlatformProvider, type Platform } from "../../src/runtime/platform/platform"
import { ServerConnection } from "../../src/runtime/server/registry"
// The app on a Windows desktop platform, so the titlebar shows the app menu. Menu actions are listed in an output.
export function mount(input: { server: string }) {
@@ -59,7 +58,6 @@ export function mount(input: { server: string }) {
<output aria-label="Desktop menu actions">{store.actions.join(",")}</output>
<AppInterface
servers={[{ type: "sidecar", variant: "base", displayName: "Local Server", http: { url: input.server } }]}
defaultServer={ServerConnection.Key.make("sidecar")}
router={(props) => <MemoryRouter {...props} history={history} />}
/>
</AppBaseProviders>
+1 -6
View File
@@ -86,7 +86,6 @@ export function AppBaseProviders(
export function AppInterface(props: {
children?: JSX.Element
defaultServer?: ServerConnection.Key
canonicalLocalServer?: ServerConnection.Key
servers?: Array<ServerConnection.Any>
router?: Component<BaseRouterProps>
@@ -108,11 +107,7 @@ export function AppInterface(props: {
)
return (
<ServersProvider
defaultServer={props.defaultServer}
canonicalLocalServer={props.canonicalLocalServer}
servers={props.servers}
>
<ServersProvider canonicalLocalServer={props.canonicalLocalServer} servers={props.servers}>
<SettingsProvider>
<Dynamic component={props.router ?? Router} root={Root}>
<AppRoutes />
+2 -2
View File
@@ -1,5 +1,6 @@
import { useCommand, type CommandOption } from "@/shell/commands/command"
import { useLanguage } from "@/runtime/i18n/language"
import { DialogSelectModel } from "@/providers/models/select-dialog"
import { useLocal, type ModelSelection } from "@/providers/models/selection"
import { useDialog } from "@opencode/ui/context/dialog"
import { getCursorPosition, setCursorPosition } from "./editor/dom"
@@ -33,7 +34,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
void dialog.show(() => <DialogConnectProvider directory={workspace().directory} />)
}
const chooseModel = async () => {
const chooseModel = () => {
const owner = sessionOwnership.capture()
const editor = document.querySelector<HTMLElement>('[data-component="composer-editor"]')
const selection = window.getSelection()
@@ -54,7 +55,6 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
})
}
const { DialogSelectModel } = await import("@/providers/models/select-dialog")
owner.run(() => {
void dialog.show(() => <DialogSelectModel model={model} />, restoreComposer)
})
@@ -204,7 +204,7 @@ export function createComposerEditor(input: {
const action = event.type === "popover.select" ? input.onSuggestionSelect?.(event.item) : undefined
if (event.type === "popover.select") {
if (!action || state.popover.type !== "command-menu") result.commands.forEach(execute)
if (!action) result.commands.forEach(execute)
if (action && event.item.kind === "command" && state.popover.type !== "command-menu") {
draft.setPrompt(draft.state.prompt.filter(isAttachment), 0)
+1 -2
View File
@@ -16,7 +16,7 @@ import pkg from "../package.json"
import { ServerConnection } from "@/runtime/server/registry"
const getLocale = () => {
if (typeof navigator !== "object") return "en" as const
if (typeof navigator === "undefined") return "en" as const
const languages = navigator.languages?.length ? navigator.languages : [navigator.language]
for (const language of languages) {
@@ -101,7 +101,6 @@ if (root instanceof HTMLElement && root.dataset.opencodeMounted === undefined) {
<PlatformProvider value={web.platform}>
<AppBaseProviders locale={locale}>
<AppInterface
defaultServer={web.defaultServerUrl ? ServerConnection.Key.make(web.defaultServerUrl) : undefined}
canonicalLocalServer={server ? ServerConnection.key(server) : undefined}
servers={server ? [server] : []}
>
+23 -14
View File
@@ -31,7 +31,6 @@ export function createHomeProjectsController(home: HomeController) {
const settings = useSettingsSurface()
const serverManagement = useServerActionsController()
const global = useGlobal()
const authenticate = ServerConnection.authenticate
const revealProject = useRevealProject()
const [_state, setState, _, ready] = persisted(Persist.global("home.servers"), HomeServersSchema, { collapsed: {} })
@@ -41,6 +40,23 @@ export function createHomeProjectsController(home: HomeController) {
{ initialValue: _state },
)
function edit(conn: ServerConnection.Http, onSave?: (saved: ServerConnection.Http) => void) {
void import("@/servers/connect/dialog").then(({ DialogServer }) => {
void dialog.show(() => <DialogServer mode="edit" server={conn} onSave={(saved) => onSave?.(saved)} />)
})
}
// An expired pairing session or a changed password signs the app out of an HTTP server; signing in again edits it,
// and the action that asked for sign-in continues once the dialog saves, as it does for extension servers. It continues
// with the saved connection: the one it started with still carries the rejected credentials.
function authenticate(conn: ServerConnection.Any, onConnected?: (conn: ServerConnection.Any) => void) {
if (conn.type !== "http" || !home.server.health(conn)?.unauthorized)
return ServerConnection.authenticate(conn, () => onConnected?.(conn))
edit(conn, onConnected)
return true
}
function directories(project: LocalProject) {
return [project.worktree, ...(project.sandboxes ?? [])]
}
@@ -70,22 +86,14 @@ export function createHomeProjectsController(home: HomeController) {
const key = ServerConnection.key(conn)
setState("collapsed", key, !state().collapsed[key])
},
canDefault: serverManagement.defaults.available,
defaultKey: serverManagement.defaults.key,
setDefault: (conn: ServerConnection.Any | undefined) =>
serverManagement.defaults.set(conn ? ServerConnection.key(conn) : null),
canRemove: (conn: ServerConnection.Any) => serverManagement.connection.canRemove(ServerConnection.key(conn)),
remove: (conn: ServerConnection.Any) => serverManagement.connection.remove(ServerConnection.key(conn)),
canHide: (conn: ServerConnection.Any) => serverManagement.connection.canHide(ServerConnection.key(conn)),
hide: (conn: ServerConnection.Any) => serverManagement.connection.setHidden(ServerConnection.key(conn), true),
edit: (conn: ServerConnection.Http) => {
void import("@/servers/connect/dialog").then(({ DialogServer }) => {
void dialog.show(() => <DialogServer mode="edit" server={conn} />)
})
},
edit: (conn: ServerConnection.Http) => edit(conn),
authenticate: (conn: ServerConnection.Any) => authenticate(conn),
focus: (conn: ServerConnection.Any) => {
if (authenticate(conn, () => home.selection.focusServer(conn))) return
if (authenticate(conn, (next) => home.selection.focusServer(next))) return
home.selection.focusServer(conn)
},
},
@@ -94,12 +102,12 @@ export function createHomeProjectsController(home: HomeController) {
recentlyClosed: home.project.recentlyClosed,
homedir: home.project.homedir,
select: (conn: ServerConnection.Any, directory: string) => {
if (authenticate(conn, () => home.project.select(conn, directory))) return
if (authenticate(conn, (next) => home.project.select(next, directory))) return
home.project.select(conn, directory)
},
add: home.project.add,
openNewSession: (conn: ServerConnection.Any, directory: string) => {
if (authenticate(conn, () => home.project.openProjectNewSession(conn, directory))) return
if (authenticate(conn, (next) => home.project.openProjectNewSession(next, directory))) return
home.project.openProjectNewSession(conn, directory)
},
canImportSession: !!platform.openAttachmentPickerDialog,
@@ -119,6 +127,7 @@ export function createHomeProjectsController(home: HomeController) {
const api = home.server.context(conn).sdk.api.session
// SAFETY: the payload is SessionTransfer.Data's own encoding, which the import endpoint decodes and validates.
const imported = await api.import({
...Schema.encodeSync(SessionTransfer.Data)(data),
location: { directory: project.worktree },
@@ -152,7 +161,7 @@ export function createHomeProjectsController(home: HomeController) {
.forEach((directory) => notification.project.markViewed(directory))
},
choose: (conn: ServerConnection.Any) => {
if (authenticate(conn, () => choose(conn))) return
if (authenticate(conn, (next) => choose(next))) return
if (home.server.health(conn)?.healthy === false) return
choose(conn)
@@ -19,8 +19,6 @@ export function HomeProjects(props: {
serverHealth={props.projects.server.health}
projectsForServer={props.projects.server.projects}
collapsed={props.projects.server.collapsed}
canDefaultServer={props.projects.server.canDefault()}
defaultServerKey={props.projects.server.defaultKey()}
canRevealProject={props.projects.project.canReveal}
unseenCount={props.projects.project.unseenCount}
onWheel={props.scroll.viewport.containWheel}
@@ -29,7 +27,6 @@ export function HomeProjects(props: {
onAuthenticateServer={props.projects.server.authenticate}
onToggleCollapsed={props.projects.server.toggleCollapsed}
onEditServer={props.projects.server.edit}
onSetDefaultServer={props.projects.server.setDefault}
canRemoveServer={props.projects.server.canRemove}
onRemoveServer={props.projects.server.remove}
canHideServer={props.projects.server.canHide}
+11 -14
View File
@@ -33,6 +33,11 @@ const HOME_PROJECT_NAV_LABEL = "min-w-0 flex-1 overflow-hidden text-ellipsis whi
const serverContextMenuID = (server: ServerConnection.Any) => `server:${ServerConnection.key(server)}`
// Extension servers ask for sign-in themselves; an HTTP server that rejects its saved credentials needs a new
// pairing link or password.
const signInRequired = (server: ServerConnection.Any, health: ServerHealth | undefined) =>
(server.type === "extension" && server.authenticationRequired) || (server.type === "http" && !!health?.unauthorized)
const projectContextMenuID = (server: ServerConnection.Any, directory: string) =>
`project:${ServerConnection.key(server)}:${directory}`
@@ -47,8 +52,6 @@ export type HomeProjectsViewProps = {
serverHealth: (server: ServerConnection.Any) => ServerHealth | undefined
projectsForServer: (server: ServerConnection.Any) => LocalProject[]
collapsed: (server: ServerConnection.Any) => boolean
canDefaultServer: boolean
defaultServerKey: ServerConnection.Key | null | undefined
canRevealProject: (server: ServerConnection.Any) => boolean
unseenCount: (server: ServerConnection.Any, project: LocalProject) => number
onWheel: (event: WheelEvent) => void
@@ -57,7 +60,6 @@ export type HomeProjectsViewProps = {
onAuthenticateServer?: (server: ServerConnection.Any) => void
onToggleCollapsed: (server: ServerConnection.Any) => void
onEditServer: (server: ServerConnection.Http) => void
onSetDefaultServer: (server: ServerConnection.Any | undefined) => void
canRemoveServer: (server: ServerConnection.Any) => boolean
onRemoveServer: (server: ServerConnection.Any) => void
canHideServer: (server: ServerConnection.Any) => boolean
@@ -158,7 +160,7 @@ export function HomeProjectsView(props: HomeProjectsViewProps) {
}
function HomeProjectsPanel(props: HomeProjectsViewProps) {
const [contextMenu, setContextMenu] = createStore({ open: undefined as string | undefined })
const [contextMenu, setContextMenu] = createStore<{ open: string | undefined }>({ open: undefined })
const contextMenuProps = {
contextMenuOpen: (id: string) => contextMenu.open === id,
@@ -216,7 +218,9 @@ function HomeProjectsPanel(props: HomeProjectsViewProps) {
when={
props.servers.length > 1 ||
props.servers.some(
(server) => server.type === "extension" && (server.authenticationRequired || server.connecting),
(server) =>
signInRequired(server, props.serverHealth(server)) ||
(server.type === "extension" && server.connecting),
)
}
fallback={
@@ -253,7 +257,7 @@ function HomeProjectsPanel(props: HomeProjectsViewProps) {
const healthy = () => !!props.serverHealth(item)?.healthy
const hasProjects = () => projects().length > 0
const collapsed = () => props.collapsed(item)
const authentication = () => item.type === "extension" && item.authenticationRequired
const authentication = () => signInRequired(item, props.serverHealth(item))
const connecting = () => item.type === "extension" && item.connecting
return (
@@ -340,12 +344,9 @@ function HomeServerRow(props: {
language: HomeProjectsViewProps["language"]
projectsForServer: HomeProjectsViewProps["projectsForServer"]
contextMenuOpen: HomeProjectsContextMenuProps["contextMenuOpen"]
canDefaultServer: HomeProjectsViewProps["canDefaultServer"]
defaultServerKey: HomeProjectsViewProps["defaultServerKey"]
onFocusServer: HomeProjectsViewProps["onFocusServer"]
onToggleCollapsed: HomeProjectsViewProps["onToggleCollapsed"]
onEditServer: HomeProjectsViewProps["onEditServer"]
onSetDefaultServer: HomeProjectsViewProps["onSetDefaultServer"]
canRemoveServer: HomeProjectsViewProps["canRemoveServer"]
onRemoveServer: HomeProjectsViewProps["onRemoveServer"]
canHideServer: HomeProjectsViewProps["canHideServer"]
@@ -358,7 +359,7 @@ function HomeServerRow(props: {
health: ServerHealth | undefined
}) {
const healthy = () => !!props.health?.healthy
const authentication = () => props.server.type === "extension" && props.server.authenticationRequired
const authentication = () => signInRequired(props.server, props.health)
const incompatible = () => !!props.health?.incompatible
const canToggle = () => healthy() && props.projectsForServer(props.server).length > 0
const contextMenuID = () => serverContextMenuID(props.server)
@@ -463,13 +464,9 @@ function HomeServerRow(props: {
<ServerRowMenuView
server={props.server}
labels={serverMenuLabels(props.language)}
canDefault={props.canDefaultServer}
isDefault={props.defaultServerKey === ServerConnection.key(props.server)}
canRemove={props.canRemoveServer(props.server)}
canHide={props.canHideServer(props.server)}
onEdit={props.onEditServer}
onSetDefault={() => props.onSetDefaultServer(props.server)}
onRemoveDefault={() => props.onSetDefaultServer(undefined)}
onRemove={() => props.onRemoveServer(props.server)}
onHide={() => props.onHideServer(props.server)}
open={props.contextMenuOpen(contextMenuID())}
@@ -8,6 +8,7 @@ import {
createCommandPaletteCommandEntry,
createServerSessionEntries,
type CommandPaletteEntry,
type PaletteHighlight,
} from "@/shell/commands/palette"
import { CommandPaletteView, matchesCommandPaletteEntry } from "@/shell/commands/dialog"
@@ -20,7 +21,7 @@ export function HomeCommandPalette(props: {
const global = useGlobal()
const language = useLanguage()
const server = global.ensureServerCtx(props.server)
const state = { cleanup: undefined as (() => void) | void, committed: false }
const state: PaletteHighlight = { cleanup: undefined, committed: false }
const commandEntries = createMemo(() => {
const category = language.t("palette.group.commands")
@@ -36,6 +37,7 @@ export function HomeCommandPalette(props: {
get: (sessionID, signal) => server.sdk.api.session.get({ sessionID }, { signal }),
untitled: () => language.t("command.session.new"),
category: () => language.t("command.category.session"),
recentCategory: () => language.t("palette.group.recentSessions"),
})
const highlight = (item: CommandPaletteEntry | undefined) => {
+1 -1
View File
@@ -70,7 +70,7 @@ export function NewSessionView(props: {
<PromptProjectAddButton controller={props.project} />
</Show>
<Show when={props.project.selected()}>
<div class="flex min-h-7 min-w-0 flex-col items-center justify-center gap-0 text-v2-text-text-faint sm:flex-row">
<div class="flex min-h-7 min-w-0 flex-row flex-wrap items-center justify-center gap-0 text-v2-text-text-faint">
<PromptProjectSelector controller={props.project} placement="bottom" />
<Show
when={props.workspace.bar.visible()}
@@ -327,7 +327,7 @@ export function PromptWorkspaceSelector(props: {
setTimeout(() => requestAnimationFrame(() => branchSearchInput?.focus({ preventScroll: true })))
}}
>
<div class="flex h-7 shrink-0 items-center gap-2 rounded-sm pl-3 pr-2.5 text-v2-icon-icon-muted">
<div class="flex h-7 shrink-0 items-center gap-2 rounded-sm pl-3 pr-1 text-v2-icon-icon-muted">
<Icon name="magnifying-glass" size="small" class="shrink-0" />
<input
ref={(element) => {
@@ -355,7 +355,7 @@ export function PromptWorkspaceSelector(props: {
<Show when={search.branches.trim()}>
<button
type="button"
class="flex size-5 items-center justify-center rounded-sm text-v2-icon-icon-muted hover:bg-v2-overlay-simple-overlay-hover"
class="flex size-5 items-center justify-center rounded-sm bg-transparent text-v2-icon-icon-faint transition-colors hover:text-v2-icon-icon-base focus-visible:text-v2-icon-icon-base active:text-v2-icon-icon-base"
onPointerDown={(event) => event.preventDefault()}
onClick={() => {
setSearch("branches", "")
@@ -363,7 +363,7 @@ export function PromptWorkspaceSelector(props: {
}}
aria-label={language.t("common.clear")}
>
<Icon name="close-small" size="small" />
<Icon name="circle-xmark" />
</button>
</Show>
</div>
@@ -7,14 +7,23 @@ import type {
import { useLanguage } from "@/runtime/i18n/language"
import { usePlatform } from "@/runtime/platform/platform"
import { useServerSDK } from "@/runtime/server/client"
import { formatServerError } from "@/runtime/server/errors"
import { useData } from "@/runtime/server/current"
import { createEffect, createMemo, on, onCleanup } from "solid-js"
import { createStore, produce } from "solid-js/store"
export type ProviderConnectMethod = Extract<IntegrationMethod, { type: "key" | "oauth" }>
export type ProviderConnectMethod = Extract<IntegrationMethod, { type: "key" | "oauth" | "external" }>
type Authorization = IntegrationOauthConnectOutput["data"]
type Polling = {
generation: number
timer?: ReturnType<typeof setTimeout>
disposed: boolean
// An attempt the server still considers open; cancelled when the dialog goes away.
attempt?: Authorization
}
// OpenCode Go and OpenCode Zen both bill through the OpenCode Console, so the
// Console sign-in is the connection method for both providers.
export const CONSOLE_INTEGRATION = "opencode"
@@ -35,7 +44,7 @@ export function providerFormDefaults(fields: ProviderConnectMethod["form"]) {
if (actual === undefined) return false
const equal = Array.isArray(actual)
? typeof condition.value === "string" && actual.includes(condition.value)
? actual.some((item) => item === condition.value)
: actual === condition.value
return condition.op === "eq" ? equal : !equal
@@ -43,7 +52,7 @@ export function providerFormDefaults(fields: ProviderConnectMethod["form"]) {
if (!active) return answer
return { ...answer, [field.key]: field.default }
return Object.assign(answer, { [field.key]: field.default })
}, {})
}
@@ -74,9 +83,8 @@ export function createProviderConnectionController(options: {
// Not createResource: the dialog is owned by whichever page opened it, so reading a pending
// resource here would suspend that page's <Suspense> and blank the screen behind the dialog.
const [integration, setIntegration] = createStore({
const [integration, setIntegration] = createStore<{ loading: boolean; latest?: IntegrationInfo }>({
loading: true,
latest: undefined as IntegrationInfo | undefined,
})
createEffect(
@@ -100,7 +108,8 @@ export function createProviderConnectionController(options: {
const methods = createMemo<ProviderConnectMethod[]>(() => {
const values = integration.latest?.methods.filter(
(method): method is ProviderConnectMethod => method.type === "key" || method.type === "oauth",
(method): method is ProviderConnectMethod =>
method.type === "key" || method.type === "oauth" || method.type === "external",
)
if (values?.length) return [...values]
@@ -108,14 +117,19 @@ export function createProviderConnectionController(options: {
return [{ type: "key", label: language.t("provider.connect.method.apiKey") }]
})
const [store, setStore] = createStore({
methodIndex: undefined as number | undefined,
authorization: undefined as Authorization | undefined,
formAnswer: undefined as FormAnswer | undefined,
const [store, setStore] = createStore<{
methodIndex?: number
authorization?: Authorization
formAnswer?: FormAnswer
// Nothing is in flight until a method is selected; `busy()` reads this, so a truthy initial
// value would keep multi-method providers on the spinner instead of the method list.
state: undefined as "pending" | "waiting" | "refreshing" | "ready" | "error" | "form" | undefined,
error: undefined as string | undefined,
state?: "pending" | "waiting" | "refreshing" | "ready" | "error" | "form"
error?: string
auto: boolean
connected: boolean
browserFailed: boolean
statusFailed: boolean
}>({
auto: false,
// The credential is stored; a retry only needs to reload the catalogs.
connected: false,
@@ -124,12 +138,9 @@ export function createProviderConnectionController(options: {
statusFailed: false,
})
const polling = {
const polling: Polling = {
generation: 0,
timer: undefined as ReturnType<typeof setTimeout> | undefined,
disposed: false,
// An attempt the server still considers open; cancelled when the dialog goes away.
attempt: undefined as Authorization | undefined,
}
const currentMethod = createMemo(() =>
@@ -206,8 +217,6 @@ export function createProviderConnectionController(options: {
)
}
const errorMessage = (error: unknown) => (error instanceof Error ? error.message : String(error))
const cancelAttempt = () => {
const attempt = polling.attempt
polling.attempt = undefined
@@ -276,7 +285,9 @@ export function createProviderConnectionController(options: {
setStore("statusFailed", true)
dispatch({
type: "auth.error",
error: isConsole() ? language.t("provider.connect.console.statusFailed") : errorMessage(result.error),
error: isConsole()
? language.t("provider.connect.console.statusFailed")
: formatServerError(result.error, language.t),
})
return
@@ -358,8 +369,6 @@ export function createProviderConnectionController(options: {
return
}
if (selected.type !== "oauth") return
if (selected.form?.some((field) => field.type !== "string")) {
dispatch({ type: "auth.error", error: language.t("provider.connect.error.unsupportedFields") })
@@ -368,11 +377,35 @@ export function createProviderConnectionController(options: {
dispatch({ type: "auth.pending" })
if (selected.type === "external") {
const saved = await serverSDK.api.integration.connect
.external({
integrationID: options.provider(),
methodID: selected.id,
answer: Object.keys(merged).length ? merged : undefined,
location: location(),
})
.then(() => ({ ok: true as const }))
.catch((error) => ({ ok: false as const, error }))
if (polling.disposed || generation !== polling.generation) return
if (!saved.ok) {
dispatch({ type: "auth.error", error: formatServerError(saved.error, language.t) })
return
}
await finish()
return
}
const result = await serverSDK.api.integration.oauth
.connect({
integrationID: options.provider(),
methodID: selected.id,
...(Object.keys(merged).length ? { answer: merged } : {}),
answer: Object.keys(merged).length ? merged : undefined,
location: location(),
})
.then((response) => {
@@ -404,7 +437,9 @@ export function createProviderConnectionController(options: {
if (!result.ok) {
dispatch({
type: "auth.error",
error: isConsole() ? language.t("provider.connect.console.startFailed") : errorMessage(result.error),
error: isConsole()
? language.t("provider.connect.console.startFailed")
: formatServerError(result.error, language.t),
})
return
@@ -448,7 +483,7 @@ export function createProviderConnectionController(options: {
integrationID: options.keyProvider?.() ?? options.provider(),
location: location(),
key,
...(store.formAnswer ? { answer: store.formAnswer } : {}),
answer: store.formAnswer,
})
await finish()
}
@@ -468,7 +503,8 @@ export function createProviderConnectionController(options: {
.then(() => ({ ok: true as const }))
.catch((error) => ({ ok: false as const, error }))
if (!result.ok) return errorMessage(result.error) || language.t("provider.connect.oauth.code.invalid")
if (!result.ok)
return formatServerError(result.error, language.t, language.t("provider.connect.oauth.code.invalid"))
await finish()
return undefined
@@ -496,11 +532,13 @@ export function createProviderConnectionController(options: {
authorization: () => store.authorization,
browserFailed: () => store.browserFailed,
// True while nothing useful can be shown yet: the integration is loading, a method is
// about to be picked automatically, or the authorization request is in flight.
// about to be picked automatically, the authorization request is in flight, or an external
// method, which has no view of its own, is refreshing the catalogs after saving.
busy: () =>
integration.loading ||
(store.methodIndex === undefined && !store.auto && autoIndex() !== undefined) ||
store.state === "pending",
store.state === "pending" ||
(store.state === "refreshing" && currentMethod()?.type === "external"),
auth: {
state: () => store.state,
error: () => store.error,
+128 -28
View File
@@ -3,6 +3,7 @@ import { Badge } from "@opencode/ui/badge"
import { useDialog } from "@opencode/ui/context/dialog"
import { Icon } from "@opencode/ui/icon"
import { List } from "@opencode/ui/list"
import { RadioGroup, RadioItem } from "@opencode/ui/radio"
import { Spinner } from "@opencode/ui/spinner"
import { TextField } from "@opencode/ui/text-field"
import { DialogBody, DialogHeader, DialogTitle, Dialog } from "@opencode/ui/dialog"
@@ -61,7 +62,7 @@ type IntegrationForm = NonNullable<ProviderConnectMethod["form"]>[number]
type StringForm = Extract<IntegrationForm, { type: "string" }>
export function useProviderConnectController() {
const [store, setStore] = createStore({ selected: undefined as string | undefined })
const [store, setStore] = createStore<{ selected?: string }>({})
const reset = () => setStore("selected", undefined)
return {
@@ -83,9 +84,13 @@ export const DialogConnectProvider: Component<{
const fallback = useProviderConnectController()
const controller = props.controller ?? fallback
const [state, setState] = createStore({
const [state, setState] = createStore<{
completed: boolean
modelProvider?: { id: string; name: string }
authorization: boolean
chatgptWelcome: boolean
}>({
completed: false,
modelProvider: undefined as { id: string; name: string } | undefined,
authorization: false,
chatgptWelcome: false,
})
@@ -216,10 +221,12 @@ function ProviderPicker(props: { directory?: string; onSelect: (provider: string
const integrations = useIntegrations(() => props.directory)
const language = useLanguage()
const [store, setStore] = createStore({
const [store, setStore] = createStore<{
filter: string
active?: string
connecting?: string
}>({
filter: "",
active: undefined as string | undefined,
connecting: undefined as string | undefined,
})
const featured = ["opencode-go", "opencode", "anthropic", "openai", "google", "openrouter", "vercel"]
@@ -421,16 +428,24 @@ function ProviderConnection(props: {
const isConsole = CONSOLE_PROVIDERS.has(props.provider)
const remote = isConsole && authServerName(sdk.server) !== undefined
const [state, setState] = createStore({
const [state, setState] = createStore<{
copied: boolean
copyFailed: boolean
firstConnection?: boolean
models: boolean
noModels: boolean
catalogPending: boolean
selectedModel: string
collapsed: Record<string, boolean>
}>({
copied: false,
copyFailed: false,
firstConnection: undefined as boolean | undefined,
models: false,
noModels: false,
// The workspace providers had not loaded when the wait ran out.
catalogPending: false,
selectedModel: "",
collapsed: {} as Record<string, boolean>,
collapsed: {},
})
const controller = createProviderConnectionController({
@@ -642,11 +657,22 @@ function ProviderConnection(props: {
function AuthFormView() {
const defaults = providerFormDefaults(controller.currentMethod()?.form)
const [formStore, setFormStore] = createStore({
const [formStore, setFormStore] = createStore<{
value: Record<string, string>
index: number
customOn: boolean
customText: string
}>({
value: Object.fromEntries(
Object.entries(defaults).flatMap(([key, value]) => (typeof value === "string" ? [[key, value]] : [])),
) as Record<string, string>,
(controller.currentMethod()?.form ?? []).flatMap((field) =>
field.type === "string" && field.key in defaults && field.default !== undefined
? [[field.key, field.default]]
: [],
),
),
index: 0,
customOn: false,
customText: "",
})
const fields = createMemo<StringForm[]>(() => {
@@ -677,14 +703,18 @@ function ProviderConnection(props: {
}
})
// Visible defaults prefill the field but enter the answer only once that field is answered,
// because the server rejects values for fields whose conditions are not met.
const answer = (field: StringForm) => formStore.value[field.key] ?? field.default
const valid = createMemo(() => {
const item = current()
if (!item || item.field.options) return false
if (!item || (item.field.options && !item.field.custom)) return false
if (!item.field.required) return true
return (formStore.value[item.field.key] ?? "").trim().length > 0
return (answer(item.field) ?? "").trim().length > 0
})
async function next(index: number, value: Record<string, string>) {
@@ -694,7 +724,7 @@ function ProviderConnection(props: {
const next = fields().findIndex((field, i) => i > index && matches(field, value))
if (next !== -1) {
setFormStore("index", next)
setFormStore({ index: next, customOn: false, customText: "" })
return
}
@@ -706,9 +736,10 @@ function ProviderConnection(props: {
e.preventDefault()
const item = current()
if (!item || item.field.options) return
if (!item || !valid()) return
const value = answer(item.field)
if (!valid()) return
if (value !== undefined) setFormStore("value", item.field.key, value)
await next(item.index, formStore.value)
}
@@ -730,6 +761,15 @@ function ProviderConnection(props: {
return field
})
const custom = () => {
const field = select()
if (!field?.custom) return false
const value = answer(field)
return formStore.customOn || (value !== undefined && !field.options?.some((option) => option.value === value))
}
return (
<form onSubmit={handleSubmit} class="flex flex-col items-start gap-4 px-3">
<Switch>
@@ -738,7 +778,7 @@ function ProviderConnection(props: {
type="text"
label={text()?.title ?? ""}
placeholder={text()?.placeholder}
value={text() ? (formStore.value[text()!.key] ?? "") : ""}
value={text() ? (answer(text()!) ?? "") : ""}
onChange={(value) => {
const field = text()
@@ -750,6 +790,62 @@ function ProviderConnection(props: {
{language.t("common.continue")}
</Button>
</Match>
<Match when={select()?.custom && select()}>
{(field) => (
<>
<div class="w-full flex flex-col gap-3">
<div class="text-14-regular text-text-base">{field().title}</div>
<RadioGroup
label={field().title}
hideLabel
description={field().description}
value={
custom()
? "custom"
: String(field().options?.findIndex((option) => option.value === answer(field())))
}
onChange={(value) => {
const option = field().options?.[Number(value)]
if (option) {
if (custom()) setFormStore("customText", answer(field()) ?? "")
setFormStore("customOn", false)
setFormStore("value", field().key, option.value)
return
}
setFormStore("customOn", true)
setFormStore("value", field().key, formStore.customText)
}}
>
<For each={field().options}>
{(option, index) => (
<RadioItem value={String(index())} label={option.label} description={option.description} />
)}
</For>
<RadioItem value="custom" label={language.t("ui.messagePart.option.typeOwnAnswer")} />
<Show when={custom()}>
<div class="pl-6">
<TextField
ref={(input: HTMLInputElement) => queueMicrotask(() => input.focus())}
type="text"
label={language.t("ui.messagePart.option.typeOwnAnswer")}
hideLabel
placeholder={field().placeholder ?? language.t("ui.question.custom.placeholder")}
value={answer(field()) ?? ""}
onChange={(value) => setFormStore("value", field().key, value)}
/>
</div>
</Show>
</RadioGroup>
</div>
<Button class="w-auto" type="submit" size="large" variant="contrast" disabled={!valid()}>
{language.t("common.continue")}
</Button>
</>
)}
</Match>
<Match when={item()?.field.options !== undefined}>
<div class="w-full flex flex-col gap-1.5">
<div class="text-14-regular text-text-base">{select()?.title}</div>
@@ -758,7 +854,7 @@ function ProviderConnection(props: {
class="px-3"
items={select()?.options ?? []}
key={(x) => x.value}
current={select()?.options?.find((x) => x.value === formStore.value[select()!.key])}
current={select()?.options?.find((x) => x.value === answer(select()!))}
onSelect={(value) => {
if (!value) return
const field = select()
@@ -876,9 +972,11 @@ function ProviderConnection(props: {
let apiKey: HTMLInputElement | undefined
const errorID = createUniqueId()
const [formStore, setFormStore] = createStore({
const [formStore, setFormStore] = createStore<{
value: string
error?: string
}>({
value: "",
error: undefined as string | undefined,
})
onMount(() => {
@@ -890,16 +988,16 @@ function ProviderConnection(props: {
if (!(e.currentTarget instanceof HTMLFormElement)) return
const value = new FormData(e.currentTarget).get("apiKey")
const apiKey = typeof value === "string" ? value : ""
const key = value instanceof File || value === null ? "" : value
if (!apiKey?.trim()) {
if (!key.trim()) {
setFormStore("error", language.t("provider.connect.apiKey.required"))
return
}
setFormStore("error", undefined)
await controller.auth.connectKey(apiKey)
await controller.auth.connectKey(key)
}
return (
@@ -954,9 +1052,11 @@ function ProviderConnection(props: {
let codeInput: HTMLInputElement | undefined
const errorID = createUniqueId()
const [formStore, setFormStore] = createStore({
const [formStore, setFormStore] = createStore<{
value: string
error?: string
}>({
value: "",
error: undefined as string | undefined,
})
onMount(() => {
@@ -968,9 +1068,9 @@ function ProviderConnection(props: {
if (!(e.currentTarget instanceof HTMLFormElement)) return
const value = new FormData(e.currentTarget).get("code")
const code = typeof value === "string" ? value : ""
const code = value instanceof File || value === null ? "" : value
if (!code?.trim()) {
if (!code.trim()) {
setFormStore("error", language.t("provider.connect.oauth.code.required"))
return
+19 -30
View File
@@ -1,7 +1,5 @@
import { Button } from "@opencode/ui/button"
import { Dialog, DialogBody, DialogHeader, DialogTitleGroup } from "@opencode/ui/dialog"
import { Icon } from "@opencode/ui/icon"
import { IconButton } from "@opencode/ui/icon-button"
import { Switch } from "@opencode/ui/switch"
import { TextInput } from "@opencode/ui/text-input"
import { useFilteredList } from "@opencode/ui/hooks"
@@ -24,7 +22,7 @@ export const DialogManageModels: Component = () => {
const local = useLocal()
const language = useLanguage()
const dialog = useDialog()
const [store, setStore] = createStore({ collapsed: {} as Record<string, boolean> })
const [store, setStore] = createStore<{ collapsed: Record<string, boolean> }>({ collapsed: {} })
const directory = () => decode64(local.slug())
const handleConnectProvider = () => {
@@ -107,33 +105,24 @@ export const DialogManageModels: Component = () => {
</DialogHeader>
<DialogBody class="flex min-h-0 flex-1 flex-col">
<div class="px-4 pt-px pb-3">
<div class="relative">
<TextInput
type="search"
appearance="base"
class="!w-full self-stretch"
value={list.filter()}
onInput={(event) => list.onInput(event.currentTarget.value)}
placeholder={language.t("dialog.model.search.placeholder")}
spellcheck={false}
autocorrect="off"
autocomplete="off"
autocapitalize="off"
autofocus
aria-label={language.t("dialog.model.search.placeholder")}
/>
<Show when={list.filter()}>
<IconButton
type="button"
variant="ghost-muted"
size="small"
class="settings-tab-search-clear"
icon={<Icon name="close" size="large" class="text-v2-icon-icon-muted" />}
onClick={() => list.clear()}
aria-label={language.t("common.clear")}
/>
</Show>
</div>
<TextInput
type="search"
appearance="base"
class="!w-full self-stretch"
value={list.filter()}
onInput={(event) => list.onInput(event.currentTarget.value)}
placeholder={language.t("dialog.model.search.placeholder")}
spellcheck={false}
autocorrect="off"
autocomplete="off"
autocapitalize="off"
autofocus
aria-label={language.t("dialog.model.search.placeholder")}
showClearButton={!!list.filter()}
clearIcon="circle-xmark"
clearLabel={language.t("common.clear")}
onClearClick={() => list.clear()}
/>
</div>
<div data-slot="manage-models-scroll" class="relative min-h-0 flex-1">
<div class="settings-panel settings-models h-full px-4 pt-1 pb-4">
@@ -9,7 +9,6 @@ import { Button } from "@opencode/ui/button"
import { Badge } from "@opencode/ui/badge"
import { Dialog, DialogBody, DialogHeader, DialogTitleGroup } from "@opencode/ui/dialog"
import { Icon } from "@opencode/ui/icon"
import { IconButton } from "@opencode/ui/icon-button"
import { ScrollView } from "@opencode/ui/scroll-view"
import { Tooltip } from "@opencode/ui/tooltip"
import { Menu } from "@opencode/ui/menu"
@@ -186,55 +185,46 @@ const ModelList: Component<{
return (
<div class="flex min-h-0 flex-1 flex-col">
<div data-slot="model-selector-search" class="shrink-0 pt-px pb-3" classList={{ "px-4": !props.mobile }}>
<div class="relative">
<TextInput
type="search"
appearance="base"
class="!w-full self-stretch"
placeholder={language.t("dialog.model.search.placeholder")}
value={store.search}
autofocus={!props.mobile}
spellcheck={false}
autocorrect="off"
autocomplete="off"
autocapitalize="off"
onInput={(event) => setSearch(event.currentTarget.value)}
onKeyDown={(event) => {
if (event.altKey || event.metaKey) return
<TextInput
type="search"
appearance="base"
class="!w-full self-stretch"
placeholder={language.t("dialog.model.search.placeholder")}
value={store.search}
autofocus={!props.mobile}
spellcheck={false}
autocorrect="off"
autocomplete="off"
autocapitalize="off"
onInput={(event) => setSearch(event.currentTarget.value)}
onKeyDown={(event) => {
if (event.altKey || event.metaKey) return
if (event.key === "ArrowDown") {
event.preventDefault()
moveActive(1)
if (event.key === "ArrowDown") {
event.preventDefault()
moveActive(1)
return
}
return
}
if (event.key === "ArrowUp") {
event.preventDefault()
moveActive(-1)
if (event.key === "ArrowUp") {
event.preventDefault()
moveActive(-1)
return
}
return
}
if (event.key === "Enter" && !event.isComposing) {
event.preventDefault()
selectActive()
}
}}
aria-label={language.t("dialog.model.search.placeholder")}
/>
<Show when={store.search}>
<IconButton
type="button"
variant="ghost-muted"
size="small"
class="settings-tab-search-clear"
icon={<Icon name="close" size="large" class="text-v2-icon-icon-muted" />}
onClick={() => setSearch("")}
aria-label={language.t("common.clear")}
/>
</Show>
</div>
if (event.key === "Enter" && !event.isComposing) {
event.preventDefault()
selectActive()
}
}}
aria-label={language.t("dialog.model.search.placeholder")}
showClearButton={!!store.search}
clearIcon="circle-xmark"
clearLabel={language.t("common.clear")}
onClearClick={() => setSearch("")}
/>
</div>
<div class="relative min-h-0" classList={{ "flex-1": !props.mobile }}>
<div
@@ -613,7 +603,7 @@ export function ModelSelectorPopoverView(props: {
onCloseAutoFocus={dismiss.onCloseAutoFocus}
>
<div class="flex flex-col p-0.5">
<div class="flex h-7 items-center gap-2 rounded-sm pl-3 pr-2.5 text-v2-icon-icon-muted">
<div class="flex h-7 items-center gap-2 rounded-sm pl-3 pr-1 text-v2-icon-icon-muted">
<Icon name="magnifying-glass" size="small" class="shrink-0" />
<input
ref={(el) => (searchRef = el)}
@@ -663,12 +653,12 @@ export function ModelSelectorPopoverView(props: {
<Show when={store.search.trim()}>
<button
type="button"
class="flex size-5 items-center justify-center rounded-sm text-v2-icon-icon-muted hover:bg-v2-overlay-simple-overlay-hover"
class="flex size-5 items-center justify-center rounded-sm bg-transparent text-v2-icon-icon-faint transition-colors hover:text-v2-icon-icon-base focus-visible:text-v2-icon-icon-base active:text-v2-icon-icon-base"
onPointerDown={(event) => event.preventDefault()}
onClick={() => setSearch("")}
aria-label={language.t("common.clear")}
>
<Icon name="close" size="small" />
<Icon name="circle-xmark" />
</button>
</Show>
</div>
@@ -69,6 +69,7 @@ type Attached = {
keybind: (command: string) => readonly string[]
matches: (command: string, event: KeyboardEvent) => boolean
servers: Accessor<readonly string[]>
server: (id: string) => ServerRef | undefined
}
/**
@@ -269,7 +270,10 @@ export function createHostApis() {
keys: (bind) => formatKeybindParts(bind, language.t),
matches: (command, event) => current()?.matches(command, event) ?? false,
}),
servers: () => ({ list: () => current()?.servers() ?? [] }),
servers: () => ({
list: () => current()?.servers() ?? [],
get: (id) => current()?.server(id),
}),
workspaces: (_extension, _owner, _context, register) => ({
on(_event, handler) {
removed.add(handler)
@@ -389,15 +393,28 @@ export function createExtensionAttachment(apis: HostApis) {
if (existing) return existing
const key = ServerConnection.Key.make(id)
// The controller starts on first use, not when the ref is made: reading `builtin` to find a server must not
// connect to every listed server, such as one the runtime holds back because it rejects its credentials.
let started: Accessor<ServerCtx> | undefined
const live = runWithOwner(owner, () =>
createMemo<ServerCtx>((previous) => global.serverCtx(key) ?? previous, global.ensureServerCtx(conn)),
)!
const live = () => {
started ??= runWithOwner(owner, () =>
createMemo<ServerCtx>(
(previous) => global.serverCtx(key) ?? previous,
global.ensureServerCtx(connection(id) ?? conn),
),
)!
return started()
}
// What the app's server list already says, without a controller.
const listed = () => connection(id) ?? live().sdk.server
const ref: ServerRef = {
id,
get name() {
return serverName(live().sdk.server) || id
return serverName(listed()) || id
},
get url() {
return live().sdk.url
@@ -412,10 +429,10 @@ export function createExtensionAttachment(apis: HostApis) {
return live().data
},
get local() {
return ServerConnection.local(live().sdk.server)
return ServerConnection.local(listed())
},
get builtin() {
return ServerConnection.builtin(live().sdk.server)
return ServerConnection.builtin(listed())
},
get compatible() {
return !global.servers.health[key]?.incompatible
@@ -783,6 +800,7 @@ export function createExtensionAttachment(apis: HostApis) {
keybind: command.keybindParts,
matches: command.matches,
servers: () => global.servers.list().map(ServerConnection.key),
server,
// SAFETY: an extension names a page it contributed through `SettingsPage`, which settings lists as an extension tab.
settings: (page) => surface.open(page as Parameters<typeof surface.open>[0]),
layout: {
-5
View File
@@ -285,9 +285,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "የይለፍ ቃል",
"dialog.server.edit.title": "አገልጋይ አርትዕ",
"dialog.server.menu.edit": "አርትዕ",
"dialog.server.menu.default": "ነባሪ አዘጋጅ",
"dialog.server.menu.defaultRemove": "ነባሪውን አስወግድ",
"dialog.server.status.default": "ነባሪ",
"dialog.project.edit.title": "ፕሮጀክት አርትዕ",
"dialog.project.edit.icon": "አዶ",
"dialog.project.edit.icon.alt": "የፕሮጀክት አዶ",
@@ -775,14 +772,12 @@ export const dict = {
"server.connect.button": "መገናኘት",
"server.connect.address.invalid": "የሚሰራ የኤችቲቲፒ ወይም የኤችቲቲፒኤስ አገልጋይ አድራሻ ያስገቡ።",
"server.connect.failed": "መገናኘት አልተቻለም። የአገልጋዩን አድራሻ እና የይለፍ ቃል ያረጋግጡ እና ከዚያ እንደገና ይሞክሩ።",
"server.connect.pair.description": "የግንኙነት ዝርዝሮችዎን ለማግኘት ይህንን ትዕዛዝ በኮምፒተርዎ ላይ ያሂዱ።",
"server.connect.scan": "QR ኮድ ይቃኙ",
"server.connect.scan.description": "ካሜራዎን opencode pair ወደሚያሳየው QR ኮድ ያነጣጥሩ።",
"server.connect.scan.invalid": "ይህ የOpenCode ማጣመሪያ ኮድ አይደለም። opencode pair የሚያሳየውን ኮድ ይቃኙ።",
"server.connect.camera": "ማጣመር ካሜራ",
"server.connect.camera.starting": "ካሜራ በመክፈት ላይ...",
"server.connect.mixedContent": "ከዚህ ኤችቲቲፒኤስ አገልጋይ ጋር ከኤችቲቲፒኤስ ገጽ ጋር መገናኘት አልተቻለም። በምትኩ የኤችቲቲፒኤስ አገልጋይ አድራሻ ይጠቀሙ።",
"server.connect.camera.insecure": "QR ቅኝት ይህንን ገጽ በኤችቲቲፒኤስ ወይም በአካባቢያዊ አስተናጋጅ መክፈት ይጠይቃል።",
"server.connect.camera.unavailable": "ለዚህ አሳሽ ምንም ካሜራ አይገኝም። የግንኙነት ዝርዝሮችዎን እራስዎ ያስገቡ።",
"server.connect.camera.error": "ካሜራውን መክፈት አልተቻለም። የካሜራ መዳረሻ ይፍቀዱ ወይም የግንኙነት ዝርዝሮችዎን እራስዎ ያስገቡ።",
"dialog.server.menu.remove": "አስወግድ",
-5
View File
@@ -297,9 +297,6 @@ export const dict = {
"dialog.server.add.password": "كلمة المرور (اختياري)",
"dialog.server.edit.title": "تحرير الخادم",
"dialog.server.menu.edit": "تعديل",
"dialog.server.menu.default": "تعيين كافتراضي",
"dialog.server.menu.defaultRemove": "إزالة الافتراضي",
"dialog.server.status.default": "افتراضي",
"dialog.project.edit.title": "تحرير المشروع",
"dialog.project.edit.icon": "أيقونة",
"dialog.project.edit.icon.alt": "أيقونة المشروع",
@@ -833,14 +830,12 @@ export const dict = {
"server.connect.button": "اتصال",
"server.connect.address.invalid": "أدخل عنوان خادم HTTP أو HTTPS صالحًا.",
"server.connect.failed": "تعذر الاتصال. تحقق من عنوان الخادم وكلمة المرور، ثم أعد المحاولة.",
"server.connect.pair.description": "نفّذ هذا الأمر على حاسوبك للحصول على تفاصيل الاتصال.",
"server.connect.scan": "مسح رمز QR",
"server.connect.scan.description": "وجّه الكاميرا نحو رمز QR الذي يعرضه opencode pair.",
"server.connect.scan.invalid": "هذا ليس رمز إقران OpenCode. امسح الرمز الذي يعرضه opencode pair.",
"server.connect.camera": "كاميرا الإقران",
"server.connect.camera.starting": "جارٍ فتح الكاميرا…",
"server.connect.mixedContent": "تعذر الاتصال بخادم HTTP هذا من صفحة HTTPS. استخدم عنوان خادم HTTPS بدلًا منه.",
"server.connect.camera.insecure": "يتطلب مسح رمز QR فتح هذه الصفحة عبر HTTPS أو على localhost.",
"server.connect.camera.unavailable": "لا تتوفر كاميرا لهذا المتصفح. أدخل تفاصيل الاتصال يدويًا.",
"server.connect.camera.error": "تعذر فتح الكاميرا. اسمح بالوصول إليها أو أدخل تفاصيل الاتصال يدويًا.",
"dialog.server.menu.remove": "إزالة",
-6
View File
@@ -288,9 +288,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "parol",
"dialog.server.edit.title": "Serveri redaktə et",
"dialog.server.menu.edit": "Redaktə et",
"dialog.server.menu.default": "Standart olaraq təyin et",
"dialog.server.menu.defaultRemove": "Standartı sil",
"dialog.server.status.default": "Standart",
"dialog.project.edit.title": "Layihəni redaktə et",
"dialog.project.edit.icon": "İkon",
"dialog.project.edit.icon.alt": "Layihə ikonu",
@@ -799,7 +796,6 @@ export const dict = {
"server.connect.button": "Qoşulun",
"server.connect.address.invalid": "Etibarlı HTTP və ya HTTPS server ünvanını daxil edin.",
"server.connect.failed": "Bağlana bilmədik. Server ünvanını və şifrəni yoxlayın, sonra yenidən cəhd edin.",
"server.connect.pair.description": "Bağlantı məlumatlarınızı almaq üçün bu əmri kompüterinizdə işlədin.",
"server.connect.scan": "QR kodu skan edin",
"server.connect.scan.description": "Kameranızı opencode pair tərəfindən göstərilən QR koda yönəldin.",
"server.connect.scan.invalid": "Bu, OpenCode qoşulma kodu deyil. opencode pair tərəfindən göstərilən kodu skan edin.",
@@ -807,8 +803,6 @@ export const dict = {
"server.connect.camera.starting": "Kamera açılır…",
"server.connect.mixedContent":
"Bu HTTPS səhifəsindən bu HTTP serverinə qoşulmaq mümkün olmadı. Bunun əvəzinə HTTPS server ünvanından istifadə edin.",
"server.connect.camera.insecure":
"QR skan edilməsi üçün bu səhifəni HTTPS üzərindən və ya localhost-da açmaq tələb olunur.",
"server.connect.camera.unavailable":
"Bu brauzer üçün heç bir kamera mövcud deyil. Bağlantı məlumatlarınızı əl ilə daxil edin.",
"server.connect.camera.error":
-6
View File
@@ -287,9 +287,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "парола",
"dialog.server.edit.title": "Редактиране на сървъра",
"dialog.server.menu.edit": "Редактиране",
"dialog.server.menu.default": "Задайте по подразбиране",
"dialog.server.menu.defaultRemove": "Премахване на подразбиране",
"dialog.server.status.default": "По подразбиране",
"dialog.project.edit.title": "Редактиране на проекта",
"dialog.project.edit.icon": "Икона",
"dialog.project.edit.icon.alt": "Икона на проекта",
@@ -797,7 +794,6 @@ export const dict = {
"server.connect.button": "Свързване",
"server.connect.address.invalid": "Въведете валиден HTTP или HTTPS адрес на сървър.",
"server.connect.failed": "Свързването е неуспешно. Проверете адреса и паролата на сървъра и опитайте отново.",
"server.connect.pair.description": "Изпълнете тази команда на компютъра си, за да получите данните за връзка.",
"server.connect.scan": "Сканиране на QR код",
"server.connect.scan.description": "Насочете камерата към QR кода, показан от opencode pair.",
"server.connect.scan.invalid": "Това не е код за сдвояване с OpenCode. Сканирайте кода, показан от opencode pair.",
@@ -805,8 +801,6 @@ export const dict = {
"server.connect.camera.starting": "Отваряне на камерата…",
"server.connect.mixedContent":
"Не може да се осъществи връзка с този HTTP сървър от HTTPS страница. Използвайте HTTPS адрес на сървъра.",
"server.connect.camera.insecure":
"Сканирането на QR код изисква тази страница да е отворена чрез HTTPS или на localhost.",
"server.connect.camera.unavailable": "Няма достъпна камера за този браузър. Въведете ръчно данните за връзка.",
"server.connect.camera.error":
"Камерата не можа да бъде отворена. Разрешете достъпа до нея или въведете ръчно данните за връзка.",
-5
View File
@@ -290,9 +290,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "পাসওয়ার্ড",
"dialog.server.edit.title": "সার্ভার সম্পাদনা করুন",
"dialog.server.menu.edit": "সম্পাদনা করুন",
"dialog.server.menu.default": "ডিফল্ট হিসেবে সেট করুন",
"dialog.server.menu.defaultRemove": "ডিফল্ট সরান",
"dialog.server.status.default": "ডিফল্ট",
"dialog.project.edit.title": "প্রকল্প সম্পাদনা করুন",
"dialog.project.edit.icon": "আইকন",
"dialog.project.edit.icon.alt": "প্রকল্প আইকন",
@@ -797,7 +794,6 @@ export const dict = {
"server.connect.button": "সংযোগ করুন",
"server.connect.address.invalid": "একটি বৈধ HTTP বা HTTPS সার্ভার ঠিকানা লিখুন৷",
"server.connect.failed": "সংযোগ করা যায়নি। সার্ভার ঠিকানা এবং পাসওয়ার্ড পরীক্ষা করুন, তারপর আবার চেষ্টা করুন.",
"server.connect.pair.description": "আপনার সংযোগের বিবরণ পেতে আপনার কম্পিউটারে এই কমান্ডটি চালান।",
"server.connect.scan": "QR কোড স্ক্যান করুন",
"server.connect.scan.description": "আপনার ক্যামেরাকে ওপেনকোড পেয়ার দ্বারা দেখানো QR কোডে নির্দেশ করুন৷",
"server.connect.scan.invalid": "এটি একটি OpenCode পেয়ারিং কোড নয়৷ ওপেনকোড পেয়ার দ্বারা দেখানো কোডটি স্ক্যান করুন।",
@@ -805,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "ক্যামেরা খোলা হচ্ছে...",
"server.connect.mixedContent":
"একটি HTTPS পৃষ্ঠা থেকে এই HTTP সার্ভারের সাথে সংযোগ করা যায়নি৷ পরিবর্তে একটি HTTPS সার্ভার ঠিকানা ব্যবহার করুন৷",
"server.connect.camera.insecure": "QR স্ক্যান করার জন্য এই পৃষ্ঠাটি HTTPS বা লোকালহোস্টে খুলতে হবে।",
"server.connect.camera.unavailable": "এই ব্রাউজারে কোন ক্যামেরা উপলব্ধ নেই৷ ম্যানুয়ালি আপনার সংযোগ বিশদ লিখুন.",
"server.connect.camera.error":
"ক্যামেরা খুলতে পারিনি। ক্যামেরা অ্যাক্সেসের অনুমতি দিন বা ম্যানুয়ালি আপনার সংযোগের বিবরণ লিখুন।",
-5
View File
@@ -22,7 +22,6 @@ export const dict = {
"server.connect.button": "Conectar",
"server.connect.address.invalid": "Insira um endereço de servidor HTTP ou HTTPS válido.",
"server.connect.failed": "Não foi possível conectar. Verifique o endereço e a senha do servidor e tente novamente.",
"server.connect.pair.description": "Execute este comando em seu computador para obter os detalhes de sua conexão.",
"server.connect.scan": "Digitalize o código QR",
"server.connect.scan.description": "Aponte sua câmera para o código QR mostrado por opencode pair.",
"server.connect.scan.invalid":
@@ -31,7 +30,6 @@ export const dict = {
"server.connect.camera.starting": "Abrindo a câmera…",
"server.connect.mixedContent":
"Não foi possível conectar-se a este servidor HTTP a partir de uma página HTTPS. Use um endereço de servidor HTTPS.",
"server.connect.camera.insecure": "A varredura QR requer a abertura desta página em HTTPS ou no host local.",
"server.connect.camera.unavailable":
"Nenhuma câmera está disponível para este navegador. Insira os detalhes da sua conexão manualmente.",
"server.connect.camera.error":
@@ -510,9 +508,6 @@ export const dict = {
"dialog.server.add.password": "Senha (opcional)",
"dialog.server.edit.title": "Editar servidor",
"dialog.server.menu.edit": "Editar",
"dialog.server.menu.default": "Definir como padrão",
"dialog.server.menu.defaultRemove": "Remover padrão",
"dialog.server.status.default": "Padrão",
"dialog.project.edit.title": "Editar projeto",
"dialog.project.edit.icon": "Ícone",
"dialog.project.edit.icon.alt": "Ícone do projeto",
-6
View File
@@ -312,9 +312,6 @@ export const dict = {
"dialog.server.edit.title": "Uredi server",
"dialog.server.menu.edit": "Uredi",
"dialog.server.menu.default": "Postavi kao podrazumijevano",
"dialog.server.menu.defaultRemove": "Ukloni podrazumijevano",
"dialog.server.status.default": "Podrazumijevano",
"dialog.project.edit.title": "Uredi projekat",
"dialog.project.edit.icon": "Ikonica",
@@ -862,7 +859,6 @@ export const dict = {
"server.connect.button": "Poveži se",
"server.connect.address.invalid": "Unesite ispravnu HTTP ili HTTPS adresu servera.",
"server.connect.failed": "Povezivanje nije uspjelo. Provjerite adresu servera i lozinku, pa pokušajte ponovo.",
"server.connect.pair.description": "Pokrenite ovu naredbu na računaru da biste dobili podatke za povezivanje.",
"server.connect.scan": "Skeniraj QR kod",
"server.connect.scan.description": "Usmjerite kameru prema QR kodu koji prikazuje opencode pair.",
"server.connect.scan.invalid": "Ovo nije OpenCode kod za uparivanje. Skenirajte kod koji prikazuje opencode pair.",
@@ -870,8 +866,6 @@ export const dict = {
"server.connect.camera.starting": "Otvaranje kamere…",
"server.connect.mixedContent":
"Nije se moguće povezati s ovim HTTP serverom s HTTPS stranice. Umjesto toga koristite HTTPS adresu servera.",
"server.connect.camera.insecure":
"Za skeniranje QR koda ovu stranicu morate otvoriti putem HTTPS-a ili na localhostu.",
"server.connect.camera.unavailable": "Ovom pregledniku nije dostupna kamera. Ručno unesite podatke za povezivanje.",
"server.connect.camera.error":
"Kameru nije bilo moguće otvoriti. Dozvolite pristup kameri ili ručno unesite podatke za povezivanje.",
-6
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "contrasenya",
"dialog.server.edit.title": "Edita el servidor",
"dialog.server.menu.edit": "Edita",
"dialog.server.menu.default": "Estableix com a predeterminat",
"dialog.server.menu.defaultRemove": "Elimina el valor predeterminat",
"dialog.server.status.default": "Per defecte",
"dialog.project.edit.title": "Edita el projecte",
"dialog.project.edit.icon": "Icona",
"dialog.project.edit.icon.alt": "Icona del projecte",
@@ -796,8 +793,6 @@ export const dict = {
"server.connect.address.invalid": "Introduïu una adreça de servidor HTTP o HTTPS vàlida.",
"server.connect.failed":
"No s'ha pogut connectar. Comproveu l'adreça i la contrasenya del servidor i torneu-ho a provar.",
"server.connect.pair.description":
"Executeu aquesta ordre al vostre ordinador per obtenir els detalls de la vostra connexió.",
"server.connect.scan": "Escaneja el codi QR",
"server.connect.scan.description": "Apunteu la càmera al codi QR que mostra opencode pair.",
"server.connect.scan.invalid":
@@ -806,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "Obertura de la càmera...",
"server.connect.mixedContent":
"No s'ha pogut connectar a aquest servidor HTTP des d'una pàgina HTTPS. Utilitzeu una adreça de servidor HTTPS.",
"server.connect.camera.insecure": "L'exploració de QR requereix obrir aquesta pàgina a HTTPS o a localhost.",
"server.connect.camera.unavailable":
"No hi ha cap càmera disponible per a aquest navegador. Introduïu els detalls de connexió manualment.",
"server.connect.camera.error":
-5
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "heslo",
"dialog.server.edit.title": "Upravit server",
"dialog.server.menu.edit": "Upravit",
"dialog.server.menu.default": "Nastavit jako výchozí",
"dialog.server.menu.defaultRemove": "Odebrat výchozí",
"dialog.server.status.default": "Výchozí",
"dialog.project.edit.title": "Upravit projekt",
"dialog.project.edit.icon": "ikona",
"dialog.project.edit.icon.alt": "Ikona projektu",
@@ -806,7 +803,6 @@ export const dict = {
"server.connect.button": "Připojit",
"server.connect.address.invalid": "Zadejte platnou adresu serveru HTTP nebo HTTPS.",
"server.connect.failed": "Připojení se nezdařilo. Zkontrolujte adresu serveru a heslo a zkuste to znovu.",
"server.connect.pair.description": "Spuštěním tohoto příkazu v počítači získáte údaje pro připojení.",
"server.connect.scan": "Naskenovat QR kód",
"server.connect.scan.description": "Namiřte kameru na QR kód zobrazený příkazem opencode pair.",
"server.connect.scan.invalid": "Toto není párovací kód OpenCode. Naskenujte kód zobrazený příkazem opencode pair.",
@@ -814,7 +810,6 @@ export const dict = {
"server.connect.camera.starting": "Otevírání kamery…",
"server.connect.mixedContent":
"K tomuto serveru HTTP se nelze připojit ze stránky HTTPS. Použijte adresu serveru HTTPS.",
"server.connect.camera.insecure": "Skenování QR kódu vyžaduje otevření této stránky přes HTTPS nebo na localhostu.",
"server.connect.camera.unavailable":
"Pro tento prohlížeč není dostupná žádná kamera. Zadejte údaje pro připojení ručně.",
"server.connect.camera.error":
-5
View File
@@ -23,7 +23,6 @@ export const dict = {
"server.connect.address.invalid": "Indtast en gyldig HTTP- eller HTTPS-serveradresse.",
"server.connect.failed":
"Kunne ikke oprette forbindelse. Tjek serveradressen og adgangskoden, og prøv derefter igen.",
"server.connect.pair.description": "Kør denne kommando på din computer for at få dine forbindelsesdetaljer.",
"server.connect.scan": "Scan QR kode",
"server.connect.scan.description": "Ret dit kamera mod QR-koden vist af opencode pair.",
"server.connect.scan.invalid": "Dette er ikke en OpenCode-parringskode. Scan koden vist af opencode pair.",
@@ -31,7 +30,6 @@ export const dict = {
"server.connect.camera.starting": "Åbner kamera...",
"server.connect.mixedContent":
"Kunne ikke oprette forbindelse til denne HTTP-server fra en HTTPS-side. Brug i stedet en HTTPS-serveradresse.",
"server.connect.camera.insecure": "QR-scanning kræver, at denne side åbnes over HTTPS eller på localhost.",
"server.connect.camera.unavailable":
"Intet kamera er tilgængeligt for denne browser. Indtast dine forbindelsesoplysninger manuelt.",
"server.connect.camera.error":
@@ -448,9 +446,6 @@ export const dict = {
"dialog.server.edit.title": "Rediger server",
"dialog.server.menu.edit": "Rediger",
"dialog.server.menu.default": "Sæt som standard",
"dialog.server.menu.defaultRemove": "Fjern som standard",
"dialog.server.status.default": "Standard",
"dialog.project.edit.title": "Rediger projekt",
"dialog.project.edit.icon": "Ikon",
-7
View File
@@ -27,8 +27,6 @@ export const dict = {
"server.connect.address.invalid": "Geben Sie eine gültige HTTP- oder HTTPS-Serveradresse ein.",
"server.connect.failed":
"Es konnte keine Verbindung hergestellt werden. Überprüfen Sie die Serveradresse und das Passwort und versuchen Sie es dann erneut.",
"server.connect.pair.description":
"Führen Sie diesen Befehl auf Ihrem Computer aus, um Ihre Verbindungsdetails abzurufen.",
"server.connect.scan": "Scannen Sie den QR-Code",
"server.connect.scan.description": "Richten Sie Ihre Kamera auf den von opencode pair angezeigten Code QR.",
"server.connect.scan.invalid":
@@ -37,8 +35,6 @@ export const dict = {
"server.connect.camera.starting": "Kamera wird geöffnet…",
"server.connect.mixedContent":
"Es konnte keine Verbindung zu diesem HTTP-Server von einer HTTPS-Seite hergestellt werden. Verwenden Sie stattdessen eine HTTPS-Serveradresse.",
"server.connect.camera.insecure":
"Zum Scannen mit QR muss diese Seite über HTTPS oder auf localhost geöffnet werden.",
"server.connect.camera.unavailable":
"Für diesen Browser ist keine Kamera verfügbar. Geben Sie Ihre Verbindungsdaten manuell ein.",
"server.connect.camera.error":
@@ -446,9 +442,6 @@ export const dict = {
"dialog.server.add.password": "Passwort (optional)",
"dialog.server.edit.title": "Server bearbeiten",
"dialog.server.menu.edit": "Bearbeiten",
"dialog.server.menu.default": "Als Standard festlegen",
"dialog.server.menu.defaultRemove": "Standard entfernen",
"dialog.server.status.default": "Standard",
"dialog.project.edit.title": "Projekt bearbeiten",
"dialog.project.edit.icon": "Symbol",
"dialog.project.edit.icon.alt": "Projektsymbol",
-6
View File
@@ -292,9 +292,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "ޕާސްވަރޑް",
"dialog.server.edit.title": "އެޑިޓް ސަރވަރ",
"dialog.server.menu.edit": "ބަދަލު ގެނައުން",
"dialog.server.menu.default": "ޑިފޯލްޓް ގޮތުގައި ސެޓްކުރުން",
"dialog.server.menu.defaultRemove": "ޑިފޯލްޓް ނައްތާލާށެވެ",
"dialog.server.status.default": "ޑީފޯލްޓް",
"dialog.project.edit.title": "އެޑިޓް ޕްރޮޖެކްޓް",
"dialog.project.edit.icon": "އައިކޮން",
"dialog.project.edit.icon.alt": "ޕްރޮޖެކްޓް އައިކޮން",
@@ -816,7 +813,6 @@ export const dict = {
"server.connect.address.invalid": "ސައްހަ HTTP ނުވަތަ HTTPS ސަރވަރ އެޑްރެހެއް ލިޔެލާށެވެ.",
"server.connect.failed":
"ގުޅެވޭ ގޮތެއް ނުވިއެވެ. ސަރވަރ އެޑްރެހާއި ޕާސްވޯޑް ޗެކްކޮށްލުމަށްފަހު އަލުން މަސައްކަތް ކުރާށެވެ.",
"server.connect.pair.description": "ކަނެކްޝަންގެ ތަފްސީލު ހޯދުމަށްޓަކައި ކޮމްޕިއުޓަރުގައި މި ކޮމާންޑް ހިންގާށެވެ.",
"server.connect.scan": "QR ކޯޑް ސްކޭން ކުރާށެވެ",
"server.connect.scan.description": "އޮޕަންކޯޑް ޖޯޑުން ދައްކާ QR ކޯޑަށް ކެމެރާ އިޝާރާތް ކުރާށެވެ.",
"server.connect.scan.invalid": "މިއީ OpenCode ޖޯޑު ކޯޑެއް ނޫނެވެ. އޮޕަންކޯޑް ޕެއާ އިން ދައްކާ ކޯޑް ސްކޭން ކުރާށެވެ.",
@@ -824,8 +820,6 @@ export const dict = {
"server.connect.camera.starting": "ކެމެރާ ހުޅުވަނީ...",
"server.connect.mixedContent":
"HTTPS ޕޭޖަކުން މި HTTP ސަރވަރ އާއި ގުޅޭ ގޮތެއް ނުވިއެވެ. އޭގެ ބަދަލުގައި HTTPS ސަރވަރ އެޑްރެހެއް ބޭނުން ކުރާށެވެ.",
"server.connect.camera.insecure":
"QR ސްކޭން ކުރުމަށް މި ޕޭޖް ހުޅުވަން ޖެހެނީ HTTPS ގެ މައްޗަށް ނުވަތަ ލޯކަލްހޯސްޓް އިންނެވެ.",
"server.connect.camera.unavailable":
"މި ބްރައުޒާއަށް އެއްވެސް ކެމެރާއެއް ނުލިބެއެވެ. ކަނެކްޝަންގެ ތަފްސީލުތައް އަމިއްލައަށް ލިޔެލާށެވެ.",
"server.connect.camera.error":
-6
View File
@@ -298,9 +298,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "གསང༌ཨང",
"dialog.server.edit.title": "སར་བར་ཞུན་དག་འབད།",
"dialog.server.menu.edit": "ཞུན༌དག",
"dialog.server.menu.default": "སྔོན་སྒྲིག་སྦེ་གཞི་སྒྲིག་འབད།",
"dialog.server.menu.defaultRemove": "སྔོན་སྒྲིག་རྩ་བསྐྲད་གཏང་།",
"dialog.server.status.default": "འཐུས་ཤོར",
"dialog.project.edit.title": "ཞུན་དག་ལས་གཞི།",
"dialog.project.edit.icon": "ངོས་དཔར།",
"dialog.project.edit.icon.alt": "ལས་འགུལ་ངོས་དཔར།",
@@ -797,8 +794,6 @@ export const dict = {
"server.connect.button": "མཐུད།",
"server.connect.address.invalid": "ནུས་ཅན་ HTTP ཡང་ན་ HTTPS སར་བར་ཁ་བྱང་ཅིག་བཙུགས།",
"server.connect.failed": "མཐུད་མ་ཚུགས། སར་བར་ཁ་བྱང་དང་ཆོག་ཡིག་ཞིབ་དཔྱད་འབད་ཞིནམ་ལས་ ལོག་སྟེ་འབད་རྩོལ་བསྐྱེད།",
"server.connect.pair.description":
"ཁྱོད་རའི་མཐུད་ལམ་རྒྱས་བཤད་ཚུ་ཐོབ་ནིའི་དོན་ལུ་ ཁྱོད་རའི་གློག་རིག་གུ་བརྡ་བཀོད་འདི་གཡོག་བཀོལ།",
"server.connect.scan": "QR གསང་གྲངས་པར་བཤུས་",
"server.connect.scan.description": "ཁྱོད་རའི་པར་ཆས་འདི་ opencode pair གིས་སྟོན་མི་ QR གསང་ཡིག་ལུ་སྟོན་དགོ།",
"server.connect.scan.invalid":
@@ -807,7 +802,6 @@ export const dict = {
"server.connect.camera.starting": "པར་ཆས་ཁ་ཕྱེ་དོ...",
"server.connect.mixedContent":
"HTTPS ཤོག་ལེབ་ཅིག་ལས་ HTTP སར་བར་འདི་ལུ་མཐུད་མ་ཚུགས། དེ་གི་ཚབ་ལུ་ HTTPS སར་བར་ཁ་བྱང་ཅིག་ལག་ལེན་འཐབ།",
"server.connect.camera.insecure": "QR པར་ལེན་འབད་ནི་ལུ་ ཤོག་ལེབ་འདི་ HTTPS ཡང་ན་ localhost གུ་ཁ་ཕྱེ་དགོཔ་ཨིན།",
"server.connect.camera.unavailable": "བརྡ་འཚོལ་འདི་ལུ་པར་ཆས་མེད། ཁྱོད་རའི་མཐུད་ལམ་རྒྱས་བཤད་ཚུ་ལག་ཐོག་ལས་བཙུགས།",
"server.connect.camera.error":
"པར་ཆས་ཁ་ཕྱེ་མ་ཚུགས། པར་ཆས་འཛུལ་སྤྱོད་འབད་བཅུགཔ་ ཡང་ན་ ཁྱོད་རའི་མཐུད་ལམ་རྒྱས་བཤད་ཚུ་ལག་ཐོག་ལས་བཙུགས།",
-6
View File
@@ -288,9 +288,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "κωδικός πρόσβασης",
"dialog.server.edit.title": "Επεξεργασία διακομιστή",
"dialog.server.menu.edit": "Επεξεργασία",
"dialog.server.menu.default": "Ορισμός ως προεπιλογή",
"dialog.server.menu.defaultRemove": "Κατάργηση προεπιλογής",
"dialog.server.status.default": "Προεπιλογή",
"dialog.project.edit.title": "Επεξεργασία έργου",
"dialog.project.edit.icon": "Εικονίδιο",
"dialog.project.edit.icon.alt": "Εικονίδιο έργου",
@@ -796,8 +793,6 @@ export const dict = {
"server.connect.address.invalid": "Εισαγάγετε μια έγκυρη διεύθυνση διακομιστή HTTP ή HTTPS.",
"server.connect.failed":
"Δεν ήταν δυνατή η σύνδεση. Ελέγξτε τη διεύθυνση του διακομιστή και τον κωδικό πρόσβασης και, στη συνέχεια, δοκιμάστε ξανά.",
"server.connect.pair.description":
"Εκτελέστε αυτήν την εντολή στον υπολογιστή σας για να λάβετε τα στοιχεία της σύνδεσής σας.",
"server.connect.scan": "Σάρωση κωδικού QR",
"server.connect.scan.description": "Στρέψτε την κάμερά σας στον κωδικό QR που εμφανίζεται από το opencode pair.",
"server.connect.scan.invalid":
@@ -806,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "Άνοιγμα κάμερας…",
"server.connect.mixedContent":
"Δεν ήταν δυνατή η σύνδεση σε αυτόν τον διακομιστή HTTP από μια σελίδα HTTPS. Χρησιμοποιήστε μια διεύθυνση διακομιστή HTTPS.",
"server.connect.camera.insecure": "Η σάρωση QR απαιτεί άνοιγμα αυτής της σελίδας μέσω HTTPS ή localhost.",
"server.connect.camera.unavailable":
"Δεν υπάρχει κάμερα διαθέσιμη σε αυτό το πρόγραμμα περιήγησης. Εισαγάγετε τα στοιχεία της σύνδεσής σας με μη αυτόματο τρόπο.",
"server.connect.camera.error":
+35 -5
View File
@@ -86,6 +86,7 @@ export const dict = {
"palette.empty": "No results found",
"palette.group.commands": "Commands",
"palette.group.files": "Files",
"palette.group.recentSessions": "Recent sessions",
"dialog.provider.search.placeholder": "Search providers",
"dialog.provider.empty": "No providers found",
@@ -340,32 +341,46 @@ export const dict = {
"server.connect.title": "Connect to a server",
"server.connect.description": "Enter your server address and password to get started.",
"server.connect.description.pairing": "Paste the pairing link from the server, or scan its QR code.",
"server.connect.link": "Pairing link",
"server.connect.link.placeholder": "http://192.168.1.2:4096/auth/connect/…",
"server.connect.link.invalid":
"Paste the full pairing link from opencode pair, or from Settings → Pairing on the server's computer.",
"server.connect.password.prompt": "No pairing link?",
"server.connect.password.use": "Use password",
"server.connect.password.hint": "To see it, run opencode service get password on the server's computer.",
"server.connect.link.prompt": "Have a pairing link?",
"server.connect.link.use": "Use pairing link",
"server.connect.button": "Connect",
"server.connect.address.invalid": "Enter a valid HTTP or HTTPS server address.",
"server.connect.failed": "Could not connect. Check the server address and password, then try again.",
"server.connect.pair.description": "Run this command on your computer to get your connection details.",
"server.connect.pair.link": "Run this command on the server's computer to get a pairing link and QR code.",
"server.connect.scan": "Scan QR code",
"server.connect.scan.description": "Point your camera at the QR code shown by opencode pair.",
"server.connect.scan.invalid": "This is not an OpenCode pairing code. Scan the code shown by opencode pair.",
"server.connect.scan.failed": "This browser could not read the QR code. Enter your connection details manually.",
"server.connect.link.expired": "This pairing link expired or was already used. Run opencode pair to get a new one.",
"server.connect.link.unreachable":
"Could not reach {{url}}. Check that this device can reach the server, then try again.",
"server.connect.link.legacy":
"This pairing code is from an older version of OpenCode. Update OpenCode on the server, then run opencode pair again.",
"server.connect.camera": "Pairing camera",
"server.connect.camera.starting": "Opening camera…",
"server.connect.mixedContent":
"Could not connect to this HTTP server from an HTTPS page. Use an HTTPS server address instead.",
"server.connect.camera.insecure": "QR scanning requires opening this page over HTTPS or on localhost.",
"server.connect.camera.native": "This page cannot use the camera over HTTP. Paste the pairing link above.",
"server.connect.camera.unavailable":
"No camera is available to this browser. Enter your connection details manually.",
"server.connect.camera.error":
"Could not open the camera. Allow camera access or enter your connection details manually.",
"dialog.server.edit.title": "Edit server",
"dialog.server.signedOut":
"Your sign-in for this server is no longer valid. Paste a new pairing link, or enter the server password.",
"dialog.server.menu.edit": "Edit",
"dialog.server.menu.default": "Set as default",
"dialog.server.menu.defaultRemove": "Remove default",
"dialog.server.menu.remove": "Remove",
"dialog.server.menu.hide": "Hide from project list",
"dialog.server.menu.show": "Show in project list",
"dialog.server.status.default": "Default",
"server.row.incompatible":
"This server is running OpenCode {{version}}, which isn't compatible with this app. Upgrade it to OpenCode V2 to continue.",
@@ -662,6 +677,21 @@ export const dict = {
"settings.about.description": "OpenCode, the open source coding agent",
"settings.about.trademark": "OpenCode is a registered trademark of Anomaly Innovations, Inc.",
"settings.about.typeset": "Typeset in Inter and IBM Plex Mono",
"settings.about.notices.title": "Third-party notices",
"settings.about.notices.description": "OpenCode includes the following open source software.",
"settings.about.notices.license": "License text",
"settings.about.notices.fonts.title": "Fonts in the Office previews",
"settings.about.notices.fonts.description":
"Each family is distributed under the SIL Open Font License 1.1, with the copyright lines below.",
"settings.about.notices.eigenpal": "Portions of BetterOffice derive from it.",
"settings.about.notices.loadFailed": "Could not load the third-party notices",
"settings.about.notices.crates.title": "Rust crates in the Office engines",
"settings.about.notices.crates.description":
"BetterOffice compiles these crates into its Word, Excel and PowerPoint engines. Where a crate offers a choice of licenses, the highlighted license applies.",
"settings.about.notices.crates.licenses": "License texts",
"settings.about.notices.crates.count.one": "{{count}} crate",
"settings.about.notices.crates.count.other": "{{count}} crates",
"settings.about.notices.crates.appliesTo": "Applies to {{names}}",
"settings.about.tagline": "AI can’t build great software, without you",
"settings.about.copyright": "© Anomaly Innovations, Inc.",
"settings.preferences.description": "Customize preferences and theme and default behavior",
-5
View File
@@ -23,7 +23,6 @@ export const dict = {
"server.connect.address.invalid": "Ingrese una dirección de servidor HTTP o HTTPS válida.",
"server.connect.failed":
"No se pudo conectar. Verifique la dirección y la contraseña del servidor y vuelva a intentarlo.",
"server.connect.pair.description": "Ejecute este comando en su computadora para obtener los detalles de su conexión.",
"server.connect.scan": "Escanea el código QR",
"server.connect.scan.description": "Apunte su cámara al código QR mostrado por opencode pair.",
"server.connect.scan.invalid":
@@ -32,7 +31,6 @@ export const dict = {
"server.connect.camera.starting": "Abriendo cámara...",
"server.connect.mixedContent":
"No se pudo conectar a este servidor HTTP desde una página HTTPS. Utilice una dirección de servidor HTTPS en su lugar.",
"server.connect.camera.insecure": "El escaneo de QR requiere abrir esta página en HTTPS o en localhost.",
"server.connect.camera.unavailable":
"No hay ninguna cámara disponible para este navegador. Ingrese los detalles de su conexión manualmente.",
"server.connect.camera.error":
@@ -537,9 +535,6 @@ export const dict = {
"dialog.server.edit.title": "Editar servidor",
"dialog.server.menu.edit": "Editar",
"dialog.server.menu.default": "Establecer como predeterminado",
"dialog.server.menu.defaultRemove": "Quitar como predeterminado",
"dialog.server.status.default": "Predeterminado",
"dialog.project.edit.title": "Editar proyecto",
"dialog.project.edit.icon": "Icono",
-5
View File
@@ -285,9 +285,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "parool",
"dialog.server.edit.title": "Muuda serverit",
"dialog.server.menu.edit": "Muuda",
"dialog.server.menu.default": "Määra vaikeväärtuseks",
"dialog.server.menu.defaultRemove": "Eemalda vaikeseade",
"dialog.server.status.default": "Vaikimisi",
"dialog.project.edit.title": "Redigeeri projekti",
"dialog.project.edit.icon": "Ikoon",
"dialog.project.edit.icon.alt": "Projekti ikoon",
@@ -775,7 +772,6 @@ export const dict = {
"server.connect.button": "Ühendage",
"server.connect.address.invalid": "Sisestage kehtiv serveri aadress HTTP või HTTPS.",
"server.connect.failed": "Ühendust ei õnnestunud luua. Kontrollige serveri aadressi ja parooli ning proovige uuesti.",
"server.connect.pair.description": "Ühenduse üksikasjade hankimiseks käivitage see käsk oma arvutis.",
"server.connect.scan": "Skaneeri QR-kood",
"server.connect.scan.description": "Suunake oma kaamera koodile QR, mida näitab opencode pair.",
"server.connect.scan.invalid": "See ei ole OpenCode sidumiskood. Skannige koodi, mida näitab opencode pair.",
@@ -783,7 +779,6 @@ export const dict = {
"server.connect.camera.starting": "Kaamera avamine…",
"server.connect.mixedContent":
"Selle HTTP serveriga ei saanud HTTPS lehelt ühendust luua. Kasutage selle asemel HTTPS serveri aadressi.",
"server.connect.camera.insecure": "QR skannimine nõuab selle lehe avamist HTTPS või localhost kaudu.",
"server.connect.camera.unavailable":
"Selle brauseri jaoks pole kaamerat saadaval. Sisestage ühenduse üksikasjad käsitsi.",
"server.connect.camera.error":
-5
View File
@@ -295,9 +295,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "رمز عبور",
"dialog.server.edit.title": "ویرایش سرور",
"dialog.server.menu.edit": "ویرایش کنید",
"dialog.server.menu.default": "به عنوان پیش فرض تنظیم کنید",
"dialog.server.menu.defaultRemove": "حذف پیش فرض",
"dialog.server.status.default": "پیش فرض",
"dialog.project.edit.title": "ویرایش پروژه",
"dialog.project.edit.icon": "نماد",
"dialog.project.edit.icon.alt": "نماد پروژه",
@@ -795,7 +792,6 @@ export const dict = {
"server.connect.button": "اتصال",
"server.connect.address.invalid": "یک نشانی معتبر سرور HTTP یا HTTPS وارد کنید.",
"server.connect.failed": "اتصال ممکن نشد. نشانی سرور و گذرواژه را بررسی کنید و دوباره تلاش کنید.",
"server.connect.pair.description": "برای دریافت جزئیات اتصال، این فرمان را روی رایانهٔ خود اجرا کنید.",
"server.connect.scan": "پویش کد QR",
"server.connect.scan.description": "دوربین را به‌سمت کد QR نمایش‌داده‌شده توسط opencode pair بگیرید.",
"server.connect.scan.invalid": "این کد جفت‌سازی OpenCode نیست. کدی را پویش کنید که opencode pair نشان می‌دهد.",
@@ -803,7 +799,6 @@ export const dict = {
"server.connect.camera.starting": "در حال باز کردن دوربین…",
"server.connect.mixedContent":
"اتصال به این سرور HTTP از صفحهٔ HTTPS ممکن نشد. به‌جای آن از نشانی سرور HTTPS استفاده کنید.",
"server.connect.camera.insecure": "پویش QR نیازمند باز کردن این صفحه از طریق HTTPS یا روی localhost است.",
"server.connect.camera.unavailable": "هیچ دوربینی برای این مرورگر در دسترس نیست. جزئیات اتصال را دستی وارد کنید.",
"server.connect.camera.error":
"باز کردن دوربین ممکن نشد. دسترسی دوربین را مجاز کنید یا جزئیات اتصال را دستی وارد کنید.",
-5
View File
@@ -23,7 +23,6 @@ export const dict = {
"server.connect.address.invalid": "Anna kelvollinen HTTP- tai HTTPS-palvelinosoite.",
"server.connect.failed":
"Yhteyttä ei voitu muodostaa. Tarkista palvelimen osoite ja salasana ja yritä sitten uudelleen.",
"server.connect.pair.description": "Suorita tämä komento tietokoneellasi saadaksesi yhteystiedot.",
"server.connect.scan": "Skannaa QR-koodi",
"server.connect.scan.description": "Suuntaa kamerasi QR-koodiin, joka näkyy opencode pair:ssä.",
"server.connect.scan.invalid": "Tämä ei ole OpenCode-pariliitoskoodi. Skannaa opencode pair:n näyttämä koodi.",
@@ -31,7 +30,6 @@ export const dict = {
"server.connect.camera.starting": "Avataan kameraa…",
"server.connect.mixedContent":
"Yhteyttä tähän HTTP-palvelimeen ei voitu muodostaa HTTPS-sivulta. Käytä sen sijaan HTTPS-palvelinosoitetta.",
"server.connect.camera.insecure": "QR-skannaus vaatii tämän sivun avaamisen HTTPS:n kautta tai localhostissa.",
"server.connect.camera.unavailable": "Kamera ei ole saatavilla tälle selaimelle. Syötä yhteystietosi manuaalisesti.",
"server.connect.camera.error": "Kameraa ei voitu avata. Salli kameran käyttö tai anna yhteystietosi manuaalisesti.",
"dialog.server.menu.remove": "Poista",
@@ -426,9 +424,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "salasana",
"dialog.server.edit.title": "Muokkaa palvelinta",
"dialog.server.menu.edit": "Muokkaa",
"dialog.server.menu.default": "Aseta oletukseksi",
"dialog.server.menu.defaultRemove": "Poista oletuspalvelin",
"dialog.server.status.default": "Oletus",
"dialog.project.edit.title": "Muokkaa projektia",
"dialog.project.edit.icon": "Kuvake",
"dialog.project.edit.icon.alt": "Projektikuvake",
-5
View File
@@ -285,9 +285,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "loyniorð",
"dialog.server.edit.title": "Rætta ambætara",
"dialog.server.menu.edit": "Rætta",
"dialog.server.menu.default": "Set sum forsett",
"dialog.server.menu.defaultRemove": "Strika forsett",
"dialog.server.status.default": "Forsett",
"dialog.project.edit.title": "Rætta verkætlan",
"dialog.project.edit.icon": "Ikon",
"dialog.project.edit.icon.alt": "Verkætlanarmerki",
@@ -779,7 +776,6 @@ export const dict = {
"server.connect.button": "Samband",
"server.connect.address.invalid": "Skriva eina gylduga HTTP ella HTTPS ambætaraadressu.",
"server.connect.failed": "Fekk ikki samband. Kanna ambætaraadressuna og loyniorðið, og royn síðani aftur.",
"server.connect.pair.description": "Koyr hesa skipanina á tínari teldu fyri at fáa tínar sambandsupplýsingar.",
"server.connect.scan": "Skanna QR-kotu",
"server.connect.scan.description": "Peika myndatólið á QR-kotuna, sum opencode pair vísir.",
"server.connect.scan.invalid": "Hetta er ikki ein OpenCode paringarkoda. Skanna kotuna, sum opencode pair vísir.",
@@ -787,7 +783,6 @@ export const dict = {
"server.connect.camera.starting": "Opna myndatól...",
"server.connect.mixedContent":
"Kundi ikki seta samband við hendan HTTP ambætaran frá eini HTTPS síðu. Brúka eina HTTPS ambætaraadressu ístaðin.",
"server.connect.camera.insecure": "QR-skanning krevur, at tú letur hesa síðuna upp yvir HTTPS ella á localhost.",
"server.connect.camera.unavailable":
"Einki myndatól er tøkt til henda kaga. Skriva tínar sambandsupplýsingar manuelt.",
"server.connect.camera.error":
-6
View File
@@ -23,8 +23,6 @@ export const dict = {
"server.connect.address.invalid": "Entrez une adresse de serveur HTTP ou HTTPS valide.",
"server.connect.failed":
"Impossible de se connecter. Vérifiez l'adresse et le mot de passe du serveur, puis réessayez.",
"server.connect.pair.description":
"Exécutez cette commande sur votre ordinateur pour obtenir les détails de votre connexion.",
"server.connect.scan": "Scanner le code QR",
"server.connect.scan.description": "Pointez votre appareil photo vers le code QR affiché par opencode pair.",
"server.connect.scan.invalid":
@@ -33,7 +31,6 @@ export const dict = {
"server.connect.camera.starting": "Ouverture de la caméra…",
"server.connect.mixedContent":
"Impossible de se connecter à ce serveur HTTP à partir d'une page HTTPS. Utilisez plutôt une adresse de serveur HTTPS.",
"server.connect.camera.insecure": "L'analyse QR nécessite l'ouverture de cette page sur HTTPS ou sur localhost.",
"server.connect.camera.unavailable":
"Aucune caméra n'est disponible pour ce navigateur. Saisissez manuellement vos informations de connexion.",
"server.connect.camera.error":
@@ -519,9 +516,6 @@ export const dict = {
"dialog.server.add.password": "Mot de passe (optionnel)",
"dialog.server.edit.title": "Modifier le serveur",
"dialog.server.menu.edit": "Modifier",
"dialog.server.menu.default": "Définir par défaut",
"dialog.server.menu.defaultRemove": "Ne plus utiliser par défaut",
"dialog.server.status.default": "Défaut",
"dialog.project.edit.title": "Modifier le projet",
"dialog.project.edit.icon": "Icône",
"dialog.project.edit.icon.alt": "Icône du projet",
-5
View File
@@ -294,9 +294,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "סיסמה",
"dialog.server.edit.title": "ערוך שרת",
"dialog.server.menu.edit": "ערוך",
"dialog.server.menu.default": "הגדר כברירת מחדל",
"dialog.server.menu.defaultRemove": "הסר את ברירת המחדל",
"dialog.server.status.default": "ברירת מחדל",
"dialog.project.edit.title": "ערוך פרויקט",
"dialog.project.edit.icon": "סמל",
"dialog.project.edit.icon.alt": "סמל פרויקט",
@@ -793,14 +790,12 @@ export const dict = {
"server.connect.button": "התחברות",
"server.connect.address.invalid": "יש להזין כתובת שרת HTTP או HTTPS תקינה.",
"server.connect.failed": "לא ניתן להתחבר. יש לבדוק את כתובת השרת והסיסמה ולנסות שוב.",
"server.connect.pair.description": "יש להריץ פקודה זו במחשב כדי לקבל את פרטי החיבור.",
"server.connect.scan": "סריקת קוד QR",
"server.connect.scan.description": "יש לכוון את המצלמה לקוד QR שמוצג על ידי opencode pair.",
"server.connect.scan.invalid": "זה אינו קוד צימוד של OpenCode. יש לסרוק את הקוד שמוצג על ידי opencode pair.",
"server.connect.camera": "מצלמת צימוד",
"server.connect.camera.starting": "פותח את המצלמה…",
"server.connect.mixedContent": "לא ניתן להתחבר לשרת HTTP זה מדף HTTPS. יש להשתמש בכתובת שרת HTTPS במקום זאת.",
"server.connect.camera.insecure": "סריקת QR דורשת פתיחת דף זה דרך HTTPS או ב-localhost.",
"server.connect.camera.unavailable": "אין מצלמה זמינה לדפדפן זה. יש להזין את פרטי החיבור ידנית.",
"server.connect.camera.error": "לא ניתן לפתוח את המצלמה. יש לאפשר גישה למצלמה או להזין את פרטי החיבור ידנית.",
"dialog.server.menu.remove": "הסרה",
-5
View File
@@ -292,9 +292,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "पासवर्ड",
"dialog.server.edit.title": "सर्वर संपादित करें",
"dialog.server.menu.edit": "संपादित करें",
"dialog.server.menu.default": "डिफाल्ट के रूप में सेट",
"dialog.server.menu.defaultRemove": "डिफ़ॉल्ट हटाएँ",
"dialog.server.status.default": "डिफ़ॉल्ट",
"dialog.project.edit.title": "प्रोजेक्ट संपादित करें",
"dialog.project.edit.icon": "आइकन",
"dialog.project.edit.icon.alt": "प्रोजेक्ट आइकन",
@@ -797,7 +794,6 @@ export const dict = {
"server.connect.button": "जोड़ना",
"server.connect.address.invalid": "एक वैध HTTP या HTTPS सर्वर पता दर्ज करें।",
"server.connect.failed": "कनेक्ट नहीं हो सका। सर्वर पता और पासवर्ड जांचें, फिर पुनः प्रयास करें।",
"server.connect.pair.description": "अपना कनेक्शन विवरण प्राप्त करने के लिए इस कमांड को अपने कंप्यूटर पर चलाएँ।",
"server.connect.scan": "QR कोड स्कैन करें",
"server.connect.scan.description": "अपने कैमरे को ओपनकोड जोड़ी द्वारा दिखाए गए QR कोड पर इंगित करें।",
"server.connect.scan.invalid": "यह कोई OpenCode युग्मन कोड नहीं है. ओपनकोड जोड़ी द्वारा दिखाए गए कोड को स्कैन करें।",
@@ -805,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "कैमरा खुल रहा है...",
"server.connect.mixedContent":
"किसी HTTPS पेज से इस HTTP सर्वर से कनेक्ट नहीं किया जा सका। इसके बजाय HTTPS सर्वर पते का उपयोग करें।",
"server.connect.camera.insecure": "QR स्कैनिंग के लिए इस पृष्ठ को HTTPS या लोकलहोस्ट पर खोलने की आवश्यकता है।",
"server.connect.camera.unavailable":
"इस ब्राउज़र पर कोई कैमरा उपलब्ध नहीं है. अपना कनेक्शन विवरण मैन्युअल रूप से दर्ज करें।",
"server.connect.camera.error":
-6
View File
@@ -298,9 +298,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "lozinka",
"dialog.server.edit.title": "Uredi poslužitelj",
"dialog.server.menu.edit": "Uredi",
"dialog.server.menu.default": "Postavi kao zadano",
"dialog.server.menu.defaultRemove": "Ukloni zadano",
"dialog.server.status.default": "Zadano",
"dialog.project.edit.title": "Uredi projekt",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Ikona projekta",
@@ -805,7 +802,6 @@ export const dict = {
"server.connect.button": "Poveži se",
"server.connect.address.invalid": "Unesite ispravnu HTTP ili HTTPS adresu poslužitelja.",
"server.connect.failed": "Povezivanje nije uspjelo. Provjerite adresu poslužitelja i lozinku, pa pokušajte ponovno.",
"server.connect.pair.description": "Pokrenite ovu naredbu na računalu da biste dobili podatke za povezivanje.",
"server.connect.scan": "Skeniraj QR kod",
"server.connect.scan.description": "Usmjerite kameru prema QR kodu koji prikazuje opencode pair.",
"server.connect.scan.invalid": "Ovo nije OpenCode kod za uparivanje. Skenirajte kod koji prikazuje opencode pair.",
@@ -813,8 +809,6 @@ export const dict = {
"server.connect.camera.starting": "Otvaranje kamere…",
"server.connect.mixedContent":
"Nije se moguće povezati s ovim HTTP poslužiteljem s HTTPS stranice. Umjesto toga koristite HTTPS adresu poslužitelja.",
"server.connect.camera.insecure":
"Za skeniranje QR koda ovu stranicu morate otvoriti putem HTTPS-a ili na localračunalu domaćinu.",
"server.connect.camera.unavailable": "Ovom pregledniku nije dostupna kamera. Ručno unesite podatke za povezivanje.",
"server.connect.camera.error":
"Kameru nije bilo moguće otvoriti. Dozvolite pristup kameri ili ručno unesite podatke za povezivanje.",
-6
View File
@@ -298,9 +298,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "jelszó",
"dialog.server.edit.title": "Szerver szerkesztése",
"dialog.server.menu.edit": "Szerkesztés",
"dialog.server.menu.default": "Beállítás alapértelmezettként",
"dialog.server.menu.defaultRemove": "Alapértelmezés eltávolítása",
"dialog.server.status.default": "Alapértelmezett",
"dialog.project.edit.title": "Projekt szerkesztése",
"dialog.project.edit.icon": "Ikon",
"dialog.project.edit.icon.alt": "Projekt ikonra",
@@ -794,8 +791,6 @@ export const dict = {
"server.connect.button": "Csatlakozás",
"server.connect.address.invalid": "Adjon meg egy érvényes HTTP vagy HTTPS szervercímet.",
"server.connect.failed": "Nem sikerült csatlakozni. Ellenőrizze a szerver címét és jelszavát, majd próbálja újra.",
"server.connect.pair.description":
"Futtassa ezt a parancsot a számítógépén a kapcsolat részleteinek megtekintéséhez.",
"server.connect.scan": "QR-kód beolvasása",
"server.connect.scan.description": "Irányítsa kameráját a opencode pair által mutatott QR kódra.",
"server.connect.scan.invalid": "Ez nem egy OpenCode párosítási kód. Olvassa be a opencode pair által mutatott kódot.",
@@ -803,7 +798,6 @@ export const dict = {
"server.connect.camera.starting": "Kamera nyitása…",
"server.connect.mixedContent":
"Nem sikerült csatlakozni ehhez a HTTP szerverhez egy HTTPS oldalról. Használjon helyette HTTPS szervercímet.",
"server.connect.camera.insecure": "A QR beolvasásához ezt az oldalt a HTTPS vagy a localhost oldalon kell megnyitni.",
"server.connect.camera.unavailable":
"Ehhez a böngészőhöz nem érhető el kamera. Adja meg manuálisan a kapcsolat adatait.",
"server.connect.camera.error":
-5
View File
@@ -287,9 +287,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "գաղտնաբառ",
"dialog.server.edit.title": "Խմբագրել սերվերը",
"dialog.server.menu.edit": "Խմբագրել",
"dialog.server.menu.default": "Սահմանել որպես լռելյայն",
"dialog.server.menu.defaultRemove": "Հեռացնել լռելյայն",
"dialog.server.status.default": "Լռելյայն",
"dialog.project.edit.title": "Խմբագրել նախագիծը",
"dialog.project.edit.icon": "Պատկերակ",
"dialog.project.edit.icon.alt": "Նախագծի պատկերակ",
@@ -795,14 +792,12 @@ export const dict = {
"server.connect.button": "Կապվել",
"server.connect.address.invalid": "Մուտքագրեք վավեր HTTP կամ HTTPS սերվերի հասցե։",
"server.connect.failed": "Չկապվեց. Ստուգեք սերվերի հասցեն և գաղտնաբառը, ապա փորձեք նորից։",
"server.connect.pair.description": "Գործարկեք այս հրամանը ձեր համակարգչում՝ ստանալու ձեր կապի մանրամասները։",
"server.connect.scan": "Սկանավորեք QR կոդը",
"server.connect.scan.description": "Տեսախցիկն ուղղեք opencode pair-ի ցուցադրած QR կոդին։",
"server.connect.scan.invalid": "Սա OpenCode-ի զուգակցման կոդ չէ։ Սկանավորեք opencode pair-ի ցուցադրած կոդը։",
"server.connect.camera": "Զույգագրման վահանակը",
"server.connect.camera.starting": "Բացվում է վահանակը…",
"server.connect.mixedContent": "Այս HTTP սերվերին հնարավոր չէ միանալ HTTPS էջից։ Օգտագործեք HTTPS սերվերի հասցե։",
"server.connect.camera.insecure": "QR սկանումը պահանջում է այս էջը բացել HTTPS-ով կամ տեղական հոստում։",
"server.connect.camera.unavailable": "Այս զննարկչին վահանակ հասանելի չէ։ Մուտքագրեք ձեր կապի մանրամասները ձեռքով։",
"server.connect.camera.error":
"Չկարողացա բացել տեսախցիկը։ Թույլատրել տեսախցիկի մուտքը կամ ձեռքով ներմուծել ձեր կապի տվյալները։",
-5
View File
@@ -323,9 +323,6 @@ export const dict = {
"dialog.server.edit.title": "Sunting server",
"dialog.server.menu.edit": "Sunting",
"dialog.server.menu.default": "Tetapkan sebagai bawaan",
"dialog.server.menu.defaultRemove": "Hapus bawaan",
"dialog.server.status.default": "Bawaan",
"dialog.project.edit.title": "Sunting proyek",
"dialog.project.edit.icon": "Ikon",
@@ -862,7 +859,6 @@ export const dict = {
"server.connect.button": "Sambungkan",
"server.connect.address.invalid": "Masukkan alamat server HTTP atau HTTPS yang valid.",
"server.connect.failed": "Tidak dapat terhubung. Periksa alamat server dan kata sandi, lalu coba lagi.",
"server.connect.pair.description": "Jalankan perintah ini di komputer Anda untuk mendapatkan detail koneksi Anda.",
"server.connect.scan": "Pindai kode QR",
"server.connect.scan.description": "Arahkan kamera Anda ke kode QR yang ditampilkan oleh opencode pair.",
"server.connect.scan.invalid": "Ini bukan kode pemasangan OpenCode. Pindai kode yang ditampilkan oleh opencode pair.",
@@ -870,7 +866,6 @@ export const dict = {
"server.connect.camera.starting": "Membuka kamera…",
"server.connect.mixedContent":
"Tidak dapat terhubung ke server HTTP ini dari halaman HTTPS. Gunakan alamat server HTTPS sebagai gantinya.",
"server.connect.camera.insecure": "Pemindaian QR memerlukan halaman ini dibuka melalui HTTPS atau di localhost.",
"server.connect.camera.unavailable":
"Tidak ada kamera yang tersedia untuk peramban ini. Masukkan detail koneksi Anda secara manual.",
"server.connect.camera.error":
-5
View File
@@ -298,9 +298,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "lykilorð",
"dialog.server.edit.title": "Breyta miðlara",
"dialog.server.menu.edit": "Breyta",
"dialog.server.menu.default": "Stillt sem sjálfgefið",
"dialog.server.menu.defaultRemove": "Fjarlægja sjálfgefið",
"dialog.server.status.default": "Sjálfgefið",
"dialog.project.edit.title": "Breyta verkefni",
"dialog.project.edit.icon": "Táknmynd",
"dialog.project.edit.icon.alt": "Verkefnistákn",
@@ -782,7 +779,6 @@ export const dict = {
"server.connect.button": "Tengdu",
"server.connect.address.invalid": "Sláðu inn gilt HTTP eða HTTPS netfang netþjóns.",
"server.connect.failed": "Ekki tókst að tengjast. Athugaðu netfang netþjóns og lykilorð, reyndu svo aftur.",
"server.connect.pair.description": "Keyrðu þessa skipun á tölvunni þinni til að fá upplýsingar um tenginguna þína.",
"server.connect.scan": "Skanna QR kóða",
"server.connect.scan.description": "Beindu myndavélinni þinni að QR kóðanum sem opencode pair sýnir.",
"server.connect.scan.invalid": "Þetta er ekki OpenCode pörunarkóði. Skannaðu kóðann sem opencode pair sýnir.",
@@ -790,7 +786,6 @@ export const dict = {
"server.connect.camera.starting": "Opnar myndavél...",
"server.connect.mixedContent":
"Gat ekki tengst þessum HTTP netþjóni frá HTTPS síðu. Notaðu HTTPS netþjónsfang í staðinn.",
"server.connect.camera.insecure": "QR skönnun krefst þess að opna þessa síðu yfir HTTPS eða á localhost.",
"server.connect.camera.unavailable":
"Engin myndavél er í boði fyrir þennan vafra. Sláðu inn tengiupplýsingar þínar handvirkt.",
"server.connect.camera.error":
-6
View File
@@ -22,8 +22,6 @@ export const dict = {
"server.connect.button": "Connettiti",
"server.connect.address.invalid": "Inserisci un indirizzo server HTTP o HTTPS valido.",
"server.connect.failed": "Impossibile connettersi. Controlla l'indirizzo del server e la password, quindi riprova.",
"server.connect.pair.description":
"Esegui questo comando sul tuo computer per ottenere i dettagli della connessione.",
"server.connect.scan": "Scansiona il codice QR",
"server.connect.scan.description": "Punta la fotocamera sul codice QR mostrato da opencode pair.",
"server.connect.scan.invalid":
@@ -32,7 +30,6 @@ export const dict = {
"server.connect.camera.starting": "Apertura della fotocamera…",
"server.connect.mixedContent":
"Impossibile connettersi a questo server HTTP da una pagina HTTPS. Utilizza invece un indirizzo server HTTPS.",
"server.connect.camera.insecure": "La scansione QR richiede l'apertura di questa pagina su HTTPS o su localhost.",
"server.connect.camera.unavailable":
"Nessuna fotocamera è disponibile per questo browser. Inserisci manualmente i dettagli della tua connessione.",
"server.connect.camera.error":
@@ -449,9 +446,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "password",
"dialog.server.edit.title": "Modifica server",
"dialog.server.menu.edit": "Modifica",
"dialog.server.menu.default": "Imposta come predefinito",
"dialog.server.menu.defaultRemove": "Rimuovi predefinito",
"dialog.server.status.default": "Predefinito",
"dialog.project.edit.title": "Modifica progetto",
"dialog.project.edit.icon": "Icona",
"dialog.project.edit.icon.alt": "Icona del progetto",
-5
View File
@@ -296,9 +296,6 @@ export const dict = {
"dialog.server.add.password": "パスワード (オプション)",
"dialog.server.edit.title": "サーバーを編集",
"dialog.server.menu.edit": "編集",
"dialog.server.menu.default": "デフォルトに設定",
"dialog.server.menu.defaultRemove": "デフォルト設定を解除",
"dialog.server.status.default": "デフォルト",
"dialog.project.edit.title": "プロジェクトを編集",
"dialog.project.edit.icon": "アイコン",
@@ -808,7 +805,6 @@ export const dict = {
"server.connect.button": "接続",
"server.connect.address.invalid": "有効なHTTPまたはHTTPSサーバーアドレスを入力してください。",
"server.connect.failed": "接続できませんでした。サーバーアドレスとパスワードを確認して、もう一度お試しください。",
"server.connect.pair.description": "このコマンドをコンピューターで実行して接続情報を取得してください。",
"server.connect.scan": "QRコードをスキャン",
"server.connect.scan.description": "opencode pair に表示されたQRコードにカメラを向けてください。",
"server.connect.scan.invalid":
@@ -817,7 +813,6 @@ export const dict = {
"server.connect.camera.starting": "カメラを開いています…",
"server.connect.mixedContent":
"HTTPSページからこのHTTPサーバーに接続できません。代わりにHTTPSサーバーのアドレスを使用してください。",
"server.connect.camera.insecure": "QRスキャンには、このページをHTTPSで開くか、ローカルホストで開く必要があります。",
"server.connect.camera.unavailable": "このブラウザで使用可能なカメラがありません。接続情報を手動で入力してください。",
"server.connect.camera.error":
"カメラを開くことができません。カメラへのアクセスを許可するか、接続情報を手動で入力してください。",
-5
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "პაროლი",
"dialog.server.edit.title": "სერვერის რედაქტირება",
"dialog.server.menu.edit": "რედაქტირება",
"dialog.server.menu.default": "დაყენება ნაგულისხმევად",
"dialog.server.menu.defaultRemove": "ნაგულისხმევის ამოღება",
"dialog.server.status.default": "ნაგულისხმევი",
"dialog.project.edit.title": "პროექტის რედაქტირება",
"dialog.project.edit.icon": "ხატულა",
"dialog.project.edit.icon.alt": "პროექტის ხატულა",
@@ -791,7 +788,6 @@ export const dict = {
"server.connect.button": "დაკავშირება",
"server.connect.address.invalid": "შეიყვანეთ ვალიდური HTTP ან HTTPS სერვერის მისამართი.",
"server.connect.failed": "ვერ მოხერხდა დაკავშირება. შეამოწმეთ სერვერის მისამართი და პაროლი, შემდეგ კვლავ სცადეთ.",
"server.connect.pair.description": "ჩაატარეთ ეს ბრძანება თქვენს კომპიუტერზე, რათა მიიღოთ თქვენი კავშირის დეტალები.",
"server.connect.scan": "სკანირება QR კოდით",
"server.connect.scan.description": "მიმართეთ კამერა opencode pair-ის მიერ ნაჩვენებ QR კოდზე.",
"server.connect.scan.invalid":
@@ -800,7 +796,6 @@ export const dict = {
"server.connect.camera.starting": "კამერის გახსნა…",
"server.connect.mixedContent":
"ვერ მოხერხდა დაკავშირება ამ HTTP სერვერთან HTTPS გვერდიდან. გამოიყენეთ HTTPS სერვერის მისამართი.",
"server.connect.camera.insecure": "QR სკანირება საჭიროებს ამ გვერდის გახსნა HTTPS-ზე ან localhost-ზე.",
"server.connect.camera.unavailable":
"ამ ბრაუზერისთვის კამერა არ არის ხელმისაწვდომი. შეიყვანეთ თქვენი კავშირის დეტალები ხელით.",
"server.connect.camera.error":
-5
View File
@@ -293,9 +293,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "ពាក្យសម្ងាត់",
"dialog.server.edit.title": "កែសម្រួលម៉ាស៊ីនមេ",
"dialog.server.menu.edit": "កែសម្រួល",
"dialog.server.menu.default": "កំណត់ជាលំនាំដើម",
"dialog.server.menu.defaultRemove": "លុបលំនាំដើមចេញ",
"dialog.server.status.default": "លំនាំដើម",
"dialog.project.edit.title": "កែសម្រួលគម្រោង",
"dialog.project.edit.icon": "រូបតំណាង",
"dialog.project.edit.icon.alt": "រូបតំណាងគម្រោង",
@@ -791,7 +788,6 @@ export const dict = {
"server.connect.button": "ភ្ជាប់",
"server.connect.address.invalid": "បញ្ចូលអាសយដ្ឋានម៉ាស៊ីនមេ HTTP ឬ HTTPS ត្រឹមត្រូវ។",
"server.connect.failed": "មិនអាចភ្ជាប់បានទេ។ សូមពិនិត្យអាសយដ្ឋានម៉ាស៊ីនមេ និងពាក្យសម្ងាត់ រួចព្យាយាមម្តងទៀត។",
"server.connect.pair.description": "បើកកម្មង់នេះនៅលើកុំព្យូទ័ររបស់អ្នកដើម្បីទទួលព័ត៌មានការភ្ជាប់របស់អ្នក។",
"server.connect.scan": "ស្កេនកូដ QR",
"server.connect.scan.description": "បង្ខំកាមេរ៉ារបស់អ្នកទៅកូដ QR ដែលបង្ហាញដោយ opencode pair។",
"server.connect.scan.invalid": "នេះមិនមែនជាកូដផ្គុំ OpenCode ទេ។ ស្កេនកូដដែលបង្ហាញដោយ opencode pair។",
@@ -799,7 +795,6 @@ export const dict = {
"server.connect.camera.starting": "កំពុងបើកកាមេរ៉ា…",
"server.connect.mixedContent":
"មិនអាចភ្ជាប់ទៅម៉ាស៊ីនបម្រើ HTTP នេះពីទំព័រ HTTPS។ សូមប្រើអាសយដ្ឋានម៉ាស៊ីនបម្រើ HTTPS ជំនួស។",
"server.connect.camera.insecure": "ការស្កេន QR ត្រូវការបើកទំព័រនេះតាម HTTPS ឬនៅលើ localhost។",
"server.connect.camera.unavailable":
"មិនមានកាមេរ៉ាដើម្បីប្រើប្រាស់ជាមួយកម្មវិធីនេះទេ។ សូមបញ្ចូលព័ត៌មានការភ្ជាប់ដោយដៃ។",
"server.connect.camera.error": "មិនអាចបើកកាមេរ៉ាបាន។ អនុញ្ញាតឱ្យចូលដំណើរការកាមេរ៉ា ឬបញ្ចូលព័ត៌មានការភ្ជាប់ដោយដៃ។",
-5
View File
@@ -218,9 +218,6 @@ export const dict = {
"dialog.server.add.password": "비밀번호 (선택 사항)",
"dialog.server.edit.title": "서버 편집",
"dialog.server.menu.edit": "편집",
"dialog.server.menu.default": "기본값으로 설정",
"dialog.server.menu.defaultRemove": "기본값 제거",
"dialog.server.status.default": "기본값",
"dialog.project.edit.title": "프로젝트 편집",
"dialog.project.edit.icon": "아이콘",
"dialog.project.edit.icon.alt": "프로젝트 아이콘",
@@ -803,7 +800,6 @@ export const dict = {
"server.connect.button": "연결",
"server.connect.address.invalid": "유효한 HTTP 또는 HTTPS 서버 주소를 입력하세요.",
"server.connect.failed": "연결할 수 없습니다. 서버 주소와 비밀번호를 확인한 후 다시 시도하세요.",
"server.connect.pair.description": "컴퓨터에서 이 명령어를 실행하여 연결 세부 정보를 확인하세요.",
"server.connect.scan": "QR 코드 스캔",
"server.connect.scan.description": "opencode pair에서 표시된 QR 코드를 카메라로 가리키세요.",
"server.connect.scan.invalid":
@@ -812,7 +808,6 @@ export const dict = {
"server.connect.camera.starting": "카메라 열기…",
"server.connect.mixedContent":
"HTTPS 페이지에서 이 HTTP 서버에 연결할 수 없습니다. 대신 HTTPS 서버 주소를 사용하세요.",
"server.connect.camera.insecure": "QR 스캔을 위해서는 HTTPS를 통해 이 페이지를 열거나 로컬호스트에서 열어야 합니다.",
"server.connect.camera.unavailable":
"이 브라우저에서 사용할 수 있는 카메라가 없습니다. 연결 세부 정보를 수동으로 입력하세요.",
"server.connect.camera.error":
-5
View File
@@ -293,9 +293,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "ລະຫັດຜ່ານ",
"dialog.server.edit.title": "ແກ້ໄຂເຊີບເວີ",
"dialog.server.menu.edit": "ແກ້ໄຂ",
"dialog.server.menu.default": "ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ",
"dialog.server.menu.defaultRemove": "ເອົາຄ່າເລີ່ມຕົ້ນ",
"dialog.server.status.default": "ຄ່າເລີ່ມຕົ້ນ",
"dialog.project.edit.title": "ແກ້ໄຂໂຄງການ",
"dialog.project.edit.icon": "ໄອຄອນ",
"dialog.project.edit.icon.alt": "ໄອຄອນໂຄງການ",
@@ -790,14 +787,12 @@ export const dict = {
"server.connect.button": "ເຊື່ອມຕໍ່",
"server.connect.address.invalid": "ໃສ່ທີ່ຢູ່ເຊີບເວີ HTTP ຫຼື HTTPS ທີ່ຖືກຕ້ອງ.",
"server.connect.failed": "ບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້.ກວດເບິ່ງທີ່ຢູ່ເຊີບເວີແລະລະຫັດຜ່ານ, ແລ້ວລອງອີກຄັ້ງ.",
"server.connect.pair.description": "ເຮັດຄໍາສັ່ງນີ້ໃນຄອມພິວເຕີຂອງທ່ານເພື່ອຮັບລາຍລະອຽດການເຊື່ອມຕໍ່.",
"server.connect.scan": "ສະແກນ QR code",
"server.connect.scan.description": "ຊີ້ກ້ອງຂອງທ່ານໄປທີ່ QR code ທີ່ສະແດງໂດຍຄູ່ opencode.",
"server.connect.scan.invalid": "ນີ້ບໍ່ແມ່ນລະຫັດການຈັດຄູ່ OpenCode.ສະແກນລະຫັດທີ່ສະແດງໂດຍຄູ່ OpenCode.",
"server.connect.camera": "ການຈັບຄູ່ກ້ອງ",
"server.connect.camera.starting": "ກໍາລັງເປີດກ້ອງ...",
"server.connect.mixedContent": "ບໍ່ສາມາດເຊື່ອມຕໍ່ກັບເຊີບເວີ HTTP ນີ້ຈາກຫນ້າ HTTPS ໄດ້.ໃຊ້ທີ່ຢູ່ເຊີບເວີ HTTPS ແທນ.",
"server.connect.camera.insecure": "ການສະແກນ QR ຈໍາເປັນຕ້ອງເປີດຫນ້ານີ້ຜ່ານ HTTPS ຫຼືໃນ localhost.",
"server.connect.camera.unavailable": "ບໍ່ມີກ້ອງຖ່າຍຮູບໃຫ້ໃຊ້ໃນເບຣາວເຊີນີ້.ໃສ່ລາຍລະອຽດການເຊື່ອມຕໍ່ຂອງທ່ານເອງ.",
"server.connect.camera.error": "ບໍ່ສາມາດເປີດກ້ອງໄດ້.ອະນຸຍາດໃຫ້ເຂົ້າເຖິງກ້ອງ ຫຼື ປ້ອນລາຍລະອຽດການເຊື່ອມຕໍ່ຂອງທ່ານເອງ.",
"dialog.server.menu.remove": "ລຶບ",
-6
View File
@@ -299,9 +299,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "slaptažodis",
"dialog.server.edit.title": "Redaguoti serverį",
"dialog.server.menu.edit": "Redaguoti",
"dialog.server.menu.default": "Nustatyti kaip numatytąjį",
"dialog.server.menu.defaultRemove": "Pašalinti numatytąjį",
"dialog.server.status.default": "Numatytoji",
"dialog.project.edit.title": "Redaguoti projektą",
"dialog.project.edit.icon": "Piktograma",
"dialog.project.edit.icon.alt": "Projekto piktograma",
@@ -805,8 +802,6 @@ export const dict = {
"server.connect.address.invalid": "Įveskite galiojantį HTTP arba HTTPS serverio adresą.",
"server.connect.failed":
"Nepavyko prisijungti. Patikrinkite serverio adresą ir slaptažodį, tada bandykite dar kartą.",
"server.connect.pair.description":
"Paleiskite šią komandą savo kompiuteryje, kad gautumėte išsamią ryšio informaciją.",
"server.connect.scan": "Nuskaitykite QR kodą",
"server.connect.scan.description": "Nukreipkite fotoaparatą į QR kodą, rodomą opencode pair.",
"server.connect.scan.invalid": "Tai nėra OpenCode susiejimo kodas. Nuskaitykite kodą, kurį rodo opencode pair.",
@@ -814,7 +809,6 @@ export const dict = {
"server.connect.camera.starting": "Atidaroma kamera…",
"server.connect.mixedContent":
"Nepavyko prisijungti prie šio HTTP serverio iš HTTPS puslapio. Vietoj to naudokite HTTPS serverio adresą.",
"server.connect.camera.insecure": "Norint nuskaityti QR, reikia atidaryti šį puslapį per HTTPS arba localhost.",
"server.connect.camera.unavailable": "Šioje naršyklėje nėra fotoaparato. Įveskite savo ryšio duomenis rankiniu būdu.",
"server.connect.camera.error":
"Nepavyko atidaryti fotoaparato. Suteikite prieigą prie fotoaparato arba įveskite savo ryšio duomenis rankiniu būdu.",
-5
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "parole",
"dialog.server.edit.title": "Rediģēt serveri",
"dialog.server.menu.edit": "Rediģēt",
"dialog.server.menu.default": "Iestatīt kā noklusējumu",
"dialog.server.menu.defaultRemove": "Noņemt noklusējumu",
"dialog.server.status.default": "Noklusējuma",
"dialog.project.edit.title": "Rediģēt projektu",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Projekta ikona",
@@ -792,7 +789,6 @@ export const dict = {
"server.connect.address.invalid": "Ievadiet derīgu HTTP vai HTTPS servera adresi.",
"server.connect.failed":
"Nevarēja izveidot savienojumu. Pārbaudiet servera adresi un paroli, pēc tam mēģiniet vēlreiz.",
"server.connect.pair.description": "Palaidiet šo komandu datorā, lai iegūtu informāciju par savienojumu.",
"server.connect.scan": "Skenējiet QR kodu",
"server.connect.scan.description": "Pavērsiet kameru pret QR kodu, ko parāda opencode pair.",
"server.connect.scan.invalid": "Šis nav kods OpenCode savienošanai pārī. Skenējiet kodu, ko parāda opencode pair.",
@@ -800,7 +796,6 @@ export const dict = {
"server.connect.camera.starting": "Tiek atvērta kamera…",
"server.connect.mixedContent":
"Nevarēja izveidot savienojumu ar šo HTTP serveri no HTTPS lapas. Tā vietā izmantojiet HTTPS servera adresi.",
"server.connect.camera.insecure": "Lai skenētu QR, šī lapa ir jāatver, izmantojot HTTPS vai localhost.",
"server.connect.camera.unavailable":
"Šai pārlūkprogrammai nav pieejama neviena kamera. Manuāli ievadiet savienojuma informāciju.",
"server.connect.camera.error":
-6
View File
@@ -287,9 +287,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "лозинка",
"dialog.server.edit.title": "Уреди сервер",
"dialog.server.menu.edit": "Уреди",
"dialog.server.menu.default": "Поставете како стандардно",
"dialog.server.menu.defaultRemove": "Отстрани стандардно",
"dialog.server.status.default": "Стандардно",
"dialog.project.edit.title": "Уреди проект",
"dialog.project.edit.icon": "Икона",
"dialog.project.edit.icon.alt": "Икона на проектот",
@@ -795,8 +792,6 @@ export const dict = {
"server.connect.address.invalid": "Внесете валидна HTTP или HTTPS адреса на серверот.",
"server.connect.failed":
"Не можеше да се поврзе. Проверете ја адресата на серверот и лозинката, потоа обидете се повторно.",
"server.connect.pair.description":
"Извршете ја оваа команда на вашиот компјутер за да ги добиете деталите за вашата конекција.",
"server.connect.scan": "Скенирај QR код",
"server.connect.scan.description": "Насочете ја вашата камера кон QR кодот прикажан од opencode pair.",
"server.connect.scan.invalid": "Ова не е OpenCode паринг код. Скенирајте го кодот прикажан од opencode pair.",
@@ -804,7 +799,6 @@ export const dict = {
"server.connect.camera.starting": "Отворање на камерата…",
"server.connect.mixedContent":
"Не можевте да се поврзете на овој HTTP сервер од HTTPS страница. Користете HTTPS сервер адреса наместо тоа.",
"server.connect.camera.insecure": "Скенирањето на QR бара отворање на оваа страница преку HTTPS или на localhost.",
"server.connect.camera.unavailable":
"Нема камера достапна за овој прелистувач. Внесете ги деталите за вашата конекција рачно.",
"server.connect.camera.error":
-6
View File
@@ -287,9 +287,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "нууц үг",
"dialog.server.edit.title": "Сервер засах",
"dialog.server.menu.edit": "Засварлах",
"dialog.server.menu.default": "Өгөгдмөл болгож тохируулах",
"dialog.server.menu.defaultRemove": "Өгөгдмөлийг арилгах",
"dialog.server.status.default": "Өгөгдмөл",
"dialog.project.edit.title": "Төслийг засварлах",
"dialog.project.edit.icon": "Дүрс",
"dialog.project.edit.icon.alt": "Төслийн дүрс тэмдэг",
@@ -797,8 +794,6 @@ export const dict = {
"server.connect.button": "Холбох",
"server.connect.address.invalid": "Хүчинтэй HTTP эсвэл HTTPS серверийн хаягийг оруулна уу.",
"server.connect.failed": "Холбогдож чадсангүй. Серверийн хаяг ба нууц үгийг шалгаад дахин оролдоно уу.",
"server.connect.pair.description":
"Энэ командыг өөрийн компьютер дээр ажиллуулж, холболтын дэлгэрэнгүй мэдээллийг аваарай.",
"server.connect.scan": "QR кодыг сканнердах",
"server.connect.scan.description": "Камераа opencode pair-ийн харуулсан QR код руу чиглүүлнэ үү.",
"server.connect.scan.invalid": "Энэ OpenCode холболтын код биш. opencode pair-ийн харуулсан кодыг уншуулна уу.",
@@ -806,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "Камер нээж байна…",
"server.connect.mixedContent":
"HTTPS хуудсаас энэ HTTP серверт холбогдож чадсангүй. Үүний оронд HTTPS серверийн хаягийг ашигла.",
"server.connect.camera.insecure": "QR сканнердах нь энэ хуудасыг HTTPS дээр эсвэл localhost дээр нээх шаардлагатай.",
"server.connect.camera.unavailable": "Энэ хөтчид камер байхгүй байна. Холболтын мэдээллээ гар аргаар оруулна уу.",
"server.connect.camera.error":
"Камерыг нээж чадсангүй. Камер ашиглахыг зөвшөөрөх эсвэл холболтын дэлгэрэнгүй мэдээллээ гараар оруулна уу.",
-5
View File
@@ -295,9 +295,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "kata laluan",
"dialog.server.edit.title": "Edit pelayan",
"dialog.server.menu.edit": "Sunting",
"dialog.server.menu.default": "Tetapkan sebagai lalai",
"dialog.server.menu.defaultRemove": "Buang lalai",
"dialog.server.status.default": "Lalai",
"dialog.project.edit.title": "Edit projek",
"dialog.project.edit.icon": "Ikon",
"dialog.project.edit.icon.alt": "Ikon projek",
@@ -795,7 +792,6 @@ export const dict = {
"server.connect.button": "Sambung",
"server.connect.address.invalid": "Masukkan alamat pelayan HTTP atau HTTPS yang sah.",
"server.connect.failed": "Tidak dapat menyambung. Semak alamat pelayan dan kata laluan, kemudian cuba lagi.",
"server.connect.pair.description": "Jalankan arahan ini pada komputer anda untuk mendapatkan butiran sambungan anda.",
"server.connect.scan": "Imbas kod QR",
"server.connect.scan.description": "Tujukan kamera anda ke kod QR yang dipaparkan oleh pasangan opencode.",
"server.connect.scan.invalid": "Ini bukan kod pasangan OpenCode. Imbas kod yang ditunjukkan oleh pasangan opencode.",
@@ -803,7 +799,6 @@ export const dict = {
"server.connect.camera.starting": "Membuka kamera…",
"server.connect.mixedContent":
"Tidak dapat sambung ke pelayan HTTP ini dari halaman HTTPS. Gunakan alamat pelayan HTTPS sebaliknya.",
"server.connect.camera.insecure": "Imbasan QR memerlukan pembukaan halaman ini melalui HTTPS atau di localhost.",
"server.connect.camera.unavailable":
"Tiada kamera tersedia untuk pelayar ini. Masukkan butiran sambungan anda secara manual.",
"server.connect.camera.error":
-6
View File
@@ -296,9 +296,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "စကားဝှက်",
"dialog.server.edit.title": "ဆာဗာကို တည်းဖြတ်ပါ။",
"dialog.server.menu.edit": "တည်းဖြတ်ရန်",
"dialog.server.menu.default": "မူရင်းအဖြစ် သတ်မှတ်ပါ။",
"dialog.server.menu.defaultRemove": "မူရင်းကို ဖယ်ရှားပါ။",
"dialog.server.status.default": "မူရင်း",
"dialog.project.edit.title": "ပရောဂျက်ကို တည်းဖြတ်ပါ။",
"dialog.project.edit.icon": "သင်္ကေတ",
"dialog.project.edit.icon.alt": "ပရောဂျက် သင်္ကေတ",
@@ -808,7 +805,6 @@ export const dict = {
"server.connect.button": "ချိတ်ဆက်မည်",
"server.connect.address.invalid": "မှန်ကန်သော HTTP သို့မဟုတ် HTTPS server လိပ်စာကို ထည့်ပါ။",
"server.connect.failed": "ချိတ်ဆက်၍ မရပါ။ Server လိပ်စာနှင့် စကားဝှက်ကို စစ်ဆေးပြီး ပြန်ကြိုးစားပါ။",
"server.connect.pair.description": "ချိတ်ဆက်ရန်အသေးစိတ်ကို ရယူရန် သင့်ကွန်ပျူတာတွင် ဤ command ကို chạy ဆောင်ရန်။",
"server.connect.scan": "QR ကုဒ် စကင်",
"server.connect.scan.description": "opencode pair မှ ပြသထားသော QR ကုဒ်ကို သင်၏ ကင်မရာဖြင့် ညွှန်ပါ။",
"server.connect.scan.invalid":
@@ -816,8 +812,6 @@ export const dict = {
"server.connect.camera": "ကင်မရာကို အစုံပေါင်းခြင်း",
"server.connect.camera.starting": "ကင်မရာဖွင့်နေသည်…",
"server.connect.mixedContent": "HTTPS စာမျက်နှာမှ ဤ HTTP ဆာဗာထံ ချိတ်ဆက်၍ မရနိုင်ပါ။ HTTPS ဆာဗာလိပ်စာကို အသုံးပြုပါ။",
"server.connect.camera.insecure":
"QR စကင်လုပ်ရန် HTTPS ဖြင့် သို့မဟုတ် localhost တွင် ဤစာမျက်နှာကို ဖွင့်ရန် လိုအပ်သည်။",
"server.connect.camera.unavailable": "ဤဘရောက်ဇာတွင် ကင်မရာမရှိပါ။ ချိတ်ဆက်မှုအချက်အလက်များကို လက်ဖြင့်ထည့်ပါ။",
"server.connect.camera.error":
"ကင်မရာဖွင့်၍ မရနိုင်ပါ။ ကင်မရာခွင့်ပြုချက်ပေးပါ သို့မဟုတ် ချိတ်ဆက်မှုအချက်အလက်များကို လက်ဖြင့်ထည့်ပါ။",
-5
View File
@@ -291,9 +291,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "पासवर्ड",
"dialog.server.edit.title": "सर्भर सम्पादन गर्नुहोस्",
"dialog.server.menu.edit": "सम्पादन गर्नुहोस्",
"dialog.server.menu.default": "पूर्वनिर्धारित रूपमा सेट गर्नुहोस्",
"dialog.server.menu.defaultRemove": "पूर्वनिर्धारित हटाउनुहोस्",
"dialog.server.status.default": "पूर्वनिर्धारित",
"dialog.project.edit.title": "परियोजना सम्पादन गर्नुहोस्",
"dialog.project.edit.icon": "आइकन",
"dialog.project.edit.icon.alt": "परियोजना आइकन",
@@ -797,7 +794,6 @@ export const dict = {
"server.connect.button": "जडान गर्नुहोस्",
"server.connect.address.invalid": "मान्य HTTP वा HTTPS सर्भर ठेगाना प्रविष्ट गर्नुहोस्।",
"server.connect.failed": "जडान हुन सकेन। सर्भर ठेगाना र पासवर्ड जाँच गर्नुहोस्, त्यसपछि फेरि प्रयास गर्नुहोस्।",
"server.connect.pair.description": "तपाइँको जडान विवरण प्राप्त गर्न तपाइँको कम्प्युटरमा यो आदेश चलाउनुहोस्।",
"server.connect.scan": "QR कोड स्क्यान गर्नुहोस्",
"server.connect.scan.description": "ओपनकोड जोडीद्वारा देखाइएको QR कोडमा आफ्नो क्यामेरा देखाउनुहोस्।",
"server.connect.scan.invalid": "यो एक OpenCode जोडा कोड होइन। ओपनकोड जोडी द्वारा देखाइएको कोड स्क्यान गर्नुहोस्।",
@@ -805,7 +801,6 @@ export const dict = {
"server.connect.camera.starting": "क्यामेरा खोल्दै…",
"server.connect.mixedContent":
"HTTPS पृष्ठबाट यो HTTP सर्भरमा जडान गर्न सकिएन। यसको सट्टा HTTPS सर्भर ठेगाना प्रयोग गर्नुहोस्।",
"server.connect.camera.insecure": "QR स्क्यानिङका लागि यो पृष्ठ HTTPS वा लोकलहोस्टमा खोल्न आवश्यक छ।",
"server.connect.camera.unavailable":
"यो ब्राउजरमा कुनै क्यामेरा उपलब्ध छैन। आफ्नो जडान विवरणहरू म्यानुअल रूपमा प्रविष्ट गर्नुहोस्।",
"server.connect.camera.error":
-6
View File
@@ -23,7 +23,6 @@ export const dict = {
"server.connect.address.invalid": "Voer een geldig HTTP- of HTTPS-serveradres in.",
"server.connect.failed":
"Kan geen verbinding maken. Controleer het serveradres en het wachtwoord en probeer het opnieuw.",
"server.connect.pair.description": "Voer deze opdracht uit op uw computer om uw verbindingsgegevens op te halen.",
"server.connect.scan": "Scan de QR-code",
"server.connect.scan.description": "Richt uw camera op de QR-code weergegeven door opencode pair.",
"server.connect.scan.invalid": "Dit is geen OpenCode-koppelingscode. Scan de code weergegeven door opencode pair.",
@@ -31,8 +30,6 @@ export const dict = {
"server.connect.camera.starting": "Camera openen…",
"server.connect.mixedContent":
"Kan geen verbinding maken met deze HTTP-server vanaf een HTTPS-pagina. Gebruik in plaats daarvan een HTTPS-serveradres.",
"server.connect.camera.insecure":
"Voor het scannen van QR moet deze pagina worden geopend via HTTPS of op localhost.",
"server.connect.camera.unavailable":
"Er is geen camera beschikbaar voor deze browser. Voer uw verbindingsgegevens handmatig in.",
"server.connect.camera.error":
@@ -501,9 +498,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "wachtwoord",
"dialog.server.edit.title": "Server bewerken",
"dialog.server.menu.edit": "Bewerken",
"dialog.server.menu.default": "Als standaard instellen",
"dialog.server.menu.defaultRemove": "Standaard verwijderen",
"dialog.server.status.default": "Standaard",
"dialog.project.edit.title": "Project bewerken",
"dialog.project.edit.icon": "Pictogram",
"dialog.project.edit.icon.alt": "Projectpictogram",
-5
View File
@@ -26,7 +26,6 @@ export const dict = {
"server.connect.button": "Koble til",
"server.connect.address.invalid": "Skriv inn en gyldig HTTP- eller HTTPS-serveradresse.",
"server.connect.failed": "Kunne ikke koble til. Sjekk serveradressen og passordet, og prøv på nytt.",
"server.connect.pair.description": "Kjør denne kommandoen på datamaskinen for å få tilkoblingsdetaljer.",
"server.connect.scan": "Skann QR-koden",
"server.connect.scan.description": "Pek kameraet mot QR-koden vist av opencode pair.",
"server.connect.scan.invalid": "Dette er ikke en OpenCode-paringskode. Skann koden vist av opencode pair.",
@@ -34,7 +33,6 @@ export const dict = {
"server.connect.camera.starting": "Åpner kamera …",
"server.connect.mixedContent":
"Kunne ikke koble til denne HTTP-serveren fra en HTTPS-side. Bruk en HTTPS-serveradresse i stedet.",
"server.connect.camera.insecure": "QR-skanning krever at denne siden åpnes over HTTPS eller på localhost.",
"server.connect.camera.unavailable":
"Ingen kamera er tilgjengelig for denne nettleseren. Skriv inn tilkoblingsdetaljene manuelt.",
"server.connect.camera.error": "Kunne ikke åpne kameraet. Gi kameratilgang eller angi tilkoblingsdetaljene manuelt.",
@@ -509,9 +507,6 @@ export const dict = {
"dialog.server.edit.title": "Rediger server",
"dialog.server.menu.edit": "Rediger",
"dialog.server.menu.default": "Sett som standard",
"dialog.server.menu.defaultRemove": "Fjern standard",
"dialog.server.status.default": "Standard",
"dialog.project.edit.title": "Rediger prosjekt",
"dialog.project.edit.icon": "Ikon",
-5
View File
@@ -293,9 +293,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "پاس ورڈ",
"dialog.server.edit.title": "سرور وچ ترمیم کرو",
"dialog.server.menu.edit": "ترمیم کرو",
"dialog.server.menu.default": "ڈیفالٹ دے طور تے سیٹ کرو",
"dialog.server.menu.defaultRemove": "ڈیفالٹ ہٹاؤ",
"dialog.server.status.default": "طے شدہ",
"dialog.project.edit.title": "پروجیکٹ وچ ترمیم کرو",
"dialog.project.edit.icon": "آئکن",
"dialog.project.edit.icon.alt": "پروجیکٹ آئیکن",
@@ -803,7 +800,6 @@ export const dict = {
"server.connect.button": "جڑیں۔",
"server.connect.address.invalid": "ایک درست HTTP یا HTTPS سرور دا پتہ درج کرو۔",
"server.connect.failed": "رابطہ نئیں ہو سکا۔ سرور دا پتہ اور پاس ورڈ چیک کرو، پھر دوبارہ کوشش کرو۔",
"server.connect.pair.description": "اپنے کنکشن دی تفصیلات حاصل کرنے لئی اس کمانڈ کو اپنے کمپیوٹر پر چلائیں۔",
"server.connect.scan": "QR کوڈ اسکین کرو۔",
"server.connect.scan.description": "اپنے کیمرے کو اوپن کوڈ پیئر دے ذریعے دکھائے گئے QR کوڈ دی طرف پوائنٹ کرو۔",
"server.connect.scan.invalid":
@@ -812,7 +808,6 @@ export const dict = {
"server.connect.camera.starting": "کیمرہ کھل رہا ہے…",
"server.connect.mixedContent":
"ایک HTTPS صفحہ سے اس HTTP سرور سے مربوط نئیں ہو سکا۔ اس دے بجائے ایک HTTPS سرور دا پتہ استعمال کرو۔",
"server.connect.camera.insecure": "QR اسکیننگ لئی اس صفحہ کو HTTPS پر یا لوکل ہوسٹ پر کھولنے دی ضرورت اے۔",
"server.connect.camera.unavailable":
"اس براؤزر پر کوئی کیمرہ دستیاب نئیں اے۔ اپنے کنکشن دی تفصیلات دستی طور پر درج کرو۔",
"server.connect.camera.error":
-5
View File
@@ -289,9 +289,6 @@ export const dict = {
"dialog.server.add.password": "Hasło (opcjonalnie)",
"dialog.server.edit.title": "Edytuj serwer",
"dialog.server.menu.edit": "Edytuj",
"dialog.server.menu.default": "Ustaw jako domyślny",
"dialog.server.menu.defaultRemove": "Usuń domyślny",
"dialog.server.status.default": "Domyślny",
"dialog.project.edit.title": "Edytuj projekt",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Ikona projektu",
@@ -820,7 +817,6 @@ export const dict = {
"server.connect.button": "Połącz",
"server.connect.address.invalid": "Wprowadź prawidłowy adres serwera HTTP lub HTTPS.",
"server.connect.failed": "Nie można się połączyć. Sprawdź adres serwera i hasło, a następnie spróbuj ponownie.",
"server.connect.pair.description": "Uruchom to polecenie na swoim komputerze, aby uzyskać szczegóły połączenia.",
"server.connect.scan": "Zeskanuj kod QR",
"server.connect.scan.description": "Skieruj kamerę na kod QR pokazany przez sparowanie opencode.",
"server.connect.scan.invalid": "To nie jest kod parowania OpenCode. Zeskanuj kod pokazany przez sparowanie opencode.",
@@ -828,7 +824,6 @@ export const dict = {
"server.connect.camera.starting": "Otwieranie kamery…",
"server.connect.mixedContent":
"Nie można połączyć się z tym serwerem HTTP z strony HTTPS. Zamiast tego użyj adresu serwera HTTPS.",
"server.connect.camera.insecure": "Skanowanie QR wymaga otwarcia tej strony przez HTTPS lub na localhost.",
"server.connect.camera.unavailable": "Ta przeglądarka nie ma dostępu do kamery. Wprowadź dane połączenia ręcznie.",
"server.connect.camera.error":
"Nie udało się otworzyć kamery. Zezwól na dostęp do kamery lub wprowadź dane połączenia ręcznie.",
-5
View File
@@ -285,9 +285,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "parolă",
"dialog.server.edit.title": "Editează server",
"dialog.server.menu.edit": "Editează",
"dialog.server.menu.default": "Setează ca implicit",
"dialog.server.menu.defaultRemove": "Elimină implicitul",
"dialog.server.status.default": "Implicit",
"dialog.project.edit.title": "Editează proiectul",
"dialog.project.edit.icon": "Pictogramă",
"dialog.project.edit.icon.alt": "Pictograma proiectului",
@@ -790,7 +787,6 @@ export const dict = {
"server.connect.button": "Conectați",
"server.connect.address.invalid": "Introduceți o adresă validă de server HTTP sau HTTPS.",
"server.connect.failed": "Nu s-a putut conecta. Verificați adresa serverului și parola, apoi încercați din nou.",
"server.connect.pair.description": "Rulați această comandă pe computer pentru a obține detaliile conexiunii.",
"server.connect.scan": "Scanează codul QR",
"server.connect.scan.description": "Îndreptați camera către codul QR afișat de opencode pair.",
"server.connect.scan.invalid": "Acesta nu este un cod de asociere OpenCode. Scanați codul afișat de opencode pair.",
@@ -798,7 +794,6 @@ export const dict = {
"server.connect.camera.starting": "Deschiderea camerei…",
"server.connect.mixedContent":
"Nu s-a putut conecta la acest server HTTP de pe o pagină HTTPS. Utilizați în schimb o adresă de server HTTPS.",
"server.connect.camera.insecure": "Scanarea QR necesită deschiderea acestei pagini prin HTTPS sau pe localhost.",
"server.connect.camera.unavailable":
"Nicio cameră nu este disponibilă pentru acest browser. Introduceți manual detaliile conexiunii.",
"server.connect.camera.error":
-6
View File
@@ -311,9 +311,6 @@ export const dict = {
"dialog.server.edit.title": "Редактировать сервер",
"dialog.server.menu.edit": "Редактировать",
"dialog.server.menu.default": "Сделать по умолчанию",
"dialog.server.menu.defaultRemove": "Отменить выбор по умолчанию",
"dialog.server.status.default": "По умолч.",
"dialog.project.edit.title": "Редактировать проект",
"dialog.project.edit.icon": "Значок",
@@ -876,7 +873,6 @@ export const dict = {
"server.connect.button": "Подключиться",
"server.connect.address.invalid": "Введите действительный адрес сервера HTTP или HTTPS.",
"server.connect.failed": "Не удалось подключиться. Проверьте адрес сервера и пароль, затем попробуйте снова.",
"server.connect.pair.description": "Выполните эту команду на вашем компьютере, чтобы получить данные подключения.",
"server.connect.scan": "Сканировать QR-код",
"server.connect.scan.description": "Наведите камеру на QR-код, показанный парой opencode.",
"server.connect.scan.invalid": "Это не код пары OpenCode. Сканируйте код, показанный парой opencode.",
@@ -884,8 +880,6 @@ export const dict = {
"server.connect.camera.starting": "Открытие камеры…",
"server.connect.mixedContent":
"Не удалось подключиться к этому HTTP-серверу с HTTPS-страницы. Используйте адрес HTTPS-сервера вместо этого.",
"server.connect.camera.insecure":
"Сканирование QR требует открытия этой страницы через HTTPS или на локальном хосте.",
"server.connect.camera.unavailable": "Камера недоступна для этого браузера. Введите данные подключения вручную.",
"server.connect.camera.error":
"Не удалось открыть камеру. Разрешите доступ к камере или введите данные подключения вручную.",
-5
View File
@@ -289,9 +289,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "මුරපදය",
"dialog.server.edit.title": "සේවාදායකය සංස්කරණය කරන්න",
"dialog.server.menu.edit": "සංස්කරණය කරන්න",
"dialog.server.menu.default": "පෙරනිමිය ලෙස සකසන්න",
"dialog.server.menu.defaultRemove": "පෙරනිමිය ඉවත් කරන්න",
"dialog.server.status.default": "පෙරනිමිය",
"dialog.project.edit.title": "ව්‍යාපෘතිය සංස්කරණය කරන්න",
"dialog.project.edit.icon": "නිරූපකය",
"dialog.project.edit.icon.alt": "ව්යාපෘති නිරූපකය",
@@ -792,7 +789,6 @@ export const dict = {
"server.connect.button": "සම්බන්ධ කරන්න",
"server.connect.address.invalid": "වලංගු HTTP හෝ HTTPS සේවාදායක ලිපිනයක් ඇතුළත් කරන්න.",
"server.connect.failed": "සම්බන්ධ වීමට නොහැකි විය. සේවාදායක ලිපිනය සහ මුරපදය පරීක්ෂා කර නැවත උත්සාහ කරන්න.",
"server.connect.pair.description": "ඔබගේ සම්බන්ධතා විස්තර ලබා ගැනීමට මෙම විධානය ඔබගේ පරිගණකයේ ක්‍රියාත්මක කරන්න.",
"server.connect.scan": "QR කේතය පරිලෝකනය කරන්න",
"server.connect.scan.description": "opencode pair මගින් පෙන්වන QR කේතය වෙත ඔබේ කැමරාව යොමු කරන්න.",
"server.connect.scan.invalid":
@@ -801,7 +797,6 @@ export const dict = {
"server.connect.camera.starting": "කැමරාව විවෘත කරමින්...",
"server.connect.mixedContent":
"මෙම HTTP සේවාදායකයට HTTPS පිටුවකින් සම්බන්ධ වීමට නොහැකි විය. ඒ වෙනුවට HTTPS සේවාදායක ලිපිනයක් භාවිතා කරන්න.",
"server.connect.camera.insecure": "QR ස්කෑන් කිරීම සඳහා මෙම පිටුව HTTPS හරහා හෝ localhost මත විවෘත කිරීම අවශ්‍ය වේ.",
"server.connect.camera.unavailable": "මෙම බ්‍රවුසරයට කැමරාවක් නොමැත. ඔබගේ සම්බන්ධතා විස්තර අතින් ඇතුලත් කරන්න.",
"server.connect.camera.error":
"කැමරාව විවෘත කිරීමට නොහැකි විය. කැමරා ප්‍රවේශයට ඉඩ දෙන්න හෝ ඔබගේ සම්බන්ධතා විස්තර හස්තීයව ඇතුලත් කරන්න.",
-5
View File
@@ -311,9 +311,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "heslo",
"dialog.server.edit.title": "Upraviť server",
"dialog.server.menu.edit": "Upraviť",
"dialog.server.menu.default": "Nastaviť ako predvolený",
"dialog.server.menu.defaultRemove": "Odstrániť predvolený",
"dialog.server.status.default": "Predvolený",
"dialog.project.edit.title": "Upraviť projekt",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Ikona projektu",
@@ -815,7 +812,6 @@ export const dict = {
"server.connect.button": "Pripojiť sa",
"server.connect.address.invalid": "Zadajte platnú adresu servera s protokolom HTTP alebo HTTPS.",
"server.connect.failed": "Nepodarilo sa pripojiť. Skontrolujte adresu servera a heslo a skúste znova.",
"server.connect.pair.description": "Spustite tento príkaz na svojom počítači, aby ste získali údaje na pripojenie.",
"server.connect.scan": "Naskenujte QR kód",
"server.connect.scan.description": "Namierte kameru na QR kód zobrazený pomocou opencode pair.",
"server.connect.scan.invalid": "Toto nie je párovací kód OpenCode. Naskenujte kód zobrazený pomocou opencode pair.",
@@ -823,7 +819,6 @@ export const dict = {
"server.connect.camera.starting": "Otvorenie kamery…",
"server.connect.mixedContent":
"Nie je možné pripojiť sa k tomuto HTTP serveru z HTTPS stránky. Namiesto toho použite adresu HTTPS.",
"server.connect.camera.insecure": "Na skenovanie QR je potrebné otvoriť túto stránku cez HTTPS alebo na localhoste.",
"server.connect.camera.unavailable":
"Tento prehliadač nemá k dispozícii žiadnu kameru. Zadajte údaje na pripojenie ručne.",
"server.connect.camera.error":
-5
View File
@@ -311,9 +311,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "geslo",
"dialog.server.edit.title": "Uredi strežnik",
"dialog.server.menu.edit": "Uredi",
"dialog.server.menu.default": "Nastavi kot privzeto",
"dialog.server.menu.defaultRemove": "Odstrani privzeto",
"dialog.server.status.default": "Privzeto",
"dialog.project.edit.title": "Uredi projekt",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Ikona projekta",
@@ -815,7 +812,6 @@ export const dict = {
"server.connect.address.invalid": "Vnesite veljaven HTTP ali HTTPS naslov strežnika.",
"server.connect.failed":
"Povezave ni bilo mogoče vzpostaviti. Preverite naslov strežnika in geslo ter poskusite znova.",
"server.connect.pair.description": "Za pridobitev podatkov o povezavi zaženite ta ukaz na svojem računalniku.",
"server.connect.scan": "Skeniraj QR kodo",
"server.connect.scan.description": "Usmerite kamero na QR kodo, ki jo prikaže opencode pair.",
"server.connect.scan.invalid": "To ni OpenCode paritna koda. Skenirajte kodo, ki jo prikaže opencode pair.",
@@ -823,7 +819,6 @@ export const dict = {
"server.connect.camera.starting": "Odpiranje kamere…",
"server.connect.mixedContent":
"Z HTTP strežnikom se ni mogoče povezati iz HTTPS strani. Uporabite HTTPS naslov strežnika.",
"server.connect.camera.insecure": "Skeniranje QR zahteva odpiranje te strani preko HTTPS ali na localhost.",
"server.connect.camera.unavailable": "Brskalnik nima na voljo kamere. Vnesite podatke o povezavi ročno.",
"server.connect.camera.error":
"Kamer ne morem odpreti. Dovolite dostop do kamere ali vnesite podatke o povezavi ročno.",
-5
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "fjalëkalimin",
"dialog.server.edit.title": "Redakto serverin",
"dialog.server.menu.edit": "Redakto",
"dialog.server.menu.default": "Cakto si parazgjedhje",
"dialog.server.menu.defaultRemove": "Hiq parazgjedhjen",
"dialog.server.status.default": "E paracaktuar",
"dialog.project.edit.title": "Redakto projektin",
"dialog.project.edit.icon": "Ikona",
"dialog.project.edit.icon.alt": "Ikona e projektit",
@@ -782,7 +779,6 @@ export const dict = {
"server.connect.address.invalid": "Fut një adresë të vlefshme serveri HTTP ose HTTPS.",
"server.connect.failed":
"Nuk mund të lidhej. Kontrolloni adresën dhe fjalëkalimin e serverit, më pas provoni përsëri.",
"server.connect.pair.description": "Ekzekutoni këtë komandë në kompjuterin tuaj për të marrë detajet e lidhjes suaj.",
"server.connect.scan": "Skanoni kodin QR",
"server.connect.scan.description": "Drejtoje kamerën drejt kodit QR të treguar nga opencode pair.",
"server.connect.scan.invalid": "Ky nuk është një kod çiftimi OpenCode. Skanoni kodin e treguar nga opencode pair.",
@@ -790,7 +786,6 @@ export const dict = {
"server.connect.camera.starting": "Hapja e kamerës…",
"server.connect.mixedContent":
"Nuk mund të lidhej me këtë server HTTP nga një faqe HTTPS. Në vend të kësaj, përdorni një adresë serveri HTTPS.",
"server.connect.camera.insecure": "Skanimi QR kërkon hapjen e kësaj faqeje mbi HTTPS ose në localhost.",
"server.connect.camera.unavailable":
"Asnjë kamerë nuk disponohet për këtë shfletues. Futni manualisht detajet e lidhjes suaj.",
"server.connect.camera.error":
-5
View File
@@ -299,9 +299,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "лозинка",
"dialog.server.edit.title": "Уреди сервер",
"dialog.server.menu.edit": "Уреди",
"dialog.server.menu.default": "Подесите као подразумевано",
"dialog.server.menu.defaultRemove": "Уклони подразумевано",
"dialog.server.status.default": "подразумевано",
"dialog.project.edit.title": "Уреди пројекат",
"dialog.project.edit.icon": "Икона",
"dialog.project.edit.icon.alt": "икона пројекта",
@@ -803,7 +800,6 @@ export const dict = {
"server.connect.button": "Повежи се",
"server.connect.address.invalid": "Унесите важећу HTTP или HTTPS адресу сервера.",
"server.connect.failed": "Није могуће повезати се. Проверите адресу сервера и лозинку, па покушајте поново.",
"server.connect.pair.description": "Покрените ову команду на рачунару да бисте добили податке за повезивање.",
"server.connect.scan": "Скенирај QR код",
"server.connect.scan.description": "Усмерите камеру на QR код који приказује opencode pair.",
"server.connect.scan.invalid": "Ово није OpenCode код за повезивање. Скенирајте код који приказује opencode pair.",
@@ -811,7 +807,6 @@ export const dict = {
"server.connect.camera.starting": "Отварање камере…",
"server.connect.mixedContent":
"Није могуће повезати се на овај HTTP сервер са HTTPS странице. Уместо тога користите HTTPS адресу сервера.",
"server.connect.camera.insecure": "Скенирање QR кода захтева отварање ове странице преко HTTPS-а или на лоцалхосту.",
"server.connect.camera.unavailable": "Овај прегледник нема доступну камеру. Унесите податке за повезивање ручно.",
"server.connect.camera.error":
"Није могуће отворити камеру. Дозволите приступ камери или унесите податке за повезивање ручно.",
-5
View File
@@ -22,7 +22,6 @@ export const dict = {
"server.connect.button": "Anslut",
"server.connect.address.invalid": "Ange en giltig HTTP- eller HTTPS-serveradress.",
"server.connect.failed": "Kunde inte ansluta. Kontrollera serveradressen och lösenordet och försök sedan igen.",
"server.connect.pair.description": "Kör det här kommandot på din dator för att få din anslutningsinformation.",
"server.connect.scan": "Skanna QR-koden",
"server.connect.scan.description": "Rikta kameran mot QR-koden som visas av opencode pair.",
"server.connect.scan.invalid": "Detta är inte en OpenCode parningskod. Skanna koden som visas av opencode pair.",
@@ -30,7 +29,6 @@ export const dict = {
"server.connect.camera.starting": "Öppnar kameran...",
"server.connect.mixedContent":
"Det gick inte att ansluta till denna HTTP-server från en HTTPS-sida. Använd en HTTPS-serveradress istället.",
"server.connect.camera.insecure": "QR-skanning kräver att den här sidan öppnas över HTTPS eller på localhost.",
"server.connect.camera.unavailable":
"Ingen kamera är tillgänglig för den här webbläsaren. Ange dina anslutningsuppgifter manuellt.",
"server.connect.camera.error":
@@ -493,9 +491,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "lösenord",
"dialog.server.edit.title": "Redigera server",
"dialog.server.menu.edit": "Redigera",
"dialog.server.menu.default": "Ställ in som standard",
"dialog.server.menu.defaultRemove": "Ta bort standard",
"dialog.server.status.default": "Standard",
"dialog.project.edit.title": "Redigera projekt",
"dialog.project.edit.icon": "Ikon",
"dialog.project.edit.icon.alt": "Projektikonen",
-6
View File
@@ -287,9 +287,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "парол",
"dialog.server.edit.title": "Серверро таҳрир кунед",
"dialog.server.menu.edit": "Таҳрир",
"dialog.server.menu.default": "Ҳамчун пешфарз таъин кунед",
"dialog.server.menu.defaultRemove": "Пешфарзро хориҷ кунед",
"dialog.server.status.default": "Пешфарз",
"dialog.project.edit.title": "Таҳрири лоиҳа",
"dialog.project.edit.icon": "Нишона",
"dialog.project.edit.icon.alt": "Нишонаи лоиҳа",
@@ -796,7 +793,6 @@ export const dict = {
"server.connect.button": "Пайваст кунед",
"server.connect.address.invalid": "Суроғаи сервери дурусти HTTP ё HTTPS-ро ворид кунед.",
"server.connect.failed": "Пайваст шуда натавонист. Суроғаи сервер ва паролро тафтиш кунед ва аз нав кӯшиш кунед.",
"server.connect.pair.description": "Барои гирифтани тафсилоти пайвасти худ ин фармонро дар компютери худ иҷро кунед.",
"server.connect.scan": "Рамзи QR-ро скан кунед",
"server.connect.scan.description": "Камераро ба рамзи QR, ки opencode pair нишон медиҳад, равона кунед.",
"server.connect.scan.invalid":
@@ -805,8 +801,6 @@ export const dict = {
"server.connect.camera.starting": "Кушодани камера…",
"server.connect.mixedContent":
"Аз саҳифаи HTTPS ба ин сервери HTTP пайваст шуда натавонист. Ба ҷои он суроғаи сервери HTTPS-ро истифода баред.",
"server.connect.camera.insecure":
"Сканкунии QR талаб мекунад, ки ин саҳифа тавассути HTTPS ё дар localhost кушода шавад.",
"server.connect.camera.unavailable":
"Барои ин браузер ягон камера дастрас нест. Тафсилоти пайвасти худро дастӣ ворид кунед.",
"server.connect.camera.error":
-5
View File
@@ -319,9 +319,6 @@ export const dict = {
"dialog.server.edit.title": "แก้ไขเซิร์ฟเวอร์",
"dialog.server.menu.edit": "แก้ไข",
"dialog.server.menu.default": "ตั้งเป็นค่าเริ่มต้น",
"dialog.server.menu.defaultRemove": "เอาค่าเริ่มต้นออก",
"dialog.server.status.default": "ค่าเริ่มต้น",
"dialog.project.edit.title": "แก้ไขโปรเจกต์",
"dialog.project.edit.icon": "ไอคอน",
@@ -852,14 +849,12 @@ export const dict = {
"server.connect.button": "เชื่อมต่อ",
"server.connect.address.invalid": "ใส่ที่อยู่เซิร์ฟเวอร์ HTTP หรือ HTTPS ที่ถูกต้อง",
"server.connect.failed": "ไม่สามารถเชื่อมต่อได้ ตรวจสอบที่อยู่เซิร์ฟเวอร์และรหัสผ่าน จากนั้นลองใหม่อีกครั้ง",
"server.connect.pair.description": "รันคำสั่งนี้บนคอมพิวเตอร์ของคุณเพื่อรับรายละเอียดการเชื่อมต่อของคุณ",
"server.connect.scan": "สแกนรหัส QR",
"server.connect.scan.description": "ชี้กล้องของคุณไปที่รหัส QR ที่แสดงโดยการจับคู่ opencode",
"server.connect.scan.invalid": "นี่ไม่ใช่รหัสจับคู่ OpenCode สแกนรหัสที่แสดงโดย opencode pair",
"server.connect.camera": "กำลังจับคู่กล้อง",
"server.connect.camera.starting": "กำลังเปิดกล้อง…",
"server.connect.mixedContent": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ HTTP จากหน้า HTTPS ใช้ที่อยู่เซิร์ฟเวอร์ HTTPS แทน",
"server.connect.camera.insecure": "การสแกน QR ต้องเปิดหน้านี้ผ่าน HTTPS หรือบน localhost",
"server.connect.camera.unavailable": "เบราว์เซอร์นี้ไม่สามารถใช้งานกล้องได้ กรอกรายละเอียดการเชื่อมต่อด้วยตนเอง",
"server.connect.camera.error": "ไม่สามารถเปิดกล้องได้ อนุญาตการเข้าถึงกล้องหรือกรอกรายละเอียดการเชื่อมต่อด้วยตนเอง",
"dialog.server.menu.remove": "ลบ",
-5
View File
@@ -286,9 +286,6 @@ export const dict = {
"dialog.server.add.passwordPlaceholder": "parol",
"dialog.server.edit.title": "Serweri redaktirläň",
"dialog.server.menu.edit": "Redaktirläň",
"dialog.server.menu.default": "Dymmaklyk hökmünde düzüň",
"dialog.server.menu.defaultRemove": "Dymmaklygy aýyryň",
"dialog.server.status.default": "Bellenen",
"dialog.project.edit.title": "Taslamany redaktirläň",
"dialog.project.edit.icon": "Nyşan",
"dialog.project.edit.icon.alt": "Taslamanyň nyşany",
@@ -791,7 +788,6 @@ export const dict = {
"server.connect.button": "Birikdiriň",
"server.connect.address.invalid": "Dogry HTTP ýa-da HTTPS serwer salgysyny giriziň.",
"server.connect.failed": "Birikip bilmedim Serweriň salgysyny we parolyny barlaň, soňra gaýtadan synanyşyň.",
"server.connect.pair.description": "Baglanyş maglumatlaryňyzy almak üçin bu buýrugy kompýuteriňizde işlediň.",
"server.connect.scan": "QR koduny skanirläň",
"server.connect.scan.description": "Kamerany opencode pair görkezýän QR koda gönükdiriň.",
"server.connect.scan.invalid": "Bu OpenCode jübütleme kody däl. opencode pair görkezýän kody skanirläň.",
@@ -799,7 +795,6 @@ export const dict = {
"server.connect.camera.starting": "Kamerany açmak…",
"server.connect.mixedContent":
"Bu HTTP serwerine HTTPS sahypasyndan birigip bilmedim. Munuň ýerine HTTPS serwer salgysyny ulanyň.",
"server.connect.camera.insecure": "QR gözlemek bu sahypany HTTPS ýa-da ýerlihostda açmagy talap edýär.",
"server.connect.camera.unavailable": "Bu brauzerde kamera ýok. Birikdiriş maglumatlaryňyzy el bilen giriziň.",
"server.connect.camera.error":
"Kamerany açyp bolmady Kamera girmegine rugsat beriň ýa-da baglanyşyk maglumatlaryňyzy el bilen giriziň.",
-5
View File
@@ -324,9 +324,6 @@ export const dict = {
"dialog.server.edit.title": "Sunucuyu düzenle",
"dialog.server.menu.edit": "Düzenle",
"dialog.server.menu.default": "Varsayılan olarak ayarla",
"dialog.server.menu.defaultRemove": "Varsayılanı kaldır",
"dialog.server.status.default": "Varsayılan",
"dialog.project.edit.title": "Projeyi düzenle",
"dialog.project.edit.icon": "Simge",
@@ -860,7 +857,6 @@ export const dict = {
"server.connect.button": "Bağlan",
"server.connect.address.invalid": "Geçerli bir HTTP veya HTTPS sunucu adresi girin.",
"server.connect.failed": "Bağlantı kurulamadı. Sunucu adresini ve şifreyi kontrol edip tekrar deneyin.",
"server.connect.pair.description": "Bağlantı ayrıntılarınızı almak için bilgisayarınızda bu komutu çalıştırın.",
"server.connect.scan": "QR kodunu tarayın",
"server.connect.scan.description": "Kameranızı opencode pair tarafından gösterilen QR koduna doğrultun.",
"server.connect.scan.invalid":
@@ -869,7 +865,6 @@ export const dict = {
"server.connect.camera.starting": "Kamera açılıyor…",
"server.connect.mixedContent":
"Bu HTTP sunucusuna bir HTTPS sayfasından bağlanılamadı. Bunun yerine HTTPS sunucu adresini kullanın.",
"server.connect.camera.insecure": "QR taraması, bu sayfanın HTTPS veya localhost üzerinden açılmasını gerektirir.",
"server.connect.camera.unavailable":
"Bu tarayıcıda kamera mevcut değil. Bağlantı ayrıntılarınızı manuel olarak girin.",
"server.connect.camera.error":
-5
View File
@@ -341,9 +341,6 @@ export const dict = {
"dialog.server.edit.title": "Редагувати сервер",
"dialog.server.menu.edit": "Редагувати",
"dialog.server.menu.default": "Встановити за замовчуванням",
"dialog.server.menu.defaultRemove": "Скасувати використання за замовчуванням",
"dialog.server.status.default": "За замовчуванням",
"dialog.project.edit.title": "Редагувати проєкт",
"dialog.project.edit.icon": "Іконка",
@@ -885,7 +882,6 @@ export const dict = {
"server.connect.button": "Підключитися",
"server.connect.address.invalid": "Введіть дійсну адресу сервера HTTP або HTTPS.",
"server.connect.failed": "Не вдалося підключитися. Перевірте адресу сервера та пароль, потім повторіть спробу.",
"server.connect.pair.description": "Запустіть цю команду на своєму комп’ютері, щоб отримати дані підключення.",
"server.connect.scan": "Сканувати QR-код",
"server.connect.scan.description": "Наведіть камеру на QR-код, показаний opencode pair.",
"server.connect.scan.invalid": "Це не код підключення OpenCode. Відскануйте код, показаний opencode pair.",
@@ -893,7 +889,6 @@ export const dict = {
"server.connect.camera.starting": "Відкриваємо камеру…",
"server.connect.mixedContent":
"Не вдалося підключитися до цього HTTP-сервера з HTTPS-сторінки. Використайте адресу HTTPS-сервера.",
"server.connect.camera.insecure": "Сканування QR вимагає відкриття цієї сторінки через HTTPS або на localhost.",
"server.connect.camera.unavailable": "У цьому веббраузері немає доступної камери. Введіть дані підключення вручну.",
"server.connect.camera.error":
"Не вдалося відкрити камеру. Дозвольте доступ до камери або введіть дані підключення вручну.",
Loaded 100 of 535 files, more files were not shown because too many files have changed in this diff. Show more