mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-07-23 00:01:24 -07:00
Compare commits
12 Commits
shell_format
...
v0.19.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 54c90d73f1 | |||
| 9351148754 | |||
| de13a2ccb4 | |||
| ee6b01f9c7 | |||
| a35d001fde | |||
| 95f9032bf4 | |||
| 578c497417 | |||
| 6169ef04ba | |||
| 933e0dc8ec | |||
| 90a5dc3da5 | |||
| 403d29c63c | |||
| e1ea24806e |
@@ -0,0 +1,54 @@
|
||||
description="Injects context of all relevant cli files"
|
||||
prompt = """
|
||||
The source code contains the content of absolutely every source code file in
|
||||
packages/cli. In addition to the source code, the following test files are
|
||||
included as they are test files that conform to the project's testing standards:
|
||||
`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`.
|
||||
You should very rarely need to read any other files from packages/cli to resolve
|
||||
prompts.
|
||||
|
||||
!{find packages/cli -path packages/cli/dist -prune -o -type f \\( -name "*.ts" -o -name "*.tsx" \\) ! -name "*.test.ts" ! -name "*.test.tsx" ! -name "*.d.ts" -exec echo "--- {} ---" \\; -exec cat {} \\; && echo "--- packages/cli/src/ui/components/InputPrompt.test.tsx ---" && cat packages/cli/src/ui/components/InputPrompt.test.tsx && echo "--- packages/cli/src/ui/App.test.tsx ---" && cat packages/cli/src/ui/App.test.tsx}
|
||||
|
||||
**Pay extremely close attention to these files.** They define the project's
|
||||
core architecture, component patterns, and testing standards.
|
||||
|
||||
In addition to the code context, you MUST strictly adhere to the following frontend-specific development guidelines while adding code to packages/cli.
|
||||
|
||||
## Testing Standards
|
||||
* **Async Testing**: ALWAYS use `waitFor` from `packages/cli/src/test-utils/async.ts` instead of `vi.waitFor` to prevent flakiness and `act` warnings. NEVER use fixed waits (e.g., `await delay(100)`).
|
||||
* **State Changes**: Wrap all blocks that change component state in `act`.
|
||||
* **Snapshots**: Use `toMatchSnapshot` to verify rendering.
|
||||
* **Rendering**: Use `render` or `renderWithProviders` from `packages/cli/src/test-utils/render.tsx` instead of `ink-testing-library` directly.
|
||||
* **Mocking**:
|
||||
* Reuse existing mocks/fakes where possible.
|
||||
* **Parameterized Tests**: Use parameterized tests with explicit types to reduce duplication and ensure type safety.
|
||||
* Avoid mocking the file system, os, or child_process if at all possible; if you have to mock the Mock critical dependencies (`fs`, `os`, `child_process`) do so ONLY at the top of the file.
|
||||
|
||||
## React & Ink Architecture
|
||||
* **Keyboard Handling**: You MUST use `useKeyPress.ts` from Gemini CLI for keyboard handling, NOT the standard ink library. This is critical for supporting slow terminals and multiple events per frame.
|
||||
* Handle multiple events gracefully (often requires a reducer pattern, see `text-buffer.ts`).
|
||||
* **State Management**:
|
||||
* NEVER trigger side effects from within the body of a `setState` callback. Use a reducer or `useRef` if necessary.
|
||||
* Initialize state explicitly (e.g., use `undefined` rather than `true` if unknown).
|
||||
* **Performance**:
|
||||
* Avoid synchronous file I/O in components.
|
||||
* Do not introduce excessive property drilling; leverage or extend existing providers.
|
||||
|
||||
## Configuration & Settings
|
||||
* **Settings vs Args**: Use settings for user-configurable options; do not add new CLI arguments.
|
||||
* **Schema**: Add new settings to `packages/cli/src/config/settingsSchema.ts`.
|
||||
* **Documentation**:
|
||||
* If `showInDialog: true`, document in `docs/get-started/configuration.md`.
|
||||
* Ensure `requiresRestart` is correctly set.
|
||||
|
||||
## Keyboard Shortcuts
|
||||
* **Registration**: Define new shortcuts in `packages/cli/src/config/keyBindings.ts`.
|
||||
* **Documentation**: Document all new shortcuts in `docs/cli/keyboard-shortcuts.md`.
|
||||
* **Compatibility**: Avoid function keys and common VSCode shortcuts. Be cautious with `Meta` key (Mac-limited support).
|
||||
|
||||
## General
|
||||
* **Logging**: Use `debugLogger` for errors. NEVER leave `console.log/warn/error` in the code.
|
||||
* **TypeScript**: Avoid the non-null assertion operator (`!`).
|
||||
|
||||
{{args}}.
|
||||
"""
|
||||
@@ -0,0 +1,57 @@
|
||||
description="Injects context of all relevant cli files"
|
||||
prompt = """
|
||||
The following output contains the complete
|
||||
source code of the gemini cli library (`packages/cli`), and {packages/core} and representative test files
|
||||
(`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`) that best conform to the project's testing standards.
|
||||
**Pay extremely close attention to these files.** They define the project's
|
||||
core architecture, component patterns, and testing standards.
|
||||
|
||||
The source code contains the content of absolutely every source code file in
|
||||
packages/cli and packages/core. In addition to the source code, the following test files are
|
||||
included as they are test files that conform to the project's testing standards:
|
||||
`packages/cli/src/ui/components/InputPrompt.test.tsx` and `packages/cli/src/ui/App.test.tsx`.
|
||||
You should very rarely need to read any other files from packages/cli to resolve
|
||||
prompts.
|
||||
|
||||
!{find packages/cli packages/core \\( -path packages/cli/dist -o -path packages/core/dist -o -name node_modules \\) -prune -o -type f \\( -name "*.ts" -o -name "*.tsx" \\) ! -name "*.test.ts" ! -name "*.test.tsx" ! -name "*.d.ts" -exec echo "--- {} ---" \\; -exec cat {} \\; && echo "--- packages/cli/src/ui/components/InputPrompt.test.tsx ---" && cat packages/cli/src/ui/components/InputPrompt.test.tsx && echo "--- packages/cli/src/ui/App.test.tsx ---" && cat packages/cli/src/ui/App.test.tsx}
|
||||
|
||||
In addition to the code context, you MUST strictly adhere to the following frontend-specific development guidelines when writing code in packages/cli.
|
||||
|
||||
## Testing Standards
|
||||
* **Async Testing**: ALWAYS use `waitFor` from `packages/cli/src/test-utils/async.ts` instead of `vi.waitFor` to prevent flakiness and `act` warnings. NEVER use fixed waits (e.g., `await delay(100)`).
|
||||
* **State Changes**: Wrap all blocks that change component state in `act`.
|
||||
* **Snapshots**: Use `toMatchSnapshot` to verify rendering.
|
||||
* **Rendering**: Use `render` or `renderWithProviders` from `packages/cli/src/test-utils/render.tsx` instead of `ink-testing-library` directly.
|
||||
* **Mocking**:
|
||||
* Reuse existing mocks/fakes where possible.
|
||||
* **Parameterized Tests**: Use parameterized tests with explicit types to reduce duplication and ensure type safety.
|
||||
* Avoid mocking the file system, os, or child_process if at all possible; if you have to mock the Mock critical dependencies (`fs`, `os`, `child_process`) do so ONLY at the top of the file.
|
||||
|
||||
## React & Ink Architecture
|
||||
* **Keyboard Handling**: You MUST use `useKeyPress.ts` from Gemini CLI for keyboard handling, NOT the standard ink library. This is critical for supporting slow terminals and multiple events per frame.
|
||||
* Handle multiple events gracefully (often requires a reducer pattern, see `text-buffer.ts`).
|
||||
* **State Management**:
|
||||
* NEVER trigger side effects from within the body of a `setState` callback. Use a reducer or `useRef` if necessary.
|
||||
* Initialize state explicitly (e.g., use `undefined` rather than `true` if unknown).
|
||||
* **Performance**:
|
||||
* Avoid synchronous file I/O in components.
|
||||
* Do not introduce excessive property drilling; leverage or extend existing providers.
|
||||
|
||||
## Configuration & Settings
|
||||
* **Settings vs Args**: Use settings for user-configurable options; do not add new CLI arguments.
|
||||
* **Schema**: Add new settings to `packages/cli/src/config/settingsSchema.ts`.
|
||||
* **Documentation**:
|
||||
* If `showInDialog: true`, document in `docs/get-started/configuration.md`.
|
||||
* Ensure `requiresRestart` is correctly set.
|
||||
|
||||
## Keyboard Shortcuts
|
||||
* **Registration**: Define new shortcuts in `packages/cli/src/config/keyBindings.ts`.
|
||||
* **Documentation**: Document all new shortcuts in `docs/cli/keyboard-shortcuts.md`.
|
||||
* **Compatibility**: Avoid function keys and common VSCode shortcuts. Be cautious with `Meta` key (Mac-limited support).
|
||||
|
||||
## General
|
||||
* **Logging**: Use `debugLogger` for errors. NEVER leave `console.log/warn/error` in the code.
|
||||
* **TypeScript**: Avoid the non-null assertion operator (`!`).
|
||||
|
||||
{{args}}.
|
||||
"""
|
||||
Generated
+64
-40
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"ink": "npm:@jrichman/ink@6.4.6",
|
||||
"latest-version": "^9.0.0",
|
||||
"simple-git": "^3.28.0"
|
||||
@@ -2407,7 +2408,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",
|
||||
@@ -2588,7 +2588,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"
|
||||
}
|
||||
@@ -2622,7 +2621,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"
|
||||
},
|
||||
@@ -2991,7 +2989,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"
|
||||
@@ -3025,7 +3022,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"
|
||||
@@ -3078,7 +3074,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",
|
||||
@@ -4237,12 +4232,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz",
|
||||
"integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==",
|
||||
"version": "24.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
|
||||
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/normalize-package-data": {
|
||||
@@ -4289,7 +4284,6 @@
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -4577,7 +4571,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",
|
||||
@@ -5501,7 +5494,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"
|
||||
},
|
||||
@@ -5937,7 +5929,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",
|
||||
@@ -7201,6 +7194,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"
|
||||
},
|
||||
@@ -8216,7 +8210,6 @@
|
||||
"integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -8806,6 +8799,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"
|
||||
}
|
||||
@@ -8815,6 +8809,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"
|
||||
}
|
||||
@@ -8824,6 +8819,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"
|
||||
}
|
||||
@@ -9077,6 +9073,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",
|
||||
@@ -9095,6 +9092,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"
|
||||
}
|
||||
@@ -9103,13 +9101,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"
|
||||
}
|
||||
@@ -10320,7 +10320,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.4.6.tgz",
|
||||
"integrity": "sha512-QHl6l1cl3zPCaRMzt9TUbTX6Q5SzvkGEZDDad0DmSf5SPmT1/90k6pGPejEvDCJprkitwObXpPaTWGHItqsy4g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alcalzone/ansi-tokenize": "^0.2.1",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
@@ -13428,7 +13427,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",
|
||||
@@ -13963,7 +13963,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -13974,7 +13973,6 @@
|
||||
"integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
@@ -16193,7 +16191,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -16358,8 +16355,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",
|
||||
@@ -16367,7 +16363,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"
|
||||
@@ -16552,7 +16547,6 @@
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -16627,9 +16621,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unicorn-magic": {
|
||||
@@ -16715,6 +16709,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"
|
||||
}
|
||||
@@ -16770,7 +16765,6 @@
|
||||
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -16887,7 +16881,6 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -16901,7 +16894,6 @@
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
@@ -17608,7 +17600,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"
|
||||
}
|
||||
@@ -17624,7 +17615,7 @@
|
||||
},
|
||||
"packages/a2a-server": {
|
||||
"name": "@google/gemini-cli-a2a-server",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"dependencies": {
|
||||
"@a2a-js/sdk": "^0.3.2",
|
||||
"@google-cloud/storage": "^7.16.0",
|
||||
@@ -17914,7 +17905,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"dependencies": {
|
||||
"@google/gemini-cli-core": "file:../core",
|
||||
"@google/genai": "1.30.0",
|
||||
@@ -17981,6 +17972,16 @@
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"packages/cli/node_modules/@types/node": {
|
||||
"version": "20.19.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
|
||||
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"packages/cli/node_modules/string-width": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz",
|
||||
@@ -18013,9 +18014,16 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"packages/cli/node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@google/gemini-cli-core",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"dependencies": {
|
||||
"@google-cloud/logging": "^11.2.1",
|
||||
"@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0",
|
||||
@@ -18150,7 +18158,6 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -18160,7 +18167,7 @@
|
||||
},
|
||||
"packages/test-utils": {
|
||||
"name": "@google/gemini-cli-test-utils",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3"
|
||||
@@ -18171,7 +18178,7 @@
|
||||
},
|
||||
"packages/vscode-ide-companion": {
|
||||
"name": "gemini-cli-vscode-ide-companion",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"license": "LICENSE",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.23.0",
|
||||
@@ -18197,6 +18204,16 @@
|
||||
"vscode": "^1.99.0"
|
||||
}
|
||||
},
|
||||
"packages/vscode-ide-companion/node_modules/@types/node": {
|
||||
"version": "20.19.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
|
||||
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"packages/vscode-ide-companion/node_modules/@types/vscode": {
|
||||
"version": "1.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.99.0.tgz",
|
||||
@@ -18325,6 +18342,13 @@
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"packages/vscode-ide-companion/node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"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.19.0-nightly.20251125.f6d97d448"
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.19.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env NODE_ENV=development node scripts/start.js",
|
||||
@@ -119,6 +119,7 @@
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"ink": "npm:@jrichman/ink@6.4.6",
|
||||
"latest-version": "^9.0.0",
|
||||
"simple-git": "^3.28.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli-a2a-server",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"description": "Gemini CLI A2A Server",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -658,7 +658,7 @@ export class Task {
|
||||
errorMessage,
|
||||
);
|
||||
|
||||
let errMessage = 'Unknown error from LLM stream';
|
||||
let errMessage = `Unknown error from LLM stream: ${JSON.stringify(event)}`;
|
||||
if (errorEvent.value) {
|
||||
errMessage = parseAndFormatApiError(errorEvent.value);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"description": "Gemini CLI",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,7 +25,7 @@
|
||||
"dist"
|
||||
],
|
||||
"config": {
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.19.0-nightly.20251125.f6d97d448"
|
||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.19.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/gemini-cli-core": "file:../core",
|
||||
|
||||
@@ -138,11 +138,14 @@ const createSession = (overrides: Partial<SessionInfo>): SessionInfo => ({
|
||||
|
||||
describe('SessionBrowser component', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date('2025-11-01T12:00:00Z'));
|
||||
keypressHandlers.length = 0;
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { render } from '../../test-utils/render.js';
|
||||
import { renderWithProviders } from '../../test-utils/render.js';
|
||||
import { waitFor } from '../../test-utils/async.js';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { ThemeDialog } from './ThemeDialog.js';
|
||||
import { LoadedSettings } from '../../config/settings.js';
|
||||
import { KeypressProvider } from '../contexts/KeypressContext.js';
|
||||
import { SettingsContext } from '../contexts/SettingsContext.js';
|
||||
import { DEFAULT_THEME, themeManager } from '../themes/theme-manager.js';
|
||||
import { act } from 'react';
|
||||
|
||||
@@ -76,12 +74,9 @@ describe('ThemeDialog Snapshots', () => {
|
||||
|
||||
it('should render correctly in theme selection mode', () => {
|
||||
const settings = createMockSettings();
|
||||
const { lastFrame } = render(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<ThemeDialog {...baseProps} settings={settings} />
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
const { lastFrame } = renderWithProviders(
|
||||
<ThemeDialog {...baseProps} settings={settings} />,
|
||||
{ settings },
|
||||
);
|
||||
|
||||
expect(lastFrame()).toMatchSnapshot();
|
||||
@@ -89,12 +84,9 @@ describe('ThemeDialog Snapshots', () => {
|
||||
|
||||
it('should render correctly in scope selector mode', async () => {
|
||||
const settings = createMockSettings();
|
||||
const { lastFrame, stdin } = render(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<ThemeDialog {...baseProps} settings={settings} />
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
const { lastFrame, stdin } = renderWithProviders(
|
||||
<ThemeDialog {...baseProps} settings={settings} />,
|
||||
{ settings },
|
||||
);
|
||||
|
||||
// Press Tab to switch to scope selector mode
|
||||
@@ -111,16 +103,13 @@ describe('ThemeDialog Snapshots', () => {
|
||||
it('should call onCancel when ESC is pressed', async () => {
|
||||
const mockOnCancel = vi.fn();
|
||||
const settings = createMockSettings();
|
||||
const { stdin } = render(
|
||||
<SettingsContext.Provider value={settings}>
|
||||
<KeypressProvider>
|
||||
<ThemeDialog
|
||||
{...baseProps}
|
||||
onCancel={mockOnCancel}
|
||||
settings={settings}
|
||||
/>
|
||||
</KeypressProvider>
|
||||
</SettingsContext.Provider>,
|
||||
const { stdin } = renderWithProviders(
|
||||
<ThemeDialog
|
||||
{...baseProps}
|
||||
onCancel={mockOnCancel}
|
||||
settings={settings}
|
||||
/>,
|
||||
{ settings },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
@@ -131,4 +120,26 @@ describe('ThemeDialog Snapshots', () => {
|
||||
expect(mockOnCancel).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call refreshStatic when a theme is selected', async () => {
|
||||
const mockRefreshStatic = vi.fn();
|
||||
const settings = createMockSettings();
|
||||
const { stdin } = renderWithProviders(
|
||||
<ThemeDialog {...baseProps} settings={settings} />,
|
||||
{
|
||||
settings,
|
||||
uiActions: { refreshStatic: mockRefreshStatic },
|
||||
},
|
||||
);
|
||||
|
||||
// Press Enter to select the theme
|
||||
act(() => {
|
||||
stdin.write('\r');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockRefreshStatic).toHaveBeenCalled();
|
||||
expect(baseProps.onSelect).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import { getScopeMessageForSetting } from '../../utils/dialogScopeUtils.js';
|
||||
import { useKeypress } from '../hooks/useKeypress.js';
|
||||
import { useAlternateBuffer } from '../hooks/useAlternateBuffer.js';
|
||||
import { ScopeSelector } from './shared/ScopeSelector.js';
|
||||
import { useUIActions } from '../contexts/UIActionsContext.js';
|
||||
|
||||
interface ThemeDialogProps {
|
||||
/** Callback function when a theme is selected */
|
||||
@@ -46,6 +47,7 @@ export function ThemeDialog({
|
||||
terminalWidth,
|
||||
}: ThemeDialogProps): React.JSX.Element {
|
||||
const isAlternateBuffer = useAlternateBuffer();
|
||||
const { refreshStatic } = useUIActions();
|
||||
const [selectedScope, setSelectedScope] = useState<LoadableSettingScope>(
|
||||
SettingScope.User,
|
||||
);
|
||||
@@ -93,8 +95,9 @@ export function ThemeDialog({
|
||||
const handleThemeSelect = useCallback(
|
||||
(themeName: string) => {
|
||||
onSelect(themeName, selectedScope);
|
||||
refreshStatic();
|
||||
},
|
||||
[onSelect, selectedScope],
|
||||
[onSelect, selectedScope, refreshStatic],
|
||||
);
|
||||
|
||||
const handleThemeHighlight = (themeName: string) => {
|
||||
@@ -109,8 +112,9 @@ export function ThemeDialog({
|
||||
const handleScopeSelect = useCallback(
|
||||
(scope: LoadableSettingScope) => {
|
||||
onSelect(highlightedThemeName, scope);
|
||||
refreshStatic();
|
||||
},
|
||||
[onSelect, highlightedThemeName],
|
||||
[onSelect, highlightedThemeName, refreshStatic],
|
||||
);
|
||||
|
||||
const [mode, setMode] = useState<'theme' | 'scope'>('theme');
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`ThemeDialog Snapshots > should render correctly in scope selector mode 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Apply To │
|
||||
│ ● 1. User Settings │
|
||||
│ 2. Workspace Settings │
|
||||
│ 3. System Settings │
|
||||
│ │
|
||||
│ (Use Enter to apply scope, Tab to select theme, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Apply To │
|
||||
│ ● 1. User Settings │
|
||||
│ 2. Workspace Settings │
|
||||
│ 3. System Settings │
|
||||
│ │
|
||||
│ (Use Enter to apply scope, Tab to select theme, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
exports[`ThemeDialog Snapshots > should render correctly in theme selection mode 1`] = `
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Select Theme Preview │
|
||||
│ ▲ ┌─────────────────────────────────────────────────┐ │
|
||||
│ 1. ANSI Dark │ │ │
|
||||
│ 2. Atom One Dark │ 1 # function │ │
|
||||
│ 3. Ayu Dark │ 2 def fibonacci(n): │ │
|
||||
│ ● 4. Default Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Shades Of Purple Dark │ 6 return a │ │
|
||||
│ 8. ANSI Light Light │ │ │
|
||||
│ 9. Ayu Light Light │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Default Light Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. GitHub Light Light │ │ │
|
||||
│ 12. Google Code Light └─────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
"╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ > Select Theme Preview │
|
||||
│ ▲ ┌────────────────────────────────────────────────────────────┐ │
|
||||
│ 1. ANSI Dark │ │ │
|
||||
│ 2. Atom One Dark │ 1 # function │ │
|
||||
│ 3. Ayu Dark │ 2 def fibonacci(n): │ │
|
||||
│ ● 4. Default Dark │ 3 a, b = 0, 1 │ │
|
||||
│ 5. Dracula Dark │ 4 for _ in range(n): │ │
|
||||
│ 6. GitHub Dark │ 5 a, b = b, a + b │ │
|
||||
│ 7. Holiday Dark │ 6 return a │ │
|
||||
│ 8. Shades Of Purple Dark │ │ │
|
||||
│ 9. ANSI Light Light │ 1 - print("Hello, " + name) │ │
|
||||
│ 10. Ayu Light Light │ 1 + print(f"Hello, {name}!") │ │
|
||||
│ 11. Default Light Light │ │ │
|
||||
│ 12. GitHub Light Light └────────────────────────────────────────────────────────────┘ │
|
||||
│ ▼ │
|
||||
│ │
|
||||
│ (Use Enter to select, Tab to configure scope, Esc to close) │
|
||||
│ │
|
||||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type ColorsTheme, Theme } from './theme.js';
|
||||
import { interpolateColor } from './color-utils.js';
|
||||
|
||||
const holidayColors: ColorsTheme = {
|
||||
type: 'dark',
|
||||
Background: '#00210e',
|
||||
Foreground: '#F0F8FF',
|
||||
LightBlue: '#B0E0E6',
|
||||
AccentBlue: '#3CB371',
|
||||
AccentPurple: '#FF9999',
|
||||
AccentCyan: '#33F9FF',
|
||||
AccentGreen: '#3CB371',
|
||||
AccentYellow: '#FFEE8C',
|
||||
AccentRed: '#FF6347',
|
||||
DiffAdded: '#2E8B57',
|
||||
DiffRemoved: '#CD5C5C',
|
||||
Comment: '#8FBC8F',
|
||||
Gray: '#D7F5D3',
|
||||
DarkGray: interpolateColor('#D7F5D3', '#151B18', 0.5),
|
||||
GradientColors: ['#FF0000', '#FFFFFF', '#008000'],
|
||||
};
|
||||
|
||||
export const Holiday: Theme = new Theme(
|
||||
'Holiday',
|
||||
'dark',
|
||||
{
|
||||
hljs: {
|
||||
display: 'block',
|
||||
overflowX: 'auto',
|
||||
padding: '0.5em',
|
||||
background: holidayColors.Background,
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-keyword': {
|
||||
color: holidayColors.AccentBlue,
|
||||
},
|
||||
'hljs-literal': {
|
||||
color: holidayColors.AccentBlue,
|
||||
},
|
||||
'hljs-symbol': {
|
||||
color: holidayColors.AccentBlue,
|
||||
},
|
||||
'hljs-name': {
|
||||
color: holidayColors.AccentBlue,
|
||||
},
|
||||
'hljs-link': {
|
||||
color: holidayColors.AccentBlue,
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
'hljs-built_in': {
|
||||
color: holidayColors.AccentCyan,
|
||||
},
|
||||
'hljs-type': {
|
||||
color: holidayColors.AccentCyan,
|
||||
},
|
||||
'hljs-number': {
|
||||
color: holidayColors.AccentGreen,
|
||||
},
|
||||
'hljs-class': {
|
||||
color: holidayColors.AccentGreen,
|
||||
},
|
||||
'hljs-string': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-meta-string': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-regexp': {
|
||||
color: holidayColors.AccentRed,
|
||||
},
|
||||
'hljs-template-tag': {
|
||||
color: holidayColors.AccentRed,
|
||||
},
|
||||
'hljs-subst': {
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-function': {
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-title': {
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-params': {
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-formula': {
|
||||
color: holidayColors.Foreground,
|
||||
},
|
||||
'hljs-comment': {
|
||||
color: holidayColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-quote': {
|
||||
color: holidayColors.Comment,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-doctag': {
|
||||
color: holidayColors.Comment,
|
||||
},
|
||||
'hljs-meta': {
|
||||
color: holidayColors.Gray,
|
||||
},
|
||||
'hljs-meta-keyword': {
|
||||
color: holidayColors.Gray,
|
||||
},
|
||||
'hljs-tag': {
|
||||
color: holidayColors.Gray,
|
||||
},
|
||||
'hljs-variable': {
|
||||
color: holidayColors.AccentPurple,
|
||||
},
|
||||
'hljs-template-variable': {
|
||||
color: holidayColors.AccentPurple,
|
||||
},
|
||||
'hljs-attr': {
|
||||
color: holidayColors.LightBlue,
|
||||
},
|
||||
'hljs-attribute': {
|
||||
color: holidayColors.LightBlue,
|
||||
},
|
||||
'hljs-builtin-name': {
|
||||
color: holidayColors.LightBlue,
|
||||
},
|
||||
'hljs-section': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-emphasis': {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'hljs-strong': {
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
'hljs-bullet': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-selector-tag': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-selector-id': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-selector-class': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-selector-attr': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-selector-pseudo': {
|
||||
color: holidayColors.AccentYellow,
|
||||
},
|
||||
'hljs-addition': {
|
||||
backgroundColor: holidayColors.DiffAdded,
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
},
|
||||
'hljs-deletion': {
|
||||
backgroundColor: holidayColors.DiffRemoved,
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
holidayColors,
|
||||
);
|
||||
@@ -11,6 +11,7 @@ import { Dracula } from './dracula.js';
|
||||
import { GitHubDark } from './github-dark.js';
|
||||
import { GitHubLight } from './github-light.js';
|
||||
import { GoogleCode } from './googlecode.js';
|
||||
import { Holiday } from './holiday.js';
|
||||
import { DefaultLight } from './default-light.js';
|
||||
import { DefaultDark } from './default.js';
|
||||
import { ShadesOfPurple } from './shades-of-purple.js';
|
||||
@@ -51,6 +52,7 @@ class ThemeManager {
|
||||
GitHubDark,
|
||||
GitHubLight,
|
||||
GoogleCode,
|
||||
Holiday,
|
||||
ShadesOfPurple,
|
||||
XCode,
|
||||
ANSI,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli-core",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"description": "Gemini CLI Core",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -8,9 +8,12 @@ import { vi, describe, it, expect, beforeEach, type Mock } from 'vitest';
|
||||
import EventEmitter from 'node:events';
|
||||
import type { Readable } from 'node:stream';
|
||||
import { type ChildProcess } from 'node:child_process';
|
||||
import type { ShellOutputEvent } from './shellExecutionService.js';
|
||||
import type {
|
||||
ShellOutputEvent,
|
||||
ShellExecutionConfig,
|
||||
} from './shellExecutionService.js';
|
||||
import { ShellExecutionService } from './shellExecutionService.js';
|
||||
import type { AnsiOutput } from '../utils/terminalSerializer.js';
|
||||
import type { AnsiOutput, AnsiToken } from '../utils/terminalSerializer.js';
|
||||
|
||||
// Hoisted Mocks
|
||||
const mockPtySpawn = vi.hoisted(() => vi.fn());
|
||||
@@ -64,7 +67,7 @@ const mockProcessKill = vi
|
||||
.spyOn(process, 'kill')
|
||||
.mockImplementation(() => true);
|
||||
|
||||
const shellExecutionConfig = {
|
||||
const shellExecutionConfig: ShellExecutionConfig = {
|
||||
terminalWidth: 80,
|
||||
terminalHeight: 24,
|
||||
pager: 'cat',
|
||||
@@ -74,21 +77,19 @@ const shellExecutionConfig = {
|
||||
|
||||
const createExpectedAnsiOutput = (text: string | string[]): AnsiOutput => {
|
||||
const lines = Array.isArray(text) ? text : text.split('\n');
|
||||
const expected: AnsiOutput = Array.from(
|
||||
{ length: shellExecutionConfig.terminalHeight },
|
||||
(_, i) => [
|
||||
{
|
||||
text: expect.stringMatching((lines[i] || '').trim()),
|
||||
bold: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
dim: false,
|
||||
inverse: false,
|
||||
fg: '',
|
||||
bg: '',
|
||||
},
|
||||
],
|
||||
);
|
||||
const len = (shellExecutionConfig.terminalHeight ?? 24) as number;
|
||||
const expected: AnsiOutput = Array.from({ length: len }, (_, i) => [
|
||||
{
|
||||
text: expect.stringMatching((lines[i] || '').trim()),
|
||||
bold: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
dim: false,
|
||||
inverse: false,
|
||||
fg: '',
|
||||
bg: '',
|
||||
} as AnsiToken,
|
||||
]);
|
||||
return expected;
|
||||
};
|
||||
|
||||
@@ -242,6 +243,113 @@ describe('ShellExecutionService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should capture large output (10000 lines)', async () => {
|
||||
const lineCount = 10000;
|
||||
const lines = Array.from({ length: lineCount }, (_, i) => `line ${i}`);
|
||||
const expectedOutput = lines.join('\n');
|
||||
|
||||
const { result } = await simulateExecution(
|
||||
'large-output-command',
|
||||
(pty) => {
|
||||
// Send data in chunks to simulate realistic streaming
|
||||
// Use \r\n to ensure the terminal moves the cursor to the start of the line
|
||||
const chunkSize = 1000;
|
||||
for (let i = 0; i < lineCount; i += chunkSize) {
|
||||
const chunk = lines.slice(i, i + chunkSize).join('\r\n') + '\r\n';
|
||||
pty.onData.mock.calls[0][0](chunk);
|
||||
}
|
||||
pty.onExit.mock.calls[0][0]({ exitCode: 0, signal: null });
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
// The terminal buffer output includes trailing spaces for each line (up to terminal width).
|
||||
// We trim each line to match our expected simple string.
|
||||
const processedOutput = result.output
|
||||
.split('\n')
|
||||
.map((l) => l.trimEnd())
|
||||
.join('\n')
|
||||
.trim();
|
||||
expect(processedOutput).toBe(expectedOutput);
|
||||
expect(result.output.split('\n').length).toBeGreaterThanOrEqual(
|
||||
lineCount,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not wrap long lines in the final output', async () => {
|
||||
// Set a small width to force wrapping
|
||||
const narrowConfig = { ...shellExecutionConfig, terminalWidth: 10 };
|
||||
const longString = '123456789012345'; // 15 chars, should wrap at 10
|
||||
|
||||
const { result } = await simulateExecution(
|
||||
'long-line-command',
|
||||
(pty) => {
|
||||
pty.onData.mock.calls[0][0](longString);
|
||||
pty.onExit.mock.calls[0][0]({ exitCode: 0, signal: null });
|
||||
},
|
||||
narrowConfig,
|
||||
);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.output.trim()).toBe(longString);
|
||||
});
|
||||
|
||||
it('should not add extra padding but preserve explicit trailing whitespace', async () => {
|
||||
const { result } = await simulateExecution('cmd', (pty) => {
|
||||
// "value" should not get terminal-width padding
|
||||
// "value2 " should keep its spaces
|
||||
pty.onData.mock.calls[0][0]('value\r\nvalue2 ');
|
||||
pty.onExit.mock.calls[0][0]({ exitCode: 0, signal: null });
|
||||
});
|
||||
|
||||
expect(result.output).toBe('value\nvalue2 ');
|
||||
});
|
||||
|
||||
it('should truncate output exceeding the scrollback limit', async () => {
|
||||
const scrollbackLimit = 100;
|
||||
const totalLines = 150;
|
||||
// Generate lines: "line 0", "line 1", ...
|
||||
const lines = Array.from({ length: totalLines }, (_, i) => `line ${i}`);
|
||||
|
||||
const { result } = await simulateExecution(
|
||||
'overflow-command',
|
||||
(pty) => {
|
||||
const chunk = lines.join('\r\n') + '\r\n';
|
||||
pty.onData.mock.calls[0][0](chunk);
|
||||
pty.onExit.mock.calls[0][0]({ exitCode: 0, signal: null });
|
||||
},
|
||||
{ ...shellExecutionConfig, scrollback: scrollbackLimit },
|
||||
);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
|
||||
// The terminal should keep the *last* 'scrollbackLimit' lines + lines in the viewport.
|
||||
// xterm.js scrollback is the number of lines *above* the viewport.
|
||||
// So total lines retained = scrollback + rows.
|
||||
// However, our `getFullBufferText` implementation iterates the *active* buffer.
|
||||
// In headless xterm, the buffer length grows.
|
||||
// Let's verify that we have fewer lines than totalLines.
|
||||
|
||||
const outputLines = result.output
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((l) => l.trimEnd());
|
||||
|
||||
// We expect the *start* of the output to be truncated.
|
||||
// The first retained line should be > "line 0".
|
||||
// Specifically, if we sent 150 lines and have space for roughly 100 + viewport(24),
|
||||
// we should miss the first ~26 lines.
|
||||
|
||||
// Check that we lost some lines from the beginning
|
||||
expect(outputLines.length).toBeLessThan(totalLines);
|
||||
expect(outputLines[0]).not.toBe('line 0');
|
||||
|
||||
// Check that we have the *last* lines
|
||||
expect(outputLines[outputLines.length - 1]).toBe(
|
||||
`line ${totalLines - 1}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call onPid with the process id', async () => {
|
||||
const abortController = new AbortController();
|
||||
const handle = await ShellExecutionService.execute(
|
||||
|
||||
@@ -24,6 +24,11 @@ const { Terminal } = pkg;
|
||||
const SIGKILL_TIMEOUT_MS = 200;
|
||||
const MAX_CHILD_PROCESS_BUFFER_SIZE = 16 * 1024 * 1024; // 16MB
|
||||
|
||||
// We want to allow shell outputs that are close to the context window in size.
|
||||
// 300,000 lines is roughly equivalent to a large context window, ensuring
|
||||
// we capture significant output from long-running commands.
|
||||
export const SCROLLBACK_LIMIT = 300000;
|
||||
|
||||
const BASH_SHOPT_OPTIONS = 'promptvars nullglob extglob nocaseglob dotglob';
|
||||
const BASH_SHOPT_GUARD = `shopt -u ${BASH_SHOPT_OPTIONS};`;
|
||||
|
||||
@@ -77,6 +82,7 @@ export interface ShellExecutionConfig {
|
||||
defaultBg?: string;
|
||||
// Used for testing
|
||||
disableDynamicLineTrimming?: boolean;
|
||||
scrollback?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,10 +116,36 @@ const getFullBufferText = (terminal: pkg.Terminal): string => {
|
||||
const lines: string[] = [];
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
const line = buffer.getLine(i);
|
||||
const lineContent = line ? line.translateToString() : '';
|
||||
lines.push(lineContent);
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
// If the NEXT line is wrapped, it means it's a continuation of THIS line.
|
||||
// We should not trim the right side of this line because trailing spaces
|
||||
// might be significant parts of the wrapped content.
|
||||
// If it's not wrapped, we trim normally.
|
||||
let trimRight = true;
|
||||
if (i + 1 < buffer.length) {
|
||||
const nextLine = buffer.getLine(i + 1);
|
||||
if (nextLine?.isWrapped) {
|
||||
trimRight = false;
|
||||
}
|
||||
}
|
||||
|
||||
const lineContent = line.translateToString(trimRight);
|
||||
|
||||
if (line.isWrapped && lines.length > 0) {
|
||||
lines[lines.length - 1] += lineContent;
|
||||
} else {
|
||||
lines.push(lineContent);
|
||||
}
|
||||
}
|
||||
return lines.join('\n').trimEnd();
|
||||
|
||||
// Remove trailing empty lines
|
||||
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
||||
lines.pop();
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -443,6 +475,7 @@ export class ShellExecutionService {
|
||||
allowProposedApi: true,
|
||||
cols,
|
||||
rows,
|
||||
scrollback: shellExecutionConfig.scrollback ?? SCROLLBACK_LIMIT,
|
||||
});
|
||||
headlessTerminal.scrollToTop();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@google/gemini-cli-test-utils",
|
||||
"version": "0.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -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.19.0-nightly.20251125.f6d97d448",
|
||||
"version": "0.19.4",
|
||||
"publisher": "google",
|
||||
"icon": "assets/icon.png",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user