fix(tui): align Ctrl+L and /model with classic CLI semantics

Make Ctrl+L non-destructive by redrawing the current screen state instead of starting a new session, and stop auto-appending --global for typed /model commands so session scope remains the default unless explicitly requested.
This commit is contained in:
Brooklyn Nicholson
2026-04-27 12:23:56 -05:00
parent d5a89283b7
commit 4909b94f99
5 changed files with 11 additions and 19 deletions

View File

@@ -26,6 +26,11 @@ describe('constants', () => {
})
})
it('documents Ctrl/Cmd+L as non-destructive redraw', () => {
expect(HOTKEYS.some(([, d]) => d === 'redraw / repaint')).toBe(true)
expect(HOTKEYS.some(([, d]) => d.includes('new session'))).toBe(false)
})
it('TOOL_VERBS maps known tools (verb-only, no emoji)', () => {
expect(TOOL_VERBS.terminal).toBe('terminal')
expect(TOOL_VERBS.read_file).toBe('reading')

View File

@@ -26,7 +26,7 @@ describe('createSlashHandler', () => {
expect(ctx.gateway.gw.request).not.toHaveBeenCalled()
})
it('persists typed /model switches by default', async () => {
it('keeps typed /model switches session-scoped by default', async () => {
patchUiState({ sid: 'sid-abc' })
const ctx = buildCtx({
@@ -40,7 +40,7 @@ describe('createSlashHandler', () => {
expect(ctx.gateway.rpc).toHaveBeenCalledWith('config.set', {
key: 'model',
session_id: 'sid-abc',
value: 'x-model --global'
value: 'x-model'
})
})

View File

@@ -16,17 +16,9 @@ import { patchOverlayState } from '../../overlayStore.js'
import { patchUiState } from '../../uiStore.js'
import type { SlashCommand } from '../types.js'
const GLOBAL_MODEL_FLAG_RE = /(?:^|\s)--global(?:\s|$)/
const TUI_SESSION_MODEL_RE = new RegExp(`(?:^|\\s)${TUI_SESSION_MODEL_FLAG}(?:\\s|$)`)
const TUI_SESSION_STRIP_RE = new RegExp(`\\s*${TUI_SESSION_MODEL_FLAG}\\b\\s*`, 'g')
const persistedModelArg = (arg: string) => {
const trimmed = arg.trim()
return !trimmed || GLOBAL_MODEL_FLAG_RE.test(trimmed) ? trimmed : `${trimmed} --global`
}
const stripTuiSessionFlag = (trimmed: string) =>
trimmed.replace(TUI_SESSION_STRIP_RE, ' ').replace(/\s+/g, ' ').trim()
@@ -41,7 +33,7 @@ const modelValueForConfigSet = (arg: string) => {
return stripTuiSessionFlag(trimmed)
}
return persistedModelArg(trimmed)
return trimmed
}
export const sessionCommands: SlashCommand[] = [

View File

@@ -379,13 +379,8 @@ export function useInputHandlers(ctx: InputHandlerContext): InputHandlerResult {
}
if (isAction(key, ch, 'l')) {
if (actions.guardBusySessionSwitch()) {
return
}
patchUiState({ status: 'forging session…' })
return actions.newSession()
clearSelection()
return patchUiState(state => ({ ...state }))
}
if (isVoiceToggleKey(key, ch)) {

View File

@@ -19,7 +19,7 @@ export const HOTKEYS: [string, string][] = [
...copyHotkeys,
[action + '+D', 'exit'],
[action + '+G / Alt+G', 'open $EDITOR (Alt+G fallback for VSCode/Cursor)'],
[action + '+L', 'new session (clear)'],
[action + '+L', 'redraw / repaint'],
[paste + '+V / /paste', 'paste text; /paste attaches clipboard image'],
['Tab', 'apply completion'],
['↑/↓', 'completions / queue edit / history'],