Compare commits

...

6 Commits

Author SHA1 Message Date
gemini-cli-robot b0ed611a06 chore(release): v0.38.2 2026-04-17 18:30:22 +00:00
gemini-cli-robot 47c35f32f7 fix(patch): cherry-pick 14b2f35 to release/v0.38.1-pr-24974 to patch version v0.38.1 and create version 0.38.2 (#25585)
Co-authored-by: Jarrod Whelan <150866123+jwhelangoog@users.noreply.github.com>
2026-04-17 10:22:51 -07:00
gemini-cli-robot 7f55800343 chore(release): v0.38.1 2026-04-15 17:46:57 +00:00
gemini-cli-robot 2a28cf2cb3 fix(patch): cherry-pick 050c303 to release/v0.38.0-pr-25317 to patch version v0.38.0 and create version 0.38.1 (#25466)
Co-authored-by: Jerop Kipruto <jerop@google.com>
2026-04-15 16:52:34 +00:00
gemini-cli-robot 3f0873a835 chore(release): v0.38.0 2026-04-14 23:14:12 +00:00
gemini-cli-robot e418e123e6 chore(release): v0.38.0-preview.0 2026-04-08 16:55:38 +00:00
20 changed files with 158 additions and 67 deletions
+4
View File
@@ -441,6 +441,10 @@ on the current phase of your task:
switches to a high-speed **Flash** model. This provides a faster, more
responsive experience during the implementation of the plan.
If the high-reasoning model is unavailable or you don't have access to it,
Gemini CLI automatically and silently falls back to a faster model to ensure
your workflow isn't interrupted.
This behavior is enabled by default to provide the best balance of quality and
performance. You can disable this automatic switching in your settings:
+9 -9
View File
@@ -1,12 +1,12 @@
{
"name": "@google/gemini-cli",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@google/gemini-cli",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"workspaces": [
"packages/*"
],
@@ -17389,7 +17389,7 @@
},
"packages/a2a-server": {
"name": "@google/gemini-cli-a2a-server",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"dependencies": {
"@a2a-js/sdk": "0.3.11",
"@google-cloud/storage": "^7.16.0",
@@ -17504,7 +17504,7 @@
},
"packages/cli": {
"name": "@google/gemini-cli",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "Apache-2.0",
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
@@ -17676,7 +17676,7 @@
},
"packages/core": {
"name": "@google/gemini-cli-core",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "Apache-2.0",
"dependencies": {
"@a2a-js/sdk": "0.3.11",
@@ -17942,7 +17942,7 @@
},
"packages/devtools": {
"name": "@google/gemini-cli-devtools",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "Apache-2.0",
"dependencies": {
"ws": "^8.16.0"
@@ -17957,7 +17957,7 @@
},
"packages/sdk": {
"name": "@google/gemini-cli-sdk",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "Apache-2.0",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -17974,7 +17974,7 @@
},
"packages/test-utils": {
"name": "@google/gemini-cli-test-utils",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "Apache-2.0",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -17991,7 +17991,7 @@
},
"packages/vscode-ide-companion": {
"name": "gemini-cli-vscode-ide-companion",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"license": "LICENSE",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.23.0",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.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.36.0-nightly.20260317.2f90b4653"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.38.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.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"description": "Gemini CLI A2A Server",
"repository": {
"type": "git",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.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.36.0-nightly.20260317.2f90b4653"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.38.2"
},
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
@@ -14,7 +14,8 @@
<text x="0" y="19" fill="#000000" textLength="900" lengthAdjust="spacingAndGlyphs">▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄</text>
<text x="0" y="53" fill="#333333" textLength="891" lengthAdjust="spacingAndGlyphs">╭─────────────────────────────────────────────────────────────────────────────────────────────────╮</text>
<text x="0" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="18" y="70" fill="#ffffaf" textLength="54" lengthAdjust="spacingAndGlyphs" font-weight="bold">? Edit</text>
<text x="18" y="70" fill="#ffffaf" textLength="63" lengthAdjust="spacingAndGlyphs" font-weight="bold">? Edit </text>
<text x="81" y="70" fill="#ffffff" textLength="783" lengthAdjust="spacingAndGlyphs">packages/.../InputPrompt.tsx: return kittyProtocolSupporte... =&gt; return kittyProto…</text>
<text x="882" y="70" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="0" y="87" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="18" y="87" fill="#333333" textLength="855" lengthAdjust="spacingAndGlyphs">╭─────────────────────────────────────────────────────────────────────────────────────────────╮</text>

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

@@ -5,7 +5,7 @@ exports[`Full Terminal Tool Confirmation Snapshot > renders tool confirmation bo
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? Edit
│ ? Edit packages/.../InputPrompt.tsx: return kittyProtocolSupporte... => return kittyProto…
│ ╭─────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ ... first 42 lines hidden (Ctrl+O to show) ... │ │
│ │ 43 const line43 = true; │ │
@@ -66,6 +66,44 @@ describe('ToolConfirmationQueue', () => {
vi.clearAllMocks();
});
it('explicitly renders the tool description (containing filename) for edit confirmations', async () => {
const confirmingTool = {
tool: {
callId: 'call-1',
name: 'Edit',
description: 'Editing src/main.ts',
status: CoreToolCallStatus.AwaitingApproval,
confirmationDetails: {
type: 'edit' as const,
title: 'Confirm edit',
fileName: 'main.ts',
filePath: '/src/main.ts',
fileDiff: '--- a/main.ts\n+++ b/main.ts\n@@ -1 +1 @@\n-old\n+new',
originalContent: 'old',
newContent: 'new',
},
},
index: 1,
total: 1,
};
const { lastFrame, unmount } = await renderWithProviders(
<ToolConfirmationQueue
confirmingTool={confirmingTool as unknown as ConfirmingToolState}
/>,
{
config: mockConfig,
uiState: {
terminalWidth: 80,
},
},
);
const output = lastFrame();
expect(output).toContain('Editing src/main.ts');
unmount();
});
it('renders the confirming tool with progress indicator', async () => {
const confirmingTool = {
tool: {
@@ -98,9 +98,9 @@ export const ToolConfirmationQueue: React.FC<ToolConfirmationQueueProps> = ({
<Box flexDirection="row" flexShrink={1} overflow="hidden">
<Text color={theme.status.warning} bold>
? {toolLabel}
{!isEdit && !!tool.description && ' '}
{!!tool.description && ' '}
</Text>
{!isEdit && !!tool.description && (
{!!tool.description && (
<Box flexShrink={1} overflow="hidden">
<Text color={theme.text.primary} wrap="truncate-end">
{tool.description}
@@ -6,7 +6,8 @@
<g transform="translate(10, 10)">
<text x="0" y="2" fill="#333333" textLength="720" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────────╮</text>
<text x="0" y="19" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="18" y="19" fill="#ffffaf" textLength="81" lengthAdjust="spacingAndGlyphs" font-weight="bold">? replace</text>
<text x="18" y="19" fill="#ffffaf" textLength="99" lengthAdjust="spacingAndGlyphs" font-weight="bold">? replace </text>
<text x="117" y="19" fill="#ffffff" textLength="234" lengthAdjust="spacingAndGlyphs">Replaces content in a file</text>
<text x="711" y="19" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="0" y="36" fill="#333333" textLength="9" lengthAdjust="spacingAndGlyphs"></text>
<text x="18" y="36" fill="#333333" textLength="684" lengthAdjust="spacingAndGlyphs">╭──────────────────────────────────────────────────────────────────────────╮</text>

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

@@ -2,7 +2,7 @@
exports[`ToolConfirmationQueue > calculates availableContentHeight based on availableTerminalHeight from UI state 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ? replace
│ ? replace edit file
│ ╭──────────────────────────────────────────────────────────────────────────╮ │
│ ╰─... 48 hidden (Ctrl+O) ...───────────────────────────────────────────────╯ │
│ Apply this change? │
@@ -17,7 +17,7 @@ exports[`ToolConfirmationQueue > calculates availableContentHeight based on avai
exports[`ToolConfirmationQueue > does not render expansion hint when constrainHeight is false 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ? replace
│ ? replace edit file
│ ╭──────────────────────────────────────────────────────────────────────────╮ │
│ │ │ │
│ │ No changes detected. │ │
@@ -63,7 +63,7 @@ exports[`ToolConfirmationQueue > height allocation and layout > should handle se
exports[`ToolConfirmationQueue > height allocation and layout > should render the full queue wrapper with borders and content for large edit diffs 1`] = `
"╭──────────────────────────────────────────────────────────────────────────────╮
│ ? replace
│ ? replace Replaces content in a file
│ ╭──────────────────────────────────────────────────────────────────────────╮ │
│ │ ... 13 hidden (Ctrl+O) ... │ │
│ │ 7 + const newLine7 = true; │ │
@@ -34,6 +34,28 @@ describe('DenseToolMessage', () => {
terminalWidth: 80,
};
it('explicitly renders the filename in the header for FileDiff results', async () => {
const fileDiff: FileDiff = {
fileName: 'test-file.ts',
filePath: '/test-file.ts',
fileDiff:
'--- a/test-file.ts\n+++ b/test-file.ts\n@@ -1 +1 @@\n-old\n+new',
originalContent: 'old',
newContent: 'new',
};
const { lastFrame, waitUntilReady } = await renderWithProviders(
<DenseToolMessage
{...defaultProps}
name="Edit"
resultDisplay={fileDiff as unknown as ToolResultDisplay}
/>,
);
await waitUntilReady();
const output = lastFrame();
expect(output).toContain('test-file.ts');
});
it('renders correctly for a successful string result', async () => {
const { lastFrame, waitUntilReady } = await renderWithProviders(
<DenseToolMessage {...defaultProps} />,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-core",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"description": "Gemini CLI Core",
"license": "Apache-2.0",
"repository": {
@@ -41,7 +41,7 @@ const DEFAULT_ACTIONS: ModelPolicyActionMap = {
unknown: 'prompt',
};
const SILENT_ACTIONS: ModelPolicyActionMap = {
export const SILENT_ACTIONS: ModelPolicyActionMap = {
terminal: 'silent',
transient: 'silent',
not_found: 'silent',
@@ -10,7 +10,7 @@ import {
buildFallbackPolicyContext,
applyModelSelection,
} from './policyHelpers.js';
import { createDefaultPolicy } from './policyCatalog.js';
import { createDefaultPolicy, SILENT_ACTIONS } from './policyCatalog.js';
import type { Config } from '../config/config.js';
import {
DEFAULT_GEMINI_FLASH_LITE_MODEL,
@@ -21,6 +21,7 @@ import {
import { AuthType } from '../core/contentGenerator.js';
import { ModelConfigService } from '../services/modelConfigService.js';
import { DEFAULT_MODEL_CONFIGS } from '../config/defaultModelConfigs.js';
import { ApprovalMode } from '../policy/types.js';
const createMockConfig = (overrides: Partial<Config> = {}): Config => {
const config = {
@@ -164,6 +165,18 @@ describe('policyHelpers', () => {
expect(chain[0]?.model).toBe(PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL);
expect(chain[1]?.model).toBe('gemini-3-flash-preview');
});
it('applies SILENT_ACTIONS when ApprovalMode is PLAN', () => {
const config = createMockConfig({
getApprovalMode: () => ApprovalMode.PLAN,
getModel: () => DEFAULT_GEMINI_MODEL_AUTO,
});
const chain = resolvePolicyChain(config);
expect(chain).toHaveLength(2);
expect(chain[0]?.actions).toEqual(SILENT_ACTIONS);
expect(chain[1]?.actions).toEqual(SILENT_ACTIONS);
});
});
describe('resolvePolicyChain behavior is identical between dynamic and legacy implementations', () => {
+50 -38
View File
@@ -18,6 +18,7 @@ import {
createSingleModelChain,
getModelPolicyChain,
getFlashLitePolicyChain,
SILENT_ACTIONS,
} from './policyCatalog.js';
import {
DEFAULT_GEMINI_FLASH_LITE_MODEL,
@@ -29,6 +30,7 @@ import {
} from '../config/models.js';
import type { ModelSelectionResult } from './modelAvailabilityService.js';
import type { ModelConfigKey } from '../services/modelConfigService.js';
import { ApprovalMode } from '../policy/types.js';
/**
* Resolves the active policy chain for the given config, ensuring the
@@ -43,7 +45,7 @@ export function resolvePolicyChain(
preferredModel ?? config.getActiveModel?.() ?? config.getModel();
const configuredModel = config.getModel();
let chain;
let chain: ModelPolicyChain | undefined;
const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
const useGemini31FlashLite =
config.getGemini31FlashLiteLaunchedSync?.() ?? false;
@@ -103,45 +105,55 @@ export function resolvePolicyChain(
// No matching modelChains found, default to single model chain
chain = createSingleModelChain(modelFromConfig);
}
return applyDynamicSlicing(chain, resolvedModel, wrapsAround);
}
// --- LEGACY PATH ---
if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
chain = getFlashLitePolicyChain();
} else if (
isGemini3Model(resolvedModel, config) ||
isAutoPreferred ||
isAutoConfigured
) {
if (hasAccessToPreview) {
const previewEnabled =
isGemini3Model(resolvedModel, config) ||
preferredModel === PREVIEW_GEMINI_MODEL_AUTO ||
configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
chain = getModelPolicyChain({
previewEnabled,
userTier: config.getUserTier(),
useGemini31,
useGemini31FlashLite,
useCustomToolModel,
});
} else {
// User requested Gemini 3 but has no access. Proactively downgrade
// to the stable Gemini 2.5 chain.
chain = getModelPolicyChain({
previewEnabled: false,
userTier: config.getUserTier(),
useGemini31,
useGemini31FlashLite,
useCustomToolModel,
});
}
chain = applyDynamicSlicing(chain, resolvedModel, wrapsAround);
} else {
chain = createSingleModelChain(modelFromConfig);
// --- LEGACY PATH ---
if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
chain = getFlashLitePolicyChain();
} else if (
isGemini3Model(resolvedModel, config) ||
isAutoPreferred ||
isAutoConfigured
) {
if (hasAccessToPreview) {
const previewEnabled =
isGemini3Model(resolvedModel, config) ||
preferredModel === PREVIEW_GEMINI_MODEL_AUTO ||
configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
chain = getModelPolicyChain({
previewEnabled,
userTier: config.getUserTier(),
useGemini31,
useGemini31FlashLite,
useCustomToolModel,
});
} else {
// User requested Gemini 3 but has no access. Proactively downgrade
// to the stable Gemini 2.5 chain.
chain = getModelPolicyChain({
previewEnabled: false,
userTier: config.getUserTier(),
useGemini31,
useGemini31FlashLite,
useCustomToolModel,
});
}
} else {
chain = createSingleModelChain(modelFromConfig);
}
chain = applyDynamicSlicing(chain, resolvedModel, wrapsAround);
}
return applyDynamicSlicing(chain, resolvedModel, wrapsAround);
// Apply Unified Silent Injection for Plan Mode with defensive checks
if (config?.getApprovalMode?.() === ApprovalMode.PLAN) {
return chain.map((policy) => ({
...policy,
actions: { ...SILENT_ACTIONS },
}));
}
return chain;
}
/**
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-devtools",
"version": "0.36.0-nightly.20260317.2f90b4653",
"version": "0.38.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.36.0-nightly.20260317.2f90b4653",
"version": "0.38.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.36.0-nightly.20260317.2f90b4653",
"version": "0.38.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.36.0-nightly.20260317.2f90b4653",
"version": "0.38.2",
"publisher": "google",
"icon": "assets/icon.png",
"repository": {