fix(server): push workspace updates instantly, reconcile in background
emitWorkspaceUpdateForCwd and emitWorkspaceUpdatesForCwds blocked on reconcileActiveWorkspaceRecords() (stat + reconcile on every active workspace) before pushing the target workspace update to clients. This caused new worktrees to appear in the sidebar with a noticeable delay after the agent was already visible. Emit the target workspace immediately from the registry snapshot, then run reconciliation in the background via reconcileAndEmitWorkspaceUpdates. Ensure the dedupeGitState early-return still triggers background reconciliation so metadata changes (branch renames, display names) are not silently dropped.
This commit is contained in:
@@ -5784,66 +5784,60 @@ export class Session {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const changedWorkspaceIds = await this.reconcileActiveWorkspaceRecords();
|
|
||||||
const activeWorkspaces = (await this.workspaceRegistry.list()).filter(
|
const activeWorkspaces = (await this.workspaceRegistry.list()).filter(
|
||||||
(workspace) => !workspace.archivedAt,
|
(workspace) => !workspace.archivedAt,
|
||||||
);
|
);
|
||||||
const workspaceId = this.resolveRegisteredWorkspaceIdForCwd(cwd, activeWorkspaces);
|
const workspaceId = this.resolveRegisteredWorkspaceIdForCwd(cwd, activeWorkspaces);
|
||||||
const all = await this.listWorkspaceDescriptorsSnapshot();
|
const all = await this.listWorkspaceDescriptorsSnapshot();
|
||||||
const descriptorsByWorkspaceId = new Map(all.map((entry) => [entry.id, entry] as const));
|
const descriptorsByWorkspaceId = new Map(all.map((entry) => [entry.id, entry] as const));
|
||||||
const workspaceIdsToEmit = new Set<string>([
|
|
||||||
workspaceId,
|
|
||||||
...changedWorkspaceIds,
|
|
||||||
]);
|
|
||||||
|
|
||||||
for (const nextWorkspaceId of workspaceIdsToEmit) {
|
const workspace = descriptorsByWorkspaceId.get(workspaceId);
|
||||||
const workspace = descriptorsByWorkspaceId.get(nextWorkspaceId);
|
const nextWorkspace =
|
||||||
const nextWorkspace =
|
workspace && this.matchesWorkspaceFilter({ workspace, filter: subscription.filter })
|
||||||
workspace && this.matchesWorkspaceFilter({ workspace, filter: subscription.filter })
|
? workspace
|
||||||
? workspace
|
: null;
|
||||||
: null;
|
if (
|
||||||
if (
|
options?.dedupeGitState &&
|
||||||
options?.dedupeGitState &&
|
this.shouldSkipWorkspaceGitWatchUpdate(workspaceId, nextWorkspace)
|
||||||
this.shouldSkipWorkspaceGitWatchUpdate(nextWorkspaceId, nextWorkspace)
|
) {
|
||||||
) {
|
void this.reconcileAndEmitWorkspaceUpdates();
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
this.rememberWorkspaceGitWatchFingerprint(nextWorkspaceId, nextWorkspace);
|
this.rememberWorkspaceGitWatchFingerprint(workspaceId, nextWorkspace);
|
||||||
|
|
||||||
if (!nextWorkspace) {
|
|
||||||
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
|
||||||
kind: "remove",
|
|
||||||
id: nextWorkspaceId,
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!nextWorkspace) {
|
||||||
|
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
||||||
|
kind: "remove",
|
||||||
|
id: workspaceId,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
||||||
kind: "upsert",
|
kind: "upsert",
|
||||||
workspace: nextWorkspace,
|
workspace: nextWorkspace,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void this.reconcileAndEmitWorkspaceUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitWorkspaceUpdatesForCwds(cwds: Iterable<string>): Promise<void> {
|
private async emitWorkspaceUpdatesForCwds(cwds: Iterable<string>): Promise<void> {
|
||||||
if (!this.workspaceUpdatesSubscription) {
|
const subscription = this.workspaceUpdatesSubscription;
|
||||||
|
if (!subscription) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const changedWorkspaceIds = await this.reconcileActiveWorkspaceRecords();
|
|
||||||
const activeWorkspaces = (await this.workspaceRegistry.list()).filter(
|
const activeWorkspaces = (await this.workspaceRegistry.list()).filter(
|
||||||
(workspace) => !workspace.archivedAt,
|
(workspace) => !workspace.archivedAt,
|
||||||
);
|
);
|
||||||
const uniqueWorkspaceCwds = new Set<string>(changedWorkspaceIds);
|
const uniqueWorkspaceIds = new Set<string>();
|
||||||
for (const cwd of cwds) {
|
for (const cwd of cwds) {
|
||||||
uniqueWorkspaceCwds.add(this.resolveRegisteredWorkspaceIdForCwd(cwd, activeWorkspaces));
|
uniqueWorkspaceIds.add(this.resolveRegisteredWorkspaceIdForCwd(cwd, activeWorkspaces));
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscription = this.workspaceUpdatesSubscription;
|
|
||||||
const all = await this.listWorkspaceDescriptorsSnapshot();
|
const all = await this.listWorkspaceDescriptorsSnapshot();
|
||||||
const descriptorsByWorkspaceId = new Map(all.map((entry) => [entry.id, entry] as const));
|
const descriptorsByWorkspaceId = new Map(all.map((entry) => [entry.id, entry] as const));
|
||||||
|
|
||||||
for (const workspaceId of uniqueWorkspaceCwds) {
|
for (const workspaceId of uniqueWorkspaceIds) {
|
||||||
const workspace = descriptorsByWorkspaceId.get(workspaceId);
|
const workspace = descriptorsByWorkspaceId.get(workspaceId);
|
||||||
const nextWorkspace =
|
const nextWorkspace =
|
||||||
workspace && this.matchesWorkspaceFilter({ workspace, filter: subscription.filter })
|
workspace && this.matchesWorkspaceFilter({ workspace, filter: subscription.filter })
|
||||||
@@ -5864,6 +5858,8 @@ export class Session {
|
|||||||
workspace: nextWorkspace,
|
workspace: nextWorkspace,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void this.reconcileAndEmitWorkspaceUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleFetchAgents(
|
private async handleFetchAgents(
|
||||||
|
|||||||
Reference in New Issue
Block a user