Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions packages/apps/app/e2e/terminal/30-terminal-core-behavior.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,54 @@ test.describe('Terminal state transitions', () => {
})
})

// ── Keyboard input ──────────────────────────────────────────────────────────

test.describe('Terminal keyboard input', () => {
let projectAbbrev: string
let taskId: string

test.beforeAll(async ({ mainWindow }) => {
const s = seed(mainWindow)
const p = await s.createProject({
name: 'Keyboard Input',
color: '#06b6d4',
path: TEST_PROJECT_PATH
})
projectAbbrev = p.name.slice(0, 2).toUpperCase()

const t = await s.createTask({
projectId: p.id,
title: 'Keyboard input task',
status: 'in_progress'
})
taskId = t.id

await mainWindow.evaluate(
(id) => window.api.db.updateTask({ id, terminalMode: 'terminal' }),
taskId
)
await s.refreshData()
})

test('lets macOS Option produce printable keyboard-layout characters', async ({ mainWindow }) => {
await openTaskTerminal(mainWindow, { projectAbbrev, taskTitle: 'Keyboard input task' })

const sessionId = getMainSessionId(taskId)
await waitForPtySession(mainWindow, sessionId)

await expect
.poll(async () =>
mainWindow.evaluate((sid) => {
const links = (window as any).__slayzone_terminalLinks as
| Record<string, { _terminal?: { options?: { macOptionIsMeta?: boolean } } }>
| undefined
return links?.[sid]?._terminal?.options?.macOptionIsMeta ?? null
}, sessionId)
)
.toBe(false)
})
})

// ── Mode switch teardown ────────────────────────────────────────────────────

test.describe('Terminal mode switch teardown', () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/domains/terminal/src/client/Terminal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const trimSelectionTrailingSpaces = (s: string): string =>
.map((l) => l.replace(/[ \t]+$/, ''))
.join('\n')

// Keep Option available for keyboard-layout chars ($, €, etc.). Option+Arrow
// word nav is handled explicitly in handleTerminalKeyEvent.
const MAC_OPTION_IS_META = false

// Override xterm underline styles - Claude Code outputs these and they persist incorrectly
// This is a definitive fix that works regardless of ANSI code filtering
const underlineOverride = document.createElement('style')
Expand Down Expand Up @@ -420,6 +424,7 @@ export const Terminal = forwardRef<TerminalHandle, TerminalProps>(function Termi
searchAddonRef.current = cached.searchAddon
webglAddonRef.current = cached.webglAddon ?? null
registerActiveAddon(sessionId, cached.serializeAddon)
cached.terminal.options.macOptionIsMeta = MAC_OPTION_IS_META
if (cached.lastRenderedSeq !== undefined) {
lastRenderedSeqRef.current = cached.lastRenderedSeq
}
Expand Down Expand Up @@ -544,7 +549,7 @@ export const Terminal = forwardRef<TerminalHandle, TerminalProps>(function Termi
// Create new terminal
const terminal = new XTerm({
allowProposedApi: true,
macOptionIsMeta: true,
macOptionIsMeta: MAC_OPTION_IS_META,
cursorBlink: false,
fontSize: terminalFontSize,
fontFamily: terminalFontFamily,
Expand Down
Loading