diff --git a/packages/cli/src/tui/app.ts b/packages/cli/src/tui/app.ts index 69998f19..554904d6 100644 --- a/packages/cli/src/tui/app.ts +++ b/packages/cli/src/tui/app.ts @@ -12,6 +12,7 @@ import { formatModeLabel, getTuiCopy, normalizeStageLabel, resolveTuiLocale, typ import { formatTuiResult } from "./output.js"; import { loadProjectSession, persistProjectSession } from "./session-store.js"; import { detectModelInfo, detectProjectLanguage, ensureProject, interactiveLlmSetup } from "./setup.js"; +import { isAppleTerminal } from "./theme.js"; import { createInteractionTools } from "./tools.js"; import { animateStartup } from "./effects.js"; @@ -172,7 +173,12 @@ export async function launchTui( tools, chatStreamBridge, }), - { exitOnCtrlC: true }, + { + exitOnCtrlC: true, + // Terminal.app crashes with rapid ANSI redraws + CJK IME input; + // halve the frame rate to reduce rendering pressure. + ...(isAppleTerminal && { maxFps: 15 }), + }, ); await app.waitUntilExit(); } finally { diff --git a/packages/cli/src/tui/dashboard.tsx b/packages/cli/src/tui/dashboard.tsx index b3bf1487..f0c1d34e 100644 --- a/packages/cli/src/tui/dashboard.tsx +++ b/packages/cli/src/tui/dashboard.tsx @@ -230,7 +230,12 @@ export function InkTuiApp(props: InkTuiAppProps): React.JSX.Element { } if (key.backspace || key.delete) { - setInputValue((current) => current.slice(0, -1)); + setInputValue((current) => { + // Use Intl.Segmenter for grapheme-aware backspace (handles CJK, emoji, etc.) + const segments = [...new Intl.Segmenter().segment(current)]; + segments.pop(); + return segments.map((s) => s.segment).join(""); + }); setSelectedSlashIndex(0); return; } diff --git a/packages/cli/src/tui/theme.ts b/packages/cli/src/tui/theme.ts index d1d4370b..00ddca0e 100644 --- a/packages/cli/src/tui/theme.ts +++ b/packages/cli/src/tui/theme.ts @@ -2,6 +2,9 @@ import { execSync } from "node:child_process"; export type TerminalTheme = "dark" | "light"; +/** Whether the terminal is macOS Terminal.app (limited ANSI support). */ +export const isAppleTerminal = process.env.TERM_PROGRAM === "Apple_Terminal"; + /** * Detect terminal background color. *