fix(ink): restore Git Bash raw input handling

## Bug 详情
Windows Git Bash 终端下,csc 4.1.x 的 REPL 输入异常:回车需要按两次,方向键无法选择历史对话,输入 / 无法正常显示或触发命令。

## 根因
Windows raw mode 风险判断将 Git for Windows 的 MINGW64/MINGW32 与 MSYS2/Cygwin/mintty 环境一并禁用 raw mode,导致 Git Bash 走 cooked input fallback,Ink 无法按预期解析 Enter、方向键和 slash 输入。

## 修复方案
将 Git for Windows 的 MINGW64/MINGW32 从 raw mode 不安全名单中排除,恢复 Git Bash 的 raw mode 输入处理,同时保留 MSYS/UCRT/CLANG/Cygwin 和显式禁用开关的保护路径。

## 变更要点
- 调整 Ink raw mode 风险检测,Git Bash 保持 raw mode
- 同步启动早期输入捕获的 Git Bash raw mode 判断
- 增加 Git Bash raw mode 回归测试,并保留 MSYS2/Cygwin 场景覆盖

## 自测
- bun test packages/@ant/ink/src/core/__tests__/raw-mode-support.test.ts src/utils/__tests__/earlyInput.test.ts
- git diff --check
- bun run typecheck(失败,失败点为仓库既有 Zod 类型、缺失声明、MACRO.COMMIT、AppState 等错误,不涉及本次修改文件)
This commit is contained in:
IronRookieCoder 2026-05-18 17:13:17 +08:00
parent 602efce18a
commit 7b3260e757
3 changed files with 42 additions and 13 deletions

View File

@ -18,11 +18,29 @@ describe('isWindowsRawModeUnsafe', () => {
).toBe(false);
});
test('does not disable raw mode for Git Bash terminals', () => {
expect(
isWindowsRawModeUnsafe({
MSYSTEM: 'MINGW64',
TERM_PROGRAM: 'mintty',
SHELL: '/usr/bin/bash',
}, 'win32'),
).toBe(false);
expect(
isWindowsRawModeUnsafe({
MSYSTEM: 'MINGW32',
TERM: 'xterm-256color',
}, 'win32'),
).toBe(false);
});
test('disables raw mode for MSYS2 and Cygwin terminals', () => {
expect(isWindowsRawModeUnsafe({ MSYSTEM: 'UCRT64' }, 'win32')).toBe(true);
expect(isWindowsRawModeUnsafe({ MSYSTEM: 'CLANG64' }, 'win32')).toBe(true);
expect(isWindowsRawModeUnsafe({ MSYSTEM: 'MSYS' }, 'win32')).toBe(true);
expect(isWindowsRawModeUnsafe({ TERM: 'cygwin' }, 'win32')).toBe(true);
expect(isWindowsRawModeUnsafe({ TERM_PROGRAM: 'mintty' }, 'win32')).toBe(
true,
false,
);
expect(isWindowsRawModeUnsafe({ SHELL: '/usr/bin/bash' }, 'win32')).toBe(
false,

View File

@ -15,18 +15,27 @@ export function isWindowsRawModeUnsafe(
}
const term = env.TERM?.toLowerCase() ?? '';
const termProgram = env.TERM_PROGRAM?.toLowerCase() ?? '';
const msystem = env.MSYSTEM?.toLowerCase() ?? '';
const shell = env.SHELL?.toLowerCase() ?? '';
// Git for Windows reports MSYSTEM=MINGW64/MINGW32 and often runs under
// mintty, but it needs raw mode for Ink key parsing. Disabling raw mode
// there makes Enter, arrows, and slash commands behave like cooked shell
// input. Keep the startup-crash workaround scoped to MSYS2/Cygwin-like
// environments and leave Git Bash on the normal raw-mode path.
const isGitForWindowsMingw =
msystem === 'mingw64' || msystem === 'mingw32';
if (isGitForWindowsMingw) {
return false;
}
return (
term === 'cygwin' ||
term.includes('mintty') ||
termProgram.includes('mintty') ||
msystem.length > 0 ||
msystem === 'msys' ||
msystem.startsWith('ucrt') ||
msystem.startsWith('clang') ||
shell.includes('msys') ||
shell.includes('cygwin') ||
shell.includes('mingw')
shell.includes('cygwin')
);
}

View File

@ -31,18 +31,20 @@ function supportsEarlyInputRawMode(): boolean {
}
const term = process.env.TERM?.toLowerCase() ?? ''
const termProgram = process.env.TERM_PROGRAM?.toLowerCase() ?? ''
const msystem = process.env.MSYSTEM?.toLowerCase() ?? ''
const shell = process.env.SHELL?.toLowerCase() ?? ''
if (msystem === 'mingw64' || msystem === 'mingw32') {
return true
}
return !(
term === 'cygwin' ||
term.includes('mintty') ||
termProgram.includes('mintty') ||
msystem.length > 0 ||
msystem === 'msys' ||
msystem.startsWith('ucrt') ||
msystem.startsWith('clang') ||
shell.includes('msys') ||
shell.includes('cygwin') ||
shell.includes('mingw')
shell.includes('cygwin')
)
}