feat: disengage surface adhesion protocols (#12989)

This commit is contained in:
N. Taylor Mullen
2025-11-12 23:36:18 -08:00
committed by GitHub
parent 0f9ec2735c
commit fe1bfc64f7
4 changed files with 108 additions and 7 deletions

View File

@@ -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);

View File

@@ -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('<Header />', () => {
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue(null);
});
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', () => {
const customArt = 'CUSTOM ART';
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', () => {
render(<Header version="1.0.0" nightly={true} />);
const textCalls = (Text as Mock).mock.calls;

View File

@@ -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<HeaderProps> = ({
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<HeaderProps> = ({
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);

View File

@@ -53,8 +53,7 @@ export interface TerminalSetupResult {
type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf';
// Terminal detection
async function detectTerminal(): Promise<SupportedTerminal | null> {
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<SupportedTerminal | null> {
if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) {
return 'vscode';
}
return null;
}
// Terminal detection
async function detectTerminal(): Promise<SupportedTerminal | null> {
const envTerminal = getTerminalProgram();
if (envTerminal) {
return envTerminal;
}
// Check parent process name
if (os.platform() !== 'win32') {