Compare commits

...

12 Commits

Author SHA1 Message Date
gemini-cli-robot 079dfef2f7 chore(release): v0.17.0 2025-11-20 22:28:50 +00:00
gemini-cli-robot 7c684e36f6 chore(release): v0.17.0-preview.5 2025-11-20 21:50:38 +00:00
gemini-cli-robot d9c3b73bfe fix(patch): cherry-pick ade9dfe to release/v0.17.0-preview.4-pr-13515 to patch version v0.17.0-preview.4 and create version 0.17.0-preview.5 (#13536)
Co-authored-by: Adib234 <30782825+Adib234@users.noreply.github.com>
2025-11-20 21:33:02 +00:00
gemini-cli-robot 17f4718d9f chore(release): v0.17.0-preview.4 2025-11-20 21:17:51 +00:00
gemini-cli-robot cc0eadffe7 fix(patch): cherry-pick 4adfdad to release/v0.17.0-preview.3-pr-13464 to patch version v0.17.0-preview.3 and create version 0.17.0-preview.4 (#13533)
Co-authored-by: Gaurav Sehgal <sehgalgaurav@google.com>
2025-11-20 21:01:45 +00:00
gemini-cli-robot 6e12a7a833 chore(release): v0.17.0-preview.3 2025-11-20 20:15:12 +00:00
gemini-cli-robot d3bf3af4a4 fix(patch): cherry-pick c7b5dcd to release/v0.17.0-preview.2-pr-13517 to patch version v0.17.0-preview.2 and create version 0.17.0-preview.3 (#13529)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2025-11-20 20:00:23 +00:00
gemini-cli-robot 7a9da63600 chore(release): v0.17.0-preview.2 2025-11-20 19:00:43 +00:00
gemini-cli-robot fbe8e9d7db fix(patch): cherry-pick 049a299 to release/v0.17.0-preview.1-pr-13483 to patch version v0.17.0-preview.1 and create version 0.17.0-preview.2 (#13518)
Co-authored-by: Adam Weidman <65992621+adamfweidman@users.noreply.github.com>
2025-11-20 13:38:27 -05:00
gemini-cli-robot 1a0e349cc3 chore(release): v0.17.0-preview.1 2025-11-20 16:28:55 +00:00
gemini-cli-robot dd1f8e12f2 fix(patch): cherry-pick ff725de to release/v0.17.0-preview.0-pr-13477 to patch version v0.17.0-preview.0 and create version 0.17.0-preview.1 (#13511)
Co-authored-by: joshualitt <joshualitt@google.com>
2025-11-20 15:52:28 +00:00
gemini-cli-robot 9e5e06e8b9 chore(release): 0.17.0-preview.0 2025-11-18 17:10:37 +00:00
17 changed files with 213 additions and 119 deletions
+1 -2
View File
@@ -101,7 +101,6 @@ their corresponding top-level category object in your `settings.json` file.
- **`general.previewFeatures`** (boolean):
- **Description:** Enable preview features (e.g., preview models).
- **Default:** `false`
- **Requires restart:** Yes
- **`general.preferredEditor`** (string):
- **Description:** The preferred editor to open files in.
@@ -305,7 +304,7 @@ their corresponding top-level category object in your `settings.json` file.
- **`model.compressionThreshold`** (number):
- **Description:** The fraction of context usage at which to trigger context
compression (e.g. 0.2, 0.3).
- **Default:** `0.7`
- **Default:** `0.5`
- **Requires restart:** Yes
- **`model.skipNextSpeakerCheck`** (boolean):
+22 -33
View File
@@ -1,12 +1,12 @@
{
"name": "@google/gemini-cli",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@google/gemini-cli",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"workspaces": [
"packages/*"
],
@@ -2285,7 +2285,6 @@
"integrity": "sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@octokit/auth-token": "^6.0.0",
"@octokit/graphql": "^9.0.2",
@@ -2466,7 +2465,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
"integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
"license": "Apache-2.0",
"peer": true,
"engines": {
"node": ">=8.0.0"
}
@@ -2500,7 +2498,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz",
"integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/semantic-conventions": "^1.29.0"
},
@@ -2869,7 +2866,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz",
"integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.0.1",
"@opentelemetry/semantic-conventions": "^1.29.0"
@@ -2903,7 +2899,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz",
"integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.0.1",
"@opentelemetry/resources": "2.0.1"
@@ -2956,7 +2951,6 @@
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz",
"integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@opentelemetry/core": "2.0.1",
"@opentelemetry/resources": "2.0.1",
@@ -4168,7 +4162,6 @@
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -4456,7 +4449,6 @@
"integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.35.0",
"@typescript-eslint/types": "8.35.0",
@@ -5380,7 +5372,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -5815,7 +5806,8 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/array-includes": {
"version": "3.1.9",
@@ -7080,6 +7072,7 @@
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"safe-buffer": "5.2.1"
},
@@ -8086,7 +8079,6 @@
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -8676,6 +8668,7 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.6"
}
@@ -8685,6 +8678,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -8694,6 +8688,7 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.8"
}
@@ -8923,6 +8918,7 @@
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
@@ -8941,6 +8937,7 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"peer": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -8949,13 +8946,15 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/finalhandler/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.8"
}
@@ -10154,7 +10153,6 @@
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.4.3.tgz",
"integrity": "sha512-2qm05tjtdia+d1gD7LQjPJyCPJluKDuR5B+FI3ZZXshFoU1igZBFvXs2++x9OT6d9755q+gkRPOdtH8jzx5MiQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@alcalzone/ansi-tokenize": "^0.2.1",
"ansi-escapes": "^7.0.0",
@@ -13242,7 +13240,8 @@
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/path-type": {
"version": "3.0.0",
@@ -13776,7 +13775,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -13787,7 +13785,6 @@
"integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"shell-quote": "^1.6.1",
"ws": "^7"
@@ -15916,7 +15913,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -16081,8 +16077,7 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true,
"license": "0BSD",
"peer": true
"license": "0BSD"
},
"node_modules/tsx": {
"version": "4.20.3",
@@ -16090,7 +16085,6 @@
"integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "~0.25.0",
"get-tsconfig": "^4.7.5"
@@ -16275,7 +16269,6 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -16437,6 +16430,7 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">= 0.4.0"
}
@@ -16492,7 +16486,6 @@
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -16609,7 +16602,6 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -16623,7 +16615,6 @@
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/chai": "^5.2.2",
"@vitest/expect": "3.2.4",
@@ -17321,7 +17312,6 @@
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
@@ -17337,7 +17327,7 @@
},
"packages/a2a-server": {
"name": "@google/gemini-cli-a2a-server",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"dependencies": {
"@a2a-js/sdk": "^0.3.2",
"@google-cloud/storage": "^7.16.0",
@@ -17627,7 +17617,7 @@
},
"packages/cli": {
"name": "@google/gemini-cli",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
"@google/genai": "1.16.0",
@@ -17728,7 +17718,7 @@
},
"packages/core": {
"name": "@google/gemini-cli-core",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"dependencies": {
"@google-cloud/logging": "^11.2.1",
"@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0",
@@ -17863,7 +17853,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -17873,7 +17862,7 @@
},
"packages/test-utils": {
"name": "@google/gemini-cli-test-utils",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"license": "Apache-2.0",
"devDependencies": {
"typescript": "^5.3.3"
@@ -17884,7 +17873,7 @@
},
"packages/vscode-ide-companion": {
"name": "gemini-cli-vscode-ide-companion",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"license": "LICENSE",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"engines": {
"node": ">=20.0.0"
},
@@ -14,7 +14,7 @@
"url": "git+https://github.com/google-gemini/gemini-cli.git"
},
"config": {
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.17.0-nightly.20251116.e650a4ee5"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.17.0"
},
"scripts": {
"start": "cross-env NODE_ENV=development node scripts/start.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-a2a-server",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"description": "Gemini CLI A2A Server",
"repository": {
"type": "git",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"description": "Gemini CLI",
"repository": {
"type": "git",
@@ -25,7 +25,7 @@
"dist"
],
"config": {
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.17.0-nightly.20251116.e650a4ee5"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.17.0"
},
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -337,7 +337,7 @@ describe('SettingsSchema', () => {
).toBe(false);
expect(
getSettingsSchema().general.properties.previewFeatures.requiresRestart,
).toBe(true);
).toBe(false);
expect(
getSettingsSchema().general.properties.previewFeatures.showInDialog,
).toBe(true);
+2 -2
View File
@@ -164,7 +164,7 @@ const SETTINGS_SCHEMA = {
type: 'boolean',
label: 'Preview Features (e.g., models)',
category: 'General',
requiresRestart: true,
requiresRestart: false,
default: false,
description: 'Enable preview features (e.g., preview models).',
showInDialog: true,
@@ -693,7 +693,7 @@ const SETTINGS_SCHEMA = {
label: 'Compression Threshold',
category: 'Model',
requiresRestart: true,
default: 0.7 as number,
default: 0.5 as number,
description:
'The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).',
showInDialog: true,
@@ -14,6 +14,7 @@ import {
setupGithubCommand,
updateGitignore,
GITHUB_WORKFLOW_PATHS,
GITHUB_COMMANDS_PATHS,
} from './setupGithubCommand.js';
import type { CommandContext, ToolActionReturn } from './types.js';
import * as commandUtils from '../utils/commandUtils.js';
@@ -56,11 +57,16 @@ describe('setupGithubCommand', async () => {
const fakeReleaseVersion = 'v1.2.3';
const workflows = GITHUB_WORKFLOW_PATHS.map((p) => path.basename(p));
for (const workflow of workflows) {
vi.mocked(global.fetch).mockReturnValueOnce(
Promise.resolve(new Response(workflow)),
);
}
const commands = GITHUB_COMMANDS_PATHS.map((p) => path.basename(p));
vi.mocked(global.fetch).mockImplementation(async (url) => {
const filename = path.basename(url.toString());
return new Response(filename, {
status: 200,
statusText: 'OK',
headers: { 'Content-Type': 'text/plain' },
});
});
vi.mocked(gitUtils.isGitHubRepository).mockReturnValueOnce(true);
vi.mocked(gitUtils.getGitRepoRoot).mockReturnValueOnce(fakeRepoRoot);
@@ -102,6 +108,12 @@ describe('setupGithubCommand', async () => {
expect(contents).toContain(workflow);
}
for (const command of commands) {
const commandFile = path.join(scratchDir, '.github', 'commands', command);
const contents = await fs.readFile(commandFile, 'utf8');
expect(contents).toContain(command);
}
// Verify that .gitignore was created with the expected entries
const gitignorePath = path.join(scratchDir, '.gitignore');
const gitignoreExists = await fs
@@ -116,6 +128,32 @@ describe('setupGithubCommand', async () => {
expect(gitignoreContent).toContain('gha-creds-*.json');
}
});
it('throws an error when download fails', async () => {
const fakeRepoRoot = scratchDir;
const fakeReleaseVersion = 'v1.2.3';
vi.mocked(global.fetch).mockResolvedValue(
new Response('Not Found', {
status: 404,
statusText: 'Not Found',
}),
);
vi.mocked(gitUtils.isGitHubRepository).mockReturnValueOnce(true);
vi.mocked(gitUtils.getGitRepoRoot).mockReturnValueOnce(fakeRepoRoot);
vi.mocked(gitUtils.getLatestGitHubRelease).mockResolvedValueOnce(
fakeReleaseVersion,
);
vi.mocked(gitUtils.getGitHubRepoInfo).mockReturnValue({
owner: 'fake',
repo: 'repo',
});
await expect(
setupGithubCommand.action?.({} as CommandContext, ''),
).rejects.toThrow(/Invalid response code downloading.*404 - Not Found/);
});
});
describe('updateGitignore', () => {
@@ -30,6 +30,16 @@ export const GITHUB_WORKFLOW_PATHS = [
'pr-review/gemini-review.yml',
];
export const GITHUB_COMMANDS_PATHS = [
'gemini-assistant/gemini-invoke.toml',
'issue-triage/gemini-scheduled-triage.toml',
'issue-triage/gemini-triage.toml',
'pr-review/gemini-review.toml',
];
const REPO_DOWNLOAD_URL =
'https://raw.githubusercontent.com/google-github-actions/run-gemini-cli';
const SOURCE_DIR = 'examples/workflows';
// Generate OS-specific commands to open the GitHub pages needed for setup.
function getOpenUrlsCommands(readmeUrl: string): string[] {
// Determine the OS-specific command to open URLs, ex: 'open', 'xdg-open', etc
@@ -90,6 +100,105 @@ export async function updateGitignore(gitRepoRoot: string): Promise<void> {
}
}
async function downloadFiles({
paths,
releaseTag,
targetDir,
proxy,
abortController,
}: {
paths: string[];
releaseTag: string;
targetDir: string;
proxy: string | undefined;
abortController: AbortController;
}): Promise<void> {
const downloads = [];
for (const fileBasename of paths) {
downloads.push(
(async () => {
const endpoint = `${REPO_DOWNLOAD_URL}/refs/tags/${releaseTag}/${SOURCE_DIR}/${fileBasename}`;
const response = await fetch(endpoint, {
method: 'GET',
dispatcher: proxy ? new ProxyAgent(proxy) : undefined,
signal: AbortSignal.any([
AbortSignal.timeout(30_000),
abortController.signal,
]),
} as RequestInit);
if (!response.ok) {
throw new Error(
`Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`,
);
}
const body = response.body;
if (!body) {
throw new Error(
`Empty body while downloading ${endpoint}: ${response.status} - ${response.statusText}`,
);
}
const destination = path.resolve(
targetDir,
path.basename(fileBasename),
);
const fileStream = fs.createWriteStream(destination, {
mode: 0o644, // -rw-r--r--, user(rw), group(r), other(r)
flags: 'w', // write and overwrite
flush: true,
});
await body.pipeTo(Writable.toWeb(fileStream));
})(),
);
}
await Promise.all(downloads).finally(() => {
abortController.abort();
});
}
async function createDirectory(dirPath: string): Promise<void> {
try {
await fs.promises.mkdir(dirPath, { recursive: true });
} catch (_error) {
debugLogger.debug(`Failed to create ${dirPath} directory:`, _error);
throw new Error(
`Unable to create ${dirPath} directory. Do you have file permissions in the current directory?`,
);
}
}
async function downloadSetupFiles({
configs,
releaseTag,
proxy,
}: {
configs: Array<{ paths: string[]; targetDir: string }>;
releaseTag: string;
proxy: string | undefined;
}): Promise<void> {
try {
await Promise.all(
configs.map(({ paths, targetDir }) => {
const abortController = new AbortController();
return downloadFiles({
paths,
releaseTag,
targetDir,
proxy,
abortController,
});
}),
);
} catch (error) {
debugLogger.debug('Failed to download required setup files: ', error);
throw error;
}
}
export const setupGithubCommand: SlashCommand = {
name: 'setup-github',
description: 'Set up GitHub Actions',
@@ -97,8 +206,6 @@ export const setupGithubCommand: SlashCommand = {
action: async (
context: CommandContext,
): Promise<SlashCommandActionReturn> => {
const abortController = new AbortController();
if (!isGitHubRepository()) {
throw new Error(
'Unable to determine the GitHub repository. /setup-github must be run from a git repository.',
@@ -121,68 +228,21 @@ export const setupGithubCommand: SlashCommand = {
const releaseTag = await getLatestGitHubRelease(proxy);
const readmeUrl = `https://github.com/google-github-actions/run-gemini-cli/blob/${releaseTag}/README.md#quick-start`;
// Create the .github/workflows directory to download the files into
const githubWorkflowsDir = path.join(gitRepoRoot, '.github', 'workflows');
try {
await fs.promises.mkdir(githubWorkflowsDir, { recursive: true });
} catch (_error) {
debugLogger.debug(
`Failed to create ${githubWorkflowsDir} directory:`,
_error,
);
throw new Error(
`Unable to create ${githubWorkflowsDir} directory. Do you have file permissions in the current directory?`,
);
}
// Create workflows directory
const workflowsDir = path.join(gitRepoRoot, '.github', 'workflows');
await createDirectory(workflowsDir);
// Download each workflow in parallel - there aren't enough files to warrant
// a full workerpool model here.
const downloads = [];
for (const workflow of GITHUB_WORKFLOW_PATHS) {
downloads.push(
(async () => {
const endpoint = `https://raw.githubusercontent.com/google-github-actions/run-gemini-cli/refs/tags/${releaseTag}/examples/workflows/${workflow}`;
const response = await fetch(endpoint, {
method: 'GET',
dispatcher: proxy ? new ProxyAgent(proxy) : undefined,
signal: AbortSignal.any([
AbortSignal.timeout(30_000),
abortController.signal,
]),
} as RequestInit);
// Create commands directory
const commandsDir = path.join(gitRepoRoot, '.github', 'commands');
await createDirectory(commandsDir);
if (!response.ok) {
throw new Error(
`Invalid response code downloading ${endpoint}: ${response.status} - ${response.statusText}`,
);
}
const body = response.body;
if (!body) {
throw new Error(
`Empty body while downloading ${endpoint}: ${response.status} - ${response.statusText}`,
);
}
const destination = path.resolve(
githubWorkflowsDir,
path.basename(workflow),
);
const fileStream = fs.createWriteStream(destination, {
mode: 0o644, // -rw-r--r--, user(rw), group(r), other(r)
flags: 'w', // write and overwrite
flush: true,
});
await body.pipeTo(Writable.toWeb(fileStream));
})(),
);
}
// Wait for all downloads to complete
await Promise.all(downloads).finally(() => {
// Stop existing downloads
abortController.abort();
await downloadSetupFiles({
configs: [
{ paths: GITHUB_WORKFLOW_PATHS, targetDir: workflowsDir },
{ paths: GITHUB_COMMANDS_PATHS, targetDir: commandsDir },
],
releaseTag,
proxy,
});
// Add entries to .gitignore file
@@ -192,7 +252,7 @@ export const setupGithubCommand: SlashCommand = {
const commands = [];
commands.push('set -eEuo pipefail');
commands.push(
`echo "Successfully downloaded ${GITHUB_WORKFLOW_PATHS.length} workflows and updated .gitignore. Follow the steps in ${readmeUrl} (skipping the /setup-github step) to complete setup."`,
`echo "Successfully downloaded ${GITHUB_WORKFLOW_PATHS.length} workflows , ${GITHUB_COMMANDS_PATHS.length} commands and updated .gitignore. Follow the steps in ${readmeUrl} (skipping the /setup-github step) to complete setup."`,
);
commands.push(...getOpenUrlsCommands(readmeUrl));
@@ -139,6 +139,7 @@ export const DialogManager = ({
onSelect={() => uiActions.closeSettingsDialog()}
onRestartRequest={() => process.exit(0)}
availableTerminalHeight={terminalHeight - staticExtraHeight}
config={config}
/>
</Box>
);
@@ -43,12 +43,14 @@ import {
} from '../../config/settingsSchema.js';
import { debugLogger } from '@google/gemini-cli-core';
import { keyMatchers, Command } from '../keyMatchers.js';
import type { Config } from '@google/gemini-cli-core';
interface SettingsDialogProps {
settings: LoadedSettings;
onSelect: (settingName: string | undefined, scope: SettingScope) => void;
onRestartRequest?: () => void;
availableTerminalHeight?: number;
config?: Config;
}
const maxItemsToShow = 8;
@@ -58,6 +60,7 @@ export function SettingsDialog({
onSelect,
onRestartRequest,
availableTerminalHeight,
config,
}: SettingsDialogProps): React.JSX.Element {
// Get vim mode context to sync vim mode changes
const { vimEnabled, toggleVimEnabled } = useVimMode();
@@ -208,6 +211,10 @@ export function SettingsDialog({
next.delete(key);
return next;
});
if (key === 'general.previewFeatures') {
config?.setPreviewFeatures(newValue as boolean);
}
} else {
// For restart-required settings, track as modified
setModifiedSettings((prev) => {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-core",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"description": "Gemini CLI Core",
"repository": {
"type": "git",
@@ -72,7 +72,7 @@ export class ModelRouterService {
if (
decision.model === DEFAULT_GEMINI_MODEL &&
this.config.getPreviewFeatures() &&
decision.metadata.source !== 'override'
!decision.metadata.source.includes('override')
) {
// We ALWAYS attempt to upgrade to Preview Model here.
// If we are in fallback mode, the 'previewModelBypassMode' flag (handled in handler.ts/geminiChat.ts)
@@ -19,7 +19,7 @@ import { getInitialChatHistory } from '../utils/environmentContext.js';
* Default threshold for compression token count as a fraction of the model's
* token limit. If the chat history exceeds this threshold, it will be compressed.
*/
export const DEFAULT_COMPRESSION_TOKEN_THRESHOLD = 0.7;
export const DEFAULT_COMPRESSION_TOKEN_THRESHOLD = 0.5;
/**
* The fraction of the latest chat history to keep. A value of 0.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-test-utils",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"private": true,
"main": "src/index.ts",
"license": "Apache-2.0",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "gemini-cli-vscode-ide-companion",
"displayName": "Gemini CLI Companion",
"description": "Enable Gemini CLI with direct access to your IDE workspace.",
"version": "0.17.0-nightly.20251116.e650a4ee5",
"version": "0.17.0",
"publisher": "google",
"icon": "assets/icon.png",
"repository": {
+3 -3
View File
@@ -26,7 +26,7 @@
"previewFeatures": {
"title": "Preview Features (e.g., models)",
"description": "Enable preview features (e.g., preview models).",
"markdownDescription": "Enable preview features (e.g., preview models).\n\n- Category: `General`\n- Requires restart: `yes`\n- Default: `false`",
"markdownDescription": "Enable preview features (e.g., preview models).\n\n- Category: `General`\n- Requires restart: `no`\n- Default: `false`",
"default": false,
"type": "boolean"
},
@@ -419,8 +419,8 @@
"compressionThreshold": {
"title": "Compression Threshold",
"description": "The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).",
"markdownDescription": "The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `0.7`",
"default": 0.7,
"markdownDescription": "The fraction of context usage at which to trigger context compression (e.g. 0.2, 0.3).\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `0.5`",
"default": 0.5,
"type": "number"
},
"skipNextSpeakerCheck": {