diff --git a/apps/web/src/pages/Shell.tsx b/apps/web/src/pages/Shell.tsx index c6a357d..e087fc7 100644 --- a/apps/web/src/pages/Shell.tsx +++ b/apps/web/src/pages/Shell.tsx @@ -662,7 +662,7 @@ export function ShellPage() { ); const inProject = Boolean(activeSpace && !activeSpace.isDefault); const coordinatorBot: Bot | undefined = useMemo(() => { - if (!inProject || !activeSpace) return undefined; + if ((!inProject && !inGroup) || !activeSpace) return undefined; const leadId = snapshot?.leadBotId ?? activeGroup?.leadBotId ?? @@ -673,10 +673,12 @@ export function ShellPage() { bots.find((b) => b.kind === "main" && b.spaceId === activeSpace.id) ?? bots.find((b) => b.spaceId === activeSpace.id); if (!found) return undefined; - const isLegacyName = found.name === "Chief" || found.name === "Projektkoordinator"; + const isLegacyName = + inProject && (found.name === "Chief" || found.name === "Projektkoordinator"); return isLegacyName ? { ...found, name: "Projektmanager" } : found; }, [ inProject, + inGroup, activeSpace, snapshot?.leadBotId, activeGroup?.leadBotId, @@ -786,6 +788,8 @@ export function ShellPage() { routeGroupId.current = groupId; const activeBotId = useRef(inGroup ? undefined : active?.id); activeBotId.current = inGroup ? undefined : active?.id; + const coordinatorBotIdRef = useRef(coordinatorBot?.id); + coordinatorBotIdRef.current = coordinatorBot?.id; const activeGroupId = useRef(groupId); activeGroupId.current = groupId; const screenRequest = useRef(0); @@ -1053,7 +1057,9 @@ export function ShellPage() { return loadComputerScreen({ load: () => rpc.computer.screenUrl({ botId: id }), isCurrent: () => - request === screenRequest.current && activeBotId.current === id && computerVisible.current, + request === screenRequest.current && + (activeBotId.current === id || coordinatorBotIdRef.current === id) && + computerVisible.current, commit: (screen) => { setScreenUrl(screen.url); setComputerError(screen.error); @@ -1480,17 +1486,21 @@ export function ShellPage() { void refreshThread(active.id).catch(() => undefined); } else if (isComputerStatusEvent(event)) { void refreshComputerScreen(active.id).catch(() => undefined); - } else if (event.type === "thread.computer") { + } + if (event.type === "thread.computer") { agentPointerFeed.publish(event.botId, event.payload, event.createdAt); - const screenRun = liveScreenRunId(event); - if (screenRun) { - setScreenRunId(screenRun); - setScreenActive(true); - window.clearTimeout(screenActiveTimer.current); - screenActiveTimer.current = window.setTimeout( - () => setScreenActive(false), - SCREEN_ACTIVE_MS, - ); + } + const screenRun = liveScreenRunId(event); + if (screenRun) { + setScreenRunId(screenRun); + setScreenActive(true); + window.clearTimeout(screenActiveTimer.current); + screenActiveTimer.current = window.setTimeout( + () => setScreenActive(false), + SCREEN_ACTIVE_MS, + ); + if (computerRef.current?.state !== "running") { + void refreshComputerScreen(active.id).catch(() => undefined); } } }, @@ -1598,6 +1608,9 @@ export function ShellPage() { // waiting_input: reconcile ask cards if a stale post-send refresh raced SSE. void refreshGroupThread(groupId).catch(() => undefined); } + if (event.type === "thread.computer") { + agentPointerFeed.publish(event.botId, event.payload, event.createdAt); + } }, }); return () => { @@ -1910,10 +1923,11 @@ export function ShellPage() { const handleRunErrorPresented = useCallback((runId: string) => { rememberSeenRunErrorId(runId); }, []); - const groupComputerBotId = - inGroup && activeSnapshot?.leadBotId && bots.some((bot) => bot.id === activeSnapshot.leadBotId) - ? activeSnapshot.leadBotId - : undefined; + const groupComputerBotId = inGroup + ? (activeSnapshot?.leadBotId && bots.some((bot) => bot.id === activeSnapshot.leadBotId) + ? activeSnapshot.leadBotId + : coordinatorBot?.id) + : undefined; // A bot message without a sender speaks for the conversation's own bot, never as an anonymous one. const defaultSpeakerId = inGroup ? activeSnapshot?.leadBotId : active?.id; const transcriptMessages = useMemo(() => { @@ -2031,6 +2045,7 @@ export function ShellPage() { const workspaceFocusRef = useRef<{ threadId: string; focus: WorkspaceFocus } | null>(null); const autoPanelRef = useRef(autoPanel); autoPanelRef.current = autoPanel; + const autoLayoutSplitRef = useRef(false); const autoCloseTimer = useRef(undefined); useEffect(() => () => window.clearTimeout(autoCloseTimer.current), []); // The pane follows the bot's work on focus edges only, so it never jumps while nothing changed. @@ -2049,7 +2064,7 @@ export function ShellPage() { if (!wideLayout) return; const paneState: PaneState = { open: - panel === "computer" + panel === "computer" || panel === "browser" ? "screen" : panel === "artifact" ? "artifact" @@ -2066,13 +2081,22 @@ export function ShellPage() { if (closing === null || autoPanelRef.current !== closing) return; setPanel(null); setAutoPanel(null); + if (autoLayoutSplitRef.current) { + autoLayoutSplitRef.current = false; + dualSurface.setLayoutMode("stream"); + } }, AUTO_SCREEN_CLOSE_DELAY_MS); return; } if (next.open === "artifact") setArtifactPane(workspaceFocus.artifact); + if (next.open === "screen") setCanvasTab("browser"); const nextPanel: Panel = next.open === "screen" ? "computer" : next.open; setPanel(nextPanel); setAutoPanel(next.auto ? nextPanel : null); + if (dualSurface.layoutMode === "stream") { + autoLayoutSplitRef.current = Boolean(next.auto); + dualSurface.setLayoutMode("split"); + } }, [workspaceFocus.key, activeSnapshot?.threadId, wideLayout]); const learnScreenPane = useCallback( (choice: "opened" | "dismissed") => { @@ -2091,6 +2115,7 @@ export function ShellPage() { if (autoPanel === "computer" && panel === null && focus?.pane === "screen" && !focus.takeover) { learnScreenPane("dismissed"); } + autoLayoutSplitRef.current = false; setAutoPanel(null); }, [panel]); const openArtifactBeside = useCallback((artifact: WorkspaceArtifact) => { @@ -3886,6 +3911,7 @@ export function ShellPage() { panel && (active || activeGroup || + coordinatorBot || panel === "create" || panel === "create-group" || panel === "browser") @@ -3898,6 +3924,7 @@ export function ShellPage() { panel && (active || activeGroup || + coordinatorBot || panel === "create" || panel === "create-group" || panel === "browser"), @@ -4116,56 +4143,46 @@ export function ShellPage() { layoutMode={showCanvasOnDesktop ? dualSurface.layoutMode : "stream"} orientation={dualSurface.orientation} onSelectMode={handleSelectLayoutMode} - onToggleOrientation={dualSurface.toggleOrientation} + onToggleOrientation={() => { + dualSurface.toggleOrientation(); + if (!showCanvasOnDesktop) { + handleSelectLayoutMode("split"); + } + }} disabled={dualSurface.isMobile} className="hidden md:flex" /> - {active || groupComputerBotId ? ( + {active || activeGroup || inProject || groupComputerBotId ? (