fix(client): inherit current workspace for new sessions

This commit is contained in:
_Kerman
2026-08-11 14:19:51 +08:00
parent a46a7bf912
commit 4ce51888be
6 changed files with 24 additions and 16 deletions

View File

@@ -21,9 +21,11 @@ export interface IWorkspaces {
*/ */
connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId> connectWorkspace(workspaceId: WorkspaceId): Promise<SessionId>
/** /**
* The New Session flow: connect the target (or recent) Workspace and open * The New Session flow: connect the explicit, current-Session, or recent
* the resulting session; failures surface on the session list state. * Workspace and open the resulting session; failures surface on the session
* @param workspaceId - explicit target; omitted uses the recency projection. * list state.
* @param workspaceId - explicit target; omitted inherits the current
* Session's Workspace before falling back to the recency projection.
*/ */
startSession(workspaceId?: WorkspaceId): void startSession(workspaceId?: WorkspaceId): void
/** /**

View File

@@ -167,14 +167,20 @@ export class WorkspacesService implements IWorkspaces {
/** /**
* The shared New Session action behind the shell entry points (sidebar * The shared New Session action behind the shell entry points (sidebar
* button, workspace browser): resolve the target Workspace — explicit wins, * button, workspace browser): resolve the target Workspace — explicit wins,
* else the recent-Workspace projection — connect its blank session and * then the current Session's Workspace, then the recent-Workspace
* navigate there; with no Workspace at all, clear the selection into the * projection — connect its blank session and navigate there; with no
* New Session view state. Connect failures are non-fatal (console * Workspace at all, clear the selection into the New Session view state.
* diagnostics; the current view stays usable). * Connect failures are non-fatal (console diagnostics; the current view
* stays usable).
* @param workspaceId - explicit target Workspace for scoped actions. * @param workspaceId - explicit target Workspace for scoped actions.
*/ */
startSession(workspaceId?: WorkspaceId): void { startSession(workspaceId?: WorkspaceId): void {
const target = workspaceId ?? this.list.getSnapshot().recentWorkspaceId const workspace = this.list.getSnapshot()
const current = this.sessions.list.getSnapshot().current
const currentWorkspaceId = current === undefined
? undefined
: workspace.items.find(item => item.sessionIds.includes(current))?.workspaceId
const target = workspaceId ?? currentWorkspaceId ?? workspace.recentWorkspaceId
if (target === undefined) { if (target === undefined) {
this.sessions.clear() this.sessions.clear()
return return

View File

@@ -58,8 +58,8 @@ export interface SidebarSettingsOwnerProps {
export type SidebarRootInjected = { export type SidebarRootInjected = {
/** /**
* Start a New Session: with a workspace, reuse-or-create its blank session * Start a New Session: with a workspace, reuse-or-create its blank session
* and open it; without one, clear the selection into the New Session pure * and open it; without one, inherit the current Session Workspace, then the
* view state (the conversation.empty seat). * recent Workspace, or clear into the New Session pure view when none exist.
*/ */
startSession: (workspaceId?: WorkspaceId) => void startSession: (workspaceId?: WorkspaceId) => void
/** Toggle the sidebar column through the layout service. */ /** Toggle the sidebar column through the layout service. */

View File

@@ -30,7 +30,7 @@ export function apply(ctx: ClientContext): void {
const injectProps = (): SidebarRootInjected => ({ const injectProps = (): SidebarRootInjected => ({
// The shell's New Session button rides the runtime's shared action // The shell's New Session button rides the runtime's shared action
// (recent-Workspace targeting; explicit Workspace wins for scoped actions). // (current Session Workspace, then recent Workspace).
startSession: (workspaceId) => { ctx.workspaces.startSession(workspaceId) }, startSession: (workspaceId) => { ctx.workspaces.startSession(workspaceId) },
toggleSidebar: () => { ctx.layout.toggleSidebar() }, toggleSidebar: () => { ctx.layout.toggleSidebar() },
}) })

View File

@@ -91,9 +91,9 @@ export type DirectoryPickingHooks = {
*/ */
export type WorkspaceBrowserInjected = DirectoryPickingInjected & { export type WorkspaceBrowserInjected = DirectoryPickingInjected & {
/** /**
* Start a New Session in a Workspace: reuse-or-create its blank session * Start a New Session in a Workspace: reuse-or-create its blank session and
* and open it; with no workspace, clear the selection into the New Session * open it; without an explicit workspace, inherit the current Session
* pure view state (the conversation.empty seat). * Workspace, then the recent Workspace, or clear into the New Session view.
*/ */
startSession: (workspaceId?: WorkspaceId) => void startSession: (workspaceId?: WorkspaceId) => void
/** Open a real Session. */ /** Open a real Session. */

View File

@@ -68,8 +68,8 @@ export function apply(ctx: ClientContext): void {
const browserFlowSource = flowSource('sidebar.workspaces.directoryFlow') const browserFlowSource = flowSource('sidebar.workspaces.directoryFlow')
const pickerFlowSource = flowSource('conversation.hero.workspace.directoryFlow') const pickerFlowSource = flowSource('conversation.hero.workspace.directoryFlow')
const browserInjected = (): WorkspaceBrowserInjected => ({ const browserInjected = (): WorkspaceBrowserInjected => ({
// Explicit group actions keep their target; unscoped New Session rides // Explicit group actions keep their target; unscoped New Session inherits
// the runtime's shared action (recent-Workspace projection inside). // the current Session Workspace before the recent-Workspace fallback.
startSession: (workspaceId) => { ctx.workspaces.startSession(workspaceId) }, startSession: (workspaceId) => { ctx.workspaces.startSession(workspaceId) },
open: (sessionId) => { ctx.sessions.open(sessionId) }, open: (sessionId) => { ctx.sessions.open(sessionId) },
searchSessions, searchSessions,