From 046289748bdf81a02da13a56f3aa67bfbc633b12 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sun, 22 Mar 2026 21:45:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B9=8B=E5=89=8D=E6=98=AF=E4=BC=9A=E8=AF=9Dta?= =?UTF-8?q?b=E6=BF=80=E6=B4=BB=E7=9A=84=E4=BC=9A=E8=AF=9D=E4=B8=8D?= =?UTF-8?q?=E8=A2=AB=E7=A9=BA=E9=97=B2=E5=9B=9E=E6=94=B6=EF=BC=8C=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E6=94=B9=E4=B8=BA=E4=BC=9A=E8=AF=9Dtab=E6=89=80?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E4=BC=9A=E8=AF=9D=E9=83=BD=E4=B8=8D=E8=A2=AB?= =?UTF-8?q?=E7=A9=BA=E9=97=B2=E5=9B=9E=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/folder/layout.tsx | 28 +++++++++++++++++++++--- src/contexts/acp-connections-context.tsx | 12 ++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/app/folder/layout.tsx b/src/app/folder/layout.tsx index a1bbd7d..b19a759 100644 --- a/src/app/folder/layout.tsx +++ b/src/app/folder/layout.tsx @@ -1,6 +1,13 @@ "use client" -import { Suspense, useCallback, useEffect, useRef, useState } from "react" +import { + Suspense, + useMemo, + useCallback, + useEffect, + useRef, + useState, +} from "react" import { useSearchParams } from "next/navigation" import type { ImperativePanelGroupHandle } from "react-resizable-panels" import { FolderTitleBar } from "@/components/layout/folder-title-bar" @@ -9,9 +16,12 @@ import { StatusBar } from "@/components/layout/status-bar" import { FolderProvider } from "@/contexts/folder-context" import { TaskProvider } from "@/contexts/task-context" import { AlertProvider } from "@/contexts/alert-context" -import { AcpConnectionsProvider } from "@/contexts/acp-connections-context" +import { + AcpConnectionsProvider, + useAcpActions, +} from "@/contexts/acp-connections-context" import { ConversationRuntimeProvider } from "@/contexts/conversation-runtime-context" -import { TabProvider } from "@/contexts/tab-context" +import { TabProvider, useTabContext } from "@/contexts/tab-context" import { SessionStatsProvider } from "@/contexts/session-stats-context" import { SidebarProvider, useSidebarContext } from "@/contexts/sidebar-context" import { @@ -58,6 +68,17 @@ const MIN_CENTER_WIDTH_PX = 420 const MIN_WORKSPACE_HEIGHT_PX = 220 const LAYOUT_EPSILON = 0.25 +/** Syncs open tab keys from TabProvider to AcpConnectionsProvider */ +function TabKeysSync() { + const { tabs } = useTabContext() + const { registerOpenTabKeys } = useAcpActions() + const keys = useMemo(() => new Set(tabs.map((t) => t.id)), [tabs]) + useEffect(() => { + registerOpenTabKeys(keys) + }, [keys, registerOpenTabKeys]) + return null +} + function isSameLayout(a: number[], b: number[]): boolean { if (a.length !== b.length) return false return a.every((value, index) => Math.abs(value - b[index]) <= LAYOUT_EPSILON) @@ -649,6 +670,7 @@ function FolderLayoutInner({ children }: { children: React.ReactNode }) { + setActiveKey(key: string | null): void touchActivity(contextKey: string): void + registerOpenTabKeys(keys: Set): void } const AcpActionsContext = createContext(null) @@ -1147,6 +1148,9 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { // connectionId → contextKey reverse mapping const reverseMapRef = useRef(new Map()) + // Open tab keys — updated by child TabProvider via registerOpenTabKeys + const openTabKeysRef = useRef(new Set()) + // Guard against concurrent connect() calls const connectingKeysRef = useRef(new Set()) // Keys whose disconnect was requested while connect was still in flight @@ -1309,6 +1313,10 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { lastActivityRef.current.set(contextKey, Date.now()) }, []) + const registerOpenTabKeys = useCallback((keys: Set) => { + openTabKeysRef.current = keys + }, []) + const flushStreamingQueue = useCallback(() => { flushTimerRef.current = null const queued = streamingQueueRef.current @@ -1649,9 +1657,11 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { const now = Date.now() const currentActiveKey = storeRef.current.activeKey + const currentOpenTabKeys = openTabKeysRef.current const toDisconnect: { contextKey: string; connectionId: string }[] = [] for (const [contextKey, conn] of storeRef.current.connections) { if (contextKey === currentActiveKey) continue + if (currentOpenTabKeys.has(contextKey)) continue if ( conn.status === "prompting" || conn.status === "connecting" || @@ -1923,6 +1933,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { respondPermission, setActiveKey, touchActivity, + registerOpenTabKeys, }), [ connect, @@ -1935,6 +1946,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { respondPermission, setActiveKey, touchActivity, + registerOpenTabKeys, ] )