fix(app): reduce workspace screen re-renders and fix archived agent handling
Replace greedy agents Map subscription with a Zustand selector that derives workspace agent visibility (ID sets only) with custom equality, so the workspace screen only re-renders when agents are added, removed, or archived — not on every status/activity update. Fix tab pruning to check against all known agents (including archived) instead of only active agents, so archived agent tabs survive reconciliation. Remove the auto-unarchive effect that called refreshAgent() as a workaround. Hide input area for archived agents.
This commit is contained in:
@@ -802,7 +802,7 @@ function AgentPanelBody({
|
|||||||
</ReanimatedAnimated.View>
|
</ReanimatedAnimated.View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{agentId && !isArchivingCurrentAgent ? (
|
{agentId && !isArchivingCurrentAgent && !agent?.archivedAt ? (
|
||||||
<AgentInputArea
|
<AgentInputArea
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
serverId={serverId}
|
serverId={serverId}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
canOpenAgentTabFromRoute,
|
canOpenAgentTabFromRoute,
|
||||||
deriveWorkspaceAgentVisibility,
|
deriveWorkspaceAgentVisibility,
|
||||||
shouldPruneWorkspaceAgentTab,
|
shouldPruneWorkspaceAgentTab,
|
||||||
|
workspaceAgentVisibilityEqual,
|
||||||
} from "@/screens/workspace/workspace-agent-visibility";
|
} from "@/screens/workspace/workspace-agent-visibility";
|
||||||
|
|
||||||
function makeAgent(input: {
|
function makeAgent(input: {
|
||||||
@@ -53,7 +54,7 @@ function makeAgent(input: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("workspace agent visibility", () => {
|
describe("workspace agent visibility", () => {
|
||||||
it("keeps archived agents hidden from visible list but present in workspace lookup", () => {
|
it("keeps archived agents out of activeAgentIds but present in knownAgentIds", () => {
|
||||||
const workspaceId = "/repo/worktree";
|
const workspaceId = "/repo/worktree";
|
||||||
const visible = makeAgent({
|
const visible = makeAgent({
|
||||||
id: "visible-agent",
|
id: "visible-agent",
|
||||||
@@ -82,87 +83,46 @@ describe("workspace agent visibility", () => {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.visibleAgents.map((agent) => agent.id)).toEqual(["visible-agent"]);
|
expect(result.activeAgentIds).toEqual(new Set(["visible-agent"]));
|
||||||
expect(result.lookupById.has("visible-agent")).toBe(true);
|
expect(result.knownAgentIds.has("visible-agent")).toBe(true);
|
||||||
expect(result.lookupById.has("archived-agent")).toBe(true);
|
expect(result.knownAgentIds.has("archived-agent")).toBe(true);
|
||||||
expect(result.lookupById.has("other-workspace-agent")).toBe(false);
|
expect(result.knownAgentIds.has("other-workspace-agent")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("allows explicit route open for archived agent once agents are hydrated", () => {
|
it("allows explicit route open for archived agent once agents are hydrated", () => {
|
||||||
const archivedAgent = makeAgent({
|
const knownAgentIds = new Set(["archived-agent"]);
|
||||||
id: "archived-agent",
|
|
||||||
cwd: "/repo/worktree",
|
|
||||||
archivedAt: new Date("2026-03-04T00:01:00.000Z"),
|
|
||||||
});
|
|
||||||
const lookup = new Map<string, Agent>([[archivedAgent.id, archivedAgent]]);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
canOpenAgentTabFromRoute({
|
canOpenAgentTabFromRoute({
|
||||||
agentId: "archived-agent",
|
agentId: "archived-agent",
|
||||||
agentsHydrated: true,
|
agentsHydrated: true,
|
||||||
workspaceAgentLookup: lookup,
|
knownAgentIds,
|
||||||
})
|
})
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not prune archived agent tabs when the workspace lookup still contains the agent", () => {
|
it("does not prune archived agent tabs when knownAgentIds contains the agent", () => {
|
||||||
const archivedAgent = makeAgent({
|
const knownAgentIds = new Set(["archived-agent"]);
|
||||||
id: "archived-agent",
|
|
||||||
cwd: "/repo/worktree",
|
|
||||||
archivedAt: new Date("2026-03-04T00:01:00.000Z"),
|
|
||||||
});
|
|
||||||
const lookup = new Map<string, Agent>([[archivedAgent.id, archivedAgent]]);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
shouldPruneWorkspaceAgentTab({
|
shouldPruneWorkspaceAgentTab({
|
||||||
agentId: "archived-agent",
|
agentId: "archived-agent",
|
||||||
agentsHydrated: true,
|
agentsHydrated: true,
|
||||||
workspaceAgentLookup: lookup,
|
knownAgentIds,
|
||||||
})
|
})
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prunes agent tabs once agents are hydrated and the agent is missing from the workspace lookup", () => {
|
it("prunes agent tabs once agents are hydrated and the agent is missing from knownAgentIds", () => {
|
||||||
expect(
|
expect(
|
||||||
shouldPruneWorkspaceAgentTab({
|
shouldPruneWorkspaceAgentTab({
|
||||||
agentId: "missing-agent",
|
agentId: "missing-agent",
|
||||||
agentsHydrated: true,
|
agentsHydrated: true,
|
||||||
workspaceAgentLookup: new Map<string, Agent>(),
|
knownAgentIds: new Set<string>(),
|
||||||
})
|
})
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sorts same-createdAt agents by lastActivityAt descending", () => {
|
|
||||||
const workspaceId = "/repo/worktree";
|
|
||||||
const createdAt = new Date("2026-03-04T00:00:00.000Z");
|
|
||||||
const newerActivity = makeAgent({
|
|
||||||
id: "newer-activity",
|
|
||||||
cwd: workspaceId,
|
|
||||||
createdAt,
|
|
||||||
lastActivityAt: new Date("2026-03-04T00:05:00.000Z"),
|
|
||||||
});
|
|
||||||
const olderActivity = makeAgent({
|
|
||||||
id: "older-activity",
|
|
||||||
cwd: workspaceId,
|
|
||||||
createdAt,
|
|
||||||
lastActivityAt: new Date("2026-03-04T00:01:00.000Z"),
|
|
||||||
});
|
|
||||||
const sessionAgents = new Map<string, Agent>([
|
|
||||||
[olderActivity.id, olderActivity],
|
|
||||||
[newerActivity.id, newerActivity],
|
|
||||||
]);
|
|
||||||
|
|
||||||
const result = deriveWorkspaceAgentVisibility({
|
|
||||||
sessionAgents,
|
|
||||||
workspaceId,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.visibleAgents.map((agent) => agent.id)).toEqual([
|
|
||||||
"newer-activity",
|
|
||||||
"older-activity",
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("matches workspace agents when cwd and route workspace differ only by trailing slash", () => {
|
it("matches workspace agents when cwd and route workspace differ only by trailing slash", () => {
|
||||||
const sessionAgents = new Map<string, Agent>([
|
const sessionAgents = new Map<string, Agent>([
|
||||||
[
|
[
|
||||||
@@ -179,7 +139,33 @@ describe("workspace agent visibility", () => {
|
|||||||
workspaceId: "/Users/moboudra/.paseo/worktrees/1luy0po7/normal-squid",
|
workspaceId: "/Users/moboudra/.paseo/worktrees/1luy0po7/normal-squid",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.visibleAgents.map((agent) => agent.id)).toEqual(["slash-agent"]);
|
expect(result.activeAgentIds).toEqual(new Set(["slash-agent"]));
|
||||||
expect(result.lookupById.has("slash-agent")).toBe(true);
|
expect(result.knownAgentIds.has("slash-agent")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("workspaceAgentVisibilityEqual", () => {
|
||||||
|
it("returns true for identical sets", () => {
|
||||||
|
const a = { activeAgentIds: new Set(["a", "b"]), knownAgentIds: new Set(["a", "b", "c"]) };
|
||||||
|
const b = { activeAgentIds: new Set(["a", "b"]), knownAgentIds: new Set(["a", "b", "c"]) };
|
||||||
|
expect(workspaceAgentVisibilityEqual(a, b)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false when activeAgentIds differ", () => {
|
||||||
|
const a = { activeAgentIds: new Set(["a"]), knownAgentIds: new Set(["a"]) };
|
||||||
|
const b = { activeAgentIds: new Set(["b"]), knownAgentIds: new Set(["a"]) };
|
||||||
|
expect(workspaceAgentVisibilityEqual(a, b)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false when knownAgentIds differ", () => {
|
||||||
|
const a = { activeAgentIds: new Set(["a"]), knownAgentIds: new Set(["a"]) };
|
||||||
|
const b = { activeAgentIds: new Set(["a"]), knownAgentIds: new Set(["a", "b"]) };
|
||||||
|
expect(workspaceAgentVisibilityEqual(a, b)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true for empty sets", () => {
|
||||||
|
const a = { activeAgentIds: new Set<string>(), knownAgentIds: new Set<string>() };
|
||||||
|
const b = { activeAgentIds: new Set<string>(), knownAgentIds: new Set<string>() };
|
||||||
|
expect(workspaceAgentVisibilityEqual(a, b)).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,68 +1,66 @@
|
|||||||
import type { Agent } from "@/stores/session-store";
|
import type { Agent } from "@/stores/session-store";
|
||||||
import { normalizeWorkspaceIdentity } from "@/utils/workspace-identity";
|
import { normalizeWorkspaceIdentity } from "@/utils/workspace-identity";
|
||||||
|
|
||||||
function sortAgentsByCreatedAtDescending(agents: Agent[]): Agent[] {
|
|
||||||
const sorted = [...agents];
|
|
||||||
sorted.sort((left, right) => {
|
|
||||||
const createdAtDelta = right.createdAt.getTime() - left.createdAt.getTime();
|
|
||||||
if (createdAtDelta !== 0) {
|
|
||||||
return createdAtDelta;
|
|
||||||
}
|
|
||||||
return right.lastActivityAt.getTime() - left.lastActivityAt.getTime();
|
|
||||||
});
|
|
||||||
return sorted;
|
|
||||||
}
|
|
||||||
|
|
||||||
function trimNonEmpty(value: string | null | undefined): string | null {
|
|
||||||
if (!value) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const trimmed = value.trim();
|
|
||||||
return trimmed.length > 0 ? trimmed : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeWorkspaceId(value: string | null | undefined): string {
|
function normalizeWorkspaceId(value: string | null | undefined): string {
|
||||||
return normalizeWorkspaceIdentity(value) ?? "";
|
return normalizeWorkspaceIdentity(value) ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceAgentVisibility {
|
||||||
|
activeAgentIds: Set<string>;
|
||||||
|
knownAgentIds: Set<string>;
|
||||||
|
}
|
||||||
|
|
||||||
export function deriveWorkspaceAgentVisibility(input: {
|
export function deriveWorkspaceAgentVisibility(input: {
|
||||||
sessionAgents: Map<string, Agent> | undefined;
|
sessionAgents: Map<string, Agent> | undefined;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}): {
|
}): WorkspaceAgentVisibility {
|
||||||
visibleAgents: Agent[];
|
|
||||||
lookupById: Map<string, Agent>;
|
|
||||||
} {
|
|
||||||
const { sessionAgents, workspaceId } = input;
|
const { sessionAgents, workspaceId } = input;
|
||||||
const normalizedWorkspaceId = normalizeWorkspaceId(workspaceId);
|
const normalizedWorkspaceId = normalizeWorkspaceId(workspaceId);
|
||||||
if (!sessionAgents || !workspaceId) {
|
if (!sessionAgents || !workspaceId) {
|
||||||
return {
|
return {
|
||||||
visibleAgents: [],
|
activeAgentIds: new Set<string>(),
|
||||||
lookupById: new Map<string, Agent>(),
|
knownAgentIds: new Set<string>(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const lookupById = new Map<string, Agent>();
|
const activeAgentIds = new Set<string>();
|
||||||
const visible: Agent[] = [];
|
const knownAgentIds = new Set<string>();
|
||||||
for (const agent of sessionAgents.values()) {
|
for (const agent of sessionAgents.values()) {
|
||||||
if (normalizeWorkspaceId(agent.cwd) !== normalizedWorkspaceId) {
|
if (normalizeWorkspaceId(agent.cwd) !== normalizedWorkspaceId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
lookupById.set(agent.id, agent);
|
knownAgentIds.add(agent.id);
|
||||||
if (!agent.archivedAt) {
|
if (!agent.archivedAt) {
|
||||||
visible.push(agent);
|
activeAgentIds.add(agent.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { activeAgentIds, knownAgentIds };
|
||||||
visibleAgents: sortAgentsByCreatedAtDescending(visible),
|
}
|
||||||
lookupById,
|
|
||||||
};
|
export function workspaceAgentVisibilityEqual(
|
||||||
|
a: WorkspaceAgentVisibility,
|
||||||
|
b: WorkspaceAgentVisibility,
|
||||||
|
): boolean {
|
||||||
|
return setsEqual(a.activeAgentIds, b.activeAgentIds) && setsEqual(a.knownAgentIds, b.knownAgentIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setsEqual(a: Set<string>, b: Set<string>): boolean {
|
||||||
|
if (a.size !== b.size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const item of a) {
|
||||||
|
if (!b.has(item)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canOpenAgentTabFromRoute(input: {
|
export function canOpenAgentTabFromRoute(input: {
|
||||||
agentId: string;
|
agentId: string;
|
||||||
agentsHydrated: boolean;
|
agentsHydrated: boolean;
|
||||||
workspaceAgentLookup: Map<string, Agent>;
|
knownAgentIds: Set<string>;
|
||||||
}): boolean {
|
}): boolean {
|
||||||
if (!input.agentId.trim()) {
|
if (!input.agentId.trim()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -70,13 +68,13 @@ export function canOpenAgentTabFromRoute(input: {
|
|||||||
if (!input.agentsHydrated) {
|
if (!input.agentsHydrated) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return input.workspaceAgentLookup.has(input.agentId);
|
return input.knownAgentIds.has(input.agentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldPruneWorkspaceAgentTab(input: {
|
export function shouldPruneWorkspaceAgentTab(input: {
|
||||||
agentId: string;
|
agentId: string;
|
||||||
agentsHydrated: boolean;
|
agentsHydrated: boolean;
|
||||||
workspaceAgentLookup: Map<string, Agent>;
|
knownAgentIds: Set<string>;
|
||||||
}): boolean {
|
}): boolean {
|
||||||
if (!input.agentId.trim()) {
|
if (!input.agentId.trim()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -84,5 +82,5 @@ export function shouldPruneWorkspaceAgentTab(input: {
|
|||||||
if (!input.agentsHydrated) {
|
if (!input.agentsHydrated) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !input.workspaceAgentLookup.has(input.agentId);
|
return !input.knownAgentIds.has(input.agentId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { useStoreWithEqualityFn } from "zustand/traditional";
|
||||||
import { useIsFocused } from "@react-navigation/native";
|
import { useIsFocused } from "@react-navigation/native";
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
@@ -96,6 +97,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
deriveWorkspaceAgentVisibility,
|
deriveWorkspaceAgentVisibility,
|
||||||
shouldPruneWorkspaceAgentTab,
|
shouldPruneWorkspaceAgentTab,
|
||||||
|
workspaceAgentVisibilityEqual,
|
||||||
} from "@/screens/workspace/workspace-agent-visibility";
|
} from "@/screens/workspace/workspace-agent-visibility";
|
||||||
import {
|
import {
|
||||||
deriveWorkspacePaneState,
|
deriveWorkspacePaneState,
|
||||||
@@ -582,18 +584,15 @@ function WorkspaceScreenContent({
|
|||||||
const client = useHostRuntimeClient(normalizedServerId);
|
const client = useHostRuntimeClient(normalizedServerId);
|
||||||
const isConnected = useHostRuntimeIsConnected(normalizedServerId);
|
const isConnected = useHostRuntimeIsConnected(normalizedServerId);
|
||||||
|
|
||||||
const sessionAgents = useSessionStore(
|
const workspaceAgentVisibility = useStoreWithEqualityFn(
|
||||||
(state) => state.sessions[normalizedServerId]?.agents
|
useSessionStore,
|
||||||
);
|
(state) =>
|
||||||
const workspaceAgentVisibility = useMemo(
|
|
||||||
() =>
|
|
||||||
deriveWorkspaceAgentVisibility({
|
deriveWorkspaceAgentVisibility({
|
||||||
sessionAgents,
|
sessionAgents: state.sessions[normalizedServerId]?.agents,
|
||||||
workspaceId: normalizedWorkspaceId,
|
workspaceId: normalizedWorkspaceId,
|
||||||
}),
|
}),
|
||||||
[normalizedWorkspaceId, sessionAgents]
|
workspaceAgentVisibilityEqual,
|
||||||
);
|
);
|
||||||
const workspaceAgents = workspaceAgentVisibility.visibleAgents;
|
|
||||||
|
|
||||||
const terminalsQueryKey = useMemo(
|
const terminalsQueryKey = useMemo(
|
||||||
() => ["terminals", normalizedServerId, normalizedWorkspaceId] as const,
|
() => ["terminals", normalizedServerId, normalizedWorkspaceId] as const,
|
||||||
@@ -823,8 +822,6 @@ function WorkspaceScreenContent({
|
|||||||
return () => handler.remove();
|
return () => handler.remove();
|
||||||
}, [closeToAgent, isExplorerOpen]);
|
}, [closeToAgent, isExplorerOpen]);
|
||||||
|
|
||||||
const agentsById = workspaceAgentVisibility.lookupById;
|
|
||||||
|
|
||||||
const persistenceKey = useMemo(
|
const persistenceKey = useMemo(
|
||||||
() =>
|
() =>
|
||||||
buildWorkspaceTabPersistenceKey({
|
buildWorkspaceTabPersistenceKey({
|
||||||
@@ -853,7 +850,6 @@ function WorkspaceScreenContent({
|
|||||||
const reorderWorkspaceTabsInPane = useWorkspaceLayoutStore((state) => state.reorderTabsInPane);
|
const reorderWorkspaceTabsInPane = useWorkspaceLayoutStore((state) => state.reorderTabsInPane);
|
||||||
const pendingByDraftId = useCreateFlowStore((state) => state.pendingByDraftId);
|
const pendingByDraftId = useCreateFlowStore((state) => state.pendingByDraftId);
|
||||||
const consumedOpenIntentsRef = useRef(new Set<string>());
|
const consumedOpenIntentsRef = useRef(new Set<string>());
|
||||||
const reopenedArchivedOpenIntentsRef = useRef(new Set<string>());
|
|
||||||
const pendingCloseTabIdsRef = useRef(new Set<string>());
|
const pendingCloseTabIdsRef = useRef(new Set<string>());
|
||||||
const [resolvedOpenIntentKey, setResolvedOpenIntentKey] = useState<string | null>(null);
|
const [resolvedOpenIntentKey, setResolvedOpenIntentKey] = useState<string | null>(null);
|
||||||
const currentOpenIntentKey = useMemo(
|
const currentOpenIntentKey = useMemo(
|
||||||
@@ -957,43 +953,6 @@ function WorkspaceScreenContent({
|
|||||||
}
|
}
|
||||||
}, [currentOpenIntentKey, resolvedOpenIntentKey]);
|
}, [currentOpenIntentKey, resolvedOpenIntentKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!client || !isConnected || openIntent?.kind !== "agent" || !currentOpenIntentKey) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const agentId = openIntent.agentId.trim();
|
|
||||||
if (!agentId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (reopenedArchivedOpenIntentsRef.current.has(currentOpenIntentKey)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const agent = agentsById.get(agentId) ?? null;
|
|
||||||
if (!agent?.archivedAt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reopenedArchivedOpenIntentsRef.current.add(currentOpenIntentKey);
|
|
||||||
void client.refreshAgent(agentId).catch((error) => {
|
|
||||||
console.warn("[WorkspaceScreen] Failed to reopen archived agent", {
|
|
||||||
serverId: normalizedServerId,
|
|
||||||
workspaceId: normalizedWorkspaceId,
|
|
||||||
agentId,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, [
|
|
||||||
agentsById,
|
|
||||||
client,
|
|
||||||
currentOpenIntentKey,
|
|
||||||
isConnected,
|
|
||||||
normalizedServerId,
|
|
||||||
normalizedWorkspaceId,
|
|
||||||
openIntent,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!openIntent || !persistenceKey) {
|
if (!openIntent || !persistenceKey) {
|
||||||
return;
|
return;
|
||||||
@@ -1075,12 +1034,12 @@ function WorkspaceScreenContent({
|
|||||||
return pending?.serverId === normalizedServerId && pending.lifecycle === "active";
|
return pending?.serverId === normalizedServerId && pending.lifecycle === "active";
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const agent of workspaceAgents) {
|
for (const agentId of workspaceAgentVisibility.activeAgentIds) {
|
||||||
const representedByTarget = uiTabs.some(
|
const representedByTarget = uiTabs.some(
|
||||||
(tab) => tab.target.kind === "agent" && tab.target.agentId === agent.id
|
(tab) => tab.target.kind === "agent" && tab.target.agentId === agentId
|
||||||
);
|
);
|
||||||
const representedByDeterministicTabId = uiTabs.some(
|
const representedByDeterministicTabId = uiTabs.some(
|
||||||
(tab) => tab.tabId === `agent_${agent.id}`
|
(tab) => tab.tabId === `agent_${agentId}`
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
hasActivePendingDraftCreateInWorkspace &&
|
hasActivePendingDraftCreateInWorkspace &&
|
||||||
@@ -1089,7 +1048,7 @@ function WorkspaceScreenContent({
|
|||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ensureWorkspaceTab({ kind: "agent", agentId: agent.id });
|
ensureWorkspaceTab({ kind: "agent", agentId });
|
||||||
}
|
}
|
||||||
for (const terminal of terminals) {
|
for (const terminal of terminals) {
|
||||||
ensureWorkspaceTab({ kind: "terminal", terminalId: terminal.id });
|
ensureWorkspaceTab({ kind: "terminal", terminalId: terminal.id });
|
||||||
@@ -1104,7 +1063,7 @@ function WorkspaceScreenContent({
|
|||||||
shouldPruneWorkspaceAgentTab({
|
shouldPruneWorkspaceAgentTab({
|
||||||
agentId: tab.target.agentId,
|
agentId: tab.target.agentId,
|
||||||
agentsHydrated: hasHydratedAgents,
|
agentsHydrated: hasHydratedAgents,
|
||||||
workspaceAgentLookup: agentsById,
|
knownAgentIds: workspaceAgentVisibility.knownAgentIds,
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
closeWorkspaceTab(persistenceKey, tab.tabId);
|
closeWorkspaceTab(persistenceKey, tab.tabId);
|
||||||
@@ -1126,7 +1085,7 @@ function WorkspaceScreenContent({
|
|||||||
terminals,
|
terminals,
|
||||||
terminalsQuery.isSuccess,
|
terminalsQuery.isSuccess,
|
||||||
uiTabs,
|
uiTabs,
|
||||||
workspaceAgents,
|
workspaceAgentVisibility,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const activeTabId = resolvedPaneTabState.activeTabId;
|
const activeTabId = resolvedPaneTabState.activeTabId;
|
||||||
@@ -1180,7 +1139,7 @@ function WorkspaceScreenContent({
|
|||||||
emptyWorkspaceSeedRef.current = null;
|
emptyWorkspaceSeedRef.current = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (workspaceAgents.length > 0 || terminals.length > 0) {
|
if (workspaceAgentVisibility.activeAgentIds.size > 0 || terminals.length > 0) {
|
||||||
emptyWorkspaceSeedRef.current = null;
|
emptyWorkspaceSeedRef.current = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1202,7 +1161,7 @@ function WorkspaceScreenContent({
|
|||||||
persistenceKey,
|
persistenceKey,
|
||||||
terminals.length,
|
terminals.length,
|
||||||
tabs.length,
|
tabs.length,
|
||||||
workspaceAgents.length,
|
workspaceAgentVisibility.activeAgentIds.size,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleOpenFileFromExplorer = useCallback(
|
const handleOpenFileFromExplorer = useCallback(
|
||||||
@@ -1485,7 +1444,7 @@ function WorkspaceScreenContent({
|
|||||||
const handleCopyResumeCommand = useCallback(
|
const handleCopyResumeCommand = useCallback(
|
||||||
async (agentId: string) => {
|
async (agentId: string) => {
|
||||||
if (!agentId) return;
|
if (!agentId) return;
|
||||||
const agent = sessionAgents?.get(agentId) ?? null;
|
const agent = useSessionStore.getState().sessions[normalizedServerId]?.agents?.get(agentId) ?? null;
|
||||||
const providerSessionId =
|
const providerSessionId =
|
||||||
agent?.runtimeInfo?.sessionId ?? agent?.persistence?.sessionId ?? null;
|
agent?.runtimeInfo?.sessionId ?? agent?.persistence?.sessionId ?? null;
|
||||||
if (!agent || !providerSessionId) {
|
if (!agent || !providerSessionId) {
|
||||||
@@ -1510,7 +1469,7 @@ function WorkspaceScreenContent({
|
|||||||
toast.error("Copy failed");
|
toast.error("Copy failed");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[sessionAgents, toast]
|
[normalizedServerId, toast]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCopyWorkspacePath = useCallback(async () => {
|
const handleCopyWorkspacePath = useCallback(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user