Merge branch 'main' into feature/extension-management-tui

This commit is contained in:
LaZzyMan 2026-03-06 16:25:08 +08:00
commit 2699b88661
282 changed files with 21375 additions and 6462 deletions

View file

@ -1335,6 +1335,40 @@ describe('KeypressContext - Kitty Protocol', () => {
);
});
describe('Printable CSI-u keys', () => {
it('parses kitty CSI-u space as a space key with literal sequence', () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
act(() => stdin.sendKittySequence(`\x1b[32u`));
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'space',
sequence: ' ',
kittyProtocol: true,
}),
);
});
it('parses kitty CSI-u printable letters as literal input', () => {
const keyHandler = vi.fn();
const { result } = renderHook(() => useKeypressContext(), { wrapper });
act(() => result.current.subscribe(keyHandler));
act(() => stdin.sendKittySequence(`\x1b[100u`)); // 'd'
expect(keyHandler).toHaveBeenCalledWith(
expect.objectContaining({
name: 'd',
sequence: 'd',
kittyProtocol: true,
}),
);
});
});
describe('Shift+Tab forms', () => {
it.each([
{ sequence: `\x1b[Z`, description: 'legacy reverse Tab' },

View file

@ -332,6 +332,36 @@ export function KeypressProvider({
};
}
// Printable CSI-u keys (including space) should behave like regular
// character input so downstream text inputs receive the literal char.
if (
terminator === 'u' &&
!ctrl &&
keyCode >= 32 &&
keyCode !== 127 &&
keyCode <= 0x10ffff
) {
const char = String.fromCodePoint(keyCode);
const printableName =
char === ' '
? 'space'
: /^[A-Za-z]$/.test(char)
? char.toLowerCase()
: char;
return {
key: {
name: printableName,
ctrl: false,
meta: alt,
shift,
paste: false,
sequence: char,
kittyProtocol: true,
},
length: m[0].length,
};
}
// Ctrl+letters
if (
ctrl &&

View file

@ -17,7 +17,6 @@ import {
import { type SettingScope } from '../../config/settings.js';
import { type CodingPlanRegion } from '../../constants/codingPlan.js';
import type { AuthState } from '../types.js';
import { type VisionSwitchOutcome } from '../components/ModelSwitchDialog.js';
// OpenAICredentials type (previously imported from OpenAIKeyPrompt)
export interface OpenAICredentials {
apiKey: string;
@ -67,9 +66,8 @@ export interface UIActions {
onSuggestionsVisibilityChange: (visible: boolean) => void;
refreshStatic: () => void;
handleFinalSubmit: (value: string) => void;
handleRetryLastPrompt: () => void;
handleClearScreen: () => void;
// Vision switch dialog
handleVisionSwitchSelect: (outcome: VisionSwitchOutcome) => void;
// Welcome back dialog
handleWelcomeBackSelection: (choice: 'continue' | 'restart') => void;
handleWelcomeBackClose: () => void;

View file

@ -115,8 +115,6 @@ export interface UIState {
extensionsUpdateState: Map<string, ExtensionUpdateState>;
activePtyId: number | undefined;
embeddedShellFocused: boolean;
// Vision switch dialog
isVisionSwitchDialogOpen: boolean;
// Welcome back dialog
showWelcomeBackDialog: boolean;
welcomeBackInfo: {