mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-16 17:11:04 -07:00
feat: disengage surface adhesion protocols (#12989)
This commit is contained in:
@@ -4,6 +4,10 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
function flipAsciiArt(art: string): string {
|
||||||
|
return art.split('\n').reverse().join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
export const shortAsciiLogo = `
|
export const shortAsciiLogo = `
|
||||||
█████████ ██████████ ██████ ██████ █████ ██████ █████ █████
|
█████████ ██████████ ██████ ██████ █████ ██████ █████ █████
|
||||||
███░░░░░███░░███░░░░░█░░██████ ██████ ░░███ ░░██████ ░░███ ░░███
|
███░░░░░███░░███░░░░░█░░██████ ██████ ░░███ ░░██████ ░░███ ░░███
|
||||||
@@ -36,3 +40,48 @@ export const tinyAsciiLogo = `
|
|||||||
███░ ░░█████████
|
███░ ░░█████████
|
||||||
░░░ ░░░░░░░░░
|
░░░ ░░░░░░░░░
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const rawShortAsciiLogoIde = `
|
||||||
|
░░░░░░░░░ ░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░
|
||||||
|
░░░ ░░░ ░░░ ░░░░░░ ░░░░░░ ░░░ ░░░░░░ ░░░░░ ░░░
|
||||||
|
░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░
|
||||||
|
█████████░░██████████ ██████ ░░██████░█████░██████ ░░█████ █████░
|
||||||
|
███░░ ███░███░░ ██████ ░██████░░███░░██████ ░█████ ███░░
|
||||||
|
███░░ ░░███░░ ███░███ ███ ███░░███░░███░███ ███░░ ███░░
|
||||||
|
███░░░░████░██████░░░░░███░░█████ ███░░███░░███░░███ ███░░░ ███░░░
|
||||||
|
███ ███ ███ ███ ███ ███ ███ ███ ██████ ███
|
||||||
|
███ ███ ███ ███ ███ ███ ███ █████ ███
|
||||||
|
█████████ ██████████ ███ ███ █████ ███ █████ █████
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const shortAsciiLogoIde = flipAsciiArt(rawShortAsciiLogoIde);
|
||||||
|
|
||||||
|
const rawLongAsciiLogoIde = `
|
||||||
|
░░░ ░░░░░░░░░ ░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░
|
||||||
|
░░░ ░░░ ░░░ ░░░ ░░░░░░ ░░░░░░ ░░░ ░░░░░░ ░░░░░ ░░░
|
||||||
|
░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░
|
||||||
|
███ ░░░ █████████░░██████████ ██████ ░░██████░█████░██████ ░░█████ █████░
|
||||||
|
███ ░░░ ███░ ███░███░░ ██████ ░██████░░███░░██████ ░█████ ███░░
|
||||||
|
███ ███░░░ ░░███░░ ███░███ ███ ███░░███░░███░███ ███░░ ███░░
|
||||||
|
░░░ ███ ███ ░░░█████░██████░░░░░███░░█████ ███░░███░░███░░███ ███░░░ ███░░░
|
||||||
|
███ ███ ███ ███ ███ ███ ███ ███ ███ ██████ ███
|
||||||
|
███ ███ ███ ███ ███ ███ ███ ███ █████ ███
|
||||||
|
███ █████████ ██████████ ███ ███ █████ ███ █████ █████
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const longAsciiLogoIde = flipAsciiArt(rawLongAsciiLogoIde);
|
||||||
|
|
||||||
|
const rawTinyAsciiLogoIde = `
|
||||||
|
░░░ ░░░░░░░░░
|
||||||
|
░░░ ░░░ ░░░
|
||||||
|
░░░ ░░░
|
||||||
|
███ ░░░ █████████░░░
|
||||||
|
███ ░░░ ███░░ ███░░
|
||||||
|
███ ███░░ ░░░
|
||||||
|
░░░ ███ ███░░░░████░
|
||||||
|
███ ███ ███
|
||||||
|
███ ███ ███
|
||||||
|
███ █████████
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const tinyAsciiLogoIde = flipAsciiArt(rawTinyAsciiLogoIde);
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ import { render } from '../../test-utils/render.js';
|
|||||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||||
import { Header } from './Header.js';
|
import { Header } from './Header.js';
|
||||||
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
||||||
import { longAsciiLogo } from './AsciiArt.js';
|
import { longAsciiLogo, longAsciiLogoIde } from './AsciiArt.js';
|
||||||
import * as semanticColors from '../semantic-colors.js';
|
import * as semanticColors from '../semantic-colors.js';
|
||||||
|
import * as terminalSetup from '../utils/terminalSetup.js';
|
||||||
import { Text } from 'ink';
|
import { Text } from 'ink';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
vi.mock('../hooks/useTerminalSize.js');
|
vi.mock('../hooks/useTerminalSize.js');
|
||||||
|
vi.mock('../utils/terminalSetup.js', () => ({
|
||||||
|
getTerminalProgram: vi.fn(),
|
||||||
|
}));
|
||||||
vi.mock('ink-gradient', () => {
|
vi.mock('ink-gradient', () => {
|
||||||
const MockGradient = ({ children }: { children: React.ReactNode }) => (
|
const MockGradient = ({ children }: { children: React.ReactNode }) => (
|
||||||
<>{children}</>
|
<>{children}</>
|
||||||
@@ -34,6 +38,7 @@ vi.mock('ink', async () => {
|
|||||||
describe('<Header />', () => {
|
describe('<Header />', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the long logo on a wide terminal', () => {
|
it('renders the long logo on a wide terminal', () => {
|
||||||
@@ -50,6 +55,22 @@ describe('<Header />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses the IDE logo when running in an IDE', () => {
|
||||||
|
vi.spyOn(useTerminalSize, 'useTerminalSize').mockReturnValue({
|
||||||
|
columns: 120,
|
||||||
|
rows: 20,
|
||||||
|
});
|
||||||
|
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue('vscode');
|
||||||
|
|
||||||
|
render(<Header version="1.0.0" nightly={false} />);
|
||||||
|
expect(Text).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
children: longAsciiLogoIde,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('renders custom ASCII art when provided', () => {
|
it('renders custom ASCII art when provided', () => {
|
||||||
const customArt = 'CUSTOM ART';
|
const customArt = 'CUSTOM ART';
|
||||||
render(
|
render(
|
||||||
@@ -63,6 +84,20 @@ describe('<Header />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders custom ASCII art as is when running in an IDE', () => {
|
||||||
|
const customArt = 'CUSTOM ART';
|
||||||
|
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue('vscode');
|
||||||
|
render(
|
||||||
|
<Header version="1.0.0" nightly={false} customAsciiArt={customArt} />,
|
||||||
|
);
|
||||||
|
expect(Text).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
children: customArt,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('displays the version number when nightly is true', () => {
|
it('displays the version number when nightly is true', () => {
|
||||||
render(<Header version="1.0.0" nightly={true} />);
|
render(<Header version="1.0.0" nightly={true} />);
|
||||||
const textCalls = (Text as Mock).mock.calls;
|
const textCalls = (Text as Mock).mock.calls;
|
||||||
|
|||||||
@@ -8,9 +8,17 @@ import type React from 'react';
|
|||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
import Gradient from 'ink-gradient';
|
import Gradient from 'ink-gradient';
|
||||||
import { theme } from '../semantic-colors.js';
|
import { theme } from '../semantic-colors.js';
|
||||||
import { shortAsciiLogo, longAsciiLogo, tinyAsciiLogo } from './AsciiArt.js';
|
import {
|
||||||
|
shortAsciiLogo,
|
||||||
|
longAsciiLogo,
|
||||||
|
tinyAsciiLogo,
|
||||||
|
shortAsciiLogoIde,
|
||||||
|
longAsciiLogoIde,
|
||||||
|
tinyAsciiLogoIde,
|
||||||
|
} from './AsciiArt.js';
|
||||||
import { getAsciiArtWidth } from '../utils/textUtils.js';
|
import { getAsciiArtWidth } from '../utils/textUtils.js';
|
||||||
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
||||||
|
import { getTerminalProgram } from '../utils/terminalSetup.js';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
customAsciiArt?: string; // For user-defined ASCII art
|
customAsciiArt?: string; // For user-defined ASCII art
|
||||||
@@ -44,6 +52,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
nightly,
|
nightly,
|
||||||
}) => {
|
}) => {
|
||||||
const { columns: terminalWidth } = useTerminalSize();
|
const { columns: terminalWidth } = useTerminalSize();
|
||||||
|
const isIde = getTerminalProgram();
|
||||||
let displayTitle;
|
let displayTitle;
|
||||||
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
||||||
const widthOfShortLogo = getAsciiArtWidth(shortAsciiLogo);
|
const widthOfShortLogo = getAsciiArtWidth(shortAsciiLogo);
|
||||||
@@ -51,11 +60,11 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
if (customAsciiArt) {
|
if (customAsciiArt) {
|
||||||
displayTitle = customAsciiArt;
|
displayTitle = customAsciiArt;
|
||||||
} else if (terminalWidth >= widthOfLongLogo) {
|
} else if (terminalWidth >= widthOfLongLogo) {
|
||||||
displayTitle = longAsciiLogo;
|
displayTitle = isIde ? longAsciiLogoIde : longAsciiLogo;
|
||||||
} else if (terminalWidth >= widthOfShortLogo) {
|
} else if (terminalWidth >= widthOfShortLogo) {
|
||||||
displayTitle = shortAsciiLogo;
|
displayTitle = isIde ? shortAsciiLogoIde : shortAsciiLogo;
|
||||||
} else {
|
} else {
|
||||||
displayTitle = tinyAsciiLogo;
|
displayTitle = isIde ? tinyAsciiLogoIde : tinyAsciiLogo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const artWidth = getAsciiArtWidth(displayTitle);
|
const artWidth = getAsciiArtWidth(displayTitle);
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ export interface TerminalSetupResult {
|
|||||||
|
|
||||||
type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf';
|
type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf';
|
||||||
|
|
||||||
// Terminal detection
|
export function getTerminalProgram(): SupportedTerminal | null {
|
||||||
async function detectTerminal(): Promise<SupportedTerminal | null> {
|
|
||||||
const termProgram = process.env['TERM_PROGRAM'];
|
const termProgram = process.env['TERM_PROGRAM'];
|
||||||
|
|
||||||
// Check VS Code and its forks - check forks first to avoid false positives
|
// Check VS Code and its forks - check forks first to avoid false positives
|
||||||
@@ -75,6 +74,15 @@ async function detectTerminal(): Promise<SupportedTerminal | null> {
|
|||||||
if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) {
|
if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) {
|
||||||
return 'vscode';
|
return 'vscode';
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminal detection
|
||||||
|
async function detectTerminal(): Promise<SupportedTerminal | null> {
|
||||||
|
const envTerminal = getTerminalProgram();
|
||||||
|
if (envTerminal) {
|
||||||
|
return envTerminal;
|
||||||
|
}
|
||||||
|
|
||||||
// Check parent process name
|
// Check parent process name
|
||||||
if (os.platform() !== 'win32') {
|
if (os.platform() !== 'win32') {
|
||||||
|
|||||||
Reference in New Issue
Block a user