Add session eject feature and terminal UX improvements

- Add eject button for tmux sessions (keeps tmux running, removes from Spiceflow)
- Add refresh button to session settings for all providers
- Improve terminal controls: larger buttons, more zoom levels (50-150%), copy selection, paste clipboard, enter key
- Fix session navigation: properly reload when switching between sessions
- Update tmux screen presets to larger dimensions (fullscreen 260x48, desktop 120x48, landscape 80x24)
- Add testing documentation to CLAUDE.md
- Refactor E2E tests to use API-based cleanup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-20 23:37:06 -05:00
parent 3d121c2e08
commit 5171059692
10 changed files with 448 additions and 131 deletions
+47 -4
View File
@@ -3,7 +3,8 @@
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { onMount, onDestroy, tick } from 'svelte';
import { activeSession } from '$lib/stores/sessions';
import { activeSession, sessions } from '$lib/stores/sessions';
import { api } from '$lib/api';
import MessageList from '$lib/components/MessageList.svelte';
import InputBar from '$lib/components/InputBar.svelte';
import PermissionRequest from '$lib/components/PermissionRequest.svelte';
@@ -31,11 +32,13 @@
autoScroll = stored === 'true';
}
}
if (sessionId) {
activeSession.load(sessionId);
}
});
// Load session when sessionId changes (handles client-side navigation)
$: if (sessionId) {
activeSession.load(sessionId);
}
function handleToggleAutoScroll(event: CustomEvent<boolean>) {
autoScroll = event.detail;
if (browser) {
@@ -128,6 +131,24 @@
activeSession.setAutoAcceptEdits(event.detail);
}
function handleRefresh() {
if (sessionId) {
activeSession.load(sessionId);
}
}
async function handleEject() {
if (!sessionId || !isTmuxSession) return;
try {
const result = await api.ejectSession(sessionId);
alert(result.message);
await sessions.load(); // Refresh sessions list so ejected session is removed
goto('/');
} catch (e) {
alert('Failed to eject session: ' + (e instanceof Error ? e.message : 'Unknown error'));
}
}
const statusColors: Record<string, string> = {
idle: 'bg-zinc-600',
processing: 'bg-green-500 animate-pulse',
@@ -200,6 +221,8 @@
on:toggleAutoAccept={handleToggleAutoAccept}
on:toggleAutoScroll={handleToggleAutoScroll}
on:condenseAll={() => messageList?.condenseAll()}
on:refresh={handleRefresh}
on:eject={handleEject}
/>
<span class="text-xs font-medium uppercase {providerColors[session.provider] || 'text-zinc-400'}">
@@ -250,6 +273,15 @@
/>
<span>Auto-scroll</span>
</label>
<button
on:click={() => { menuOpen = false; handleRefresh(); }}
class="w-full px-3 py-2 text-left text-sm hover:bg-zinc-700 flex items-center gap-2 transition-colors"
>
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Refresh
</button>
{#if !isTmuxSession}
<button
on:click={() => { menuOpen = false; messageList?.condenseAll(); }}
@@ -272,6 +304,17 @@
<span>Auto-accept edits</span>
</label>
{/if}
{#if isTmuxSession}
<button
on:click={() => { menuOpen = false; handleEject(); }}
class="w-full px-3 py-2 text-left text-sm hover:bg-zinc-700 flex items-center gap-2 transition-colors border-t border-zinc-700 text-amber-400"
>
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
Eject session
</button>
{/if}
</div>
{/if}
</div>