diff --git a/packages/cli/src/ui/components/AsciiArt.ts b/packages/cli/src/ui/components/AsciiArt.ts
index 79eb522c80..6ca17d51a1 100644
--- a/packages/cli/src/ui/components/AsciiArt.ts
+++ b/packages/cli/src/ui/components/AsciiArt.ts
@@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
+function flipAsciiArt(art: string): string {
+ return art.split('\n').reverse().join('\n');
+}
+
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);
diff --git a/packages/cli/src/ui/components/Header.test.tsx b/packages/cli/src/ui/components/Header.test.tsx
index 8b4aa6b674..4cadc73a48 100644
--- a/packages/cli/src/ui/components/Header.test.tsx
+++ b/packages/cli/src/ui/components/Header.test.tsx
@@ -8,12 +8,16 @@ import { render } from '../../test-utils/render.js';
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
import { Header } from './Header.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 terminalSetup from '../utils/terminalSetup.js';
import { Text } from 'ink';
import type React from 'react';
vi.mock('../hooks/useTerminalSize.js');
+vi.mock('../utils/terminalSetup.js', () => ({
+ getTerminalProgram: vi.fn(),
+}));
vi.mock('ink-gradient', () => {
const MockGradient = ({ children }: { children: React.ReactNode }) => (
<>{children}>
@@ -34,6 +38,7 @@ vi.mock('ink', async () => {
describe('', () => {
beforeEach(() => {
vi.clearAllMocks();
+ vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue(null);
});
it('renders the long logo on a wide terminal', () => {
@@ -50,6 +55,22 @@ describe('', () => {
);
});
+ 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();
+ expect(Text).toHaveBeenCalledWith(
+ expect.objectContaining({
+ children: longAsciiLogoIde,
+ }),
+ undefined,
+ );
+ });
+
it('renders custom ASCII art when provided', () => {
const customArt = 'CUSTOM ART';
render(
@@ -63,6 +84,20 @@ describe('', () => {
);
});
+ it('renders custom ASCII art as is when running in an IDE', () => {
+ const customArt = 'CUSTOM ART';
+ vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue('vscode');
+ render(
+ ,
+ );
+ expect(Text).toHaveBeenCalledWith(
+ expect.objectContaining({
+ children: customArt,
+ }),
+ undefined,
+ );
+ });
+
it('displays the version number when nightly is true', () => {
render();
const textCalls = (Text as Mock).mock.calls;
diff --git a/packages/cli/src/ui/components/Header.tsx b/packages/cli/src/ui/components/Header.tsx
index 51e9cd8c71..08b356ef89 100644
--- a/packages/cli/src/ui/components/Header.tsx
+++ b/packages/cli/src/ui/components/Header.tsx
@@ -8,9 +8,17 @@ import type React from 'react';
import { Box, Text } from 'ink';
import Gradient from 'ink-gradient';
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 { useTerminalSize } from '../hooks/useTerminalSize.js';
+import { getTerminalProgram } from '../utils/terminalSetup.js';
interface HeaderProps {
customAsciiArt?: string; // For user-defined ASCII art
@@ -44,6 +52,7 @@ export const Header: React.FC = ({
nightly,
}) => {
const { columns: terminalWidth } = useTerminalSize();
+ const isIde = getTerminalProgram();
let displayTitle;
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
const widthOfShortLogo = getAsciiArtWidth(shortAsciiLogo);
@@ -51,11 +60,11 @@ export const Header: React.FC = ({
if (customAsciiArt) {
displayTitle = customAsciiArt;
} else if (terminalWidth >= widthOfLongLogo) {
- displayTitle = longAsciiLogo;
+ displayTitle = isIde ? longAsciiLogoIde : longAsciiLogo;
} else if (terminalWidth >= widthOfShortLogo) {
- displayTitle = shortAsciiLogo;
+ displayTitle = isIde ? shortAsciiLogoIde : shortAsciiLogo;
} else {
- displayTitle = tinyAsciiLogo;
+ displayTitle = isIde ? tinyAsciiLogoIde : tinyAsciiLogo;
}
const artWidth = getAsciiArtWidth(displayTitle);
diff --git a/packages/cli/src/ui/utils/terminalSetup.ts b/packages/cli/src/ui/utils/terminalSetup.ts
index 87e4ae1501..a0b541318d 100644
--- a/packages/cli/src/ui/utils/terminalSetup.ts
+++ b/packages/cli/src/ui/utils/terminalSetup.ts
@@ -53,8 +53,7 @@ export interface TerminalSetupResult {
type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf';
-// Terminal detection
-async function detectTerminal(): Promise {
+export function getTerminalProgram(): SupportedTerminal | null {
const termProgram = process.env['TERM_PROGRAM'];
// Check VS Code and its forks - check forks first to avoid false positives
@@ -75,6 +74,15 @@ async function detectTerminal(): Promise {
if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) {
return 'vscode';
}
+ return null;
+}
+
+// Terminal detection
+async function detectTerminal(): Promise {
+ const envTerminal = getTerminalProgram();
+ if (envTerminal) {
+ return envTerminal;
+ }
// Check parent process name
if (os.platform() !== 'win32') {