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
@@ -0,0 +1,42 @@
|
||||
import { afterEach, describe, expect, test } from 'bun:test';
|
||||
import { useInlineCommentDraftStore } from './useInlineCommentDraftStore';
|
||||
|
||||
const selection = {
|
||||
sessionKey: 'session-1',
|
||||
source: 'terminal' as const,
|
||||
fileLabel: 'Terminal 1',
|
||||
startLine: 4,
|
||||
endLine: 5,
|
||||
code: 'first\nsecond',
|
||||
language: 'term-1',
|
||||
text: '',
|
||||
};
|
||||
|
||||
describe('terminal context drafts', () => {
|
||||
afterEach(() => { useInlineCommentDraftStore.setState({ drafts: {} }); });
|
||||
|
||||
test('persists snapshots by chat session and deduplicates identical selections', () => {
|
||||
useInlineCommentDraftStore.getState().addDraft(selection);
|
||||
useInlineCommentDraftStore.getState().addDraft(selection);
|
||||
const drafts = useInlineCommentDraftStore.getState().getDrafts('session-1');
|
||||
expect(drafts).toHaveLength(1);
|
||||
expect({ ...drafts[0], id: undefined, createdAt: undefined }).toEqual({ ...selection, id: undefined, createdAt: undefined });
|
||||
});
|
||||
|
||||
test('supports individual removal and ordered consume', () => {
|
||||
useInlineCommentDraftStore.getState().addDraft(selection);
|
||||
useInlineCommentDraftStore.getState().addDraft({ ...selection, startLine: 8, endLine: 8, code: 'third' });
|
||||
const drafts = useInlineCommentDraftStore.getState().getDrafts('session-1');
|
||||
useInlineCommentDraftStore.getState().removeDraft('session-1', drafts[0].id);
|
||||
expect(useInlineCommentDraftStore.getState().consumeDrafts('session-1')).toHaveLength(1);
|
||||
expect(useInlineCommentDraftStore.getState().getDrafts('session-1')).toEqual([]);
|
||||
});
|
||||
|
||||
test('restores consumed drafts after a failed send without duplicating them', () => {
|
||||
useInlineCommentDraftStore.getState().addDraft(selection);
|
||||
const consumed = useInlineCommentDraftStore.getState().consumeDrafts('session-1');
|
||||
useInlineCommentDraftStore.getState().restoreDrafts('session-1', consumed);
|
||||
useInlineCommentDraftStore.getState().restoreDrafts('session-1', consumed);
|
||||
expect(useInlineCommentDraftStore.getState().getDrafts('session-1')).toEqual(consumed);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user