Merge branch 'main' into docs/kiloclaw-top-level-section

This commit is contained in:
Ligia Zanchet
2026-03-10 10:44:17 +01:00
committed by GitHub
38 changed files with 2034 additions and 459 deletions
+63 -4
View File
@@ -204,6 +204,7 @@
"version": "7.0.40",
"dependencies": {
"@kobalte/core": "0.13.11",
"@solid-primitives/resize-observer": "2.1.5",
"lucide-solid": "0.576.0",
},
"devDependencies": {
@@ -1586,7 +1587,7 @@
"@solid-primitives/event-bus": ["@solid-primitives/event-bus@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-l+n10/51neGcMaP3ypYt21bXfoeWh8IaC8k7fYuY3ww2a8S1Zv2N2a7FF5Qn+waTu86l0V8/nRHjkyqVIZBYwA=="],
"@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.5", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-nwRV558mIabl4yVAhZKY8cb6G+O1F0M6Z75ttTu5hk+SxdOnKSGj+eetDIu7Oax1P138ZdUU01qnBPR8rnxaEA=="],
"@solid-primitives/i18n": ["@solid-primitives/i18n@2.2.1", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-TnTnE2Ku11MGYZ1JzhJ8pYscwg1fr9MteoYxPwsfxWfh9Jp5K7RRJncJn9BhOHvNLwROjqOHZ46PT7sPHqbcXw=="],
@@ -1600,15 +1601,15 @@
"@solid-primitives/refs": ["@solid-primitives/refs@1.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-K7tf2thy7L+YJjdqXspXOg5xvNEOH8tgEWsp0+1mQk3obHBRD6hEjYZk7p7FlJphSZImS35je3UfmWuD7MhDfg=="],
"@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.5", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.5", "@solid-primitives/rootless": "^1.5.3", "@solid-primitives/static-store": "^0.1.3", "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AiyTknKcNBaKHbcSMuxtSNM8FjIuiSuFyFghdD0TcCMU9hKi9EmsC5pjfjDwxE+5EueB1a+T/34PLRI5vbBbKw=="],
"@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA=="],
"@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="],
"@solid-primitives/scroll": ["@solid-primitives/scroll@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-Ejq/Z7zKo/6eIEFr1bFLzXFxiGBCMLuqCM8QB8urr3YdPzjSETFLzYRWUyRiDWaBQN0F7k0SY6S7ig5nWOP7vg=="],
"@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.3", "", { "dependencies": { "@solid-primitives/utils": "^6.4.0" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-uxez7SXnr5GiRnzqO2IEDjOJRIXaG+0LZLBizmUA1FwSi+hrpuMzVBwyk70m4prcl8X6FDDXUl9O8hSq8wHbBQ=="],
"@solid-primitives/storage": ["@solid-primitives/storage@4.3.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "@tauri-apps/plugin-store": "*", "solid-js": "^1.6.12" }, "optionalPeers": ["@tauri-apps/plugin-store"] }, "sha512-ACbNwMZ1s8VAvld6EUXkDkX/US3IhtlPLxg6+B2s9MwNUugwdd51I98LPEaHrdLpqPmyzqgoJe0TxEFlf3Dqrw=="],
@@ -4206,6 +4207,10 @@
"@kilocode/kilo-gateway/@opentui/solid": ["@opentui/solid@0.1.75", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.1.75", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.9", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.9" } }, "sha512-WjKsZIfrm29znfRlcD9w3uUn/+uvoy2MmeoDwTvg1YOa0OjCTCmjZ43L9imp0m9S4HmVU8ma6o2bR4COzcyDdg=="],
"@kobalte/core/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@kobalte/utils/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@modelcontextprotocol/sdk/jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
"@modelcontextprotocol/sdk/zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
@@ -4250,6 +4255,8 @@
"@opencode-ai/app/@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="],
"@opencode-ai/app/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@opencode-ai/app/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"@opencode-ai/app/vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="],
@@ -4260,6 +4267,8 @@
"@opencode-ai/desktop/vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="],
"@opencode-ai/ui/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@opencode-ai/ui/tailwindcss": ["tailwindcss@4.1.11", "", {}, "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA=="],
"@opencode-ai/ui/vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="],
@@ -4302,6 +4311,36 @@
"@shikijs/themes/@shikijs/types": ["@shikijs/types@3.20.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw=="],
"@solid-primitives/active-element/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@solid-primitives/audio/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/bounds/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@solid-primitives/bounds/@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
"@solid-primitives/bounds/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/event-listener/@solid-primitives/utils": ["@solid-primitives/utils@6.4.0", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A=="],
"@solid-primitives/media/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@solid-primitives/media/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@solid-primitives/media/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/resize-observer/@solid-primitives/utils": ["@solid-primitives/utils@6.4.0", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A=="],
"@solid-primitives/rootless/@solid-primitives/utils": ["@solid-primitives/utils@6.4.0", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A=="],
"@solid-primitives/scroll/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@solid-primitives/scroll/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@solid-primitives/scroll/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@solid-primitives/static-store/@solid-primitives/utils": ["@solid-primitives/utils@6.4.0", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A=="],
"@storybook/addon-docs/react": ["react@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ=="],
"@storybook/addon-docs/react-dom": ["react-dom@18.2.0", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" }, "peerDependencies": { "react": "^18.2.0" } }, "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g=="],
@@ -5244,6 +5283,12 @@
"@kilocode/kilo-gateway/@opentui/solid/solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="],
"@kobalte/core/@solid-primitives/resize-observer/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@kobalte/core/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@kobalte/core/@solid-primitives/resize-observer/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
"@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
@@ -5278,12 +5323,24 @@
"@opencode-ai/app/@playwright/test/playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="],
"@opencode-ai/app/@solid-primitives/resize-observer/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@opencode-ai/app/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@opencode-ai/app/@solid-primitives/resize-observer/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@opencode-ai/app/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"@opencode-ai/desktop/@actions/artifact/@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="],
"@opencode-ai/desktop/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"@opencode-ai/ui/@solid-primitives/resize-observer/@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
"@opencode-ai/ui/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@opencode-ai/ui/@solid-primitives/resize-observer/@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
"@opencode-ai/ui/vite/esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core/@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.39.0", "", {}, "sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg=="],
@@ -5314,6 +5371,8 @@
"@pierre/diffs/@shikijs/transformers/@shikijs/types": ["@shikijs/types@3.19.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-Z2hdeEQlzuntf/BZpFG8a+Fsw9UVXdML7w0o3TgSXV3yNESGon+bs9ITkQb3Ki7zxoXOOu5oJWqZ2uto06V9iQ=="],
"@solid-primitives/bounds/@solid-primitives/resize-observer/@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
"@storybook/addon-docs/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
"@tailwindcss/node/lightningcss/detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1770812194,
"narHash": "sha256-OH+lkaIKAvPXR3nITO7iYZwew2nW9Y7Xxq0yfM/UcUU=",
"lastModified": 1772956932,
"narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8482c7ded03bae7550f3d69884f1e611e3bd19e8",
"rev": "608d0cadfed240589a7eea422407a547ad626a14",
"type": "github"
},
"original": {
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-AIHdAoZ6f1J9uNuZ36X493dVLukXZ6e2SS4Y4fFSOGQ=",
"aarch64-linux": "sha256-o5aQJgSXEDF/hp8WvnhnTjYhg8uzNf2QFspOyH8HnCc=",
"aarch64-darwin": "sha256-086kLWpb1NNZGngb6YWMJlFtuJeMihTOWr1etS21xFU=",
"x86_64-darwin": "sha256-Exz71XKxPeAHutx7w8B5DhgoF9J/G5ZLqq4GrwbCzZk="
"x86_64-linux": "sha256-2SnZbJPIvgCkb4jNh49CnbDAOpghgO9XihSiTlL6rYI=",
"aarch64-linux": "sha256-HV/Sm4rBAZPjxG+SQJ95634yTyJXDjlSeYemMYg8eCE=",
"aarch64-darwin": "sha256-PAJSd1VkNc7LUSrOAeG+rmYUw8VefR8GfkAIy8H3iV0=",
"x86_64-darwin": "sha256-Qdk8nu4FoGjp6+7Ji5vuHw2HhM1Z+ivE7meqJivTiHk="
}
}
@@ -19,6 +19,7 @@ A user or organization may want to use BYOK to:
Kilo Gateway currently supports BYOK keys for these providers:
- Anthropic
- AWS Bedrock
- OpenAI
- Google AI Studio
- Minimax
@@ -33,6 +34,29 @@ Kilo Gateway currently supports BYOK keys for these providers:
3. Click `Add Your First Key`, select the provider, and paste your API key.
4. Save.
### AWS Bedrock configuration
AWS Bedrock requires credentials in a different format than other providers. Instead of a single API key, you must provide your AWS credentials as a JSON object:
```json
{
"accessKeyId": "AKIA...",
"secretAccessKey": "...",
"region": "us-east-1"
}
```
| Field | Description |
| ----------------- | ------------------------------------------------------------------------ |
| `accessKeyId` | Your AWS access key ID |
| `secretAccessKey` | Your AWS secret access key |
| `region` | The AWS region where Bedrock is enabled (e.g., `us-east-1`, `eu-west-1`) |
Your IAM user or role must have the following permissions:
- `bedrock:InvokeModel`
- `bedrock:InvokeModelWithResponseStream`
## How Bring Your Own Key works
- When you use the **Kilo Gateway** provider, Kilo checks if there's a BYOK key for the selected model's provider.
+1
View File
@@ -106,6 +106,7 @@
},
"dependencies": {
"@kobalte/core": "0.13.11",
"@solid-primitives/resize-observer": "2.1.5",
"lucide-solid": "0.576.0"
}
}
@@ -0,0 +1,256 @@
// kilocode_change - new file
import { createEffect, on, onCleanup } from "solid-js"
import { createStore } from "solid-js/store"
import { createResizeObserver } from "@solid-primitives/resize-observer"
const DEBOUNCE_MS = 100
export interface AutoScrollOptions {
working: () => boolean
onUserInteracted?: () => void
overflowAnchor?: "none" | "auto" | "dynamic"
bottomThreshold?: number
}
export function createAutoScroll(options: AutoScrollOptions) {
let scroll: HTMLElement | undefined
let settling = false
let settleTimer: ReturnType<typeof setTimeout> | undefined
let autoTimer: ReturnType<typeof setTimeout> | undefined
let stopTimer: ReturnType<typeof setTimeout> | undefined
let cleanup: (() => void) | undefined
let auto: { time: number } | undefined
const threshold = () => options.bottomThreshold ?? 10
const [store, setStore] = createStore({
contentRef: undefined as HTMLElement | undefined,
userScrolled: false,
})
const active = () => options.working() || settling
const distanceFromBottom = (el: HTMLElement) => {
return el.scrollHeight - el.clientHeight - el.scrollTop
}
const canScroll = (el: HTMLElement) => {
return el.scrollHeight - el.clientHeight > 1
}
// Browsers can dispatch scroll events asynchronously. If new content arrives
// between us calling `scrollTo()` and the subsequent `scroll` event firing,
// the handler can see a non-zero `distanceFromBottom` and incorrectly assume
// the user scrolled.
const markAuto = (_el: HTMLElement) => {
auto = { time: Date.now() }
if (autoTimer) clearTimeout(autoTimer)
autoTimer = setTimeout(() => {
auto = undefined
autoTimer = undefined
}, 250)
}
const isAuto = (_el: HTMLElement) => {
const a = auto
if (!a) return false
if (Date.now() - a.time > 250) {
auto = undefined
return false
}
return true
}
const scrollToBottomNow = (behavior: ScrollBehavior) => {
const el = scroll
if (!el) return
markAuto(el)
if (behavior === "smooth") {
el.scrollTo({ top: el.scrollHeight, behavior })
return
}
// `scrollTop` assignment bypasses any CSS `scroll-behavior: smooth`.
el.scrollTop = el.scrollHeight
}
const scrollToBottom = (force: boolean) => {
if (!force && !active()) return
const el = scroll
if (!el) return
if (!force && store.userScrolled) return
if (force && store.userScrolled) setStore("userScrolled", false)
const distance = distanceFromBottom(el)
if (distance < 2) return
// For auto-following content we prefer immediate updates to avoid
// visible "catch up" animations while content is still settling.
scrollToBottomNow("auto")
}
const stop = () => {
const el = scroll
if (!el) return
if (!canScroll(el)) {
if (store.userScrolled) setStore("userScrolled", false)
return
}
if (store.userScrolled) return
setStore("userScrolled", true)
options.onUserInteracted?.()
}
const handleWheel = (e: WheelEvent) => {
if (e.deltaY >= 0) return
// If the user is scrolling within a nested scrollable region (tool output,
// code block, etc), don't treat it as leaving the "follow bottom" mode.
// Those regions opt in via `data-scrollable`.
const el = scroll
const target = e.target instanceof Element ? e.target : undefined
const nested = target?.closest("[data-scrollable]")
if (el && nested && nested !== el) return
stop()
}
const handleScroll = () => {
const el = scroll
if (!el) return
if (!canScroll(el)) {
if (store.userScrolled) setStore("userScrolled", false)
return
}
if (distanceFromBottom(el) < threshold()) {
if (store.userScrolled) setStore("userScrolled", false)
return
}
// Ignore scroll events triggered by our own scrollToBottom calls.
if (!store.userScrolled && isAuto(el)) {
scrollToBottom(false)
return
}
// Debounce to avoid layout-induced scroll shifts (e.g. images loading,
// virtual-list reflows) from incorrectly breaking auto-follow.
if (stopTimer) clearTimeout(stopTimer)
stopTimer = setTimeout(() => {
stopTimer = undefined
const cur = scroll
if (!cur) return
if (distanceFromBottom(cur) < threshold()) return
if (!store.userScrolled && isAuto(cur)) return
stop()
}, DEBOUNCE_MS)
}
const handleInteraction = () => {
if (!active()) return
stop()
}
const updateOverflowAnchor = (el: HTMLElement) => {
const mode = options.overflowAnchor ?? "dynamic"
if (mode === "none") {
el.style.overflowAnchor = "none"
return
}
if (mode === "auto") {
el.style.overflowAnchor = "auto"
return
}
el.style.overflowAnchor = store.userScrolled ? "auto" : "none"
}
createResizeObserver(
() => store.contentRef,
() => {
const el = scroll
if (el && !canScroll(el)) {
if (store.userScrolled) setStore("userScrolled", false)
return
}
if (!active()) return
if (store.userScrolled) return
// ResizeObserver fires after layout, before paint.
// Keep the bottom locked in the same frame to avoid visible
// "jump up then catch up" artifacts while streaming content.
scrollToBottom(false)
},
)
createEffect(
on(options.working, (working: boolean) => {
settling = false
if (settleTimer) clearTimeout(settleTimer)
settleTimer = undefined
if (working) {
scrollToBottom(true)
return
}
settling = true
settleTimer = setTimeout(() => {
settling = false
}, 300)
}),
)
createEffect(() => {
// Track `userScrolled` even before `scrollRef` is attached, so we can
// update overflow anchoring once the element exists.
store.userScrolled
const el = scroll
if (!el) return
updateOverflowAnchor(el)
})
onCleanup(() => {
if (settleTimer) clearTimeout(settleTimer)
if (autoTimer) clearTimeout(autoTimer)
if (stopTimer) clearTimeout(stopTimer)
if (cleanup) cleanup()
})
return {
scrollRef: (el: HTMLElement | undefined) => {
if (cleanup) {
cleanup()
cleanup = undefined
}
scroll = el
if (!el) return
updateOverflowAnchor(el)
el.addEventListener("wheel", handleWheel, { passive: true })
cleanup = () => {
el.removeEventListener("wheel", handleWheel)
}
},
contentRef: (el: HTMLElement | undefined) => setStore("contentRef", el),
handleScroll,
handleInteraction,
pause: stop,
resume: () => {
if (store.userScrolled) setStore("userScrolled", false)
scrollToBottom(true)
},
scrollToBottom: () => scrollToBottom(false),
forceScrollToBottom: () => scrollToBottom(true),
userScrolled: () => store.userScrolled,
}
}
+2 -1
View File
@@ -1 +1,2 @@
export * from "@opencode-ai/ui/hooks"
export { useFilteredList } from "@opencode-ai/ui/hooks"
export * from "./create-auto-scroll"
+42 -2
View File
@@ -647,6 +647,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
await this.syncWebviewState("sse-connected")
await this.flushPendingSessionRefresh("sse-connected")
await this.fetchAndSendPendingPermissions()
} catch (error) {
console.error("[Kilo New] KiloProvider: ❌ Failed during connected state handling:", error)
this.postMessage({
@@ -825,6 +826,10 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
sessionID,
messages,
})
// Recover any permission.asked events that were missed while the webview
// was loading or during an SSE reconnection (fire-and-forget).
void this.fetchAndSendPendingPermissions()
} catch (error) {
// Silently ignore aborted requests — the user switched to a different session
if (abort.signal.aborted) return
@@ -1515,23 +1520,58 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
response: "once" | "always" | "reject",
): Promise<void> {
if (!this.client) {
this.postMessage({ type: "permissionError", permissionID: permissionId })
return
}
const targetSessionID = sessionID || this.currentSession?.id
if (!targetSessionID) {
console.error("[Kilo New] KiloProvider: No sessionID for permission response")
this.postMessage({ type: "permissionError", permissionID: permissionId })
return
}
try {
const workspaceDir = this.getWorkspaceDirectory(targetSessionID)
await this.client.permission.respond(
{ sessionID: targetSessionID, permissionID: permissionId, response, directory: workspaceDir },
await this.client.permission.reply(
{ requestID: permissionId, reply: response, directory: workspaceDir },
{ throwOnError: true },
)
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to respond to permission:", error)
this.postMessage({ type: "permissionError", permissionID: permissionId })
}
}
/**
* Fetch all pending permissions from the backend and forward any that belong
* to tracked sessions to the webview. Called after SSE reconnects and after
* loading messages for a session so that missed permission.asked events are
* recovered instead of leaving the server blocked indefinitely.
*/
private async fetchAndSendPendingPermissions(): Promise<void> {
if (!this.client) return
try {
const workspaceDir = this.getWorkspaceDirectory()
const { data } = await this.client.permission.list({ directory: workspaceDir })
if (!data) return
for (const perm of data) {
if (!this.trackedSessionIds.has(perm.sessionID)) continue
this.postMessage({
type: "permissionRequest",
permission: {
id: perm.id,
sessionID: perm.sessionID,
toolName: perm.permission,
patterns: perm.patterns,
args: perm.metadata,
message: `Permission required: ${perm.permission}`,
tool: perm.tool,
},
})
}
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to fetch pending permissions:", error)
}
}
@@ -169,6 +169,8 @@ export type WebviewMessage =
| { type: "todoUpdated"; sessionID: string; items: unknown[] }
| { type: "questionRequest"; question: { id: string; sessionID: string; questions: unknown[]; tool?: unknown } }
| { type: "questionResolved"; requestID: string }
| { type: "permissionResolved"; permissionID: string }
| { type: "permissionError"; permissionID: string }
| { type: "sessionCreated"; session: ReturnType<typeof sessionToWebview> }
| { type: "sessionUpdated"; session: ReturnType<typeof sessionToWebview> }
| null
@@ -228,6 +230,11 @@ export function mapSSEEventToWebviewMessage(event: Event, sessionID: string | un
tool: event.properties.tool,
},
}
case "permission.replied":
return {
type: "permissionResolved",
permissionID: event.properties.requestID,
}
case "todo.updated":
return {
type: "todoUpdated",
@@ -17,6 +17,7 @@ import type {
EventMessageUpdated,
EventSessionStatus,
EventPermissionAsked,
EventPermissionReplied,
EventTodoUpdated,
EventQuestionAsked,
EventQuestionReplied,
@@ -302,6 +303,42 @@ describe("mapSSEEventToWebviewMessage", () => {
}
})
it("maps permission.replied to permissionResolved", () => {
const event: EventPermissionReplied = {
type: "permission.replied",
properties: { sessionID: "sess-1", requestID: "perm-1", reply: "once" },
}
const msg = mapSSEEventToWebviewMessage(event, "sess-1")
expect(msg?.type).toBe("permissionResolved")
if (msg?.type === "permissionResolved") {
expect(msg.permissionID).toBe("perm-1")
}
})
it("maps permission.replied (always) to permissionResolved", () => {
const event: EventPermissionReplied = {
type: "permission.replied",
properties: { sessionID: "sess-1", requestID: "perm-2", reply: "always" },
}
const msg = mapSSEEventToWebviewMessage(event, "sess-1")
expect(msg?.type).toBe("permissionResolved")
if (msg?.type === "permissionResolved") {
expect(msg.permissionID).toBe("perm-2")
}
})
it("maps permission.replied (reject) to permissionResolved", () => {
const event: EventPermissionReplied = {
type: "permission.replied",
properties: { sessionID: "sess-1", requestID: "perm-3", reply: "reject" },
}
const msg = mapSSEEventToWebviewMessage(event, "sess-1")
expect(msg?.type).toBe("permissionResolved")
if (msg?.type === "permissionResolved") {
expect(msg.permissionID).toBe("perm-3")
}
})
it("maps todo.updated to todoUpdated", () => {
const event: EventTodoUpdated = {
type: "todo.updated",
@@ -8,11 +8,16 @@
* tool call rather than in the bottom dock.
*/
import { Component, For, Show, createMemo, createSignal } from "solid-js"
import { Component, For, Show, createMemo } from "solid-js"
import { Dynamic } from "solid-js/web"
import { Part, PART_MAPPING, ToolRegistry } from "@kilocode/kilo-ui/message-part"
import { Button } from "@kilocode/kilo-ui/button"
import type { AssistantMessage as SDKAssistantMessage, Part as SDKPart, Message as SDKMessage, ToolPart } from "@kilocode/sdk/v2"
import type {
AssistantMessage as SDKAssistantMessage,
Part as SDKPart,
Message as SDKMessage,
ToolPart,
} from "@kilocode/sdk/v2"
import { useData } from "@kilocode/kilo-ui/context/data"
import { useSession } from "../../context/session"
import { useLanguage } from "../../context/language"
@@ -101,13 +106,9 @@ export const AssistantMessage: Component<AssistantMessageProps> = (props) => {
// Questions linked to this message (rendered after the last part)
const questionForMessage = () => questions().find((q) => q.tool!.messageID === props.message.id)
const [responding, setResponding] = createSignal(false)
const decide = (permissionId: string, response: "once" | "always" | "reject") => {
if (responding()) return
setResponding(true)
if (session.respondingPermissions().has(permissionId)) return
session.respondToPermission(permissionId, response)
setResponding(false)
}
return (
@@ -117,7 +118,8 @@ export const AssistantMessage: Component<AssistantMessageProps> = (props) => {
const perm = () => permissionForPart(part)
// Upstream PART_MAPPING["tool"] returns null for todowrite/todoread,
// so we detect them here and render via ToolRegistry directly.
const isUpstreamSuppressed = part.type === "tool" && UPSTREAM_SUPPRESSED_TOOLS.has((part as SDKPart & { tool: string }).tool)
const isUpstreamSuppressed =
part.type === "tool" && UPSTREAM_SUPPRESSED_TOOLS.has((part as SDKPart & { tool: string }).tool)
return (
<Show when={isUpstreamSuppressed || PART_MAPPING[part.type]}>
<div data-component="tool-part-wrapper" data-permission={!!perm()} data-part-type={part.type}>
@@ -141,49 +143,49 @@ export const AssistantMessage: Component<AssistantMessageProps> = (props) => {
// For other tools: show patterns only if they're meaningful (not just '*')
const meaningfulPatterns = p.patterns.filter((pat) => pat !== "*")
return (
<div data-component="permission-prompt" onClick={(e: MouseEvent) => e.stopPropagation()}>
<Show when={!isTodoPerm && meaningfulPatterns.length > 0}>
<div class="permission-dock-patterns">
<For each={meaningfulPatterns}>
{(pattern) => <code class="permission-dock-pattern">{pattern}</code>}
</For>
<div data-component="permission-prompt" onClick={(e: MouseEvent) => e.stopPropagation()}>
<Show when={!isTodoPerm && meaningfulPatterns.length > 0}>
<div class="permission-dock-patterns">
<For each={meaningfulPatterns}>
{(pattern) => <code class="permission-dock-pattern">{pattern}</code>}
</For>
</div>
</Show>
<Show when={isTodoPerm}>
<p data-slot="permission-description">
{p.toolName === "todowrite"
? language.t("settings.permissions.tool.todowrite.description")
: language.t("settings.permissions.tool.todoread.description")}
</p>
</Show>
<div data-slot="permission-actions">
<Button
variant="ghost"
size="small"
onClick={() => decide(p.id, "reject")}
disabled={session.respondingPermissions().has(p.id)}
>
{language.t("ui.permission.deny")}
</Button>
<Button
variant="secondary"
size="small"
onClick={() => decide(p.id, "always")}
disabled={session.respondingPermissions().has(p.id)}
>
{language.t("ui.permission.allowAlways")}
</Button>
<Button
variant="primary"
size="small"
onClick={() => decide(p.id, "once")}
disabled={session.respondingPermissions().has(p.id)}
>
{language.t("ui.permission.allowOnce")}
</Button>
</div>
</Show>
<Show when={isTodoPerm}>
<p data-slot="permission-description">
{p.toolName === "todowrite"
? language.t("settings.permissions.tool.todowrite.description")
: language.t("settings.permissions.tool.todoread.description")}
</p>
</Show>
<div data-slot="permission-actions">
<Button
variant="ghost"
size="small"
onClick={() => decide(p.id, "reject")}
disabled={responding()}
>
{language.t("ui.permission.deny")}
</Button>
<Button
variant="secondary"
size="small"
onClick={() => decide(p.id, "always")}
disabled={responding()}
>
{language.t("ui.permission.allowAlways")}
</Button>
<Button
variant="primary"
size="small"
onClick={() => decide(p.id, "once")}
disabled={responding()}
>
{language.t("ui.permission.allowOnce")}
</Button>
<p data-slot="permission-hint">{language.t("ui.permission.sessionHint")}</p>
</div>
<p data-slot="permission-hint">{language.t("ui.permission.sessionHint")}</p>
</div>
)
}}
</Show>
@@ -3,7 +3,7 @@
* Main chat container that combines all chat components
*/
import { Component, For, Show, createSignal, createEffect, on, onCleanup, onMount } from "solid-js"
import { Component, For, Show, createEffect, on, onCleanup, onMount } from "solid-js"
import { Button } from "@kilocode/kilo-ui/button"
import { Icon } from "@kilocode/kilo-ui/icon"
import { BasicTool } from "@kilocode/kilo-ui/basic-tool"
@@ -54,8 +54,6 @@ export const ChatView: Component<ChatViewProps> = (props) => {
}),
)
const [responding, setResponding] = createSignal(false)
onMount(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === "Escape" && session.status() === "busy") {
@@ -69,10 +67,8 @@ export const ChatView: Component<ChatViewProps> = (props) => {
const decide = (response: "once" | "always" | "reject") => {
const perm = permissionRequest()
if (!perm || responding()) return
setResponding(true)
if (!perm || session.respondingPermissions().has(perm.id)) return
session.respondToPermission(perm.id, response)
setResponding(false)
}
return (
@@ -111,13 +107,28 @@ export const ChatView: Component<ChatViewProps> = (props) => {
</BasicTool>
<div data-component="permission-prompt">
<div data-slot="permission-actions">
<Button variant="ghost" size="small" onClick={() => decide("reject")} disabled={responding()}>
<Button
variant="ghost"
size="small"
onClick={() => decide("reject")}
disabled={session.respondingPermissions().has(perm.id)}
>
{language.t("ui.permission.deny")}
</Button>
<Button variant="secondary" size="small" onClick={() => decide("always")} disabled={responding()}>
<Button
variant="secondary"
size="small"
onClick={() => decide("always")}
disabled={session.respondingPermissions().has(perm.id)}
>
{language.t("ui.permission.allowAlways")}
</Button>
<Button variant="primary" size="small" onClick={() => decide("once")} disabled={responding()}>
<Button
variant="primary"
size="small"
onClick={() => decide("once")}
disabled={session.respondingPermissions().has(perm.id)}
>
{language.t("ui.permission.allowOnce")}
</Button>
</div>
@@ -151,9 +162,7 @@ export const ChatView: Component<ChatViewProps> = (props) => {
</Show>
</div>
</Show>
<Show when={!blocked()}>
<PromptInput />
</Show>
<PromptInput />
</div>
</Show>
</div>
@@ -8,6 +8,7 @@
*/
import { Component, For, Show, createEffect, createMemo, onCleanup, JSX } from "solid-js"
import { Icon } from "@kilocode/kilo-ui/icon"
import { Spinner } from "@kilocode/kilo-ui/spinner"
import { Button } from "@kilocode/kilo-ui/button"
import { useDialog } from "@kilocode/kilo-ui/context/dialog"
@@ -77,7 +78,6 @@ export const MessageList: Component<MessageListProps> = (props) => {
<div
ref={autoScroll.scrollRef}
onScroll={autoScroll.handleScroll}
onClick={autoScroll.handleInteraction}
class="message-list"
role="log"
aria-live="polite"
@@ -144,7 +144,7 @@ export const MessageList: Component<MessageListProps> = (props) => {
onClick={() => autoScroll.resume()}
aria-label={language.t("session.messages.scrollToBottom")}
>
↓
<Icon name="arrow-down-to-line" />
</button>
</Show>
</div>
@@ -1,28 +1,9 @@
import { Component, For, createMemo } from "solid-js"
import { Component, For, Show, createEffect, createMemo, createSignal } from "solid-js"
import { Select } from "@kilocode/kilo-ui/select"
import { Card } from "@kilocode/kilo-ui/card"
import { IconButton } from "@kilocode/kilo-ui/icon-button"
import { useConfig } from "../../context/config"
import { useLanguage } from "../../context/language"
import type { PermissionLevel } from "../../types/messages"
const TOOLS = [
"read",
"edit",
"glob",
"grep",
"list",
"bash",
"task",
"skill",
"lsp",
"todoread",
"todowrite",
"webfetch",
"websearch",
"codesearch",
"external_directory",
"doom_loop",
] as const
import type { PermissionLevel, PermissionRule } from "../../types/messages"
interface LevelOption {
value: PermissionLevel
@@ -35,104 +16,527 @@ const LEVEL_OPTIONS: LevelOption[] = [
{ value: "deny", labelKey: "settings.autoApprove.level.deny" },
]
interface GranularConfig {
wildcardKey: string
addKey: string
placeholderKey: string
}
interface ToolDef {
id: string
descriptionKey: string
granular?: GranularConfig
}
interface GranularToolDef extends ToolDef {
granular: GranularConfig
}
/** Grouped tool: maps a single UI row to multiple config keys */
interface GroupedToolDef {
ids: string[]
label: string
descriptionKey: string
}
const GRANULAR_TOOLS: GranularToolDef[] = [
{
id: "external_directory",
descriptionKey: "settings.autoApprove.tool.external_directory",
granular: {
wildcardKey: "settings.autoApprove.wildcardLabel.paths",
addKey: "settings.autoApprove.addPath",
placeholderKey: "settings.autoApprove.placeholder.path",
},
},
{
id: "bash",
descriptionKey: "settings.autoApprove.tool.bash",
granular: {
wildcardKey: "settings.autoApprove.wildcardLabel.commands",
addKey: "settings.autoApprove.addCommand",
placeholderKey: "settings.autoApprove.placeholder.command",
},
},
{
id: "read",
descriptionKey: "settings.autoApprove.tool.read",
granular: {
wildcardKey: "settings.autoApprove.wildcardLabel.paths",
addKey: "settings.autoApprove.addPath",
placeholderKey: "settings.autoApprove.placeholder.path",
},
},
{
id: "edit",
descriptionKey: "settings.autoApprove.tool.edit",
granular: {
wildcardKey: "settings.autoApprove.wildcardLabel.paths",
addKey: "settings.autoApprove.addPath",
placeholderKey: "settings.autoApprove.placeholder.path",
},
},
]
const SIMPLE_TOOLS: ToolDef[] = [
{ id: "glob", descriptionKey: "settings.autoApprove.tool.glob" },
{ id: "grep", descriptionKey: "settings.autoApprove.tool.grep" },
{ id: "list", descriptionKey: "settings.autoApprove.tool.list" },
{ id: "task", descriptionKey: "settings.autoApprove.tool.task" },
{ id: "skill", descriptionKey: "settings.autoApprove.tool.skill" },
{ id: "lsp", descriptionKey: "settings.autoApprove.tool.lsp" },
]
const GROUPED_TOOLS: GroupedToolDef[] = [
{
ids: ["todoread", "todowrite"],
label: "todoread / todowrite",
descriptionKey: "settings.autoApprove.tool.todoreadwrite",
},
{
ids: ["websearch", "codesearch"],
label: "websearch / codesearch",
descriptionKey: "settings.autoApprove.tool.websearchcodesearch",
},
]
const TRAILING_TOOLS: ToolDef[] = [
{ id: "webfetch", descriptionKey: "settings.autoApprove.tool.webfetch" },
{ id: "doom_loop", descriptionKey: "settings.autoApprove.tool.doom_loop" },
]
/**
* Backend default permission levels — mirrors the base defaults defined in
* packages/opencode/src/agent/agent.ts (lines 61-78). The global default
* is "*": "allow"; these are the per-tool overrides. If the backend defaults
* change, this map must be updated to match.
*/
const TOOL_DEFAULTS: Partial<Record<string, PermissionLevel>> = {
doom_loop: "ask",
external_directory: "ask",
}
const RESTRICTION_ORDER: Record<PermissionLevel, number> = { allow: 0, ask: 1, deny: 2 }
/** For grouped tools, return the most restrictive level across all IDs. */
function mostRestrictive(levels: PermissionLevel[]): PermissionLevel {
return levels.reduce<PermissionLevel>(
(best, l) => (RESTRICTION_ORDER[l] > RESTRICTION_ORDER[best] ? l : best),
levels[0] ?? "allow",
)
}
function wildcardAction(rule: PermissionRule | undefined, fallback: PermissionLevel): PermissionLevel {
if (!rule) return fallback
if (typeof rule === "string") return rule
return rule["*"] ?? fallback
}
function exceptions(rule: PermissionRule | undefined): Array<{ pattern: string; action: PermissionLevel }> {
if (!rule || typeof rule === "string") return []
return Object.entries(rule)
.filter(([key]) => key !== "*")
.map(([pattern, action]) => ({ pattern, action }))
}
function toolTitle(id: string): string {
return id
.split("_")
.map((word) => word[0].toUpperCase() + word.slice(1))
.join(" ")
.split(" / ")
.map((part) => part[0].toUpperCase() + part.slice(1))
.join(" / ")
}
const AutoApproveTab: Component = () => {
const { config, updateConfig } = useConfig()
const language = useLanguage()
const permissions = createMemo(() => config().permission ?? {})
const getLevel = (tool: string): PermissionLevel => {
return permissions()[tool] ?? permissions()["*"] ?? "ask"
const globalFallback = createMemo((): PermissionLevel => {
const star = permissions()["*"]
if (typeof star === "string") return star
return "allow" // backend default: "*": "allow" (agent.ts)
})
const defaultFor = (tool: string): PermissionLevel => TOOL_DEFAULTS[tool] ?? globalFallback()
const levelFor = (tool: string): PermissionLevel => wildcardAction(permissions()[tool], defaultFor(tool))
const ruleFor = (tool: string): PermissionRule | undefined => permissions()[tool]
const setSimple = (tool: string, level: PermissionLevel) => {
updateConfig({ permission: { [tool]: level } })
}
const setPermission = (tool: string, level: PermissionLevel) => {
updateConfig({
permission: { ...permissions(), [tool]: level },
})
const setGrouped = (ids: string[], level: PermissionLevel) => {
const patch: Record<string, PermissionLevel> = {}
for (const id of ids) patch[id] = level
updateConfig({ permission: patch })
}
const setAll = (level: PermissionLevel) => {
const updated: Record<string, PermissionLevel> = {}
for (const tool of TOOLS) {
updated[tool] = level
const setWildcard = (tool: string, level: PermissionLevel) => {
const current = ruleFor(tool)
const excs = exceptions(current)
if (excs.length === 0) {
updateConfig({ permission: { [tool]: level } })
return
}
const obj: Record<string, PermissionLevel> = { "*": level }
for (const exc of excs) obj[exc.pattern] = exc.action
updateConfig({ permission: { [tool]: obj } })
}
const setException = (tool: string, pattern: string, level: PermissionLevel) => {
const current = ruleFor(tool)
const base: Record<string, PermissionLevel> =
typeof current === "string" ? { "*": current } : { ...(current ?? {}) }
base[pattern] = level
updateConfig({ permission: { [tool]: base } })
}
const addException = (tool: string, pattern: string) => {
const current = ruleFor(tool)
const base: Record<string, PermissionLevel> =
typeof current === "string" ? { "*": current } : { ...(current ?? {}) }
base[pattern] = "allow"
updateConfig({ permission: { [tool]: base } })
}
const removeException = (tool: string, pattern: string) => {
const current = ruleFor(tool)
if (!current || typeof current === "string") return
const rebuilt: Record<string, PermissionLevel> = {}
for (const [k, v] of Object.entries(current)) {
if (k !== pattern) rebuilt[k] = v
}
const keys = Object.keys(rebuilt)
const fallback = defaultFor(tool)
const value: PermissionRule =
keys.length === 0 ? fallback : keys.length === 1 && keys[0] === "*" ? rebuilt["*"]! : rebuilt
// patchJsonc only sets keys present in the patch — it won't remove the deleted key
// from the JSONC file. To work around this, first set the tool to a plain string
// (which replaces the entire JSONC node), then immediately send the rebuilt object
// in a second call only when necessary.
// Both messages are dispatched synchronously before any reactive flush, so the
// second call always operates on the value we just computed — not on stale signal
// state — avoiding a race condition.
// Ideally when keys.length === 0 we'd remove the tool key entirely so it
// inherits the global default, but that requires backend support for null
// delete sentinels (tracked in #6625).
const wildcard = rebuilt["*"] ?? fallback
// Single call covers string and collapsed-to-string cases
updateConfig({ permission: { [tool]: wildcard } })
// Only send the second call when the result must remain an object
if (typeof value === "object") {
// This runs synchronously in the same microtask tick; the first updateConfig
// queues a JSONC node replacement, and this one immediately overwrites it with
// the full object — no intervening reactive update occurs.
updateConfig({ permission: { [tool]: value } })
}
updateConfig({ permission: updated })
}
return (
<div data-component="auto-approve-settings">
{/* Set All control */}
<Card>
<div
data-slot="settings-row"
style={{ display: "flex", "align-items": "center", "justify-content": "space-between", padding: "8px 0" }}
>
<span style={{ "font-weight": "600" }}>{language.t("settings.autoApprove.setAll")}</span>
<Select
options={LEVEL_OPTIONS}
value={(o) => o.value}
label={(o) => language.t(o.labelKey)}
onSelect={(option) => option && setAll(option.value)}
variant="secondary"
size="small"
triggerVariant="settings"
placeholder={language.t("common.choose")}
<div
style={{
"font-size": "12px",
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
"padding-bottom": "12px",
"border-bottom": "1px solid var(--border-weak-base)",
}}
>
{language.t("settings.autoApprove.description")}
</div>
<For each={GRANULAR_TOOLS}>
{(tool) => (
<GranularToolRow
tool={tool}
rule={ruleFor(tool.id)}
fallback={defaultFor(tool.id)}
onWildcardChange={(level) => setWildcard(tool.id, level)}
onExceptionChange={(pattern, level) => setException(tool.id, pattern, level)}
onExceptionAdd={(pattern) => addException(tool.id, pattern)}
onExceptionRemove={(pattern) => removeException(tool.id, pattern)}
/>
</div>
</Card>
)}
</For>
<div style={{ "margin-top": "12px" }} />
<For each={SIMPLE_TOOLS}>
{(tool) => (
<SimpleToolRow
id={tool.id}
descriptionKey={tool.descriptionKey}
level={levelFor(tool.id)}
onChange={(level) => setSimple(tool.id, level)}
/>
)}
</For>
{/* Tool permission list */}
<Card>
<For each={[...TOOLS]}>
{(tool, index) => (
<div
data-slot="settings-row"
style={{
display: "flex",
"align-items": "center",
"justify-content": "space-between",
padding: "8px 0",
"border-bottom": index() < TOOLS.length - 1 ? "1px solid var(--border-weak-base)" : "none",
}}
>
<div style={{ flex: 1, "min-width": 0 }}>
<div
style={{
"font-family": "var(--vscode-editor-font-family, monospace)",
"font-size": "12px",
"text-transform": "capitalize",
}}
>
{tool}
</div>
<div
style={{
"font-size": "12px",
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
"margin-top": "2px",
}}
>
{language.t(`settings.autoApprove.tool.${tool}`)}
</div>
</div>
<Select
options={LEVEL_OPTIONS}
current={LEVEL_OPTIONS.find((o) => o.value === getLevel(tool))}
value={(o) => o.value}
label={(o) => language.t(o.labelKey)}
onSelect={(option) => option && setPermission(tool, option.value)}
variant="secondary"
size="small"
triggerVariant="settings"
/>
</div>
)}
</For>
</Card>
<For each={GROUPED_TOOLS}>
{(group) => (
<SimpleToolRow
id={group.label}
descriptionKey={group.descriptionKey}
level={mostRestrictive(group.ids.map(levelFor))}
onChange={(level) => setGrouped(group.ids, level)}
/>
)}
</For>
<For each={TRAILING_TOOLS}>
{(tool) => (
<SimpleToolRow
id={tool.id}
descriptionKey={tool.descriptionKey}
level={levelFor(tool.id)}
onChange={(level) => setSimple(tool.id, level)}
/>
)}
</For>
</div>
)
}
const SimpleToolRow: Component<{
id: string
descriptionKey: string
level: PermissionLevel
onChange: (level: PermissionLevel) => void
}> = (props) => {
const language = useLanguage()
return (
<div
style={{
display: "flex",
gap: "24px",
"align-items": "flex-start",
"justify-content": "space-between",
padding: "12px 0",
"border-bottom": "1px solid var(--border-weak-base)",
}}
>
<div style={{ flex: 1, "min-width": 0 }}>
<div style={{ "font-size": "13px", color: "var(--text-strong-base, white)" }}>{toolTitle(props.id)}</div>
<div
style={{
"font-size": "12px",
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
"margin-top": "6px",
}}
>
{language.t(props.descriptionKey)}
</div>
</div>
<ActionSelect level={props.level} onChange={props.onChange} />
</div>
)
}
const GranularToolRow: Component<{
tool: GranularToolDef
rule: PermissionRule | undefined
fallback: PermissionLevel
onWildcardChange: (level: PermissionLevel) => void
onExceptionChange: (pattern: string, level: PermissionLevel) => void
onExceptionAdd: (pattern: string) => void
onExceptionRemove: (pattern: string) => void
}> = (props) => {
const language = useLanguage()
const [adding, setAdding] = createSignal(false)
const [input, setInput] = createSignal("")
let inputRef: HTMLInputElement | undefined
createEffect(() => {
if (adding()) inputRef?.focus()
})
const excs = createMemo(() => exceptions(props.rule))
const level = createMemo(() => wildcardAction(props.rule, props.fallback))
const submit = () => {
const val = input().trim()
if (val) {
props.onExceptionAdd(val)
setInput("")
}
setAdding(false)
}
const cancel = () => {
setInput("")
setAdding(false)
}
return (
<div style={{ padding: "12px 0", "border-bottom": "1px solid var(--border-weak-base)" }}>
{/* Tool header with name and description */}
<div style={{ display: "flex", gap: "24px", "align-items": "flex-start", "justify-content": "space-between" }}>
<div style={{ flex: 1, "min-width": 0 }}>
<div style={{ "font-size": "13px", color: "var(--text-strong-base, white)" }}>{toolTitle(props.tool.id)}</div>
<div
style={{
"font-size": "12px",
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
"margin-top": "6px",
}}
>
{language.t(props.tool.descriptionKey)}
</div>
</div>
</div>
{/* Wildcard row */}
<div
style={{
display: "flex",
gap: "24px",
"align-items": "center",
"justify-content": "space-between",
padding: "8px 0",
}}
>
<div style={{ flex: 1, "min-width": 0 }}>
<div style={{ "font-size": "12px", color: "var(--text-base, #ccc)" }}>
{language.t(props.tool.granular.wildcardKey)}
</div>
</div>
<ActionSelect level={level()} onChange={props.onWildcardChange} />
</div>
{/* Exceptions */}
<Show when={excs().length > 0}>
<div style={{ "margin-top": "4px" }}>
<div
style={{
"font-size": "12px",
color: "var(--text-weak-base, var(--vscode-descriptionForeground))",
"margin-bottom": "4px",
}}
>
{language.t("settings.autoApprove.exceptions")}
</div>
<For each={excs()}>
{(exc) => (
<div
style={{
display: "flex",
gap: "8px",
"align-items": "center",
padding: "4px 0",
"padding-left": "12px",
"border-top": "1px solid var(--border-weak-base)",
}}
>
<div
style={{
flex: "1 1 0%",
"min-width": 0,
"font-size": "13px",
"font-family": "var(--vscode-editor-font-family, monospace)",
color: "var(--text-base, #ccc)",
overflow: "hidden",
"text-overflow": "ellipsis",
"white-space": "nowrap",
}}
title={exc.pattern}
>
{exc.pattern}
</div>
<div style={{ display: "flex", gap: "4px", "align-items": "center", "flex-shrink": 0 }}>
<ActionSelect level={exc.action} onChange={(level) => props.onExceptionChange(exc.pattern, level)} />
<IconButton
variant="ghost"
size="small"
icon="close"
onClick={() => props.onExceptionRemove(exc.pattern)}
/>
</div>
</div>
)}
</For>
</div>
</Show>
{/* Add button / inline input */}
<Show
when={adding()}
fallback={
<button
style={{
display: "flex",
gap: "4px",
"align-items": "center",
padding: "4px 0",
background: "none",
border: "none",
cursor: "pointer",
"font-size": "12px",
color: "var(--text-link-base, #3794ff)",
"font-family": "inherit",
"margin-top": "4px",
}}
onClick={() => setAdding(true)}
>
<span style={{ "font-size": "14px" }}>+</span>
{language.t(props.tool.granular.addKey)}
</button>
}
>
<div style={{ display: "flex", gap: "8px", "align-items": "center", "margin-top": "4px" }}>
<input
ref={(el) => (inputRef = el)}
type="text"
value={input()}
onInput={(e) => setInput(e.currentTarget.value)}
onKeyDown={(e) => {
if (e.key === "Enter") submit()
if (e.key === "Escape") cancel()
}}
onBlur={() => {
if (!input().trim()) cancel()
}}
placeholder={language.t(props.tool.granular.placeholderKey)}
style={{
flex: 1,
"min-width": 0,
background: "var(--surface-strong-base, #252526)",
border: "1px solid var(--border-base, #434443)",
"border-radius": "2px",
color: "var(--text-base, #ccc)",
"font-size": "13px",
"font-family": "var(--vscode-editor-font-family, monospace)",
padding: "4px 8px",
outline: "none",
}}
/>
<IconButton variant="ghost" size="small" icon="close" onClick={cancel} />
</div>
</Show>
</div>
)
}
const ActionSelect: Component<{
level: PermissionLevel
onChange: (level: PermissionLevel) => void
}> = (props) => {
const language = useLanguage()
return (
<Select
options={LEVEL_OPTIONS}
current={LEVEL_OPTIONS.find((o) => o.value === props.level)}
value={(o) => o.value}
label={(o) => language.t(o.labelKey)}
onSelect={(option) => option && props.onChange(option.value)}
variant="secondary"
size="small"
triggerVariant="settings"
/>
)
}
export default AutoApproveTab
@@ -71,8 +71,17 @@ export const WorkingIndicator: Component = () => {
return `${m}m ${rem}s`
}
const blocked = () => {
const id = session.currentSessionID()
const perms = session
.permissions()
.filter((p) => p.sessionID === id && !(p.tool && ["todowrite", "todoread"].includes(p.toolName)))
const questions = session.questions().filter((q) => q.sessionID === id)
return perms.length > 0 || questions.length > 0
}
return (
<Show when={session.status() !== "idle"}>
<Show when={session.status() !== "idle" && !blocked()}>
<div class="working-indicator">
<Spinner />
<span class="working-text">{statusText()}</span>
@@ -92,6 +92,7 @@ interface SessionContextValue {
// Pending permission requests
permissions: Accessor<PermissionRequest[]>
respondingPermissions: Accessor<Set<string>>
// Pending question requests
questions: Accessor<QuestionRequest[]>
@@ -175,6 +176,9 @@ export const SessionProvider: ParentComponent = (props) => {
// Pending permissions
const [permissions, setPermissions] = createSignal<PermissionRequest[]>([])
// Permission IDs that have been responded to but not yet confirmed by the server
const [respondingPermissions, setRespondingPermissions] = createSignal<Set<string>>(new Set())
// Pending questions
const [questions, setQuestions] = createSignal<QuestionRequest[]>([])
@@ -395,6 +399,14 @@ export const SessionProvider: ParentComponent = (props) => {
handlePermissionRequest(message.permission)
break
case "permissionResolved":
handlePermissionResolved(message.permissionID)
break
case "permissionError":
handlePermissionError(message.permissionID)
break
case "todoUpdated":
handleTodoUpdated(message.sessionID, message.items)
break
@@ -601,6 +613,30 @@ export const SessionProvider: ParentComponent = (props) => {
setPermissions((prev) => upsertPermission(prev, permission))
}
function handlePermissionResolved(permissionID: string) {
setPermissions((prev) => prev.filter((p) => p.id !== permissionID))
setRespondingPermissions((prev) => {
if (!prev.has(permissionID)) return prev
const next = new Set(prev)
next.delete(permissionID)
return next
})
}
function handlePermissionError(permissionID: string) {
// Remove from responding set so buttons re-enable (permission prompt is still visible)
setRespondingPermissions((prev) => {
if (!prev.has(permissionID)) return prev
const next = new Set(prev)
next.delete(permissionID)
return next
})
showToast({
variant: "error",
title: language.t("settings.permissions.toast.updateFailed.title"),
})
}
function handleQuestionRequest(question: QuestionRequest) {
setQuestions((prev) => {
const idx = prev.findIndex((q) => q.id === question.id)
@@ -904,15 +940,16 @@ export const SessionProvider: ParentComponent = (props) => {
const permission = permissions().find((p) => p.id === permissionId)
const sessionID = permission?.sessionID ?? currentSessionID() ?? ""
// Mark as responding so the UI disables the buttons.
// The permission is removed when the server confirms via permission.replied SSE.
setRespondingPermissions((prev) => new Set(prev).add(permissionId))
vscode.postMessage({
type: "permissionResponse",
permissionId,
sessionID,
response,
})
// Remove from pending permissions
setPermissions((prev) => prev.filter((p) => p.id !== permissionId))
}
function clearQuestionError(requestID: string) {
@@ -957,6 +994,7 @@ export const SessionProvider: ParentComponent = (props) => {
setCloudPreviewId(null)
setLoading(false)
setPermissions([])
setRespondingPermissions(new Set<string>())
setQuestions([])
setQuestionErrors(new Set<string>())
setPendingAgentSelection(defaultAgent())
@@ -1097,6 +1135,7 @@ export const SessionProvider: ParentComponent = (props) => {
getParts,
todos,
permissions,
respondingPermissions,
questions,
questionErrors,
selected,
+24 -17
View File
@@ -935,26 +935,33 @@ export const dict = {
"settings.agentBehaviour.mcpEmpty": "لم يتم تهيئة خوادم MCP. قم بتحرير ملف تهيئة opencode لإضافة خوادم MCP.",
"settings.agentBehaviour.workflowsPlaceholder": "تُدار سير العمل عبر ملفات سير العمل في مساحة العمل.",
"settings.agentBehaviour.notImplemented": "لم يتم التنفيذ بعد.",
"settings.autoApprove.setAll": "تعيين جميع الأذونات",
"settings.autoApprove.description":
"تحديد كيفية السماح بتشغيل الأدوات. معظم الأدوات معينة افتراضياً على السماح. doom_loop و external_directory معينة افتراضياً على السؤال.",
"settings.autoApprove.level.allow": "سماح",
"settings.autoApprove.level.ask": "سؤال",
"settings.autoApprove.level.deny": "رفض",
"settings.autoApprove.tool.read": "قراءة محتويات الملفات",
"settings.autoApprove.tool.edit": "تحرير أو إنشاء الملفات",
"settings.autoApprove.tool.glob": "البحث عن ملفات بنمط",
"settings.autoApprove.tool.grep": "البحث في محتويات الملفات",
"settings.autoApprove.tool.list": "عرض محتويات المجلد",
"settings.autoApprove.tool.bash": "تنفيذ أوامر الصدفة",
"settings.autoApprove.tool.task": "إنشاء مهام وكيل فرعي",
"settings.autoApprove.tool.skill": "تنفيذ المهارات",
"settings.autoApprove.tool.lsp": "عمليات خادم اللغة",
"settings.autoApprove.tool.todoread": "قراءة قوائم المهام",
"settings.autoApprove.tool.todowrite": "كتابة قوائم المهام",
"settings.autoApprove.tool.webfetch": "جلب صفحات الويب",
"settings.autoApprove.tool.websearch": "البحث في الويب",
"settings.autoApprove.tool.codesearch": "البحث في قاعدة الكود",
"settings.autoApprove.tool.external_directory": "الوصول للملفات خارج مساحة العمل",
"settings.autoApprove.tool.doom_loop": "المتابعة بعد الإخفاقات المتكررة",
"settings.autoApprove.wildcardLabel.commands": "جميع الأوامر (*)",
"settings.autoApprove.wildcardLabel.paths": "جميع المسارات (*)",
"settings.autoApprove.exceptions": "الاستثناءات",
"settings.autoApprove.addCommand": "إضافة أمر",
"settings.autoApprove.addPath": "إضافة مسار",
"settings.autoApprove.placeholder.command": "مثال: git *",
"settings.autoApprove.placeholder.path": "مثال: *.env",
"settings.autoApprove.tool.read": "قراءة الملفات. يسمح للوكيل بقراءة الملفات التي تطابق المسار المحدد.",
"settings.autoApprove.tool.edit": "تعديل الملفات. يسمح للوكيل بإنشاء أو تحرير الملفات، بما في ذلك التصحيحات والتحديثات متعددة الملفات.",
"settings.autoApprove.tool.glob": "مطابقة الملفات بالنمط. يسمح بمطابقة الملفات باستخدام أنماط glob (مثل src/**/*.ts).",
"settings.autoApprove.tool.grep": "البحث في محتويات الملفات. يسمح بالبحث المستند إلى التعبيرات النمطية (regex) داخل الملفات.",
"settings.autoApprove.tool.list": "عرض محتويات المجلد. يسمح بعرض الملفات والمجلدات داخل الدليل.",
"settings.autoApprove.tool.bash": "تنفيذ أوامر الطرفية. يسمح بتنفيذ أوامر الصدفة (مثل git status).",
"settings.autoApprove.tool.task": "إطلاق وكلاء فرعيين. يسمح ببدء وكلاء فرعيين متخصصين لمهام محددة.",
"settings.autoApprove.tool.skill": "تحميل المهارات. يسمح بتحميل المهارات المحددة مسبقًا بالاسم.",
"settings.autoApprove.tool.lsp": "الاستعلام من خادم اللغة. يسمح بتشغيل استعلامات خادم اللغة لذكاء الكود.",
"settings.autoApprove.tool.todoreadwrite": "إدارة قائمة المهام. يسمح بقراءة وتحديث قائمة المهام الداخلية.",
"settings.autoApprove.tool.webfetch": "جلب رابط ويب. يسمح باسترداد المحتوى من رابط (URL) محدد.",
"settings.autoApprove.tool.websearchcodesearch":
"البحث في الويب أو الكود. يسمح بإجراء عمليات بحث خارجية في الويب أو الكود.",
"settings.autoApprove.tool.external_directory": "الوصول للملفات خارج مساحة العمل. يتم تشغيله عند الوصول إلى ملفات خارج مسار المشروع الحالي.",
"settings.autoApprove.tool.doom_loop": "منع الإجراءات المتطابقة المتكررة. يتم تشغيله عندما يتكرر نفس استدعاء الأداة بمدخلات متطابقة.",
"settings.checkpoints.enable.title": "تمكين اللقطات",
"settings.checkpoints.enable.description": "إنشاء نقاط فحص قبل تحرير الملفات",
"settings.context.autoCompaction.title": "ضغط تلقائي",
+25 -17
View File
@@ -949,26 +949,34 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder":
"Fluxos de trabalho são gerenciados por arquivos de fluxo de trabalho no espaço de trabalho.",
"settings.agentBehaviour.notImplemented": "Ainda não implementado.",
"settings.autoApprove.setAll": "Definir todas as permissões",
"settings.autoApprove.description":
"Defina como as ferramentas têm permissão para serem executadas. A maioria das ferramentas tem o padrão Permitir. doom_loop e external_directory têm o padrão Perguntar.",
"settings.autoApprove.level.allow": "Permitir",
"settings.autoApprove.level.ask": "Perguntar",
"settings.autoApprove.level.deny": "Negar",
"settings.autoApprove.tool.read": "Ler conteúdo de arquivos",
"settings.autoApprove.tool.edit": "Editar ou criar arquivos",
"settings.autoApprove.tool.glob": "Encontrar arquivos por padrão",
"settings.autoApprove.tool.grep": "Pesquisar conteúdo de arquivos",
"settings.autoApprove.tool.list": "Listar conteúdo do diretório",
"settings.autoApprove.tool.bash": "Executar comandos shell",
"settings.autoApprove.tool.task": "Criar tarefas de sub-agente",
"settings.autoApprove.tool.skill": "Executar habilidades",
"settings.autoApprove.tool.lsp": "Operações do servidor de linguagem",
"settings.autoApprove.tool.todoread": "Ler listas de tarefas",
"settings.autoApprove.tool.todowrite": "Escrever listas de tarefas",
"settings.autoApprove.tool.webfetch": "Buscar páginas web",
"settings.autoApprove.tool.websearch": "Pesquisar na web",
"settings.autoApprove.tool.codesearch": "Pesquisar no código",
"settings.autoApprove.tool.external_directory": "Acessar arquivos fora do espaço de trabalho",
"settings.autoApprove.tool.doom_loop": "Continuar após falhas repetidas",
"settings.autoApprove.wildcardLabel.commands": "Todos os comandos (*)",
"settings.autoApprove.wildcardLabel.paths": "Todos os caminhos (*)",
"settings.autoApprove.exceptions": "Exceções",
"settings.autoApprove.addCommand": "Adicionar comando",
"settings.autoApprove.addPath": "Adicionar caminho",
"settings.autoApprove.placeholder.command": "ex. git *",
"settings.autoApprove.placeholder.path": "ex. *.env",
"settings.autoApprove.tool.read": "Ler arquivos. Permite que o agente leia arquivos correspondentes ao caminho especificado.",
"settings.autoApprove.tool.edit": "Modificar arquivos. Permite que o agente crie ou edite arquivos, incluindo patches e atualizações de múltiplos arquivos.",
"settings.autoApprove.tool.glob": "Corresponder arquivos por padrão. Permite a correspondência de arquivos usando padrões glob (ex: src/**/*.ts).",
"settings.autoApprove.tool.grep": "Pesquisar conteúdo de arquivos. Permite a pesquisa baseada em regex dentro de arquivos.",
"settings.autoApprove.tool.list": "Listar conteúdo de diretórios. Permite visualizar arquivos e pastas dentro de um diretório.",
"settings.autoApprove.tool.bash": "Executar comandos de terminal. Permite a execução de comandos shell (ex: git status).",
"settings.autoApprove.tool.task": "Iniciar subagentes. Permite iniciar subagentes especializados para tarefas específicas.",
"settings.autoApprove.tool.skill": "Carregar habilidades. Permite carregar habilidades predefinidas pelo nome.",
"settings.autoApprove.tool.lsp": "Consultar language server. Permite executar consultas ao servidor de linguagem para inteligência de código.",
"settings.autoApprove.tool.todoreadwrite":
"Gerenciar lista de tarefas. Permite ler e atualizar a lista de tarefas interna.",
"settings.autoApprove.tool.webfetch": "Buscar uma URL. Permite recuperar o conteúdo de uma URL específica.",
"settings.autoApprove.tool.websearchcodesearch":
"Pesquisar na web ou no código. Permite realizar pesquisas externas na web ou no código.",
"settings.autoApprove.tool.external_directory": "Acessar arquivos fora do workspace. Acionado ao acessar arquivos fora do diretório do projeto atual.",
"settings.autoApprove.tool.doom_loop": "Prevenir ações idênticas repetidas. Acionado quando a mesma chamada de ferramenta se repete com entrada idêntica.",
"settings.checkpoints.enable.title": "Ativar snapshots",
"settings.checkpoints.enable.description": "Criar pontos de verificação antes de editar arquivos",
"settings.context.autoCompaction.title": "Compactação automática",
+25 -17
View File
@@ -948,26 +948,34 @@ export const dict = {
"Nema konfiguriranih MCP servera. Uredite konfiguracijsku datoteku opencode za dodavanje MCP servera.",
"settings.agentBehaviour.workflowsPlaceholder": "Tokovi rada se upravljaju putem datoteka tokova rada.",
"settings.agentBehaviour.notImplemented": "Još nije implementirano.",
"settings.autoApprove.setAll": "Postavi sve dozvole",
"settings.autoApprove.description":
"Definišite kako je dozvoljeno pokretanje alata. Većina alata je podrazumijevano na Dozvoli. doom_loop i external_directory su podrazumijevano na Pitaj.",
"settings.autoApprove.level.allow": "Dozvoli",
"settings.autoApprove.level.ask": "Pitaj",
"settings.autoApprove.level.deny": "Odbij",
"settings.autoApprove.tool.read": "Čitanje sadržaja datoteka",
"settings.autoApprove.tool.edit": "Uređivanje ili kreiranje datoteka",
"settings.autoApprove.tool.glob": "Pronalaženje datoteka po uzorku",
"settings.autoApprove.tool.grep": "Pretraživanje sadržaja datoteka",
"settings.autoApprove.tool.list": "Prikaz sadržaja direktorija",
"settings.autoApprove.tool.bash": "Pokretanje shell naredbi",
"settings.autoApprove.tool.task": "Kreiranje podzadataka agenta",
"settings.autoApprove.tool.skill": "Pokretanje vještina",
"settings.autoApprove.tool.lsp": "Operacije jezičkog servera",
"settings.autoApprove.tool.todoread": "Čitanje popisa zadataka",
"settings.autoApprove.tool.todowrite": "Pisanje popisa zadataka",
"settings.autoApprove.tool.webfetch": "Dohvaćanje web stranica",
"settings.autoApprove.tool.websearch": "Pretraživanje weba",
"settings.autoApprove.tool.codesearch": "Pretraživanje baze koda",
"settings.autoApprove.tool.external_directory": "Pristup datotekama izvan radnog prostora",
"settings.autoApprove.tool.doom_loop": "Nastavi nakon ponovljenih neuspjeha",
"settings.autoApprove.wildcardLabel.commands": "Sve komande (*)",
"settings.autoApprove.wildcardLabel.paths": "Sve putanje (*)",
"settings.autoApprove.exceptions": "Izuzeci",
"settings.autoApprove.addCommand": "Dodaj komandu",
"settings.autoApprove.addPath": "Dodaj putanju",
"settings.autoApprove.placeholder.command": "npr. git *",
"settings.autoApprove.placeholder.path": "npr. *.env",
"settings.autoApprove.tool.read": "Čitanje datoteka. Omogućava agentu da čita datoteke koje odgovaraju navedenoj putanji.",
"settings.autoApprove.tool.edit": "Izmjena datoteka. Omogućava agentu da kreira ili uređuje datoteke, uključujući zakrpe i ažuriranja više datoteka.",
"settings.autoApprove.tool.glob": "Podudaranje datoteka po uzorku. Omogućava podudaranje datoteka koristeći glob uzorke (npr. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Pretraživanje sadržaja datoteka. Omogućava pretraživanje zasnovano na regex-u unutar datoteka.",
"settings.autoApprove.tool.list": "Prikaz sadržaja direktorija. Omogućava pregled datoteka i fascikli unutar direktorija.",
"settings.autoApprove.tool.bash": "Pokretanje terminalskih komandi. Omogućava izvršavanje shell komandi (npr. git status).",
"settings.autoApprove.tool.task": "Pokretanje pod-agenata. Omogućava pokretanje specijalizovanih pod-agenata za određene zadatke.",
"settings.autoApprove.tool.skill": "Učitavanje vještina. Omogućava učitavanje unaprijed definisanih vještina po imenu.",
"settings.autoApprove.tool.lsp": "Upit ka jezičkom serveru. Omogućava pokretanje upita jezičkom serveru za analizu koda.",
"settings.autoApprove.tool.todoreadwrite":
"Upravljanje listom zadataka. Dozvoljava čitanje i ažuriranje interne liste zadataka.",
"settings.autoApprove.tool.webfetch": "Preuzimanje URL-a. Omogućava preuzimanje sadržaja sa određenog URL-a.",
"settings.autoApprove.tool.websearchcodesearch":
"Pretraga weba ili koda. Dozvoljava izvršavanje eksternih pretraga weba ili koda.",
"settings.autoApprove.tool.external_directory": "Pristup datotekama izvan radnog prostora. Pokreće se prilikom pristupa datotekama izvan trenutnog direktorija projekta.",
"settings.autoApprove.tool.doom_loop": "Sprečavanje ponavljanja identičnih radnji. Pokreće se kada se isti poziv alata ponovi sa identičnim unosom.",
"settings.checkpoints.enable.title": "Omogući snimke",
"settings.checkpoints.enable.description": "Kreiraj kontrolne točke prije uređivanja datoteka",
"settings.context.autoCompaction.title": "Automatska kompresija",
+25 -17
View File
@@ -944,26 +944,34 @@ export const dict = {
"Ingen MCP-servere konfigureret. Rediger opencode-konfigurationsfilen for at tilføje MCP-servere.",
"settings.agentBehaviour.workflowsPlaceholder": "Workflows administreres via workflow-filer i dit arbejdsområde.",
"settings.agentBehaviour.notImplemented": "Endnu ikke implementeret.",
"settings.autoApprove.setAll": "Indstil alle tilladelser",
"settings.autoApprove.description":
"Definer, hvordan værktøjer må køre. De fleste værktøjer er som standard indstillet til Tillad. doom_loop og external_directory er som standard indstillet til Spørg.",
"settings.autoApprove.level.allow": "Tillad",
"settings.autoApprove.level.ask": "Spørg",
"settings.autoApprove.level.deny": "Afvis",
"settings.autoApprove.tool.read": "Læs filindhold",
"settings.autoApprove.tool.edit": "Rediger eller opret filer",
"settings.autoApprove.tool.glob": "Find filer efter mønster",
"settings.autoApprove.tool.grep": "Søg i filindhold",
"settings.autoApprove.tool.list": "List mappeindhold",
"settings.autoApprove.tool.bash": "Udfør shell-kommandoer",
"settings.autoApprove.tool.task": "Opret underagentopgaver",
"settings.autoApprove.tool.skill": "Udfør skills",
"settings.autoApprove.tool.lsp": "Sprogserveroperationer",
"settings.autoApprove.tool.todoread": "Læs opgavelister",
"settings.autoApprove.tool.todowrite": "Skriv opgavelister",
"settings.autoApprove.tool.webfetch": "Hent websider",
"settings.autoApprove.tool.websearch": "Søg på nettet",
"settings.autoApprove.tool.codesearch": "Søg i kodebasen",
"settings.autoApprove.tool.external_directory": "Adgang til filer uden for arbejdsområdet",
"settings.autoApprove.tool.doom_loop": "Fortsæt efter gentagne fejl",
"settings.autoApprove.wildcardLabel.commands": "Alle kommandoer (*)",
"settings.autoApprove.wildcardLabel.paths": "Alle stier (*)",
"settings.autoApprove.exceptions": "Undtagelser",
"settings.autoApprove.addCommand": "Tilføj kommando",
"settings.autoApprove.addPath": "Tilføj sti",
"settings.autoApprove.placeholder.command": "f.eks. git *",
"settings.autoApprove.placeholder.path": "f.eks. *.env",
"settings.autoApprove.tool.read": "Læs filer. Tillader agenten at læse filer, der matcher den angivne sti.",
"settings.autoApprove.tool.edit": "Rediger filer. Tillader agenten at oprette eller redigere filer, herunder patches og opdateringer af flere filer.",
"settings.autoApprove.tool.glob": "Find filer efter mønster. Tillader filsøgning ved hjælp af glob-mønstre (f.eks. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Søg i filindhold. Tillader regex-baseret søgning i filer.",
"settings.autoApprove.tool.list": "Vis mappeindhold. Tillader visning af filer og mapper i en mappe.",
"settings.autoApprove.tool.bash": "Kør terminalkommandoer. Tillader udførelse af shell-kommandoer (f.eks. git status).",
"settings.autoApprove.tool.task": "Start underagenter. Tillader start af specialiserede underagenter til specifikke opgaver.",
"settings.autoApprove.tool.skill": "Indlæs færdigheder. Tillader indlæsning af foruddefinerede færdigheder efter navn.",
"settings.autoApprove.tool.lsp": "Forespørg sprogserver. Tillader kørsel af sprogserverforespørgsler til kodeintelligens.",
"settings.autoApprove.tool.todoreadwrite":
"Administrer opgaveliste. Tillader læsning og opdatering af den interne opgaveliste.",
"settings.autoApprove.tool.webfetch": "Hent en URL. Tillader hentning af indhold fra en specifik URL.",
"settings.autoApprove.tool.websearchcodesearch":
"Søg på nettet eller i kode. Tillader udførelse af eksterne web- eller kodesøgninger.",
"settings.autoApprove.tool.external_directory": "Få adgang til filer uden for arbejdsområdet. Udløses ved adgang til filer uden for den aktuelle projektmappe.",
"settings.autoApprove.tool.doom_loop": "Forhindr gentagne identiske handlinger. Udløses, når det samme værktøjskald gentages med identisk input.",
"settings.checkpoints.enable.title": "Aktiver snapshots",
"settings.checkpoints.enable.description": "Opret kontrolpunkter før filredigeringer",
"settings.context.autoCompaction.title": "Automatisk komprimering",
+25 -17
View File
@@ -960,26 +960,34 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder":
"Workflows werden über Workflow-Dateien in Ihrem Arbeitsbereich verwaltet.",
"settings.agentBehaviour.notImplemented": "Noch nicht implementiert.",
"settings.autoApprove.setAll": "Alle Berechtigungen festlegen",
"settings.autoApprove.description":
"Legen Sie fest, wie Tools ausgeführt werden dürfen. Die meisten Tools sind standardmäßig auf Zulassen eingestellt. doom_loop und external_directory sind standardmäßig auf Fragen eingestellt.",
"settings.autoApprove.level.allow": "Erlauben",
"settings.autoApprove.level.ask": "Fragen",
"settings.autoApprove.level.deny": "Ablehnen",
"settings.autoApprove.tool.read": "Dateiinhalte lesen",
"settings.autoApprove.tool.edit": "Dateien bearbeiten oder erstellen",
"settings.autoApprove.tool.glob": "Dateien nach Muster suchen",
"settings.autoApprove.tool.grep": "Dateiinhalte durchsuchen",
"settings.autoApprove.tool.list": "Verzeichnisinhalte auflisten",
"settings.autoApprove.tool.bash": "Shell-Befehle ausführen",
"settings.autoApprove.tool.task": "Unter-Agent-Aufgaben erstellen",
"settings.autoApprove.tool.skill": "Skills ausführen",
"settings.autoApprove.tool.lsp": "Sprachserver-Operationen",
"settings.autoApprove.tool.todoread": "Aufgabenlisten lesen",
"settings.autoApprove.tool.todowrite": "Aufgabenlisten schreiben",
"settings.autoApprove.tool.webfetch": "Webseiten abrufen",
"settings.autoApprove.tool.websearch": "Im Web suchen",
"settings.autoApprove.tool.codesearch": "Codebasis durchsuchen",
"settings.autoApprove.tool.external_directory": "Auf Dateien außerhalb des Arbeitsbereichs zugreifen",
"settings.autoApprove.tool.doom_loop": "Nach wiederholten Fehlern fortfahren",
"settings.autoApprove.wildcardLabel.commands": "Alle Befehle (*)",
"settings.autoApprove.wildcardLabel.paths": "Alle Pfade (*)",
"settings.autoApprove.exceptions": "Ausnahmen",
"settings.autoApprove.addCommand": "Befehl hinzufügen",
"settings.autoApprove.addPath": "Pfad hinzufügen",
"settings.autoApprove.placeholder.command": "z. B. git *",
"settings.autoApprove.placeholder.path": "z. B. *.env",
"settings.autoApprove.tool.read": "Dateien lesen. Erlaubt dem Agenten, Dateien zu lesen, die dem angegebenen Pfad entsprechen.",
"settings.autoApprove.tool.edit": "Dateien ändern. Erlaubt dem Agenten, Dateien zu erstellen oder zu bearbeiten, einschließlich Patches und Aktualisierungen mehrerer Dateien.",
"settings.autoApprove.tool.glob": "Dateien nach Muster abgleichen. Erlaubt den Dateiabgleich mithilfe von Glob-Mustern (z. B. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Dateiinhalte durchsuchen. Erlaubt Regex-basierte Suchen innerhalb von Dateien.",
"settings.autoApprove.tool.list": "Verzeichnisinhalte auflisten. Erlaubt das Anzeigen von Dateien und Ordnern innerhalb eines Verzeichnisses.",
"settings.autoApprove.tool.bash": "Terminalbefehle ausführen. Erlaubt die Ausführung von Shell-Befehlen (z. B. git status).",
"settings.autoApprove.tool.task": "Sub-Agenten starten. Erlaubt das Starten spezialisierter Sub-Agenten für bestimmte Aufgaben.",
"settings.autoApprove.tool.skill": "Fähigkeiten laden. Erlaubt das Laden vordefinierter Fähigkeiten nach Namen.",
"settings.autoApprove.tool.lsp": "Sprachserver abfragen. Erlaubt das Ausführen von Sprachserver-Abfragen für Code-Intelligenz.",
"settings.autoApprove.tool.todoreadwrite":
"Aufgabenliste verwalten. Ermöglicht das Lesen und Aktualisieren der internen Aufgabenliste.",
"settings.autoApprove.tool.webfetch": "URL abrufen. Erlaubt das Abrufen von Inhalten einer bestimmten URL.",
"settings.autoApprove.tool.websearchcodesearch":
"Web oder Code durchsuchen. Ermöglicht die Durchführung externer Web- oder Code-Suchen.",
"settings.autoApprove.tool.external_directory": "Zugriff auf Dateien außerhalb des Arbeitsbereichs. Wird ausgelöst, wenn auf Dateien außerhalb des aktuellen Projektverzeichnisses zugegriffen wird.",
"settings.autoApprove.tool.doom_loop": "Wiederholte identische Aktionen verhindern. Wird ausgelöst, wenn sich derselbe Werkzeugaufruf mit identischer Eingabe wiederholt.",
"settings.checkpoints.enable.title": "Snapshots aktivieren",
"settings.checkpoints.enable.description":
"Prüfpunkte vor Dateibearbeitungen erstellen, um vorherige Zustände wiederherstellen zu können",
+29 -17
View File
@@ -957,26 +957,38 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder": "Workflows are managed via workflow files in your workspace.",
"settings.agentBehaviour.notImplemented": "Not yet implemented.",
"settings.autoApprove.setAll": "Set all permissions",
"settings.autoApprove.description":
"Define how tools are allowed to run. Most tools default to Allow. doom_loop and external_directory default to Ask.",
"settings.autoApprove.level.allow": "Allow",
"settings.autoApprove.level.ask": "Ask",
"settings.autoApprove.level.deny": "Deny",
"settings.autoApprove.tool.read": "Read file contents",
"settings.autoApprove.tool.edit": "Edit or create files",
"settings.autoApprove.tool.glob": "Find files by pattern",
"settings.autoApprove.tool.grep": "Search file contents",
"settings.autoApprove.tool.list": "List directory contents",
"settings.autoApprove.tool.bash": "Execute shell commands",
"settings.autoApprove.tool.task": "Create sub-agent tasks",
"settings.autoApprove.tool.skill": "Execute skills",
"settings.autoApprove.tool.lsp": "Language server operations",
"settings.autoApprove.tool.todoread": "Read todo lists",
"settings.autoApprove.tool.todowrite": "Write todo lists",
"settings.autoApprove.tool.webfetch": "Fetch web pages",
"settings.autoApprove.tool.websearch": "Search the web",
"settings.autoApprove.tool.codesearch": "Search codebase",
"settings.autoApprove.tool.external_directory": "Access files outside workspace",
"settings.autoApprove.tool.doom_loop": "Continue after repeated failures",
"settings.autoApprove.wildcardLabel.commands": "All commands (*)",
"settings.autoApprove.wildcardLabel.paths": "All paths (*)",
"settings.autoApprove.exceptions": "Exceptions",
"settings.autoApprove.addCommand": "Add command",
"settings.autoApprove.addPath": "Add path",
"settings.autoApprove.placeholder.command": "e.g. git *",
"settings.autoApprove.placeholder.path": "e.g. *.env",
"settings.autoApprove.tool.external_directory":
"Access files outside workspace. Triggered when accessing files outside the current project directory.",
"settings.autoApprove.tool.bash": "Run terminal commands. Allows execution of shell commands (e.g., git status).",
"settings.autoApprove.tool.read": "Read files. Allows the agent to read files matching the specified path.",
"settings.autoApprove.tool.edit":
"Modify files. Allows the agent to create or edit files, including patches and multi-file updates.",
"settings.autoApprove.tool.glob":
"Match files by pattern. Allows file matching using glob patterns (e.g., src/**/*.ts).",
"settings.autoApprove.tool.grep": "Search file contents. Allows regex-based search inside files.",
"settings.autoApprove.tool.list": "List directory contents. Allows viewing files and folders within a directory.",
"settings.autoApprove.tool.task": "Launch sub-agents. Allows starting specialized sub-agents for specific tasks.",
"settings.autoApprove.tool.skill": "Load skills. Allows loading predefined skills by name.",
"settings.autoApprove.tool.lsp":
"Query language server. Allows running language server queries for code intelligence.",
"settings.autoApprove.tool.todoreadwrite": "Manage task list. Allows reading and updating the internal task list.",
"settings.autoApprove.tool.webfetch": "Fetch a URL. Allows retrieving content from a specific URL.",
"settings.autoApprove.tool.websearchcodesearch":
"Search web or code. Allows performing external web or code searches.",
"settings.autoApprove.tool.doom_loop":
"Prevent repeated identical actions. Triggered when the same tool call repeats with identical input.",
"settings.checkpoints.enable.title": "Enable Snapshots",
"settings.checkpoints.enable.description": "Create checkpoints before file edits so you can restore previous states",
+25 -17
View File
@@ -952,26 +952,34 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder":
"Los flujos de trabajo se gestionan mediante archivos de flujo de trabajo en su espacio de trabajo.",
"settings.agentBehaviour.notImplemented": "Aún no implementado.",
"settings.autoApprove.setAll": "Establecer todos los permisos",
"settings.autoApprove.description":
"Defina cómo se permite la ejecución de las herramientas. La mayoría de las herramientas tienen como valor predeterminado Permitir. doom_loop y external_directory tienen como valor predeterminado Preguntar.",
"settings.autoApprove.level.allow": "Permitir",
"settings.autoApprove.level.ask": "Preguntar",
"settings.autoApprove.level.deny": "Denegar",
"settings.autoApprove.tool.read": "Leer contenido de archivos",
"settings.autoApprove.tool.edit": "Editar o crear archivos",
"settings.autoApprove.tool.glob": "Buscar archivos por patrón",
"settings.autoApprove.tool.grep": "Buscar contenido de archivos",
"settings.autoApprove.tool.list": "Listar contenido de directorio",
"settings.autoApprove.tool.bash": "Ejecutar comandos de shell",
"settings.autoApprove.tool.task": "Crear tareas de sub-agente",
"settings.autoApprove.tool.skill": "Ejecutar habilidades",
"settings.autoApprove.tool.lsp": "Operaciones del servidor de lenguaje",
"settings.autoApprove.tool.todoread": "Leer listas de tareas",
"settings.autoApprove.tool.todowrite": "Escribir listas de tareas",
"settings.autoApprove.tool.webfetch": "Obtener páginas web",
"settings.autoApprove.tool.websearch": "Buscar en la web",
"settings.autoApprove.tool.codesearch": "Buscar en el código",
"settings.autoApprove.tool.external_directory": "Acceder a archivos fuera del espacio de trabajo",
"settings.autoApprove.tool.doom_loop": "Continuar tras fallos repetidos",
"settings.autoApprove.wildcardLabel.commands": "Todos los comandos (*)",
"settings.autoApprove.wildcardLabel.paths": "Todas las rutas (*)",
"settings.autoApprove.exceptions": "Excepciones",
"settings.autoApprove.addCommand": "Agregar comando",
"settings.autoApprove.addPath": "Agregar ruta",
"settings.autoApprove.placeholder.command": "ej. git *",
"settings.autoApprove.placeholder.path": "ej. *.env",
"settings.autoApprove.tool.read": "Leer archivos. Permite que el agente lea archivos que coincidan con la ruta especificada.",
"settings.autoApprove.tool.edit": "Modificar archivos. Permite que el agente cree o edite archivos, incluyendo parches y actualizaciones de múltiples archivos.",
"settings.autoApprove.tool.glob": "Buscar archivos por patrón. Permite la búsqueda de archivos mediante patrones glob (ej. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Buscar en el contenido de archivos. Permite la búsqueda basada en expresiones regulares dentro de los archivos.",
"settings.autoApprove.tool.list": "Listar contenido del directorio. Permite ver archivos y carpetas dentro de un directorio.",
"settings.autoApprove.tool.bash": "Ejecutar comandos de terminal. Permite la ejecución de comandos de shell (ej. git status).",
"settings.autoApprove.tool.task": "Iniciar subagentes. Permite iniciar subagentes especializados para tareas específicas.",
"settings.autoApprove.tool.skill": "Cargar habilidades. Permite cargar habilidades predefinidas por su nombre.",
"settings.autoApprove.tool.lsp": "Consultar servidor de lenguaje. Permite ejecutar consultas al servidor de lenguaje para la inteligencia del código.",
"settings.autoApprove.tool.todoreadwrite":
"Administrar lista de tareas. Permite leer y actualizar la lista de tareas interna.",
"settings.autoApprove.tool.webfetch": "Obtener una URL. Permite recuperar contenido de una URL específica.",
"settings.autoApprove.tool.websearchcodesearch":
"Buscar en la web o en el código. Permite realizar búsquedas externas en la web o en el código.",
"settings.autoApprove.tool.external_directory": "Acceder a archivos fuera del espacio de trabajo. Se activa al acceder a archivos fuera del directorio del proyecto actual.",
"settings.autoApprove.tool.doom_loop": "Evitar acciones idénticas repetidas. Se activa cuando se repite la misma llamada de herramienta con entrada idéntica.",
"settings.checkpoints.enable.title": "Habilitar instantáneas",
"settings.checkpoints.enable.description": "Crear puntos de control antes de editar archivos",
"settings.context.autoCompaction.title": "Compactación automática",
+25 -17
View File
@@ -961,26 +961,34 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder":
"Les workflows sont gérés via les fichiers de workflow dans votre espace de travail.",
"settings.agentBehaviour.notImplemented": "Pas encore implémenté.",
"settings.autoApprove.setAll": "Définir toutes les autorisations",
"settings.autoApprove.description":
"Définissez comment les outils sont autorisés à s'exécuter. La plupart des outils sont définis sur Autoriser par défaut. doom_loop et external_directory sont définis sur Demander par défaut.",
"settings.autoApprove.level.allow": "Autoriser",
"settings.autoApprove.level.ask": "Demander",
"settings.autoApprove.level.deny": "Refuser",
"settings.autoApprove.tool.read": "Lire le contenu des fichiers",
"settings.autoApprove.tool.edit": "Modifier ou créer des fichiers",
"settings.autoApprove.tool.glob": "Rechercher des fichiers par motif",
"settings.autoApprove.tool.grep": "Rechercher le contenu des fichiers",
"settings.autoApprove.tool.list": "Lister le contenu du répertoire",
"settings.autoApprove.tool.bash": "Exécuter des commandes shell",
"settings.autoApprove.tool.task": "Créer des tâches de sous-agent",
"settings.autoApprove.tool.skill": "Exécuter des compétences",
"settings.autoApprove.tool.lsp": "Opérations du serveur de langage",
"settings.autoApprove.tool.todoread": "Lire les listes de tâches",
"settings.autoApprove.tool.todowrite": "Écrire les listes de tâches",
"settings.autoApprove.tool.webfetch": "Récupérer des pages web",
"settings.autoApprove.tool.websearch": "Rechercher sur le web",
"settings.autoApprove.tool.codesearch": "Rechercher dans le code",
"settings.autoApprove.tool.external_directory": "Accéder aux fichiers hors de l'espace de travail",
"settings.autoApprove.tool.doom_loop": "Continuer après des échecs répétés",
"settings.autoApprove.wildcardLabel.commands": "Toutes les commandes (*)",
"settings.autoApprove.wildcardLabel.paths": "Tous les chemins (*)",
"settings.autoApprove.exceptions": "Exceptions",
"settings.autoApprove.addCommand": "Ajouter une commande",
"settings.autoApprove.addPath": "Ajouter un chemin",
"settings.autoApprove.placeholder.command": "ex. git *",
"settings.autoApprove.placeholder.path": "ex. *.env",
"settings.autoApprove.tool.read": "Lire des fichiers. Permet à l'agent de lire les fichiers correspondant au chemin spécifié.",
"settings.autoApprove.tool.edit": "Modifier des fichiers. Permet à l'agent de créer ou d'éditer des fichiers, y compris les patchs et les mises à jour de plusieurs fichiers.",
"settings.autoApprove.tool.glob": "Faire correspondre les fichiers par modèle. Permet la correspondance de fichiers à l'aide de modèles glob (ex. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Rechercher dans le contenu des fichiers. Permet la recherche basée sur les expressions régulières dans les fichiers.",
"settings.autoApprove.tool.list": "Lister le contenu du répertoire. Permet de visualiser les fichiers et dossiers dans un répertoire.",
"settings.autoApprove.tool.bash": "Exécuter des commandes de terminal. Permet l'exécution de commandes shell (ex. git status).",
"settings.autoApprove.tool.task": "Lancer des sous-agents. Permet de démarrer des sous-agents spécialisés pour des tâches spécifiques.",
"settings.autoApprove.tool.skill": "Charger des compétences. Permet de charger des compétences prédéfinies par leur nom.",
"settings.autoApprove.tool.lsp": "Interroger le serveur de langage. Permet d'exécuter des requêtes de serveur de langage pour l'intelligence du code.",
"settings.autoApprove.tool.todoreadwrite":
"Gérer la liste des tâches. Permet de lire et de mettre à jour la liste des tâches interne.",
"settings.autoApprove.tool.webfetch": "Récupérer une URL. Permet de récupérer le contenu d'une URL spécifique.",
"settings.autoApprove.tool.websearchcodesearch":
"Rechercher sur le Web ou dans le code. Permet d'effectuer des recherches externes sur le Web ou dans le code.",
"settings.autoApprove.tool.external_directory": "Accéder aux fichiers en dehors de l'espace de travail. Déclenché lors de l'accès à des fichiers en dehors du répertoire de projet actuel.",
"settings.autoApprove.tool.doom_loop": "Prévenir les actions identiques répétées. Déclenché lorsque le même appel d'outil se répète avec une entrée identique.",
"settings.checkpoints.enable.title": "Activer les instantanés",
"settings.checkpoints.enable.description": "Créer des points de contrôle avant les modifications de fichiers",
"settings.context.autoCompaction.title": "Compaction automatique",
+24 -17
View File
@@ -944,26 +944,33 @@ export const dict = {
"settings.agentBehaviour.workflowsPlaceholder":
"ワークフローはワークスペース内のワークフローファイルを通じて管理されます。",
"settings.agentBehaviour.notImplemented": "まだ実装されていません。",
"settings.autoApprove.setAll": "すべての権限を設定",
"settings.autoApprove.description":
"ツールの実行許可を定義します。ほとんどのツールはデフォルトで「許可」されます。doom_loop と external_directory はデフォルトで「確認」になります。",
"settings.autoApprove.level.allow": "許可",
"settings.autoApprove.level.ask": "確認",
"settings.autoApprove.level.deny": "拒否",
"settings.autoApprove.tool.read": "ファイルの内容を読み取る",
"settings.autoApprove.tool.edit": "ファイルを編集または作成",
"settings.autoApprove.tool.glob": "パターンでファイルを検索",
"settings.autoApprove.tool.grep": "ファイルの内容を検索",
"settings.autoApprove.tool.list": "ディレクトリの内容を一覧表示",
"settings.autoApprove.tool.bash": "シェルコマンドを実行",
"settings.autoApprove.tool.task": "サブエージェントタスクを作成",
"settings.autoApprove.tool.skill": "スキルを実行",
"settings.autoApprove.tool.lsp": "言語サーバー操作",
"settings.autoApprove.tool.todoread": "TODOリストを読み取る",
"settings.autoApprove.tool.todowrite": "TODOリストに書き込む",
"settings.autoApprove.tool.webfetch": "ウェブページを取得",
"settings.autoApprove.tool.websearch": "ウェブ検索",
"settings.autoApprove.tool.codesearch": "コードベースを検索",
"settings.autoApprove.tool.external_directory": "ワークスペース外のファイルにアクセス",
"settings.autoApprove.tool.doom_loop": "繰り返しの失敗後に続行",
"settings.autoApprove.wildcardLabel.commands": "すべてのコマンド (*)",
"settings.autoApprove.wildcardLabel.paths": "すべてのパス (*)",
"settings.autoApprove.exceptions": "例外",
"settings.autoApprove.addCommand": "コマンドを追加",
"settings.autoApprove.addPath": "パスを追加",
"settings.autoApprove.placeholder.command": "例: git *",
"settings.autoApprove.placeholder.path": "例: *.env",
"settings.autoApprove.tool.read": "ファイルを読み取る。指定されたパスに一致するファイルをエージェントが読み取ることを許可します。",
"settings.autoApprove.tool.edit": "ファイルを変更する。パッチや複数ファイルの更新を含め、エージェントがファイルを作成または編集することを許可します。",
"settings.autoApprove.tool.glob": "パターンでファイルを一致。globパターン(例:src/**/*.ts)を使用したファイルの一致を許可します。",
"settings.autoApprove.tool.grep": "ファイル内容を検索。ファイル内の正規表現ベースの検索を許可します。",
"settings.autoApprove.tool.list": "ディレクトリの内容を一覧表示。ディレクトリ内のファイルとフォルダの表示を許可します。",
"settings.autoApprove.tool.bash": "ターミナルコマンドを実行。シェルコマンド(例:git status)の実行を許可します。",
"settings.autoApprove.tool.task": "サブエージェントを起動。特定のタスク用に特化したサブエージェントを開始することを許可します。",
"settings.autoApprove.tool.skill": "スキルを読み込む。事前定義されたスキルを名前で読み込むことを許可します。",
"settings.autoApprove.tool.lsp": "言語サーバーにクエリ。コードインテリジェンスのために言語サーバークエリの実行を許可します。",
"settings.autoApprove.tool.todoreadwrite": "タスクリストの管理。内部タスクリストの読み取りと更新を許可します。",
"settings.autoApprove.tool.webfetch": "URLをフェッチ。特定のURLからコンテンツを取得することを許可します。",
"settings.autoApprove.tool.websearchcodesearch":
"Webまたはコードの検索。外部のWebまたはコード検索の実行を許可します。",
"settings.autoApprove.tool.external_directory": "ワークスペース外のファイルにアクセス。現在のプロジェクトディレクトリ外のファイルにアクセスしたときにトリガーされます。",
"settings.autoApprove.tool.doom_loop": "繰り返し同一のアクションを防止。同じツール呼び出しが同一の入力で繰り返されたときにトリガーされます。",
"settings.checkpoints.enable.title": "スナップショットを有効にする",
"settings.checkpoints.enable.description": "ファイル編集前にチェックポイントを作成して以前の状態を復元可能にする",
"settings.context.autoCompaction.title": "自動圧縮",
+24 -17
View File
@@ -941,26 +941,33 @@ export const dict = {
"MCP 서버가 구성되지 않았습니다. opencode 구성 파일을 편집하여 MCP 서버를 추가하세요.",
"settings.agentBehaviour.workflowsPlaceholder": "워크플로우는 워크스페이스의 워크플로우 파일을 통해 관리됩니다.",
"settings.agentBehaviour.notImplemented": "아직 구현되지 않았습니다.",
"settings.autoApprove.setAll": "모든 권한 설정",
"settings.autoApprove.description":
"도구 실행 허용 방식을 정의합니다. 대부분의 도구 기본값은 '허용'입니다. doom_loop 및 external_directory의 기본값은 '확인'입니다.",
"settings.autoApprove.level.allow": "허용",
"settings.autoApprove.level.ask": "확인",
"settings.autoApprove.level.deny": "거부",
"settings.autoApprove.tool.read": "파일 내용 읽기",
"settings.autoApprove.tool.edit": "파일 편집 또는 생성",
"settings.autoApprove.tool.glob": "패턴으로 파일 찾기",
"settings.autoApprove.tool.grep": "파일 내용 검색",
"settings.autoApprove.tool.list": "디렉토리 내용 나열",
"settings.autoApprove.tool.bash": "셸 명령 실행",
"settings.autoApprove.tool.task": "하위 에이전트 작업 생성",
"settings.autoApprove.tool.skill": "스킬 실행",
"settings.autoApprove.tool.lsp": "언어 서버 작업",
"settings.autoApprove.tool.todoread": "할 일 목록 읽기",
"settings.autoApprove.tool.todowrite": "할 일 목록 쓰기",
"settings.autoApprove.tool.webfetch": "웹 페이지 가져오기",
"settings.autoApprove.tool.websearch": "웹 검색",
"settings.autoApprove.tool.codesearch": "코드베이스 검색",
"settings.autoApprove.tool.external_directory": "워크스페이스 외부 파일 접근",
"settings.autoApprove.tool.doom_loop": "반복 실패 후 계속",
"settings.autoApprove.wildcardLabel.commands": "모든 명령 (*)",
"settings.autoApprove.wildcardLabel.paths": "모든 경로 (*)",
"settings.autoApprove.exceptions": "예외",
"settings.autoApprove.addCommand": "명령 추가",
"settings.autoApprove.addPath": "경로 추가",
"settings.autoApprove.placeholder.command": "예: git *",
"settings.autoApprove.placeholder.path": "예: *.env",
"settings.autoApprove.tool.read": "파일 읽기. 에이전트가 지정된 경로와 일치하는 파일을 읽을 수 있도록 허용합니다.",
"settings.autoApprove.tool.edit": "파일 수정. 패치 및 다중 파일 업데이트를 포함하여 에이전트가 파일을 생성하거나 편집할 수 있도록 허용합니다.",
"settings.autoApprove.tool.glob": "패턴으로 파일 찾기. glob 패턴(예: src/**/*.ts)을 사용한 파일 찾기를 허용합니다.",
"settings.autoApprove.tool.grep": "파일 내용 검색. 파일 내에서 정규식 기반 검색을 허용합니다.",
"settings.autoApprove.tool.list": "디렉토리 내용 나열. 디렉토리 내의 파일 및 폴더 보기를 허용합니다.",
"settings.autoApprove.tool.bash": "터미널 명령어 실행. 셸 명령어(예: git status) 실행을 허용합니다.",
"settings.autoApprove.tool.task": "하위 에이전트 시작. 특정 작업을 위한 특수 하위 에이전트 시작을 허용합니다.",
"settings.autoApprove.tool.skill": "기술 로드. 사전 정의된 기술을 이름으로 로드할 수 있도록 허용합니다.",
"settings.autoApprove.tool.lsp": "언어 서버 쿼리. 코드 인텔리전스를 위해 언어 서버 쿼리 실행을 허용합니다.",
"settings.autoApprove.tool.todoreadwrite": "작업 목록 관리. 내부 작업 목록을 읽고 업데이트할 수 있도록 허용합니다.",
"settings.autoApprove.tool.webfetch": "URL 가져오기. 특정 URL에서 콘텐츠를 검색할 수 있도록 허용합니다.",
"settings.autoApprove.tool.websearchcodesearch":
"웹 또는 코드 검색. 외부 웹 또는 코드 검색을 수행할 수 있도록 허용합니다.",
"settings.autoApprove.tool.external_directory": "작업 공간 외부 파일 접근. 현재 프로젝트 디렉토리 외부의 파일에 접근할 때 트리거됩니다.",
"settings.autoApprove.tool.doom_loop": "반복되는 동일한 작업 방지. 동일한 입력으로 동일한 도구 호출이 반복될 때 트리거됩니다.",
"settings.checkpoints.enable.title": "스냅샷 활성화",
"settings.checkpoints.enable.description": "파일 편집 전 체크포인트를 생성하여 이전 상태를 복원할 수 있습니다",
"settings.context.autoCompaction.title": "자동 압축",
+25 -17
View File
@@ -946,26 +946,34 @@ export const dict = {
"Ingen MCP-servere konfigurert. Rediger opencode-konfigurasjonsfilen for å legge til MCP-servere.",
"settings.agentBehaviour.workflowsPlaceholder": "Arbeidsflyter administreres via arbeidsflytfiler i arbeidsområdet.",
"settings.agentBehaviour.notImplemented": "Ikke implementert ennå.",
"settings.autoApprove.setAll": "Sett alle tillatelser",
"settings.autoApprove.description":
"Definer hvordan verktøy kan kjøre. De fleste verktøy har Tillat som standard. doom_loop og external_directory har Spør som standard.",
"settings.autoApprove.level.allow": "Tillat",
"settings.autoApprove.level.ask": "Spør",
"settings.autoApprove.level.deny": "Avvis",
"settings.autoApprove.tool.read": "Les filinnhold",
"settings.autoApprove.tool.edit": "Rediger eller opprett filer",
"settings.autoApprove.tool.glob": "Finn filer etter mønster",
"settings.autoApprove.tool.grep": "Søk i filinnhold",
"settings.autoApprove.tool.list": "List mappeinnhold",
"settings.autoApprove.tool.bash": "Kjør skallkommandoer",
"settings.autoApprove.tool.task": "Opprett underagentoppgaver",
"settings.autoApprove.tool.skill": "Kjør ferdigheter",
"settings.autoApprove.tool.lsp": "Språkserveroperasjoner",
"settings.autoApprove.tool.todoread": "Les oppgavelister",
"settings.autoApprove.tool.todowrite": "Skriv oppgavelister",
"settings.autoApprove.tool.webfetch": "Hent nettsider",
"settings.autoApprove.tool.websearch": "Søk på nettet",
"settings.autoApprove.tool.codesearch": "Søk i kodebasen",
"settings.autoApprove.tool.external_directory": "Tilgang til filer utenfor arbeidsområdet",
"settings.autoApprove.tool.doom_loop": "Fortsett etter gjentatte feil",
"settings.autoApprove.wildcardLabel.commands": "Alle kommandoer (*)",
"settings.autoApprove.wildcardLabel.paths": "Alle stier (*)",
"settings.autoApprove.exceptions": "Unntak",
"settings.autoApprove.addCommand": "Legg til kommando",
"settings.autoApprove.addPath": "Legg til sti",
"settings.autoApprove.placeholder.command": "f.eks. git *",
"settings.autoApprove.placeholder.path": "f.eks. *.env",
"settings.autoApprove.tool.read": "Les filer. Tillater agenten å lese filer som samsvarer med den angitte stien.",
"settings.autoApprove.tool.edit": "Endre filer. Tillater agenten å opprette eller redigere filer, inkludert oppdateringer og flerfilsoppdateringer.",
"settings.autoApprove.tool.glob": "Søk etter filer med mønster. Tillater filsøk ved bruk av glob-mønstre (f.eks. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Søk i filinnhold. Tillater regex-basert søk inne i filer.",
"settings.autoApprove.tool.list": "Vis kataloginnhold. Tillater visning av filer og mapper i en katalog.",
"settings.autoApprove.tool.bash": "Kjør terminalkommandoer. Tillater kjøring av shell-kommandoer (f.eks. git status).",
"settings.autoApprove.tool.task": "Start underagenter. Tillater start av spesialiserte underagenter for spesifikke oppgaver.",
"settings.autoApprove.tool.skill": "Last inn ferdigheter. Tillater innlasting av forhåndsdefinerte ferdigheter etter navn.",
"settings.autoApprove.tool.lsp": "Spør språkserver. Tillater kjøring av språkserverforespørsler for kodeintelligens.",
"settings.autoApprove.tool.todoreadwrite":
"Administrer oppgaveliste. Tillater lesing og oppdatering av den interne oppgavelisten.",
"settings.autoApprove.tool.webfetch": "Hent en URL. Tillater henting av innhold fra en spesifikk URL.",
"settings.autoApprove.tool.websearchcodesearch":
"Søk på nettet eller i kode. Tillater å utføre eksterne nett- eller kodesøk.",
"settings.autoApprove.tool.external_directory": "Få tilgang til filer utenfor arbeidsområdet. Utløses ved tilgang til filer utenfor gjeldende prosjektkatalog.",
"settings.autoApprove.tool.doom_loop": "Forhindre gjentatte identiske handlinger. Utløses når det samme verktøyanropet gjentas med identisk inndata.",
"settings.checkpoints.enable.title": "Aktiver øyeblikksbilder",
"settings.checkpoints.enable.description": "Opprett kontrollpunkter før filredigeringer",
"settings.context.autoCompaction.title": "Automatisk komprimering",
+25 -17
View File
@@ -947,26 +947,34 @@ export const dict = {
"Brak skonfigurowanych serwerów MCP. Edytuj plik konfiguracyjny opencode, aby dodać serwery MCP.",
"settings.agentBehaviour.workflowsPlaceholder": "Przepływy pracy zarządzane są za pomocą plików przepływów pracy.",
"settings.agentBehaviour.notImplemented": "Jeszcze nie zaimplementowano.",
"settings.autoApprove.setAll": "Ustaw wszystkie uprawnienia",
"settings.autoApprove.description":
"Zdefiniuj, jak narzędzia mogą być uruchamiane. Większość narzędzi domyślnie ma ustawienie Zezwalaj. doom_loop i external_directory domyślnie mają ustawienie Pytaj.",
"settings.autoApprove.level.allow": "Zezwól",
"settings.autoApprove.level.ask": "Pytaj",
"settings.autoApprove.level.deny": "Odmów",
"settings.autoApprove.tool.read": "Odczyt zawartości plików",
"settings.autoApprove.tool.edit": "Edycja lub tworzenie plików",
"settings.autoApprove.tool.glob": "Wyszukiwanie plików według wzorca",
"settings.autoApprove.tool.grep": "Przeszukiwanie zawartości plików",
"settings.autoApprove.tool.list": "Listowanie zawartości katalogu",
"settings.autoApprove.tool.bash": "Wykonywanie poleceń powłoki",
"settings.autoApprove.tool.task": "Tworzenie podzadań agenta",
"settings.autoApprove.tool.skill": "Wykonywanie umiejętności",
"settings.autoApprove.tool.lsp": "Operacje serwera języka",
"settings.autoApprove.tool.todoread": "Odczyt list zadań",
"settings.autoApprove.tool.todowrite": "Zapis list zadań",
"settings.autoApprove.tool.webfetch": "Pobieranie stron internetowych",
"settings.autoApprove.tool.websearch": "Wyszukiwanie w internecie",
"settings.autoApprove.tool.codesearch": "Przeszukiwanie bazy kodu",
"settings.autoApprove.tool.external_directory": "Dostęp do plików poza obszarem roboczym",
"settings.autoApprove.tool.doom_loop": "Kontynuuj po powtarzających się błędach",
"settings.autoApprove.wildcardLabel.commands": "Wszystkie polecenia (*)",
"settings.autoApprove.wildcardLabel.paths": "Wszystkie ścieżki (*)",
"settings.autoApprove.exceptions": "Wyjątki",
"settings.autoApprove.addCommand": "Dodaj polecenie",
"settings.autoApprove.addPath": "Dodaj ścieżkę",
"settings.autoApprove.placeholder.command": "np. git *",
"settings.autoApprove.placeholder.path": "np. *.env",
"settings.autoApprove.tool.read": "Odczytywanie plików. Pozwala agentowi na odczytywanie plików pasujących do określonej ścieżki.",
"settings.autoApprove.tool.edit": "Modyfikowanie plików. Pozwala agentowi na tworzenie lub edytowanie plików, w tym wprowadzanie poprawek i aktualizację wielu plików.",
"settings.autoApprove.tool.glob": "Dopasowywanie plików do wzorca. Pozwala na dopasowywanie plików za pomocą wzorców glob (np. src/**/*.ts).",
"settings.autoApprove.tool.grep": "Przeszukiwanie zawartości plików. Pozwala na wyszukiwanie oparte na wyrażeniach regularnych wewnątrz plików.",
"settings.autoApprove.tool.list": "Wyświetlanie zawartości katalogu. Pozwala na przeglądanie plików i folderów w katalogu.",
"settings.autoApprove.tool.bash": "Uruchamianie poleceń terminala. Pozwala na wykonanie poleceń powłoki (np. git status).",
"settings.autoApprove.tool.task": "Uruchamianie podagentów. Pozwala na uruchamianie wyspecjalizowanych podagentów do określonych zadań.",
"settings.autoApprove.tool.skill": "Ładowanie umiejętności. Pozwala na ładowanie predefiniowanych umiejętności po nazwie.",
"settings.autoApprove.tool.lsp": "Zapytania do serwera języka. Pozwala na uruchamianie zapytań do serwera języka w celu analizy kodu.",
"settings.autoApprove.tool.todoreadwrite":
"Zarządzaj listą zadań. Pozwala na odczytywanie i aktualizowanie wewnętrznej listy zadań.",
"settings.autoApprove.tool.webfetch": "Pobieranie URL. Pozwala na pobieranie zawartości z określonego adresu URL.",
"settings.autoApprove.tool.websearchcodesearch":
"Przeszukuj sieć lub kod. Pozwala na wykonywanie zewnętrznych wyszukiwań w sieci lub kodzie.",
"settings.autoApprove.tool.external_directory": "Dostęp do plików poza obszarem roboczym. Uruchamiane przy dostępie do plików poza bieżącym katalogiem projektu.",
"settings.autoApprove.tool.doom_loop": "Zapobieganie powtarzaniu tych samych akcji. Uruchamiane, gdy to samo wywołanie narzędzia powtarza się z identycznymi danymi wejściowymi.",
"settings.checkpoints.enable.title": "Włącz migawki",
"settings.checkpoints.enable.description": "Twórz punkty kontrolne przed edycją plików",
"settings.context.autoCompaction.title": "Automatyczna kompakcja",
+25 -17
View File
@@ -949,26 +949,34 @@ export const dict = {
"MCP-серверы не настроены. Отредактируйте файл конфигурации opencode для добавления MCP-серверов.",
"settings.agentBehaviour.workflowsPlaceholder": "Рабочие процессы управляются через файлы рабочих процессов.",
"settings.agentBehaviour.notImplemented": "Ещё не реализовано.",
"settings.autoApprove.setAll": "Установить все разрешения",
"settings.autoApprove.description":
"Определите правила запуска инструментов. Большинство инструментов по умолчанию Разрешены. Для doom_loop и external_directory по умолчанию установлено Спрашивать.",
"settings.autoApprove.level.allow": "Разрешить",
"settings.autoApprove.level.ask": "Спросить",
"settings.autoApprove.level.deny": "Отклонить",
"settings.autoApprove.tool.read": "Чтение содержимого файлов",
"settings.autoApprove.tool.edit": "Редактирование или создание файлов",
"settings.autoApprove.tool.glob": "Поиск файлов по шаблону",
"settings.autoApprove.tool.grep": "Поиск в содержимом файлов",
"settings.autoApprove.tool.list": "Список содержимого каталога",
"settings.autoApprove.tool.bash": "Выполнение команд оболочки",
"settings.autoApprove.tool.task": "Создание подзадач агента",
"settings.autoApprove.tool.skill": "Выполнение навыков",
"settings.autoApprove.tool.lsp": "Операции языкового сервера",
"settings.autoApprove.tool.todoread": "Чтение списков задач",
"settings.autoApprove.tool.todowrite": "Запись списков задач",
"settings.autoApprove.tool.webfetch": "Получение веб-страниц",
"settings.autoApprove.tool.websearch": "Поиск в интернете",
"settings.autoApprove.tool.codesearch": "Поиск в кодовой базе",
"settings.autoApprove.tool.external_directory": "Доступ к файлам вне рабочей области",
"settings.autoApprove.tool.doom_loop": "Продолжить после повторных сбоев",
"settings.autoApprove.wildcardLabel.commands": "Все команды (*)",
"settings.autoApprove.wildcardLabel.paths": "Все пути (*)",
"settings.autoApprove.exceptions": "Исключения",
"settings.autoApprove.addCommand": "Добавить команду",
"settings.autoApprove.addPath": "Добавить путь",
"settings.autoApprove.placeholder.command": "например, git *",
"settings.autoApprove.placeholder.path": "например, *.env",
"settings.autoApprove.tool.read": "Чтение файлов. Разрешает агенту читать файлы, соответствующие указанному пути.",
"settings.autoApprove.tool.edit": "Изменение файлов. Разрешает агенту создавать или редактировать файлы, включая патчи и обновления нескольких файлов.",
"settings.autoApprove.tool.glob": "Поиск файлов по шаблону. Разрешает поиск файлов с использованием glob-шаблонов (например, src/**/*.ts).",
"settings.autoApprove.tool.grep": "Поиск по содержимому файлов. Разрешает поиск на основе регулярных выражений внутри файлов.",
"settings.autoApprove.tool.list": "Просмотр содержимого каталогов. Разрешает просмотр файлов и папок внутри каталога.",
"settings.autoApprove.tool.bash": "Выполнение команд терминала. Разрешает выполнение команд оболочки (например, git status).",
"settings.autoApprove.tool.task": "Запуск субагентов. Разрешает запуск специализированных субагентов для конкретных задач.",
"settings.autoApprove.tool.skill": "Загрузка навыков. Разрешает загрузку предопределенных навыков по имени.",
"settings.autoApprove.tool.lsp": "Запрос к языковому серверу. Разрешает выполнение запросов к языковому серверу для анализа кода.",
"settings.autoApprove.tool.todoreadwrite":
"Управление списком задач. Разрешает чтение и обновление внутреннего списка задач.",
"settings.autoApprove.tool.webfetch": "Получение URL. Разрешает извлечение содержимого по указанному URL-адресу.",
"settings.autoApprove.tool.websearchcodesearch":
"Поиск в интернете или коде. Разрешает выполнение внешних поисковых запросов в интернете или коде.",
"settings.autoApprove.tool.external_directory": "Доступ к файлам вне рабочей области. Срабатывает при доступе к файлам за пределами текущего каталога проекта.",
"settings.autoApprove.tool.doom_loop": "Предотвращение повторных идентичных действий. Срабатывает, когда один и тот же вызов инструмента повторяется с идентичными входными данными.",
"settings.checkpoints.enable.title": "Включить снимки",
"settings.checkpoints.enable.description": "Создавать контрольные точки перед редактированием файлов",
"settings.context.autoCompaction.title": "Автоматическое сжатие",
+23 -17
View File
@@ -937,26 +937,32 @@ export const dict = {
"ไม่ได้กำหนดค่าเซิร์ฟเวอร์ MCP แก้ไขไฟล์กำหนดค่า opencode เพื่อเพิ่มเซิร์ฟเวอร์ MCP",
"settings.agentBehaviour.workflowsPlaceholder": "เวิร์กโฟลว์จัดการผ่านไฟล์เวิร์กโฟลว์ในพื้นที่ทำงาน",
"settings.agentBehaviour.notImplemented": "ยังไม่ได้ใช้งาน",
"settings.autoApprove.setAll": "ตั้งค่าสิทธิ์ทั้งหมด",
"settings.autoApprove.description":
"กำหนดวิธีอนุญาตการทำงานของเครื่องมือ โดยค่าเริ่มต้นเครื่องมือส่วนใหญ่คืออนุญาต ส่วน doom_loop และ external_directory ค่าเริ่มต้นคือถาม",
"settings.autoApprove.level.allow": "อนุญาต",
"settings.autoApprove.level.ask": "ถาม",
"settings.autoApprove.level.deny": "ปฏิเสธ",
"settings.autoApprove.tool.read": "อ่านเนื้อหาไฟล์",
"settings.autoApprove.tool.edit": "แก้ไขหรือสร้างไฟล์",
"settings.autoApprove.tool.glob": "ค้นหาไฟล์ตามรูปแบบ",
"settings.autoApprove.tool.grep": "ค้นหาเนื้อหาไฟล์",
"settings.autoApprove.tool.list": "แสดงเนื้อหาไดเรกทอรี",
"settings.autoApprove.tool.bash": "เรียกใช้คำสั่ง shell",
"settings.autoApprove.tool.task": "สร้างงานเอเจนต์ย่อย",
"settings.autoApprove.tool.skill": "เรียกใช้ทักษะ",
"settings.autoApprove.tool.lsp": "การดำเนินการเซิร์ฟเวอร์ภาษา",
"settings.autoApprove.tool.todoread": "อ่านรายการสิ่งที่ต้องทำ",
"settings.autoApprove.tool.todowrite": "เขียนรายการสิ่งที่ต้องทำ",
"settings.autoApprove.tool.webfetch": "ดึงหน้าเว็บ",
"settings.autoApprove.tool.websearch": "ค้นหาเว็บ",
"settings.autoApprove.tool.codesearch": "ค้นหาโค้ดเบส",
"settings.autoApprove.tool.external_directory": "เข้าถึงไฟล์นอกพื้นที่ทำงาน",
"settings.autoApprove.tool.doom_loop": "ดำเนินต่อหลังจากล้มเหลวซ้ำ",
"settings.autoApprove.wildcardLabel.commands": "คำสั่งทั้งหมด (*)",
"settings.autoApprove.wildcardLabel.paths": "พาธทั้งหมด (*)",
"settings.autoApprove.exceptions": "ข้อยกเว้น",
"settings.autoApprove.addCommand": "เพิ่มคำสั่ง",
"settings.autoApprove.addPath": "เพิ่มพาธ",
"settings.autoApprove.placeholder.command": "เช่น git *",
"settings.autoApprove.placeholder.path": "เช่น *.env",
"settings.autoApprove.tool.read": "อ่านไฟล์ อนุญาตให้ตัวแทน (Agent) อ่านไฟล์ที่ตรงกับเส้นทางที่ระบุ",
"settings.autoApprove.tool.edit": "แก้ไขไฟล์ อนุญาตให้ตัวแทน (Agent) สร้างหรือแก้ไขไฟล์ รวมถึงแพตช์ (Patch) และการอัปเดตหลายไฟล์",
"settings.autoApprove.tool.glob": "จับคู่ไฟล์ด้วยรูปแบบ อนุญาตให้จับคู่ไฟล์โดยใช้รูปแบบ glob (เช่น src/**/*.ts)",
"settings.autoApprove.tool.grep": "ค้นหาเนื้อหาไฟล์ อนุญาตให้ค้นหาเนื้อหาภายในไฟล์โดยใช้นิพจน์ทั่วไป (Regex)",
"settings.autoApprove.tool.list": "แสดงเนื้อหาในไดเรกทอรี อนุญาตให้ดูไฟล์และโฟลเดอร์ภายในไดเรกทอรี",
"settings.autoApprove.tool.bash": "เรียกใช้คำสั่งเทอร์มินัล อนุญาตให้ดำเนินการคำสั่งเชลล์ (เช่น git status)",
"settings.autoApprove.tool.task": "เปิดใช้งานตัวแทนย่อย อนุญาตให้เริ่มต้นตัวแทนย่อยเฉพาะทางสำหรับงานเฉพาะ",
"settings.autoApprove.tool.skill": "โหลดทักษะ อนุญาตให้โหลดทักษะที่กำหนดไว้ล่วงหน้าตามชื่อ",
"settings.autoApprove.tool.lsp": "สอบถามเซิร์ฟเวอร์ภาษา อนุญาตให้เรียกใช้การสืบค้นเซิร์ฟเวอร์ภาษาสำหรับระบบอัจฉริยะของโค้ด",
"settings.autoApprove.tool.todoreadwrite": "จัดการรายการงาน อนุญาตให้อ่านและอัปเดตรายการงานภายใน",
"settings.autoApprove.tool.webfetch": "ดึงข้อมูลจาก URL อนุญาตให้ดึงเนื้อหาจาก URL ที่ระบุ",
"settings.autoApprove.tool.websearchcodesearch": "ค้นหาเว็บหรือโค้ด อนุญาตให้ทำการค้นหาเว็บหรือโค้ดภายนอก",
"settings.autoApprove.tool.external_directory": "เข้าถึงไฟล์นอกพื้นที่ทำงาน (Workspace) ถูกเรียกเมื่อเข้าถึงไฟล์ภายนอกไดเรกทอรีโปรเจ็กต์ปัจจุบัน",
"settings.autoApprove.tool.doom_loop": "ป้องกันการกระทำที่ซ้ำกัน ถูกเรียกเมื่อเครื่องมือเดิมถูกเรียกซ้ำด้วยข้อมูลนำเข้าที่เหมือนกัน",
"settings.checkpoints.enable.title": "เปิดใช้งานสแนปชอต",
"settings.checkpoints.enable.description": "สร้างจุดตรวจก่อนแก้ไขไฟล์",
"settings.context.autoCompaction.title": "การบีบอัดอัตโนมัติ",
+23 -17
View File
@@ -930,26 +930,32 @@ export const dict = {
"settings.agentBehaviour.mcpEmpty": "未配置 MCP 服务器。编辑 opencode 配置文件以添加 MCP 服务器。",
"settings.agentBehaviour.workflowsPlaceholder": "工作流通过工作区中的工作流文件管理。",
"settings.agentBehaviour.notImplemented": "尚未实现。",
"settings.autoApprove.setAll": "设置所有权限",
"settings.autoApprove.description":
"定义工具的运行权限。大多数工具默认为「允许」。doom_loop 和 external_directory 默认为「询问」。",
"settings.autoApprove.level.allow": "允许",
"settings.autoApprove.level.ask": "询问",
"settings.autoApprove.level.deny": "拒绝",
"settings.autoApprove.tool.read": "读取文件内容",
"settings.autoApprove.tool.edit": "编辑或创建文件",
"settings.autoApprove.tool.glob": "按模式查找文件",
"settings.autoApprove.tool.grep": "搜索文件内容",
"settings.autoApprove.tool.list": "列出目录内容",
"settings.autoApprove.tool.bash": "执行 shell 命令",
"settings.autoApprove.tool.task": "创建子智能体任务",
"settings.autoApprove.tool.skill": "执行技能",
"settings.autoApprove.tool.lsp": "语言服务器操作",
"settings.autoApprove.tool.todoread": "读取待办列表",
"settings.autoApprove.tool.todowrite": "写入待办列表",
"settings.autoApprove.tool.webfetch": "获取网页",
"settings.autoApprove.tool.websearch": "搜索网络",
"settings.autoApprove.tool.codesearch": "搜索代码库",
"settings.autoApprove.tool.external_directory": "访问工作区外的文件",
"settings.autoApprove.tool.doom_loop": "重复失败后继续",
"settings.autoApprove.wildcardLabel.commands": "所有命令 (*)",
"settings.autoApprove.wildcardLabel.paths": "所有路径 (*)",
"settings.autoApprove.exceptions": "例外",
"settings.autoApprove.addCommand": "添加命令",
"settings.autoApprove.addPath": "添加路径",
"settings.autoApprove.placeholder.command": "例如:git *",
"settings.autoApprove.placeholder.path": "例如:*.env",
"settings.autoApprove.tool.read": "读取文件。允许代理读取符合指定路径的文件。",
"settings.autoApprove.tool.edit": "修改文件。允许代理创建或编辑文件,包括补丁和多文件更新。",
"settings.autoApprove.tool.glob": "按模式匹配文件。允许使用 glob 模式匹配文件(例如 src/**/*.ts)。",
"settings.autoApprove.tool.grep": "搜索文件内容。允许在文件内进行基于正则表达式的搜索。",
"settings.autoApprove.tool.list": "列出目录内容。允许查看目录内的文件和文件夹。",
"settings.autoApprove.tool.bash": "运行终端命令。允许执行 shell 命令(例如 git status)。",
"settings.autoApprove.tool.task": "启动子代理。允许启动执行特定任务的专用子代理。",
"settings.autoApprove.tool.skill": "加载技能。允许按名称加载预定义的技能。",
"settings.autoApprove.tool.lsp": "查询语言服务器。允许运行语言服务器查询以获取代码智能。",
"settings.autoApprove.tool.todoreadwrite": "管理任务列表。允许读取和更新内部任务列表。",
"settings.autoApprove.tool.webfetch": "获取 URL。允许从特定 URL 检索内容。",
"settings.autoApprove.tool.websearchcodesearch": "搜索 Web 或代码。允许执行外部 Web 或代码搜索。",
"settings.autoApprove.tool.external_directory": "访问工作区外部的文件。访问当前项目目录之外的文件时触发。",
"settings.autoApprove.tool.doom_loop": "防止重复相同操作。当相同的工具调用以相同的输入重复时触发。",
"settings.checkpoints.enable.title": "启用快照",
"settings.checkpoints.enable.description": "在文件编辑前创建检查点,以便恢复之前的状态",
"settings.context.autoCompaction.title": "自动压缩",
+23 -17
View File
@@ -931,26 +931,32 @@ export const dict = {
"settings.agentBehaviour.mcpEmpty": "未設定 MCP 伺服器。編輯 opencode 設定檔以新增 MCP 伺服器。",
"settings.agentBehaviour.workflowsPlaceholder": "工作流程透過工作區中的工作流程檔案管理。",
"settings.agentBehaviour.notImplemented": "尚未實作。",
"settings.autoApprove.setAll": "設定所有權限",
"settings.autoApprove.description":
"定義工具的執行權限。大多數工具預設為允許。doom_loop 與 external_directory 預設為詢問。",
"settings.autoApprove.level.allow": "允許",
"settings.autoApprove.level.ask": "詢問",
"settings.autoApprove.level.deny": "拒絕",
"settings.autoApprove.tool.read": "讀取檔案內容",
"settings.autoApprove.tool.edit": "編輯或建立檔案",
"settings.autoApprove.tool.glob": "按模式尋找檔案",
"settings.autoApprove.tool.grep": "搜尋檔案內容",
"settings.autoApprove.tool.list": "列出目錄內容",
"settings.autoApprove.tool.bash": "執行 shell 命令",
"settings.autoApprove.tool.task": "建立 sub-agent 任務",
"settings.autoApprove.tool.skill": "執行技能",
"settings.autoApprove.tool.lsp": "語言伺服器操作",
"settings.autoApprove.tool.todoread": "讀取待辦清單",
"settings.autoApprove.tool.todowrite": "寫入待辦清單",
"settings.autoApprove.tool.webfetch": "擷取網頁",
"settings.autoApprove.tool.websearch": "搜尋網路",
"settings.autoApprove.tool.codesearch": "搜尋程式碼庫",
"settings.autoApprove.tool.external_directory": "存取工作區外的檔案",
"settings.autoApprove.tool.doom_loop": "重複失敗後繼續",
"settings.autoApprove.wildcardLabel.commands": "所有命令 (*)",
"settings.autoApprove.wildcardLabel.paths": "所有路徑 (*)",
"settings.autoApprove.exceptions": "例外情況",
"settings.autoApprove.addCommand": "新增命令",
"settings.autoApprove.addPath": "新增路徑",
"settings.autoApprove.placeholder.command": "例如:git *",
"settings.autoApprove.placeholder.path": "例如:*.env",
"settings.autoApprove.tool.read": "讀取檔案。允許代理讀取符合指定路徑的檔案。",
"settings.autoApprove.tool.edit": "修改檔案。允許代理建立或編輯檔案,包括修補程式和多檔案更新。",
"settings.autoApprove.tool.glob": "依模式匹配檔案。允許使用 glob 模式匹配檔案(例如 src/**/*.ts)。",
"settings.autoApprove.tool.grep": "搜尋檔案內容。允許在檔案內進行基於正規表示式的搜尋。",
"settings.autoApprove.tool.list": "列出目錄內容。允許檢視目錄內的檔案和資料夾。",
"settings.autoApprove.tool.bash": "執行終端機命令。允許執行 shell 命令(例如 git status)。",
"settings.autoApprove.tool.task": "啟動子代理。允許啟動執行特定任務的專用子代理。",
"settings.autoApprove.tool.skill": "載入技能。允許依名稱載入預先定義的技能。",
"settings.autoApprove.tool.lsp": "查詢語言伺服器。允許執行語言伺服器查詢以取得程式碼智慧。",
"settings.autoApprove.tool.todoreadwrite": "管理任務清單。允許讀取和更新內部任務清單。",
"settings.autoApprove.tool.webfetch": "擷取 URL。允許從特定 URL 擷取內容。",
"settings.autoApprove.tool.websearchcodesearch": "搜尋網路或程式碼。允許執行外部網路或程式碼搜尋。",
"settings.autoApprove.tool.external_directory": "存取工作區外部的檔案。存取目前專案目錄之外的檔案時觸發。",
"settings.autoApprove.tool.doom_loop": "防止重複相同操作。當相同的工具呼叫以相同的輸入重複時觸發。",
"settings.checkpoints.enable.title": "啟用快照",
"settings.checkpoints.enable.description": "在檔案編輯前建立檢查點,以便恢復之前的狀態",
"settings.context.autoCompaction.title": "自動壓縮",
@@ -132,6 +132,7 @@ export function mockSessionValue(overrides?: {
getParts: () => [],
todos: () => [],
permissions: () => permissions,
respondingPermissions: () => new Set<string>(),
questions: () => qs,
questionErrors: () => new Set<string>(),
selected: () => ({ providerID: "kilo", modelID: "anthropic/claude-sonnet-4-6" }),
@@ -254,7 +254,9 @@ export interface ModelSelection {
export type PermissionLevel = "allow" | "ask" | "deny"
export type PermissionConfig = Partial<Record<string, PermissionLevel>>
export type PermissionRule = PermissionLevel | Record<string, PermissionLevel>
export type PermissionConfig = Partial<Record<string, PermissionRule>>
export interface AgentConfig {
model?: string | null
@@ -386,6 +388,16 @@ export interface PermissionRequestMessage {
permission: PermissionRequest
}
export interface PermissionResolvedMessage {
type: "permissionResolved"
permissionID: string
}
export interface PermissionErrorMessage {
type: "permissionError"
permissionID: string
}
export interface TodoUpdatedMessage {
type: "todoUpdated"
sessionID: string
@@ -955,6 +967,8 @@ export type ExtensionMessage =
| PartUpdatedMessage
| SessionStatusMessage
| PermissionRequestMessage
| PermissionResolvedMessage
| PermissionErrorMessage
| TodoUpdatedMessage
| SessionCreatedMessage
| SessionUpdatedMessage
@@ -132,6 +132,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
}
state.pending = false
Filesystem.writeJson(filePath, {
model: modelStore.model, // kilocode_change
recent: modelStore.recent,
favorite: modelStore.favorite,
variant: modelStore.variant,
@@ -142,6 +143,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
.then((x: any) => {
if (Array.isArray(x.recent)) setModelStore("recent", x.recent)
if (Array.isArray(x.favorite)) setModelStore("favorite", x.favorite)
if (typeof x.model === "object" && x.model !== null) setModelStore("model", x.model) // kilocode_change
if (typeof x.variant === "object" && x.variant !== null) setModelStore("variant", x.variant)
})
.catch(() => {})
@@ -241,6 +243,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const val = recent[next]
if (!val) return
setModelStore("model", agent.current().name, { ...val })
save() // kilocode_change
},
cycleFavorite(direction: 1 | -1) {
const favorites = modelStore.favorite.filter((item) => isModelValid(item))
@@ -293,8 +296,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
"recent",
uniq.map((x) => ({ providerID: x.providerID, modelID: x.modelID })),
)
save()
}
save() // kilocode_change
})
},
toggleFavorite(model: { providerID: string; modelID: string }) {
+26 -4
View File
@@ -12,13 +12,17 @@ import { lazy } from "../util/lazy"
import { NamedError } from "@opencode-ai/util/error"
import { Flag } from "../flag/flag"
import { Auth } from "../auth"
// kilocode_change start
import {
type ParseError as JsoncParseError,
applyEdits,
findNodeAtLocation,
modify,
parse as parseJsonc,
parseTree,
printParseErrorCode,
} from "jsonc-parser"
// kilocode_change end
import { Instance } from "../project/instance"
import { LSPServer } from "../lsp/server"
import { BunProc } from "@/bun"
@@ -1130,10 +1134,12 @@ export namespace Config {
.optional()
.describe("When set, ONLY these providers will be enabled. All other providers will be ignored"),
// kilocode_change start - nullable for delete sentinel
model: ModelId.nullable().describe("Model to use in the format of provider/model, eg anthropic/claude-2").optional(),
small_model: ModelId.nullable().describe(
"Small model to use for tasks like title generation in the format of provider/model",
).optional(),
model: ModelId.nullable()
.describe("Model to use in the format of provider/model, eg anthropic/claude-2")
.optional(),
small_model: ModelId.nullable()
.describe("Small model to use for tasks like title generation in the format of provider/model")
.optional(),
// kilocode_change end
// kilocode_change start - renamed from "build" to "code"
default_agent: z
@@ -1457,6 +1463,22 @@ export namespace Config {
return applyEdits(input, edits)
}
// kilocode_change start — when the existing JSONC node at this path is a
// scalar (e.g. permission.bash is "ask" as a string), jsonc-parser cannot
// add child keys to it. Detect this case and replace the whole node with
// the patch object in a single modify() call instead of recursing.
if (path.length > 0) {
const tree = parseTree(input)
const node = tree && findNodeAtLocation(tree, path)
if (node && node.type !== "object") {
const edits = modify(input, path, patch, {
formattingOptions: { insertSpaces: true, tabSize: 2 },
})
return applyEdits(input, edits)
}
}
// kilocode_change end
return Object.entries(patch).reduce((result, [key, value]) => {
if (value === undefined) return result
return patchJsonc(result, value, [...path, key])
@@ -0,0 +1,450 @@
// kilocode_change - new file
// Tests for per-agent model persistence in local.tsx (model.json read/write)
//
// NOTE: Bun test uses solid-js/dist/server.js (SSR build) where createMemo
// evaluates once and never re-evaluates. The @opentui/solid preload plugin
// that swaps server→client build is only in the top-level bunfig preload,
// not the [test] section. Assertions therefore verify persistence via
// model.json file contents rather than model.current() reactive state.
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
import { createRoot } from "solid-js"
import path from "path"
import fs from "fs/promises"
// ── Mutable mock state ──────────────────────────────────────────────────────
const mockProviders = [
{
id: "anthropic",
name: "Anthropic",
source: "env" as const,
env: ["ANTHROPIC_API_KEY"],
options: {},
models: {
"claude-sonnet": {
id: "claude-sonnet",
providerID: "anthropic",
name: "Claude Sonnet",
capabilities: {},
},
"claude-opus": {
id: "claude-opus",
providerID: "anthropic",
name: "Claude Opus",
capabilities: {},
},
},
},
]
let mockAgents = [
{ name: "code", mode: "primary" as const, hidden: false, model: undefined as any, color: undefined as any, permission: {} },
{ name: "plan", mode: "primary" as const, hidden: false, model: undefined as any, color: undefined as any, permission: {} },
]
let mockConfig: { model?: string } = {}
let mockArgs: { model?: string } = {}
let toastMessages: Array<{ variant: string; message: string }> = []
// ── Mocks ────────────────────────────────────────────────────────────────────
// Only mock TUI context modules that are specific to the CLI layer and not
// used by other test files. Do NOT mock widely-used modules like @/global,
// @/provider/provider, or @opentui/core — they persist process-wide in Bun
// and would break other test files.
let capturedInit: (() => any) | undefined
mock.module("@tui/context/helper", () => ({
createSimpleContext: (input: { name: string; init: () => any }) => {
capturedInit = input.init
return { use: () => {}, provider: () => {} }
},
}))
mock.module("@tui/context/sync", () => ({
useSync: () => ({
data: {
provider: mockProviders,
provider_default: { anthropic: "claude-sonnet" },
agent: mockAgents,
config: mockConfig,
mcp: {},
},
}),
}))
mock.module("@tui/context/theme", () => ({
useTheme: () => ({
theme: {
primary: { buffer: new Float32Array(4) },
secondary: { buffer: new Float32Array(4) },
accent: { buffer: new Float32Array(4) },
success: { buffer: new Float32Array(4) },
warning: { buffer: new Float32Array(4) },
error: { buffer: new Float32Array(4) },
info: { buffer: new Float32Array(4) },
},
}),
}))
mock.module("@tui/context/args", () => ({
useArgs: () => mockArgs,
}))
mock.module("@tui/context/sdk", () => ({
useSDK: () => ({
client: {
mcp: {
disconnect: async () => {},
connect: async () => {},
},
},
}),
}))
const toastMock = {
show: (opts: { variant: string; message: string; duration?: number }) => {
toastMessages.push({ variant: opts.variant, message: opts.message })
},
}
mock.module("@tui/ui/toast", () => ({
useToast: () => toastMock,
}))
// ── Import under test (after mocks) ────────────────────────────────────────
await import("@tui/context/local")
// Import the real Global to get the state path (set by test preload via XDG_STATE_HOME)
const { Global } = await import("@/global")
const modelJsonPath = path.join(Global.Path.state, "model.json")
// ── Helpers ─────────────────────────────────────────────────────────────────
function resetMockState() {
mockAgents = [
{ name: "code", mode: "primary", hidden: false, model: undefined, color: undefined, permission: {} },
{ name: "plan", mode: "primary", hidden: false, model: undefined, color: undefined, permission: {} },
]
mockConfig = {}
mockArgs = {}
toastMessages = []
}
function runInRoot(): { local: any; dispose: () => void } {
let local: any
let dispose!: () => void
createRoot((d) => {
dispose = d
local = capturedInit!()
})
return { local: local!, dispose }
}
async function initLocal(options?: {
prewrite?: Record<string, any>
}): Promise<{ local: any; dispose: () => void }> {
if (options?.prewrite) {
await fs.writeFile(modelJsonPath, JSON.stringify(options.prewrite))
}
if (!capturedInit) throw new Error("capturedInit not set — mock.module for helper failed")
const { local, dispose } = runInRoot()
// Poll until model.ready is true
const deadline = Date.now() + 2000
while (!local.model.ready && Date.now() < deadline) {
await Bun.sleep(10)
}
if (!local.model.ready) throw new Error("model.ready never became true within 2s")
return { local, dispose }
}
async function readModelJson(): Promise<any> {
const text = await fs.readFile(modelJsonPath, "utf-8")
return JSON.parse(text)
}
async function removeModelJson() {
await fs.rm(modelJsonPath, { force: true }).catch(() => {})
}
const SONNET = { providerID: "anthropic", modelID: "claude-sonnet" }
const OPUS = { providerID: "anthropic", modelID: "claude-opus" }
// ── Setup ───────────────────────────────────────────────────────────────────
beforeEach(async () => {
resetMockState()
await removeModelJson()
})
afterEach(async () => {
await removeModelJson()
})
// ── Tests ───────────────────────────────────────────────────────────────────
describe("model.set persists per-agent model", () => {
test("1: model.set for agent 'code' writes model.code to model.json", async () => {
const { local, dispose } = await initLocal()
try {
local.model.set(OPUS, { recent: true })
await Bun.sleep(50)
const data = await readModelJson()
expect(data.model.code).toEqual(OPUS)
expect(data.recent).toBeArrayOfSize(1)
expect(data.recent[0]).toEqual(OPUS)
} finally {
dispose()
}
})
test("2: set code→sonnet, plan→opus persists both in model.json", async () => {
const { local, dispose } = await initLocal()
try {
local.model.set(SONNET, { recent: true })
local.agent.set("plan")
local.model.set(OPUS, { recent: true })
await Bun.sleep(50)
const data = await readModelJson()
expect(data.model.code).toEqual(SONNET)
expect(data.model.plan).toEqual(OPUS)
} finally {
dispose()
}
})
test("3: save → dispose → re-init from same dir loads persisted data", async () => {
// First session: set and save
{
const { local, dispose } = runInRoot()
const deadline = Date.now() + 2000
while (!local.model.ready && Date.now() < deadline) await Bun.sleep(10)
local.model.set(OPUS, { recent: true })
await Bun.sleep(50)
dispose()
}
// Verify file was written correctly
const fileData = await readModelJson()
expect(fileData.model.code).toEqual(OPUS)
expect(fileData.recent[0]).toEqual(OPUS)
// Second session: re-init from same dir — verify file data was loaded
{
const { local, dispose } = runInRoot()
const deadline = Date.now() + 2000
while (!local.model.ready && Date.now() < deadline) await Bun.sleep(10)
// recent() reads the store directly (not a memo), so it reflects the loaded file
expect(local.model.recent()).toEqual([OPUS])
// Setting a new model on top of loaded data should produce correct file
local.model.set(SONNET, { recent: true })
await Bun.sleep(50)
const data2 = await readModelJson()
expect(data2.model.code).toEqual(SONNET)
expect(data2.recent[0]).toEqual(SONNET)
expect(data2.recent[1]).toEqual(OPUS)
dispose()
}
})
})
describe("model.cycle and model.cycleFavorite", () => {
test("4: cycle(1) advances to next recent model, persists per-agent", async () => {
const { local, dispose } = await initLocal({
prewrite: {
recent: [SONNET, OPUS],
model: { code: SONNET },
favorite: [],
variant: {},
},
})
try {
local.model.cycle(1)
await Bun.sleep(50)
const data = await readModelJson()
expect(data.model.code).toEqual(OPUS)
} finally {
dispose()
}
})
test("5: cycleFavorite(1) cycles to next favorite and persists", async () => {
const { local, dispose } = await initLocal({
prewrite: {
recent: [SONNET],
model: { code: SONNET },
favorite: [SONNET, OPUS],
variant: {},
},
})
try {
local.model.cycleFavorite(1)
await Bun.sleep(50)
const data = await readModelJson()
expect(data.model.code).toEqual(OPUS)
expect(data.recent.some((r: any) => r.modelID === "claude-opus")).toBe(true)
} finally {
dispose()
}
})
})
describe("edge cases and error handling", () => {
test("6: model.json without 'model' field does not crash, falls back", async () => {
const { local, dispose } = await initLocal({
prewrite: {
recent: [SONNET],
favorite: [],
variant: {},
},
})
try {
expect(local.model.ready).toBe(true)
// recent() reads the store directly and should have loaded
expect(local.model.recent()).toEqual([SONNET])
// current() evaluates once at init before file loads — falls to provider default
expect(local.model.current()).toBeDefined()
} finally {
dispose()
}
})
test("7: corrupt model.json does not crash, defaults to empty state", async () => {
await fs.writeFile(modelJsonPath, "{{{not valid json")
const { local, dispose } = runInRoot()
const deadline = Date.now() + 2000
while (!local.model.ready && Date.now() < deadline) await Bun.sleep(10)
try {
expect(local.model.ready).toBe(true)
// Should not have loaded any data
expect(local.model.recent()).toEqual([])
expect(local.model.favorite()).toEqual([])
} finally {
dispose()
}
})
test("8: pre-written model.code with invalid provider — valid models still load", async () => {
const { local, dispose } = await initLocal({
prewrite: {
recent: [SONNET],
model: { code: { providerID: "nonexistent", modelID: "fake-model" } },
favorite: [],
variant: {},
},
})
try {
// recent loaded correctly despite invalid model.code
expect(local.model.recent()).toEqual([SONNET])
// The initial current() evaluates before file loads, so it falls to default
const current = local.model.current()
expect(current).toBeDefined()
expect(current!.providerID).toBe("anthropic")
} finally {
dispose()
}
})
test("9: model.set before ready still persists after ready", async () => {
const { local, dispose } = runInRoot()
// Immediately set before ready (ready is false because file load is async)
const wasReadyBefore = local.model.ready
local.model.set(OPUS, { recent: true })
// Wait for ready
const deadline = Date.now() + 2000
while (!local.model.ready && Date.now() < deadline) await Bun.sleep(10)
await Bun.sleep(50)
try {
expect(wasReadyBefore).toBe(false)
expect(local.model.ready).toBe(true)
const data = await readModelJson()
expect(data.model.code).toEqual(OPUS)
} finally {
dispose()
}
})
test("10: agent with config model persists when applied", async () => {
// NOTE: In production, a createEffect in local.tsx auto-applies agent config
// models when switching agents. In bun test, createEffect is a no-op (SSR build).
// This test verifies the underlying persistence: when an agent has a config model,
// model.set (what the effect would call) correctly persists it.
mockAgents = [
{ name: "code", mode: "primary", hidden: false, model: undefined, color: undefined, permission: {} },
{ name: "plan", mode: "primary", hidden: false, model: OPUS, color: undefined, permission: {} },
]
const { local, dispose } = await initLocal()
try {
// Switch to "plan" agent which has config model OPUS
local.agent.set("plan")
// Simulate what createEffect would do: apply the agent's config model
local.model.set(OPUS)
await Bun.sleep(50)
const data = await readModelJson()
expect(data.model.plan).toEqual(OPUS)
} finally {
dispose()
}
})
test("11: user override from file is retained after load", async () => {
mockAgents = [
{ name: "code", mode: "primary", hidden: false, model: OPUS, color: undefined, permission: {} },
{ name: "plan", mode: "primary", hidden: false, model: undefined, color: undefined, permission: {} },
]
const { local, dispose } = await initLocal({
prewrite: {
recent: [SONNET, OPUS],
model: { code: SONNET },
favorite: [],
variant: {},
},
})
try {
// The file had model.code = SONNET, recent = [SONNET, OPUS]
// Verify file data was loaded into the store
expect(local.model.recent()).toEqual([SONNET, OPUS])
// Setting a new model should layer on top of the loaded state
local.model.set(OPUS, { recent: true })
await Bun.sleep(50)
const data = await readModelJson()
// model.code should now be OPUS (the new set)
expect(data.model.code).toEqual(OPUS)
} finally {
dispose()
}
})
test("12: switching agents without config models produces no warning toasts", async () => {
const { local, dispose } = await initLocal()
try {
toastMessages = []
local.agent.set("plan")
local.agent.set("code")
await Bun.sleep(50)
const warnings = toastMessages.filter((t) => t.message.includes("configured model"))
expect(warnings).toHaveLength(0)
} finally {
dispose()
}
})
})
@@ -0,0 +1,74 @@
// kilocode_change - new file
import { describe, expect, test } from "bun:test"
import { applyEdits, modify, findNodeAtLocation, parseTree } from "jsonc-parser"
// Replicate patchJsonc logic locally to test it in isolation
function isRecord(value: unknown): value is Record<string, unknown> {
return !!value && typeof value === "object" && !Array.isArray(value)
}
function patchJsonc(input: string, patch: unknown, path: string[] = []): string {
if (!isRecord(patch)) {
const edits = modify(input, path, patch === null ? undefined : patch, {
formattingOptions: { insertSpaces: true, tabSize: 2 },
})
return applyEdits(input, edits)
}
if (path.length > 0) {
const tree = parseTree(input)
const node = tree && findNodeAtLocation(tree, path)
if (node && node.type !== "object") {
const edits = modify(input, path, patch, {
formattingOptions: { insertSpaces: true, tabSize: 2 },
})
return applyEdits(input, edits)
}
}
return Object.entries(patch).reduce((result, [key, value]) => {
if (value === undefined) return result
return patchJsonc(result, value, [...path, key])
}, input)
}
describe("patchJsonc scalar-to-object transition", () => {
test("sets object when node does not yet exist", () => {
const input = `{ "permission": {} }`
const result = patchJsonc(input, { permission: { bash: { "*": "ask", uname: "allow" } } })
const parsed = JSON.parse(result)
expect(parsed.permission.bash).toEqual({ "*": "ask", uname: "allow" })
})
test("transitions permission rule from string to object (the bug scenario)", () => {
// bash is stored as a plain string "ask" in the JSONC file
const input = `{ "permission": { "bash": "ask" } }`
// User adds exception "uname" → "allow"; this would previously throw:
// "Can not add index to parent of type string"
const result = patchJsonc(input, { permission: { bash: { "*": "ask", uname: "allow" } } })
const parsed = JSON.parse(result)
expect(parsed.permission.bash).toEqual({ "*": "ask", uname: "allow" })
})
test("does not disturb sibling keys when replacing scalar", () => {
const input = `{ "permission": { "bash": "ask", "glob": "allow" } }`
const result = patchJsonc(input, { permission: { bash: { "*": "ask", uname: "allow" } } })
const parsed = JSON.parse(result)
expect(parsed.permission.glob).toBe("allow")
expect(parsed.permission.bash).toEqual({ "*": "ask", uname: "allow" })
})
test("updates existing object permission by adding a new key", () => {
const input = `{ "permission": { "bash": { "*": "ask" } } }`
const result = patchJsonc(input, { permission: { bash: { "*": "ask", uname: "allow" } } })
const parsed = JSON.parse(result)
expect(parsed.permission.bash).toEqual({ "*": "ask", uname: "allow" })
})
test("plain string permission update still works", () => {
const input = `{ "permission": { "bash": "allow" } }`
const result = patchJsonc(input, { permission: { bash: "ask" } })
const parsed = JSON.parse(result)
expect(parsed.permission.bash).toBe("ask")
})
})