Compare commits

...

5 Commits

Author SHA1 Message Date
gemini-cli-robot cd4bebba9e chore(release): v0.12.0-preview.3 2025-10-30 22:44:31 +00:00
gemini-cli-robot 3876379bf7 fix(patch): cherry-pick 82c1042 to release/v0.12.0-preview.2-pr-12231 to patch version v0.12.0-preview.2 and create version 0.12.0-preview.3 (#12320)
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
2025-10-30 22:28:07 +00:00
gemini-cli-robot 7124551aa5 chore(release): v0.12.0-preview.2 2025-10-30 22:07:18 +00:00
matt korwel b4a63bf73b Merge commit 'b382ae6803ce21ead2a91682fc58126f3786f15b' into HEAD 2025-10-30 14:52:52 -07:00
gemini-cli-robot fe98c85535 chore(release): v0.12.0-preview.0 2025-10-29 00:57:46 +00:00
13 changed files with 172 additions and 137 deletions
+9
View File
@@ -67,3 +67,12 @@ This document lists the available keyboard shortcuts in the Gemini CLI.
| Shortcut | Description |
| -------- | --------------------------------- |
| `Ctrl+G` | See context CLI received from IDE |
## Meta+key combos on mac
On Mac, all Meta+char combos should work normally except for these three which
are mapped to special functionality.
- `meta+b`: "∫" back one word
- `meta+f`: "ƒ" forward one word
- `meta+m`: "µ" toggle markup view
+25
View File
@@ -161,6 +161,31 @@ export default tseslint.config(
'default-case': 'error',
},
},
{
// Prevent self-imports in packages
files: ['packages/core/src/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
name: '@google/gemini-cli-core',
message: 'Please use relative imports within the @google/gemini-cli-core package.',
},
],
},
},
{
files: ['packages/cli/src/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
name: '@google/gemini-cli',
message: 'Please use relative imports within the @google/gemini-cli package.',
},
],
},
},
{
files: ['packages/*/src/**/*.test.{ts,tsx}'],
plugins: {
+7 -7
View File
@@ -1,12 +1,12 @@
{
"name": "@google/gemini-cli",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@google/gemini-cli",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"workspaces": [
"packages/*"
],
@@ -17434,7 +17434,7 @@
},
"packages/a2a-server": {
"name": "@google/gemini-cli-a2a-server",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"dependencies": {
"@a2a-js/sdk": "^0.3.2",
"@google-cloud/storage": "^7.16.0",
@@ -17708,7 +17708,7 @@
},
"packages/cli": {
"name": "@google/gemini-cli",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"dependencies": {
"@google/gemini-cli-core": "file:../core",
"@google/genai": "1.16.0",
@@ -17828,7 +17828,7 @@
},
"packages/core": {
"name": "@google/gemini-cli-core",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"dependencies": {
"@google-cloud/logging": "^11.2.1",
"@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0",
@@ -17969,7 +17969,7 @@
},
"packages/test-utils": {
"name": "@google/gemini-cli-test-utils",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"license": "Apache-2.0",
"devDependencies": {
"typescript": "^5.3.3"
@@ -17980,7 +17980,7 @@
},
"packages/vscode-ide-companion": {
"name": "gemini-cli-vscode-ide-companion",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"license": "LICENSE",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
+6 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"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.12.0-nightly.20251022.0542de95"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0-preview.3"
},
"scripts": {
"start": "cross-env NODE_ENV=development node scripts/start.js",
@@ -127,7 +127,10 @@
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write",
"eslint --fix --max-warnings 0"
"eslint --fix --max-warnings 0 --no-warn-ignored"
],
"eslint.config.js": [
"prettier --write"
],
"*.{json,md}": [
"prettier --write"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-a2a-server",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"description": "Gemini CLI A2A Server",
"repository": {
"type": "git",
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"description": "Gemini CLI",
"repository": {
"type": "git",
@@ -25,7 +25,7 @@
"dist"
],
"config": {
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0-nightly.20251022.0542de95"
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0-preview.3"
},
"dependencies": {
"@google/gemini-cli-core": "file:../core",
@@ -872,99 +872,118 @@ describe('Kitty Sequence Parsing', () => {
vi.useRealTimers();
});
// Terminals to test
const terminals = ['iTerm2', 'Ghostty', 'MacTerminal', 'VSCodeTerminal'];
describe('Cross-terminal Alt key handling (simulating macOS)', () => {
let originalPlatform: NodeJS.Platform;
// Key mappings: letter -> [keycode, accented character]
const keys: Record<string, [number, string]> = {
a: [97, 'å'],
o: [111, 'ø'],
m: [109, 'µ'],
};
it.each(
terminals.flatMap((terminal) =>
Object.entries(keys).map(([key, [keycode, accentedChar]]) => {
if (terminal === 'Ghostty') {
// Ghostty uses kitty protocol sequences
return {
terminal,
key,
chunk: `\x1b[${keycode};3u`,
expected: {
name: key,
ctrl: false,
meta: true,
shift: false,
paste: false,
kittyProtocol: true,
},
};
} else if (terminal === 'MacTerminal') {
// Mac Terminal sends ESC + letter
return {
terminal,
key,
kitty: false,
chunk: `\x1b${key}`,
expected: {
sequence: `\x1b${key}`,
name: key,
ctrl: false,
meta: true,
shift: false,
paste: false,
},
};
} else {
// iTerm2 and VSCode send accented characters (å, ø, µ)
// Note: µ (mu) is sent with meta:false on iTerm2/VSCode but
// gets converted to m with meta:true
return {
terminal,
key,
chunk: accentedChar,
expected: {
name: key,
ctrl: false,
meta: true, // Always expect meta:true after conversion
shift: false,
paste: false,
sequence: accentedChar,
},
};
}
}),
),
)(
'should handle Alt+$key in $terminal',
({
chunk,
expected,
kitty = true,
}: {
chunk: string;
expected: Partial<Key>;
kitty?: boolean;
}) => {
const keyHandler = vi.fn();
const testWrapper = ({ children }: { children: React.ReactNode }) => (
<KeypressProvider kittyProtocolEnabled={kitty}>
{children}
</KeypressProvider>
);
const { result } = renderHook(() => useKeypressContext(), {
wrapper: testWrapper,
beforeEach(() => {
originalPlatform = process.platform;
Object.defineProperty(process, 'platform', {
value: 'darwin',
configurable: true,
});
act(() => result.current.subscribe(keyHandler));
});
act(() => stdin.write(chunk));
afterEach(() => {
Object.defineProperty(process, 'platform', {
value: originalPlatform,
configurable: true,
});
});
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining(expected),
);
},
);
// Terminals to test
const terminals = ['iTerm2', 'Ghostty', 'MacTerminal', 'VSCodeTerminal'];
// Key mappings: letter -> [keycode, accented character]
const keys: Record<string, [number, string]> = {
b: [98, '\u222B'],
f: [102, '\u0192'],
m: [109, '\u00B5'],
};
it.each(
terminals.flatMap((terminal) =>
Object.entries(keys).map(([key, [keycode, accentedChar]]) => {
if (terminal === 'Ghostty') {
// Ghostty uses kitty protocol sequences
return {
terminal,
key,
chunk: `\x1b[${keycode};3u`,
expected: {
name: key,
ctrl: false,
meta: true,
shift: false,
paste: false,
kittyProtocol: true,
},
};
} else if (terminal === 'MacTerminal') {
// Mac Terminal sends ESC + letter
return {
terminal,
key,
kitty: false,
chunk: `\x1b${key}`,
expected: {
sequence: `\x1b${key}`,
name: key,
ctrl: false,
meta: true,
shift: false,
paste: false,
},
};
} else {
// iTerm2 and VSCode send accented characters (å, ø, µ)
// Note: µ (mu) is sent with meta:false on iTerm2/VSCode but
// gets converted to m with meta:true
return {
terminal,
key,
chunk: accentedChar,
expected: {
name: key,
ctrl: false,
meta: true, // Always expect meta:true after conversion
shift: false,
paste: false,
sequence: accentedChar,
},
};
}
}),
),
)(
'should handle Alt+$key in $terminal',
({
chunk,
expected,
kitty = true,
}: {
chunk: string;
expected: Partial<Key>;
kitty?: boolean;
}) => {
const keyHandler = vi.fn();
const testWrapper = ({ children }: { children: React.ReactNode }) => (
<KeypressProvider kittyProtocolEnabled={kitty}>
{children}
</KeypressProvider>
);
const { result } = renderHook(() => useKeypressContext(), {
wrapper: testWrapper,
});
act(() => result.current.subscribe(keyHandler));
act(() => stdin.write(chunk));
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining(expected),
);
},
);
});
describe('Backslash key handling', () => {
beforeEach(() => {
@@ -48,33 +48,12 @@ export const PASTE_CODE_TIMEOUT_MS = 50; // Flush incomplete paste code after 50
export const SINGLE_QUOTE = "'";
export const DOUBLE_QUOTE = '"';
const ALT_KEY_CHARACTER_MAP: Record<string, string> = {
'\u00E5': 'a',
'\u222B': 'b',
'\u00E7': 'c',
'\u2202': 'd',
'\u00B4': 'e',
'\u0192': 'f',
'\u00A9': 'g',
'\u02D9': 'h',
'\u02C6': 'i',
'\u2206': 'j',
'\u02DA': 'k',
'\u00AC': 'l',
'\u00B5': 'm',
'\u02DC': 'n',
'\u00F8': 'o',
'\u03C0': 'p',
'\u0153': 'q',
'\u00AE': 'r',
'\u00DF': 's',
'\u2020': 't',
'\u00A8': 'u',
'\u221A': 'v',
'\u2211': 'w',
'\u2248': 'x',
'\u00A5': 'y',
'\u03A9': 'z',
// On Mac, hitting alt+char will yield funny characters.
// Remap these three since we listen for them.
const MAC_ALT_KEY_CHARACTER_MAP: Record<string, string> = {
'\u222B': 'b', // "∫" back one word
'\u0192': 'f', // "ƒ" forward one word
'\u00B5': 'm', // "µ" toggle markup view
};
/**
@@ -615,8 +594,8 @@ export function KeypressProvider({
return;
}
const mappedLetter = ALT_KEY_CHARACTER_MAP[key.sequence];
if (mappedLetter && !key.meta) {
const mappedLetter = MAC_ALT_KEY_CHARACTER_MAP[key.sequence];
if (process.platform === 'darwin' && mappedLetter && !key.meta) {
broadcast({
name: mappedLetter,
ctrl: false,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-core",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"description": "Gemini CLI Core",
"repository": {
"type": "git",
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { coreEvents } from '@google/gemini-cli-core';
import { coreEvents } from '../utils/events.js';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { promises as fs } from 'node:fs';
import * as path from 'node:path';
@@ -34,7 +34,7 @@ vi.mock('../config/storage.js', () => ({
},
}));
vi.mock('@google/gemini-cli-core', () => ({
vi.mock('../utils/events.js', () => ({
coreEvents: {
emitFeedback: vi.fn(),
},
+1 -1
View File
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { coreEvents } from '@google/gemini-cli-core';
import { coreEvents } from '../utils/events.js';
import { promises as fs } from 'node:fs';
import * as path from 'node:path';
import { Storage } from '../config/storage.js';
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@google/gemini-cli-test-utils",
"version": "0.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"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.12.0-nightly.20251022.0542de95",
"version": "0.12.0-preview.3",
"publisher": "google",
"icon": "assets/icon.png",
"repository": {