Compare commits

..

5 Commits

18 changed files with 293 additions and 502 deletions
+1 -2
View File
@@ -2,8 +2,7 @@
name: docs-changelog
description: >-
Generates and formats changelog files for a new release based on provided
version and raw changelog data. For maintenance and troubleshooting help, see
references/changelog-automation.md.
version and raw changelog data.
---
# Procedure: Updating Changelog for New Releases
@@ -1,87 +0,0 @@
# Guide to automated release notes maintenance
This guide is for maintainers and reviewers who manage the automated release
notes generated by Gemini CLI. It covers the architecture of the automation and
provides troubleshooting steps for common issues.
## Architecture and governance
The automated release notes process is divided between a GitHub Action and a
Gemini CLI skill.
### GitHub Action
The GitHub Action (`.github/workflows/release-notes.yml`) governs the triggering
mechanism and infrastructure. It runs automatically when a release is published
or when manually dispatched. The action is responsible for:
- Extracting the release **version**, **date**, and **raw notes** from the
GitHub release.
- Passing the extracted information to Gemini CLI.
- Updating changelog pages.
- Creating a pull request with the generated changelog files.
### docs-changelog skill
The `docs-changelog` skill governs the actual content generation. It takes the
provided version, date, and raw data, processes it, and updates the markdown
files. It formats the content according to project standards and determines
whether to append to an existing page or create a new one based on the semantic
version.
Specifically, the skill updates the following pages based on the release
version:
- **New Minor Stable Versions (e.g., `v1.2.0`):**
- Fully replaces `docs/changelogs/latest.md` with a new highlights section and
the full changelog.
- Prepends a brief announcement summary to `docs/changelogs/index.md`.
- **New Minor Preview Versions (e.g., `v1.3.0-preview.0`):**
- Fully replaces `docs/changelogs/preview.md` with a new highlights section
and the full changelog.
- **Patch Stable Versions (e.g., `v1.2.1`):**
- Edits `docs/changelogs/latest.md` by updating the version header, date, and
"Full Changelog" link, and prepending new "What's Changed" items without
replacing the entire file.
- **Patch Preview Versions (e.g., `v1.3.0-preview.1`):**
- Edits `docs/changelogs/preview.md` similarly to stable patches, updating the
header, date, and link, and appending new items without rewriting the file.
- **Nightly Releases:**
- The skill skips nightly versions entirely and makes no updates.
## Troubleshooting
This section covers common issues you might encounter with the automated release
notes and how to resolve them.
### Skipped minor versions do not create a new entry
Sometimes new releases skip straight to a minor or patch version, such as
`x.x.1`. In these cases, a new entry is not created.
The skill expects to update the date and append a line for any new changes to an
existing `x.x.0` page, instead of fully refreshing the page. If the `x.x.0` page
does not exist, the skill cannot append the notes.
To fix this issue:
1. Navigate to the **Actions** tab and select the **Generate Release Notes**
workflow.
2. Manually run the action.
3. Copy and paste the version information, but use the `x.x.0` nomenclature (for
example, `1.2.0` instead of `1.2.1`) to force the skill to generate a fresh
page.
4. Once the pull request is created, manually edit the version number in the
generated markdown file to match the correct `x.x.1` version before merging.
### Pull request contains too many changed files
Occasionally, the generation process results in a pull request that has too many
changed files. The exact cause of this behavior is unknown.
To fix this issue:
1. Go to the Actions run that generated the pull request (this fix also applies
to failed runs).
2. Rerun the action. A fresh run typically resolves the issue and correctly
scopes the file changes to only the changelog.
-2
View File
@@ -97,8 +97,6 @@ jobs:
body: |
This PR contains the auto-generated changelog for the ${{ steps.release_info.outputs.VERSION }} release.
For troubleshooting the automated release notes, see the [maintenance guide](https://github.com/google-gemini/gemini-cli/blob/main/.gemini/skills/docs-changelog/references/changelog-automation.md).
Please review and merge.
Related to #18505
-18
View File
@@ -18,24 +18,6 @@ on GitHub.
| [Preview](preview.md) | Experimental features ready for early feedback. |
| [Stable](latest.md) | Stable, recommended for general use. |
## Announcements: v0.45.0 - 2026-06-03
- **Context Simplification:** Completed major architectural work to simplify the
`ContextManager`, improving system robustness and performance
([#27345](https://github.com/google-gemini/gemini-cli/pull/27345) by
@joshualitt).
- **A2A Usage Metadata:** Exposed critical usage metadata in the Agent-to-Agent
(A2A) protocol for better resource tracking
([#27288](https://github.com/google-gemini/gemini-cli/pull/27288) by
@jvargassanchez-dot).
- **Reliability Fixes:** Addressed Termux relaunch loops, PTY resize errors, and
forced sequential execution for topic updates
([#27110](https://github.com/google-gemini/gemini-cli/pull/27110) by @saymanq,
[#27357](https://github.com/google-gemini/gemini-cli/pull/27357) by
@jvargassanchez-dot,
[#27461](https://github.com/google-gemini/gemini-cli/pull/27461) by
@scidomino).
## Announcements: v0.44.0 - 2026-05-27
- **Unified Auto Mode:** Streamlined the automation experience by merging
+202 -46
View File
@@ -1,6 +1,6 @@
# Latest stable release: v0.45.0
# Latest stable release: v0.44.0
Released: June 03, 2026
Released: May 27, 2026
For most users, our latest stable release is the recommended release. Install
the latest stable version with:
@@ -11,55 +11,211 @@ npm install -g @google/gemini-cli
## Highlights
- **Context Manager Simplification:** Completed a significant refactoring of the
context management system to improve reliability and architectural clarity.
- **A2A Usage Metadata:** Enhanced the Agent-to-Agent protocol to expose usage
metadata, enabling more transparent resource monitoring.
- **Terminal & PTY Robustness:** Resolved several critical issues related to
terminal interactions, including Termux relaunch loops and PTY resize errors.
- **Routing Optimizations:** Updated default auto-routing and bypassed
classifiers for specific tool responses to prevent orphaned function errors.
- **Tool Execution Control:** Forced the `update_topic` tool to execute
sequentially, ensuring consistent narrative flow in agent interactions.
- **Unified Auto Mode:** Merged all "Auto" modes into a single, unified Auto
mode, simplifying the automation workflow and providing a more consistent
experience across tasks.
- **Expanded Editor Support:** Native support for Sublime Text and Emacs Client
has been added, giving developers more flexibility in their choice of external
editors.
- **TUI Automation Skills:** New `agent-tui` and `tui-tester` skills enable the
programmatic testing and automation of terminal UI (TUI) applications,
facilitating robust verification of terminal-based tools.
- **Improved UI Performance:** Throttled shell text output and added bounds to
the live UI buffer to ensure smooth rendering and stability during high-volume
output sessions.
- **Stabilized Sandbox Environments:** Explicitly clearing entrypoints when
spawning sandbox containers ensures reliable and consistent environment
initialization across different Linux distributions.
## What's Changed
- chore(release): bump version to 0.45.0-nightly.20260521.g854f811be by
- chore(release): bump version to 0.44.0-nightly.20260512.g022e8baef by
@gemini-cli-robot in
[#27362](https://github.com/google-gemini/gemini-cli/pull/27362)
- fix(cli): prevent Termux relaunch and resize remount loops by @saymanq in
[#27110](https://github.com/google-gemini/gemini-cli/pull/27110)
- Feat/a2a expose usage metadata by @jvargassanchez-dot in
[#27288](https://github.com/google-gemini/gemini-cli/pull/27288)
- feat(context): Complete simplification work. by @joshualitt in
[#27345](https://github.com/google-gemini/gemini-cli/pull/27345)
- fix(core): force update_topic tool to execute sequentially by
@jvargassanchez-dot in
[#27357](https://github.com/google-gemini/gemini-cli/pull/27357)
- Changelog for v0.44.0-preview.0 by @gemini-cli-robot in
[#27360](https://github.com/google-gemini/gemini-cli/pull/27360)
- Changelog for v0.43.0 by @gemini-cli-robot in
[#27361](https://github.com/google-gemini/gemini-cli/pull/27361)
- Revert "fix(core): prevent SIGHUP kills in PTY environments" by @bbiggs in
[#27401](https://github.com/google-gemini/gemini-cli/pull/27401)
- fix(cli): filter internal session context from history during resumption by
[#26957](https://github.com/google-gemini/gemini-cli/pull/26957)
- Changelog for v0.42.0 by @gemini-cli-robot in
[#26958](https://github.com/google-gemini/gemini-cli/pull/26958)
- Refactor: Eliminate `no-unsafe-return` suppressions via strict type validation
by @M-DEV-1 in
[#20668](https://github.com/google-gemini/gemini-cli/pull/20668)
- Changelog for v0.43.0-preview.0 by @gemini-cli-robot in
[#26959](https://github.com/google-gemini/gemini-cli/pull/26959)
- feat(core): change agent registration to first-wins and prioritize project by
@adamfweidman in
[#26953](https://github.com/google-gemini/gemini-cli/pull/26953)
- feat(cli): merge Auto modes into a single Auto mode by @DavidAPierce in
[#26714](https://github.com/google-gemini/gemini-cli/pull/26714)
- fix(core): preserve OAuth refresh tokens during rotation and retrieval by
@cocosheng-g in
[#26924](https://github.com/google-gemini/gemini-cli/pull/26924)
- fix(cli): allow keychain auth for --list-sessions and non-interactive mode by
@cocosheng-g in
[#26921](https://github.com/google-gemini/gemini-cli/pull/26921)
- fix(core): handle EISDIR on virtual drives in memory discovery by @cocosheng-g
in [#26985](https://github.com/google-gemini/gemini-cli/pull/26985)
- fix(cli): auto-approve shell redirections in AUTO_EDIT mode by @cocosheng-g in
[#27003](https://github.com/google-gemini/gemini-cli/pull/27003)
- ci: suppress bot comments during standard triage maintenance by @cocosheng-g
in [#27006](https://github.com/google-gemini/gemini-cli/pull/27006)
- fix(core): refresh MCP OAuth token usage after re-auth by @sahilkirad in
[#26312](https://github.com/google-gemini/gemini-cli/pull/26312)
- fix(ui): clamped table column widths by @devr0306 in
[#26991](https://github.com/google-gemini/gemini-cli/pull/26991)
- fix(core): isolate subagent thread context by @akh64bit in
[#26449](https://github.com/google-gemini/gemini-cli/pull/26449)
- chore: add execution permission to scripts/review.sh by @scidomino in
[#27009](https://github.com/google-gemini/gemini-cli/pull/27009)
- fix(core): made context files append instead of replace by @devr0306 in
[#26950](https://github.com/google-gemini/gemini-cli/pull/26950)
- fix: add system PATH fallback for ripgrep resolution (#26777) by @cocosheng-g
in [#26868](https://github.com/google-gemini/gemini-cli/pull/26868)
- chore: clean up launched memory features by @SandyTao520 in
[#26941](https://github.com/google-gemini/gemini-cli/pull/26941)
- fix(core): throttle shell text output and bound live UI buffer by
@emersonbusson in
[#26955](https://github.com/google-gemini/gemini-cli/pull/26955)
- fix(cli): don't crash when an @-mention captures a non-path blob by @ifitisit
in [#25980](https://github.com/google-gemini/gemini-cli/pull/25980)
- fix(core): ensure stable fallback for restricted preview models by @galz10 in
[#26999](https://github.com/google-gemini/gemini-cli/pull/26999)
- feat(core): expose RAG snippets to local log file for debugging by @spencer426
in [#27016](https://github.com/google-gemini/gemini-cli/pull/27016)
- fix(acp/auth): prevent conflicting credentials on enterprise gateways and
support optional API keys natively by @sripasg in
[#27021](https://github.com/google-gemini/gemini-cli/pull/27021)
- fix(core): respect NO_PROXY for network-based MCP servers by @cocosheng-g in
[#27012](https://github.com/google-gemini/gemini-cli/pull/27012)
- fix(cli): resolve permission denied in sandbox on NixOS and other distros by
@cocosheng-g in
[#27004](https://github.com/google-gemini/gemini-cli/pull/27004)
- fix(ui): preserve new line at the end of edit window by @devr0306 in
[#27057](https://github.com/google-gemini/gemini-cli/pull/27057)
- fix(core): ensure Vertex AI sets hasAccessToPreviewModels and remove
aggressive 404 fallback revocation by @galz10 in
[#27067](https://github.com/google-gemini/gemini-cli/pull/27067)
- fix(core): ensure stable admin settings comparison across IPC to prevent
restart loop by @DavidAPierce in
[#27066](https://github.com/google-gemini/gemini-cli/pull/27066)
- fix(deps): update vulnerable dependencies by @scidomino in
[#27062](https://github.com/google-gemini/gemini-cli/pull/27062)
- fix(core): resolve EISDIR errors during file processing (#21527) by @ProthamD
in [#27041](https://github.com/google-gemini/gemini-cli/pull/27041)
- docs(extensions): clarify env var sanitization policy for MCP and ext… by
@galz10 in [#22854](https://github.com/google-gemini/gemini-cli/pull/22854)
- fix(ui): add ENAMETOOLONG and ENOTDIR to exceptions for file parsing errors by
@devr0306 in [#27069](https://github.com/google-gemini/gemini-cli/pull/27069)
- fix(cli): explicitly clear entrypoint when spawning sandbox container by
@cocosheng-g in
[#27059](https://github.com/google-gemini/gemini-cli/pull/27059)
- docs: update sandbox image command by @sjhddh in
[#26774](https://github.com/google-gemini/gemini-cli/pull/26774)
- fix(core): externalize https-proxy-agent to fix proxy support by @sotokisehiro
in [#26361](https://github.com/google-gemini/gemini-cli/pull/26361)
- security: update dependencies to fix critical and high vulnerabilities by
@scidomino in [#27077](https://github.com/google-gemini/gemini-cli/pull/27077)
- Fix/web fetch ctrl c abort by @ProthamD in
[#24320](https://github.com/google-gemini/gemini-cli/pull/24320)
- fix(core): add aliases and thinking config for gemini-3.1 models by
@anishs1207 in
[#27007](https://github.com/google-gemini/gemini-cli/pull/27007)
- fix(core): use hasAccessToPreview for auto model resolution and fix
disappearing models by @DavidAPierce in
[#27112](https://github.com/google-gemini/gemini-cli/pull/27112)
- feat(core): add adk.agentSessionSubagentEnabled flag by @adamfweidman in
[#26947](https://github.com/google-gemini/gemini-cli/pull/26947)
- fix(core): enforce compile-time exhaustiveness in content-utils by
@adamfweidman in
[#27207](https://github.com/google-gemini/gemini-cli/pull/27207)
- feat(skills): add agent-tui and tui-tester skills by @adamfweidman in
[#27121](https://github.com/google-gemini/gemini-cli/pull/27121)
- fix(context): Fix snapshot recovery across sessions. by @joshualitt in
[#26939](https://github.com/google-gemini/gemini-cli/pull/26939)
- fix(core): add unit tests for stableStringify by @devr0306 in
[#27212](https://github.com/google-gemini/gemini-cli/pull/27212)
- fix(core): prefer pwsh.exe over Windows PowerShell 5.1 (#25859) by @kaluchi in
[#25900](https://github.com/google-gemini/gemini-cli/pull/25900)
- feat(core): add LocalSessionInvocation by @adamfweidman in
[#26665](https://github.com/google-gemini/gemini-cli/pull/26665)
- refactor: decouple auto model description and configuration from
releaseChannel by @danielweis in
[#27227](https://github.com/google-gemini/gemini-cli/pull/27227)
- fix(core): prevent isBinary false-positive on Windows PTY streams by
@TirthNaik-99 in
[#26565](https://github.com/google-gemini/gemini-cli/pull/26565)
- fix(cli): Prevent unmapped keys in Vim Normal mode from inserting text into
prompt Input. by @Rajeshpatel07 in
[#25139](https://github.com/google-gemini/gemini-cli/pull/25139)
- fix(a2a-server): Implement default policy loading for parity with CLI by
@kschaab in [#27073](https://github.com/google-gemini/gemini-cli/pull/27073)
- feat(core): add RemoteSessionInvocation by @adamfweidman in
[#26937](https://github.com/google-gemini/gemini-cli/pull/26937)
- fix: allow configured MCP servers in non-interactive mode by @cocosheng-g in
[#27215](https://github.com/google-gemini/gemini-cli/pull/27215)
- fix(core): add exception handling to migrateFromFileStorage by @devr0306 in
[#27229](https://github.com/google-gemini/gemini-cli/pull/27229)
- fix(cli): bundle ink worker-entry.js by @rmedranollamas in
[#27249](https://github.com/google-gemini/gemini-cli/pull/27249)
- feat(core): wire AgentSession invocations into agent-tool by @adamfweidman in
[#26948](https://github.com/google-gemini/gemini-cli/pull/26948)
- fix(core): prevent path traversal in custome command file injection by
@ompatel-aiml in
[#27234](https://github.com/google-gemini/gemini-cli/pull/27234)
- fix(core): respect NO_PROXY in global fetch dispatcher by @cocosheng-g in
[#27216](https://github.com/google-gemini/gemini-cli/pull/27216)
- fix(core): correctly handle nullable array types in MCP tools by @devr0306 in
[#27228](https://github.com/google-gemini/gemini-cli/pull/27228)
- fix(cli): preserve proxy-agent named exports in ESM bundle by @ashishch432 in
[#27145](https://github.com/google-gemini/gemini-cli/pull/27145)
- Proposal: deterministic encoding for child-process I/O by @kaluchi in
[#27247](https://github.com/google-gemini/gemini-cli/pull/27247)
- feat(cli): add Sublime Text and Emacs Client editors, improve error messages
and documentation by @alberti42 in
[#21090](https://github.com/google-gemini/gemini-cli/pull/21090)
- Changelog for v0.43.0-preview.1 by @gemini-cli-robot in
[#27297](https://github.com/google-gemini/gemini-cli/pull/27297)
- fix(devtools): bundle devtools package to avoid resolution errors by
@rmedranollamas in
[#27391](https://github.com/google-gemini/gemini-cli/pull/27391)
- Update default auto routing by @DavidAPierce in
[#27071](https://github.com/google-gemini/gemini-cli/pull/27071)
- fix(core): bypass routing classifiers to prevent orphaned function response
errors by @danielweis in
[#27389](https://github.com/google-gemini/gemini-cli/pull/27389)
- fix(core): suppress PTY resize EBADF errors by @scidomino in
[#27461](https://github.com/google-gemini/gemini-cli/pull/27461)
- fix(core): prevent blacklist bypass in mcp list by @ompatel-aiml in
[#27377](https://github.com/google-gemini/gemini-cli/pull/27377)
- fix(cli): ignore unmapped vim normal keys by @MukundaKatta in
[#27102](https://github.com/google-gemini/gemini-cli/pull/27102)
- fix(patch): cherry-pick bd53951 to release/v0.45.0-preview.0-pr-27496 to patch
version v0.45.0-preview.0 and create version 0.45.0-preview.1 by
[#27250](https://github.com/google-gemini/gemini-cli/pull/27250)
- fix(cli): integrate PolicyEngine into ACP session to prevent deadlocks
(#23507) by @cocosheng-g in
[#27252](https://github.com/google-gemini/gemini-cli/pull/27252)
- fix: robust ripgrep path resolution and 1p hermetic execution support by
@cocosheng-g in
[#27253](https://github.com/google-gemini/gemini-cli/pull/27253)
- refactor: decouple stored session deletion from ChatRecordingService (#22920)
by @yuvrajangadsingh in
[#27039](https://github.com/google-gemini/gemini-cli/pull/27039)
- fix(core): improve Alpine shell compatibility by @dibyx in
[#26770](https://github.com/google-gemini/gemini-cli/pull/26770)
- fix(core): generalize MCP compliance fix for tool results by @cocosheng-g in
[#27045](https://github.com/google-gemini/gemini-cli/pull/27045)
- fix(scripts): scrub CI env vars in dev to keep interactive mode by @Hashaam101
in [#27159](https://github.com/google-gemini/gemini-cli/pull/27159)
- fix(core): Added date field for the GCal MCP by @devr0306 in
[#27251](https://github.com/google-gemini/gemini-cli/pull/27251)
- fix(core): centralize path validation to prevent crashes from malformed
prompts by @cocosheng-g in
[#27211](https://github.com/google-gemini/gemini-cli/pull/27211)
- fix(core): prevent SIGHUP kills in PTY environments (WSL2/Kitty/Alacritty) by
@ProthamD in [#27267](https://github.com/google-gemini/gemini-cli/pull/27267)
- fix(core): dynamic fallback routing for exhausted quota models by @cocosheng-g
in [#27315](https://github.com/google-gemini/gemini-cli/pull/27315)
- Auto detect pnpm global installation path for macOS and Windows by @tisonkun
in [#22748](https://github.com/google-gemini/gemini-cli/pull/22748)
- fix(windows): resolve interactive shell arrow-key navigation on Windows by
@KumarADITHYA123 in
[#23505](https://github.com/google-gemini/gemini-cli/pull/23505)
- ci: robust stale issue lifecycle and consolidated triage labels by
@cocosheng-g in
[#27015](https://github.com/google-gemini/gemini-cli/pull/27015)
- fix(context): Ensure last message is processed. by @joshualitt in
[#27232](https://github.com/google-gemini/gemini-cli/pull/27232)
- chore/release: bump version to 0.44.0-nightly.20260521.g57c42a5c4 by
@gemini-cli-robot in
[#27535](https://github.com/google-gemini/gemini-cli/pull/27535)
[#27324](https://github.com/google-gemini/gemini-cli/pull/27324)
- fix(ui): added volta to auto update check by @devr0306 in
[#27353](https://github.com/google-gemini/gemini-cli/pull/27353)
- perf: optimize issue triage and lifecycle management by @cocosheng-g in
[#27346](https://github.com/google-gemini/gemini-cli/pull/27346)
**Full Changelog**:
https://github.com/google-gemini/gemini-cli/compare/v0.44.1...v0.45.0
https://github.com/google-gemini/gemini-cli/compare/v0.43.0...v0.44.0
+46 -28
View File
@@ -1,6 +1,6 @@
# Preview release: v0.46.0-preview.0
# Preview release: v0.45.0-preview.0
Released: June 3, 2026
Released: May 27, 2026
Our preview release includes the latest, new, and experimental features. This
release may not be as stable as our [latest weekly release](latest.md).
@@ -13,34 +13,52 @@ npm install -g @google/gemini-cli@preview
## Highlights
- **Model Update:** Added support for transitioning to the Flash GA model when
the experimental flag is enabled, providing access to the latest model
improvements.
- **Improved Stability:** Hardened PTY resize logic to prevent native crashes,
ensuring a more robust terminal experience.
- **Bug Fix:** Resolved an issue where an invalid `preferredEditor`
configuration could lead to a notification spam loop.
- **CI Enhancements:** Optimized Pull Request labeling and introduced batch
workflows to improve development efficiency.
- **Context Simplification:** Completed major architectural work to simplify and
optimize how the agent manages and processes session context.
- **A2A Usage Metadata:** The Agent-to-Agent (A2A) interface now exposes
detailed usage metadata, providing better visibility into resource
consumption.
- **Improved Routing:** Updated default auto-routing logic and added bypasses
for certain routing classifiers to prevent orphaned function response errors.
- **Terminal Stability:** Fixed several issues affecting terminal environments,
including Termux relaunch loops and PTY resize errors.
- **Security & Fixes:** Strengthened MCP list security and addressed issues with
session resumption and PTY environment signals.
## What's Changed
- fix(core): harden PTY resize against native crashes by @scidomino in
[#27496](https://github.com/google-gemini/gemini-cli/pull/27496)
- Changelog for v0.45.0-preview.0 by @gemini-cli-robot in
[#27495](https://github.com/google-gemini/gemini-cli/pull/27495)
- Changelog for v0.44.0 by @gemini-cli-robot in
[#27569](https://github.com/google-gemini/gemini-cli/pull/27569)
- fix(cli): prevent spam loop when preferredEditor is invalid by @Niralisj in
[#25324](https://github.com/google-gemini/gemini-cli/pull/25324)
- Adding quote by @scidomino in
[#27571](https://github.com/google-gemini/gemini-cli/pull/27571)
- Transition to flash GA model when experiment flag is present. by @DavidAPierce
in [#27570](https://github.com/google-gemini/gemini-cli/pull/27570)
- chore(ci): add optimized PR size labeler and batch workflows by @sripasg in
[#27616](https://github.com/google-gemini/gemini-cli/pull/27616)
- fix(ci): use pull_request_target trigger to grant write access on fork PRs by
@sripasg in [#27637](https://github.com/google-gemini/gemini-cli/pull/27637)
- chore(release): bump version to 0.45.0-nightly.20260521.g854f811be by
@gemini-cli-robot in
[#27362](https://github.com/google-gemini/gemini-cli/pull/27362)
- fix(cli): prevent Termux relaunch and resize remount loops by @saymanq in
[#27110](https://github.com/google-gemini/gemini-cli/pull/27110)
- Feat/a2a expose usage metadata by @jvargassanchez-dot in
[#27288](https://github.com/google-gemini/gemini-cli/pull/27288)
- feat(context): Complete simplification work. by @joshualitt in
[#27345](https://github.com/google-gemini/gemini-cli/pull/27345)
- fix(core): force update_topic tool to execute sequentially by
@jvargassanchez-dot in
[#27357](https://github.com/google-gemini/gemini-cli/pull/27357)
- Changelog for v0.44.0-preview.0 by @gemini-cli-robot in
[#27360](https://github.com/google-gemini/gemini-cli/pull/27360)
- Changelog for v0.43.0 by @gemini-cli-robot in
[#27361](https://github.com/google-gemini/gemini-cli/pull/27361)
- Revert "fix(core): prevent SIGHUP kills in PTY environments" by @bbiggs in
[#27401](https://github.com/google-gemini/gemini-cli/pull/27401)
- fix(cli): filter internal session context from history during resumption by
@rmedranollamas in
[#27391](https://github.com/google-gemini/gemini-cli/pull/27391)
- Update default auto routing by @DavidAPierce in
[#27071](https://github.com/google-gemini/gemini-cli/pull/27071)
- fix(core): bypass routing classifiers to prevent orphaned function response
errors by @danielweis in
[#27389](https://github.com/google-gemini/gemini-cli/pull/27389)
- fix(core): suppress PTY resize EBADF errors by @scidomino in
[#27461](https://github.com/google-gemini/gemini-cli/pull/27461)
- fix(core): prevent blacklist bypass in mcp list by @ompatel-aiml in
[#27377](https://github.com/google-gemini/gemini-cli/pull/27377)
- fix(cli): ignore unmapped vim normal keys by @MukundaKatta in
[#27102](https://github.com/google-gemini/gemini-cli/pull/27102)
**Full Changelog**:
https://github.com/google-gemini/gemini-cli/compare/v0.45.0-preview.1...v0.46.0-preview.0
https://github.com/google-gemini/gemini-cli/compare/v0.44.0-preview.0...v0.45.0-preview.0
+9 -9
View File
@@ -1,12 +1,12 @@
{
"name": "@google/gemini-cli",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@google/gemini-cli",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"workspaces": [
"packages/*"
],
@@ -18117,7 +18117,7 @@
},
"packages/a2a-server": {
"name": "@google/gemini-cli-a2a-server",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"dependencies": {
"@a2a-js/sdk": "0.3.11",
"@google-cloud/storage": "^7.19.0",
@@ -18246,7 +18246,7 @@
},
"packages/cli": {
"name": "@google/gemini-cli",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
@@ -18394,7 +18394,7 @@
},
"packages/core": {
"name": "@google/gemini-cli-core",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"dependencies": {
"@a2a-js/sdk": "0.3.11",
@@ -18674,7 +18674,7 @@
},
"packages/devtools": {
"name": "@google/gemini-cli-devtools",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"dependencies": {
"ws": "^8.16.0"
@@ -18689,7 +18689,7 @@
},
"packages/sdk": {
"name": "@google/gemini-cli-sdk",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -18720,7 +18720,7 @@
},
"packages/test-utils": {
"name": "@google/gemini-cli-test-utils",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -18752,7 +18752,7 @@
},
"packages/vscode-ide-companion": {
"name": "gemini-cli-vscode-ide-companion",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "LICENSE",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.23.0",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"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.47.0-nightly.20260602.gcfcecebe8"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.46.0-preview.2"
},
"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.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"description": "Gemini CLI A2A Server",
"repository": {
"type": "git",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"description": "Gemini CLI",
"license": "Apache-2.0",
"repository": {
@@ -27,7 +27,7 @@
"dist"
],
"config": {
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.47.0-nightly.20260602.gcfcecebe8"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.46.0-preview.2"
},
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-core",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"description": "Gemini CLI Core",
"license": "Apache-2.0",
"repository": {
+8 -51
View File
@@ -9,7 +9,6 @@ import * as path from 'node:path';
import * as crypto from 'node:crypto';
import { fileURLToPath } from 'node:url';
import { Storage } from '../config/storage.js';
import { debugLogger } from '../utils/debugLogger.js';
import {
ApprovalMode,
type PolicyEngineConfig,
@@ -29,6 +28,7 @@ import {
} from '../confirmation-bus/types.js';
import { type MessageBus } from '../confirmation-bus/message-bus.js';
import { coreEvents } from '../utils/events.js';
import { debugLogger } from '../utils/debugLogger.js';
import { SHELL_TOOL_NAMES } from '../utils/shell-utils.js';
import {
SHELL_TOOL_NAME,
@@ -794,7 +794,6 @@ export function createPolicyUpdater(
if (message.persist) {
persistenceQueue = persistenceQueue.then(async () => {
let tmpFile: string | undefined;
try {
const policyFile =
message.persistScope === 'workspace'
@@ -815,27 +814,11 @@ export function createPolicyUpdater(
existingData = parsed as { rule?: TomlRule[] };
}
} catch (error) {
if (isNodeError(error) && error.code === 'ENOENT') {
// File doesn't exist yet, start fresh
} else if (!isNodeError(error)) {
// TOML parse error — back up corrupted file and recover
coreEvents.emitFeedback(
'warning',
`Syntax error found in policy file. Backing up corrupted file to ${policyFile}.bak and starting fresh.`,
if (!isNodeError(error) || error.code !== 'ENOENT') {
debugLogger.warn(
`Failed to parse ${policyFile}, overwriting with new policy.`,
error,
);
if (
!(
await fs.lstat(policyFile).catch(() => null)
)?.isSymbolicLink()
) {
await fs
.copyFile(policyFile, `${policyFile}.bak`)
.catch(() => {});
}
existingData = {};
} else {
// Real filesystem error (e.g. EACCES) — throw to prevent silent failure
throw error;
}
}
@@ -883,7 +866,7 @@ export function createPolicyUpdater(
// Using a unique suffix avoids race conditions where concurrent processes
// overwrite each other's temporary files, leading to ENOENT errors on rename.
const tmpSuffix = crypto.randomBytes(8).toString('hex');
tmpFile = `${policyFile}.${tmpSuffix}.tmp`;
const tmpFile = `${policyFile}.${tmpSuffix}.tmp`;
let handle: fs.FileHandle | undefined;
try {
@@ -893,37 +876,11 @@ export function createPolicyUpdater(
} finally {
await handle?.close();
}
try {
await fs.rename(tmpFile, policyFile);
} catch (renameError) {
// Cross-device rename fails with EXDEV on some Linux mount configurations.
// Fall back to copy + unlink which works across filesystems.
if (
isNodeError(renameError) &&
(renameError.code === 'EXDEV' || renameError.code === 'EBUSY')
) {
if (
(
await fs.lstat(policyFile).catch(() => null)
)?.isSymbolicLink()
)
throw renameError;
await fs.copyFile(tmpFile, policyFile);
await fs.unlink(tmpFile).catch(() => {});
} else {
throw renameError;
}
}
await fs.rename(tmpFile, policyFile);
} catch (error) {
// Clean up orphaned tmp file if it was created
if (tmpFile) {
await fs.unlink(tmpFile).catch(() => {});
}
const reason =
error instanceof Error ? error.message : String(error);
coreEvents.emitFeedback(
'error',
`Failed to persist policy for ${toolName}: ${reason}`,
`Failed to persist policy for ${toolName}`,
error,
);
}
+2 -226
View File
@@ -5,7 +5,6 @@
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import {
createPolicyUpdater,
@@ -17,20 +16,10 @@ import { MessageBusType } from '../confirmation-bus/types.js';
import { Storage, AUTO_SAVED_POLICY_FILENAME } from '../config/storage.js';
import { ApprovalMode } from './types.js';
import { vol, fs as memfs } from 'memfs';
import { coreEvents } from '../utils/events.js';
// Use memfs for all fs operations in this test
vi.mock('node:fs/promises', () => import('memfs').then((m) => m.fs.promises));
/**
* Creates a Node.js-style error with a `code` property.
*/
function makeNodeError(message: string, code: string): NodeJS.ErrnoException {
const err = new Error(message) as NodeJS.ErrnoException;
err.code = code;
return err;
}
vi.mock('../config/storage.js');
describe('createPolicyUpdater', () => {
@@ -68,6 +57,8 @@ describe('createPolicyUpdater', () => {
persist: true,
});
// Policy updater handles persistence asynchronously in a promise queue.
// We use advanceTimersByTimeAsync to yield to the microtask queue.
await vi.advanceTimersByTimeAsync(100);
const fileExists = memfs.existsSync(policyFile);
@@ -252,147 +243,6 @@ decision = "deny"
expect(content).toContain('toolName = "test_tool"');
});
it('should include error details in feedback message on persistence failure', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const workspacePoliciesDir = '/mock/project/.gemini/policies';
const policyFile = path.join(
workspacePoliciesDir,
AUTO_SAVED_POLICY_FILENAME,
);
vi.spyOn(mockStorage, 'getWorkspacePoliciesDir').mockReturnValue(
workspacePoliciesDir,
);
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
vi.spyOn(fs, 'mkdir').mockRejectedValue(new Error('Permission denied'));
const feedbackSpy = vi.spyOn(coreEvents, 'emitFeedback');
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.runAllTimersAsync();
expect(feedbackSpy).toHaveBeenCalledWith(
'error',
expect.stringContaining('Permission denied'),
expect.any(Error),
);
});
it('should clean up tmp file on write failure', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const workspacePoliciesDir = '/mock/project/.gemini/policies';
const policyFile = path.join(
workspacePoliciesDir,
AUTO_SAVED_POLICY_FILENAME,
);
vi.spyOn(mockStorage, 'getWorkspacePoliciesDir').mockReturnValue(
workspacePoliciesDir,
);
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined as never);
vi.spyOn(fs, 'readFile').mockRejectedValue(
makeNodeError('ENOENT: no such file or directory', 'ENOENT'),
);
const mockFileHandle = {
writeFile: vi.fn().mockRejectedValue(new Error('Disk full')),
close: vi.fn().mockResolvedValue(undefined),
};
vi.spyOn(fs, 'open').mockResolvedValue(mockFileHandle as never);
vi.spyOn(fs, 'unlink').mockResolvedValue(undefined as never);
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.runAllTimersAsync();
expect(fs.unlink).toHaveBeenCalledWith(expect.stringMatching(/\.tmp$/));
});
it('should abort persistence on non-ENOENT read errors', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const workspacePoliciesDir = '/mock/project/.gemini/policies';
const policyFile = path.join(
workspacePoliciesDir,
AUTO_SAVED_POLICY_FILENAME,
);
vi.spyOn(mockStorage, 'getWorkspacePoliciesDir').mockReturnValue(
workspacePoliciesDir,
);
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined as never);
vi.spyOn(fs, 'readFile').mockRejectedValue(
makeNodeError('Permission denied', 'EACCES'),
);
const openSpy = vi.spyOn(fs, 'open');
const feedbackSpy = vi.spyOn(coreEvents, 'emitFeedback');
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.runAllTimersAsync();
expect(openSpy).not.toHaveBeenCalled();
expect(feedbackSpy).toHaveBeenCalledWith(
'error',
expect.stringContaining('Permission denied'),
expect.any(Error),
);
});
it('should fall back to copy+unlink when rename fails with EXDEV', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const workspacePoliciesDir = '/mock/project/.gemini/policies';
const policyFile = path.join(
workspacePoliciesDir,
AUTO_SAVED_POLICY_FILENAME,
);
vi.spyOn(mockStorage, 'getWorkspacePoliciesDir').mockReturnValue(
workspacePoliciesDir,
);
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined as never);
vi.spyOn(fs, 'readFile').mockRejectedValue(
makeNodeError('ENOENT: no such file or directory', 'ENOENT'),
);
const mockFileHandle = {
writeFile: vi.fn().mockResolvedValue(undefined),
close: vi.fn().mockResolvedValue(undefined),
};
vi.spyOn(fs, 'open').mockResolvedValue(mockFileHandle as never);
vi.spyOn(fs, 'rename').mockRejectedValue(
makeNodeError('EXDEV: cross-device link not permitted', 'EXDEV'),
);
vi.spyOn(fs, 'copyFile').mockResolvedValue(undefined as never);
vi.spyOn(fs, 'unlink').mockResolvedValue(undefined as never);
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.runAllTimersAsync();
expect(fs.copyFile).toHaveBeenCalledWith(
expect.stringMatching(/\.tmp$/),
policyFile,
);
expect(fs.unlink).toHaveBeenCalledWith(expect.stringMatching(/\.tmp$/));
});
it('should include modes if provided', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
@@ -445,78 +295,4 @@ modes = [ "autoEdit", "yolo" ]
expect(ruleCount).toBe(1);
expect(content).toContain('modes = [ "default", "autoEdit", "yolo" ]');
});
it('should fall back to copy+unlink when rename fails with EBUSY', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const workspacePoliciesDir = '/mock/project/.gemini/policies';
const policyFile = path.join(
workspacePoliciesDir,
AUTO_SAVED_POLICY_FILENAME,
);
vi.spyOn(mockStorage, 'getWorkspacePoliciesDir').mockReturnValue(
workspacePoliciesDir,
);
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
vi.spyOn(fs, 'mkdir').mockResolvedValue(undefined);
vi.spyOn(fs, 'readFile').mockRejectedValue(
makeNodeError('ENOENT: no such file or directory', 'ENOENT'),
);
const mockFileHandle = {
writeFile: vi.fn().mockResolvedValue(undefined),
close: vi.fn().mockResolvedValue(undefined),
};
vi.spyOn(fs, 'open').mockResolvedValue(
mockFileHandle as unknown as fs.FileHandle,
);
vi.spyOn(fs, 'rename').mockRejectedValue(
makeNodeError('EBUSY: resource busy or locked', 'EBUSY'),
);
vi.spyOn(fs, 'copyFile').mockResolvedValue(undefined);
vi.spyOn(fs, 'unlink').mockResolvedValue(undefined);
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.runAllTimersAsync();
expect(fs.copyFile).toHaveBeenCalledWith(
expect.stringMatching(/\.tmp$/),
policyFile,
);
expect(fs.unlink).toHaveBeenCalledWith(expect.stringMatching(/\.tmp$/));
});
it('should back up corrupted TOML file and recover', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const policyFile = '/mock/user/.gemini/policies/auto-saved.toml';
vi.spyOn(mockStorage, 'getAutoSavedPolicyPath').mockReturnValue(policyFile);
const dir = path.dirname(policyFile);
memfs.mkdirSync(dir, { recursive: true });
memfs.writeFileSync(policyFile, 'this is not valid toml ][[[');
const feedbackSpy = vi.spyOn(coreEvents, 'emitFeedback');
await messageBus.publish({
type: MessageBusType.UPDATE_POLICY,
toolName: 'test_tool',
persist: true,
});
await vi.advanceTimersByTimeAsync(100);
expect(feedbackSpy).toHaveBeenCalledWith(
'warning',
expect.stringContaining('.bak'),
);
expect(memfs.existsSync(policyFile)).toBe(true);
const content = memfs.readFileSync(policyFile, 'utf-8') as string;
expect(content).toContain('toolName = "test_tool"');
});
});
+15 -23
View File
@@ -121,11 +121,7 @@ describe('createPolicyUpdater', () => {
it('should persist mcpName to TOML', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
vi.mocked(fs.readFile).mockRejectedValue(
Object.assign(new Error('ENOENT: no such file or directory'), {
code: 'ENOENT',
}),
);
vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' });
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
const mockFileHandle = {
@@ -146,9 +142,9 @@ describe('createPolicyUpdater', () => {
});
// Wait for the async listener to complete
await vi.waitFor(() => {
expect(fs.open).toHaveBeenCalled();
});
await new Promise((resolve) => setTimeout(resolve, 0));
expect(fs.open).toHaveBeenCalled();
const [content] = mockFileHandle.writeFile.mock.calls[0] as [
string,
string,
@@ -203,11 +199,7 @@ describe('createPolicyUpdater', () => {
it('should persist multiple rules correctly to TOML', async () => {
createPolicyUpdater(policyEngine, messageBus, mockStorage);
const enoentError = Object.assign(
new Error('ENOENT: no such file or directory'),
{ code: 'ENOENT' },
);
vi.mocked(fs.readFile).mockRejectedValue(enoentError);
vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' });
vi.mocked(fs.mkdir).mockResolvedValue(undefined);
const mockFileHandle = {
@@ -227,17 +219,17 @@ describe('createPolicyUpdater', () => {
});
// Wait for the async listener to complete
await vi.waitFor(() => {
expect(fs.open).toHaveBeenCalled();
const [content] = mockFileHandle.writeFile.mock.calls[0] as [
string,
string,
];
const parsed = toml.parse(content) as unknown as ParsedPolicy;
await new Promise((resolve) => setTimeout(resolve, 0));
expect(parsed.rule).toHaveLength(1);
expect(parsed.rule![0].commandPrefix).toEqual(['echo', 'ls']);
});
expect(fs.open).toHaveBeenCalled();
const [content] = mockFileHandle.writeFile.mock.calls[0] as [
string,
string,
];
const parsed = toml.parse(content) as unknown as ParsedPolicy;
expect(parsed.rule).toHaveLength(1);
expect(parsed.rule![0].commandPrefix).toEqual(['echo', 'ls']);
});
it('should reject unsafe regex patterns', async () => {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-devtools",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"license": "Apache-2.0",
"type": "module",
"main": "dist/src/index.js",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-sdk",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"description": "Gemini CLI SDK",
"license": "Apache-2.0",
"repository": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-test-utils",
"version": "0.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"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.47.0-nightly.20260602.gcfcecebe8",
"version": "0.46.0-preview.2",
"publisher": "google",
"icon": "assets/icon.png",
"repository": {