Keep legacy daemon agents attached to workspaces

Old daemons can report agents by cwd without workspace IDs. Build path-backed workspace rows for that compatibility path and reapply ownership to legacy snapshots so tab reconciliation keeps those agents visible.
This commit is contained in:
Mohamed Boudra
2026-06-18 22:41:48 +07:00
parent ef87b09146
commit 3d5059ab05
7 changed files with 852 additions and 86 deletions
+73 -30
View File
@@ -38,6 +38,10 @@ import {
} from "@/desktop/daemon/desktop-daemon-transport";
import { replaceFetchedAgentDirectory } from "@/utils/agent-directory-sync";
import { useSessionStore } from "@/stores/session-store";
import {
fetchLegacyDaemonWorkspaceDirectory,
shouldUseLegacyDaemonWorkspaceDirectory,
} from "@/workspace/legacy-daemon-workspaces";
import { invalidateCheckoutGitQueriesForServer } from "@/git/query-keys";
import { queryClient } from "@/query/query-client";
@@ -187,6 +191,54 @@ function readFetchAgentsNextCursor(
return null;
}
interface AgentDirectoryFetchInput {
client: DaemonClient;
filter?: FetchAgentsOptions["filter"];
subscribe?: FetchAgentsOptions["subscribe"];
page?: FetchAgentsOptions["page"];
}
interface AgentDirectoryFetchResult {
entries: FetchAgentsEntry[];
subscriptionId: string | null;
}
async function fetchCurrentAgentDirectory(
input: AgentDirectoryFetchInput,
): Promise<AgentDirectoryFetchResult> {
const pageLimit = input.page?.limit ?? DEFAULT_AGENT_DIRECTORY_PAGE_LIMIT;
let cursor = input.page?.cursor ?? null;
let includeSubscribe = true;
let subscriptionId: string | null = null;
const entries: FetchAgentsEntry[] = [];
while (true) {
const payload = await input.client.fetchAgents({
scope: input.filter ? undefined : "active",
...(input.filter ? { filter: input.filter } : {}),
sort: DEFAULT_AGENT_DIRECTORY_SORT,
...(includeSubscribe && input.subscribe ? { subscribe: input.subscribe } : {}),
page: cursor ? { limit: pageLimit, cursor } : { limit: pageLimit },
});
entries.push(...payload.entries);
subscriptionId = subscriptionId ?? payload.subscriptionId ?? null;
includeSubscribe = false;
if (!readFetchAgentsHasMore(payload.pageInfo)) {
break;
}
const nextCursor = readFetchAgentsNextCursor(payload.pageInfo);
if (!nextCursor) {
break;
}
cursor = nextCursor;
}
return { entries, subscriptionId };
}
function toActiveConnection(connection: HostConnection): ActiveConnection {
if (connection.type === "directSocket") {
return {
@@ -1912,46 +1964,37 @@ export class HostRuntimeStore {
controller.markAgentDirectorySyncLoading();
try {
const pageLimit = input.page?.limit ?? DEFAULT_AGENT_DIRECTORY_PAGE_LIMIT;
let cursor = input.page?.cursor ?? null;
let includeSubscribe = true;
let subscriptionId: string | null = null;
const allEntries: FetchAgentsEntry[] = [];
while (true) {
const payload = await client.fetchAgents({
scope: input.filter ? undefined : "active",
...(input.filter ? { filter: input.filter } : {}),
sort: DEFAULT_AGENT_DIRECTORY_SORT,
...(includeSubscribe && input.subscribe ? { subscribe: input.subscribe } : {}),
page: cursor ? { limit: pageLimit, cursor } : { limit: pageLimit },
const session = useSessionStore.getState().sessions[input.serverId];
if (!input.filter && shouldUseLegacyDaemonWorkspaceDirectory(session?.serverInfo)) {
const result = await fetchLegacyDaemonWorkspaceDirectory({
client,
serverId: input.serverId,
subscribe: input.subscribe,
page: input.page,
});
allEntries.push(...payload.entries);
subscriptionId = subscriptionId ?? payload.subscriptionId ?? null;
includeSubscribe = false;
if (!readFetchAgentsHasMore(payload.pageInfo)) {
break;
}
const nextCursor = readFetchAgentsNextCursor(payload.pageInfo);
if (!nextCursor) {
break;
}
cursor = nextCursor;
controller.markAgentDirectorySyncReady();
return {
agents: result.agents,
subscriptionId: result.subscriptionId,
};
}
const directory = await fetchCurrentAgentDirectory({
client,
filter: input.filter,
subscribe: input.subscribe,
page: input.page,
});
const { agents } = replaceFetchedAgentDirectory({
serverId: input.serverId,
entries: allEntries,
entries: directory.entries,
});
controller.markAgentDirectorySyncReady();
return {
agents,
subscriptionId,
subscriptionId: directory.subscriptionId,
};
} catch (error) {
controller.markAgentDirectorySyncError(toErrorMessage(error));