feat(terminal): refactor runtime and add mobile workspace (#2280)
Replace the legacy terminal flow with a shared authenticated WebSocket runtime used across web, desktop, relay, and mobile surfaces. - introduce the v3 terminal protocol with scoped attachments, snapshots, ordered output, bounded replay history, reconnects, and explicit lifecycle - harden PTY creation, restart, resize, close, force-kill, idle cleanup, shell selection, login mode, environment sanitization, and appearance sync - add runtime-aware terminal APIs with relay authentication and Electron parity - add a fullscreen mobile terminal workspace with touch scrolling, long-press selection, safe-area controls, quick keys, and Ctrl/Alt input - add terminal selection attachments, preview detection, project actions, shell settings, and localized UI - harden Ghostty rendering, resize recovery, Unicode handling, block characters, line height, and stale-row behavior - remove the obsolete terminal SSE path and update reverse-proxy guidance - expand terminal runtime, transport, input, selection, and store coverage - avoid duplicate web builds when preparing mobile assets in root CI builds
This commit is contained in:
committed by
GitHub
parent
f5b4a267c0
commit
d4a8c4d2e1
@@ -3,6 +3,7 @@ import { updateDesktopSettings } from '@/lib/persistence';
|
||||
import type { DesktopSettings } from '@/lib/desktop';
|
||||
import type { MonoFontOption, UiFontOption } from '@/lib/fontOptions';
|
||||
import type { MobileKeyboardMode } from '@/lib/mobileKeyboardMode';
|
||||
import type { TerminalShell } from '@/lib/api/types';
|
||||
|
||||
type AppearanceSlice = {
|
||||
showReasoningTraces: boolean;
|
||||
@@ -34,6 +35,8 @@ type AppearanceSlice = {
|
||||
sessionRetentionAction: 'archive' | 'delete';
|
||||
fontSize: number;
|
||||
terminalFontSize: number;
|
||||
terminalShell: TerminalShell;
|
||||
terminalLoginShells: TerminalShell[];
|
||||
editorFontSize: number;
|
||||
uiFont: UiFontOption;
|
||||
monoFont: MonoFontOption;
|
||||
@@ -79,6 +82,8 @@ export const startAppearanceAutoSave = (): void => {
|
||||
sessionRetentionAction: useUIStore.getState().sessionRetentionAction,
|
||||
fontSize: useUIStore.getState().fontSize,
|
||||
terminalFontSize: useUIStore.getState().terminalFontSize,
|
||||
terminalShell: useUIStore.getState().terminalShell,
|
||||
terminalLoginShells: useUIStore.getState().terminalLoginShells,
|
||||
editorFontSize: useUIStore.getState().editorFontSize,
|
||||
uiFont: useUIStore.getState().uiFont,
|
||||
monoFont: useUIStore.getState().monoFont,
|
||||
@@ -90,26 +95,6 @@ export const startAppearanceAutoSave = (): void => {
|
||||
gitChangesViewMode: useUIStore.getState().gitChangesViewMode,
|
||||
};
|
||||
|
||||
let pending: Partial<DesktopSettings> | null = null;
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const flush = () => {
|
||||
const payload = pending;
|
||||
pending = null;
|
||||
timer = null;
|
||||
if (payload && Object.keys(payload).length > 0) {
|
||||
void updateDesktopSettings(payload);
|
||||
}
|
||||
};
|
||||
|
||||
const schedule = (changes: Partial<DesktopSettings>) => {
|
||||
pending = { ...(pending ?? {}), ...changes };
|
||||
if (timer) {
|
||||
return;
|
||||
}
|
||||
timer = setTimeout(flush, 150);
|
||||
};
|
||||
|
||||
useUIStore.subscribe((state) => {
|
||||
const current: AppearanceSlice = {
|
||||
showReasoningTraces: state.showReasoningTraces,
|
||||
@@ -136,6 +121,8 @@ export const startAppearanceAutoSave = (): void => {
|
||||
sessionRetentionAction: state.sessionRetentionAction,
|
||||
fontSize: state.fontSize,
|
||||
terminalFontSize: state.terminalFontSize,
|
||||
terminalShell: state.terminalShell,
|
||||
terminalLoginShells: state.terminalLoginShells,
|
||||
editorFontSize: state.editorFontSize,
|
||||
uiFont: state.uiFont,
|
||||
monoFont: state.monoFont,
|
||||
@@ -221,6 +208,12 @@ export const startAppearanceAutoSave = (): void => {
|
||||
if (current.terminalFontSize !== previous.terminalFontSize) {
|
||||
diff.terminalFontSize = current.terminalFontSize;
|
||||
}
|
||||
if (current.terminalShell !== previous.terminalShell) {
|
||||
diff.terminalShell = current.terminalShell;
|
||||
}
|
||||
if (current.terminalLoginShells !== previous.terminalLoginShells) {
|
||||
diff.terminalLoginShells = current.terminalLoginShells;
|
||||
}
|
||||
if (current.editorFontSize !== previous.editorFontSize) {
|
||||
diff.editorFontSize = current.editorFontSize;
|
||||
}
|
||||
@@ -252,7 +245,7 @@ export const startAppearanceAutoSave = (): void => {
|
||||
previous = current;
|
||||
|
||||
if (Object.keys(diff).length > 0) {
|
||||
schedule(diff);
|
||||
void updateDesktopSettings(diff);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user