refactor(app): move agent tab visibility policy (#851)
This commit is contained in:
@@ -133,9 +133,10 @@ import {
|
|||||||
} from "@/screens/workspace/workspace-route-state";
|
} from "@/screens/workspace/workspace-route-state";
|
||||||
import { renderWorkspaceRouteGate } from "@/screens/workspace/workspace-route-state-views";
|
import { renderWorkspaceRouteGate } from "@/screens/workspace/workspace-route-state-views";
|
||||||
import {
|
import {
|
||||||
|
buildWorkspaceTabSnapshot,
|
||||||
deriveWorkspaceAgentVisibility,
|
deriveWorkspaceAgentVisibility,
|
||||||
workspaceAgentVisibilityEqual,
|
workspaceAgentVisibilityEqual,
|
||||||
} from "@/screens/workspace/workspace-agent-visibility";
|
} from "@/workspace-tabs/agent-visibility";
|
||||||
import { deriveWorkspacePaneState } from "@/screens/workspace/workspace-pane-state";
|
import { deriveWorkspacePaneState } from "@/screens/workspace/workspace-pane-state";
|
||||||
import {
|
import {
|
||||||
buildWorkspacePaneContentModel,
|
buildWorkspacePaneContentModel,
|
||||||
@@ -1919,16 +1920,17 @@ function WorkspaceScreenContent({
|
|||||||
return pending?.serverId === normalizedServerId && pending.lifecycle === "active";
|
return pending?.serverId === normalizedServerId && pending.lifecycle === "active";
|
||||||
});
|
});
|
||||||
|
|
||||||
reconcileWorkspaceTabs(persistenceKey, {
|
reconcileWorkspaceTabs(
|
||||||
agentsHydrated: hasHydratedAgents,
|
persistenceKey,
|
||||||
terminalsHydrated: terminalsQuery.isSuccess,
|
buildWorkspaceTabSnapshot({
|
||||||
activeAgentIds: Array.from(workspaceAgentVisibility.activeAgentIds),
|
agentVisibility: workspaceAgentVisibility,
|
||||||
autoOpenAgentIds: Array.from(workspaceAgentVisibility.autoOpenAgentIds),
|
agentsHydrated: hasHydratedAgents,
|
||||||
knownAgentIds: Array.from(workspaceAgentVisibility.knownAgentIds),
|
terminalsHydrated: terminalsQuery.isSuccess,
|
||||||
knownTerminalIds,
|
knownTerminalIds,
|
||||||
standaloneTerminalIds,
|
standaloneTerminalIds,
|
||||||
hasActivePendingDraftCreate: hasActivePendingDraftCreateInWorkspace,
|
hasActivePendingDraftCreate: hasActivePendingDraftCreateInWorkspace,
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
}, [
|
}, [
|
||||||
hasHydratedAgents,
|
hasHydratedAgents,
|
||||||
hasHydratedWorkspaceLayoutStore,
|
hasHydratedWorkspaceLayoutStore,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import type { DaemonClient } from "@server/client/daemon-client";
|
import type { DaemonClient } from "@server/client/daemon-client";
|
||||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
import {
|
import {
|
||||||
|
buildWorkspaceTabSnapshot,
|
||||||
deriveWorkspaceAgentVisibility,
|
deriveWorkspaceAgentVisibility,
|
||||||
type WorkspaceAgentVisibility,
|
type WorkspaceAgentVisibility,
|
||||||
} from "@/screens/workspace/workspace-agent-visibility";
|
} from "@/workspace-tabs/agent-visibility";
|
||||||
import { selectSubagentsForParent } from "@/subagents";
|
import { selectSubagentsForParent } from "@/subagents";
|
||||||
import { buildWorkspaceTabPersistenceKey, useWorkspaceLayoutStore } from "./workspace-layout-store";
|
import { buildWorkspaceTabPersistenceKey, useWorkspaceLayoutStore } from "./workspace-layout-store";
|
||||||
import { useSessionStore, type Agent } from "./session-store";
|
import { useSessionStore, type Agent } from "./session-store";
|
||||||
@@ -151,15 +152,17 @@ function deriveVisibilityFromSession(): WorkspaceAgentVisibility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reconcileWorkspaceTabs(workspaceKey: string, visibility: WorkspaceAgentVisibility): void {
|
function reconcileWorkspaceTabs(workspaceKey: string, visibility: WorkspaceAgentVisibility): void {
|
||||||
useWorkspaceLayoutStore.getState().reconcileTabs(workspaceKey, {
|
useWorkspaceLayoutStore.getState().reconcileTabs(
|
||||||
agentsHydrated: true,
|
workspaceKey,
|
||||||
terminalsHydrated: true,
|
buildWorkspaceTabSnapshot({
|
||||||
activeAgentIds: visibility.activeAgentIds,
|
agentVisibility: visibility,
|
||||||
autoOpenAgentIds: visibility.autoOpenAgentIds,
|
agentsHydrated: true,
|
||||||
knownAgentIds: visibility.knownAgentIds,
|
terminalsHydrated: true,
|
||||||
standaloneTerminalIds: [],
|
knownTerminalIds: [],
|
||||||
hasActivePendingDraftCreate: false,
|
standaloneTerminalIds: [],
|
||||||
});
|
hasActivePendingDraftCreate: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWorkspaceTabIds(workspaceKey: string): string[] {
|
function getWorkspaceTabIds(workspaceKey: string): string[] {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Pure-data entry point for callers that don't want React Native deps in
|
// Pure-data entry point for callers that don't want React Native deps in
|
||||||
// their dependency graph (e.g. workspace-agent-visibility.ts is plain JS
|
// their dependency graph (e.g. workspace-tabs/agent-visibility.ts is plain
|
||||||
// data derivation and its tests run without an RN environment).
|
// data derivation and its tests run without an RN environment).
|
||||||
//
|
//
|
||||||
// The full module entry `@/subagents` re-exports these too, alongside the
|
// The full module entry `@/subagents` re-exports these too, alongside the
|
||||||
|
|||||||
+30
-1
@@ -1,10 +1,11 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { Agent } from "@/stores/session-store";
|
import type { Agent } from "@/stores/session-store";
|
||||||
import {
|
import {
|
||||||
|
buildWorkspaceTabSnapshot,
|
||||||
deriveWorkspaceAgentVisibility,
|
deriveWorkspaceAgentVisibility,
|
||||||
shouldPruneWorkspaceAgentTab,
|
shouldPruneWorkspaceAgentTab,
|
||||||
workspaceAgentVisibilityEqual,
|
workspaceAgentVisibilityEqual,
|
||||||
} from "@/screens/workspace/workspace-agent-visibility";
|
} from "@/workspace-tabs/agent-visibility";
|
||||||
|
|
||||||
function makeAgent(input: {
|
function makeAgent(input: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -265,6 +266,34 @@ describe("workspace agent visibility", () => {
|
|||||||
expect(result.knownAgentIds).toEqual(new Set(["recent-agent"]));
|
expect(result.knownAgentIds).toEqual(new Set(["recent-agent"]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("builds the tab reconciliation snapshot without callers unpacking agent visibility", () => {
|
||||||
|
const agentVisibility = {
|
||||||
|
activeAgentIds: new Set(["active-agent"]),
|
||||||
|
autoOpenAgentIds: new Set(["root-agent"]),
|
||||||
|
knownAgentIds: new Set(["active-agent", "archived-agent"]),
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildWorkspaceTabSnapshot({
|
||||||
|
agentVisibility,
|
||||||
|
agentsHydrated: true,
|
||||||
|
terminalsHydrated: true,
|
||||||
|
knownTerminalIds: ["terminal-1", "script-terminal"],
|
||||||
|
standaloneTerminalIds: ["terminal-1"],
|
||||||
|
hasActivePendingDraftCreate: false,
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
agentsHydrated: true,
|
||||||
|
terminalsHydrated: true,
|
||||||
|
activeAgentIds: agentVisibility.activeAgentIds,
|
||||||
|
autoOpenAgentIds: agentVisibility.autoOpenAgentIds,
|
||||||
|
knownAgentIds: agentVisibility.knownAgentIds,
|
||||||
|
knownTerminalIds: ["terminal-1", "script-terminal"],
|
||||||
|
standaloneTerminalIds: ["terminal-1"],
|
||||||
|
hasActivePendingDraftCreate: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("workspaceAgentVisibilityEqual", () => {
|
describe("workspaceAgentVisibilityEqual", () => {
|
||||||
it("returns true for identical sets", () => {
|
it("returns true for identical sets", () => {
|
||||||
const a = {
|
const a = {
|
||||||
+21
@@ -1,4 +1,5 @@
|
|||||||
import type { Agent } from "@/stores/session-store";
|
import type { Agent } from "@/stores/session-store";
|
||||||
|
import type { WorkspaceTabSnapshot } from "@/stores/workspace-layout-actions";
|
||||||
import { shouldAutoOpenAgentTab } from "@/subagents/policies";
|
import { shouldAutoOpenAgentTab } from "@/subagents/policies";
|
||||||
import { normalizeWorkspacePath } from "@/utils/workspace-identity";
|
import { normalizeWorkspacePath } from "@/utils/workspace-identity";
|
||||||
|
|
||||||
@@ -52,6 +53,26 @@ export function deriveWorkspaceAgentVisibility(input: {
|
|||||||
return { activeAgentIds, autoOpenAgentIds, knownAgentIds };
|
return { activeAgentIds, autoOpenAgentIds, knownAgentIds };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildWorkspaceTabSnapshot(input: {
|
||||||
|
agentVisibility: WorkspaceAgentVisibility;
|
||||||
|
agentsHydrated: boolean;
|
||||||
|
terminalsHydrated: boolean;
|
||||||
|
knownTerminalIds: Iterable<string>;
|
||||||
|
standaloneTerminalIds: Iterable<string>;
|
||||||
|
hasActivePendingDraftCreate: boolean;
|
||||||
|
}): WorkspaceTabSnapshot {
|
||||||
|
return {
|
||||||
|
agentsHydrated: input.agentsHydrated,
|
||||||
|
terminalsHydrated: input.terminalsHydrated,
|
||||||
|
activeAgentIds: input.agentVisibility.activeAgentIds,
|
||||||
|
autoOpenAgentIds: input.agentVisibility.autoOpenAgentIds,
|
||||||
|
knownAgentIds: input.agentVisibility.knownAgentIds,
|
||||||
|
knownTerminalIds: input.knownTerminalIds,
|
||||||
|
standaloneTerminalIds: input.standaloneTerminalIds,
|
||||||
|
hasActivePendingDraftCreate: input.hasActivePendingDraftCreate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function workspaceAgentVisibilityEqual(
|
export function workspaceAgentVisibilityEqual(
|
||||||
a: WorkspaceAgentVisibility,
|
a: WorkspaceAgentVisibility,
|
||||||
b: WorkspaceAgentVisibility,
|
b: WorkspaceAgentVisibility,
|
||||||
Reference in New Issue
Block a user