From d3747d62555ebcb09c78cfabcaa3b6177758d6ea Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 2 Sep 2026 17:17:58 +0200 Subject: [PATCH] feat(sessions): offer the item you came from when starting a new session (#10940) * fix: connect to dev server instead of localhost * fix: derive WebSocket scheme from location.protocol Mirror the protocol-aware pattern used by initSqlWebSocket in dev.ts so the WebSocket connects over wss:// when the dev server is reached through an HTTPS proxy/tunnel, avoiding mixed-content blocking. * refactor: drop now-unused port parameter of wmillTsDev Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HsfdN82yP88qyQ3h8Lwv2v * feat(sessions): offer the item you came from when starting a new session Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm * docs(sessions): state the new-session seed latch's real lifetime Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm * fix(sessions): let Enter act on the focused answer of the new-session offer Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm * feat(sessions): start on the item instead of resuming a stale session from the rail Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm * fix(sessions): hand the rail's item entry through the editor's own hand-off Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm * fix(sessions): snap the rail toggle back when a session switch does not navigate Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VkrstcgtV4AC4jZRHVzFdm --------- Co-authored-by: Nathan A. Ferch Co-authored-by: Claude Opus 5 (1M context) --- .../sessions/SessionModeSwitch.svelte | 23 ++- .../components/sessions/SessionPicker.svelte | 74 +++++++- .../sessions/openInSessionContext.ts | 36 +++- .../sessions/sessionSwitch.svelte.ts | 104 +++++++++-- .../components/sessions/sessionSwitch.test.ts | 163 +++++++++++++++++- 5 files changed, 374 insertions(+), 26 deletions(-) diff --git a/frontend/src/lib/components/sessions/SessionModeSwitch.svelte b/frontend/src/lib/components/sessions/SessionModeSwitch.svelte index d721b6f16f..9a7fb20bd6 100644 --- a/frontend/src/lib/components/sessions/SessionModeSwitch.svelte +++ b/frontend/src/lib/components/sessions/SessionModeSwitch.svelte @@ -2,8 +2,9 @@ import { Building, MessagesSquare } from 'lucide-svelte' import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte' import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte' - import { enterSessionMode, exitSessionMode } from './sessionSwitch.svelte' + import { enterSessionModeFromNav, exitSessionMode } from './sessionSwitch.svelte' import { goto } from '$lib/navigation' + import { sendUserToast } from '$lib/toast' import { page } from '$app/state' import { base } from '$lib/base' @@ -17,11 +18,25 @@ onToggle }: { mode: 'nav' | 'session'; isCollapsed?: boolean; onToggle?: () => void } = $props() + // The group's highlighted side. Melt moves it on click, before the navigation + // that would change `mode`, so it is derived from the route (which wins once + // a switch navigates) and pushed back when one does not, or the rail would + // read "AI Sessions" on an editor page with the clicked side inert until + // "Workspace" was pressed first. + let selected: string | string[] | null | undefined = $derived(mode) + function onSelected(next: 'nav' | 'session') { if (next === mode) return onToggle?.() - if (next === 'session') void enterSessionMode() - else void exitSessionMode() + if (next === 'session') { + // An editor whose draft could not be persisted keeps the user on the + // page, as its own "Open in AI session" button does, rather than open a + // session on an older draft than the one on screen. + void enterSessionModeFromNav().catch((e) => { + selected = mode + sendUserToast(e instanceof Error ? e.message : String(e), true) + }) + } else void exitSessionMode() } // Pressing the already-active "Workspace" side goes home, so the toggle doubles @@ -41,7 +56,7 @@ child of the group's track — so the buttons fill the rail width only if those wrappers grow. `[&>*]:flex-1` makes every direct child split the track evenly. --> *]:w-full' : 'w-full [&>*]:flex-1'} > diff --git a/frontend/src/lib/components/sessions/SessionPicker.svelte b/frontend/src/lib/components/sessions/SessionPicker.svelte index 87462e301b..e5b62da0eb 100644 --- a/frontend/src/lib/components/sessions/SessionPicker.svelte +++ b/frontend/src/lib/components/sessions/SessionPicker.svelte @@ -1,5 +1,6 @@