Make workspace git registration nonblocking (#542)

This commit is contained in:
Mohamed Boudra
2026-04-23 18:21:59 +08:00
committed by GitHub
parent 083cd34db4
commit dfc8223bcc
13 changed files with 557 additions and 318 deletions
@@ -10,6 +10,7 @@ import type {
SessionOutboundMessage,
} from "../shared/messages.js";
import type { WorkspaceGitRuntimeSnapshot } from "./workspace-git-service.js";
import { createNoopWorkspaceGitService } from "./test-utils/workspace-git-service-stub.js";
import {
createPersistedProjectRecord,
createPersistedWorkspaceRecord,
@@ -112,67 +113,6 @@ function agentIdsFromEntries(entries: Array<{ agent: Pick<AgentSnapshotPayload,
return entries.map((entry) => entry.agent.id);
}
function createNoopWorkspaceGitService() {
return {
subscribe: async (params: { cwd: string }) => ({
initial: {
cwd: params.cwd,
git: {
isGit: false,
repoRoot: null,
mainRepoRoot: null,
currentBranch: null,
remoteUrl: null,
isPaseoOwnedWorktree: false,
isDirty: null,
aheadBehind: null,
aheadOfOrigin: null,
behindOfOrigin: null,
diffStat: null,
},
github: {
featuresEnabled: false,
pullRequest: null,
error: null,
},
},
unsubscribe: () => {},
}),
peekSnapshot: (_cwd: string) => null,
getSnapshot: async (cwd: string) => ({
cwd,
git: {
isGit: false,
repoRoot: null,
mainRepoRoot: null,
currentBranch: null,
remoteUrl: null,
isPaseoOwnedWorktree: false,
isDirty: null,
aheadBehind: null,
aheadOfOrigin: null,
behindOfOrigin: null,
diffStat: null,
},
github: {
featuresEnabled: false,
pullRequest: null,
error: null,
},
}),
resolveRepoRemoteUrl: async () => null,
resolveRepoRoot: async (cwd: string) => cwd,
resolveDefaultBranch: async () => "main",
refresh: async () => {},
requestWorkingTreeWatch: async (cwd: string) => ({
repoRoot: cwd,
unsubscribe: () => {},
}),
scheduleRefreshForCwd: () => {},
dispose: () => {},
};
}
function createWorkspaceRuntimeSnapshot(
cwd: string,
overrides?: {
@@ -301,7 +241,7 @@ function createSessionForWorkspaceTests(
}),
dispose: () => {},
} as any,
workspaceGitService: (options.workspaceGitService ?? createNoopWorkspaceGitService()) as any,
workspaceGitService: options.workspaceGitService ?? createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -593,7 +533,7 @@ describe("workspace aggregation", () => {
}),
dispose: () => {},
} as any,
workspaceGitService: createNoopWorkspaceGitService() as any,
workspaceGitService: createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -745,7 +685,7 @@ describe("workspace aggregation", () => {
}),
dispose: () => {},
} as any,
workspaceGitService: createNoopWorkspaceGitService() as any,
workspaceGitService: createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -924,7 +864,7 @@ describe("workspace aggregation", () => {
}),
dispose: () => {},
} as any,
workspaceGitService: createNoopWorkspaceGitService() as any,
workspaceGitService: createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -1066,7 +1006,7 @@ describe("workspace aggregation", () => {
}),
dispose: () => {},
} as any,
workspaceGitService: createNoopWorkspaceGitService() as any,
workspaceGitService: createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -1683,7 +1623,7 @@ describe("workspace aggregation", () => {
}),
dispose: () => {},
} as any,
workspaceGitService: createNoopWorkspaceGitService() as any,
workspaceGitService: createNoopWorkspaceGitService(),
mcpBaseUrl: null,
stt: null,
tts: null,
@@ -2646,8 +2586,7 @@ describe("workspace aggregation", () => {
});
const workspaceGitService = createNoopWorkspaceGitService();
workspaceGitService.peekSnapshot = vi.fn(() => runtimeSnapshot);
workspaceGitService.subscribe = vi.fn(async () => ({
initial: runtimeSnapshot,
workspaceGitService.registerWorkspace = vi.fn(() => ({
unsubscribe: () => {},
}));
@@ -2728,6 +2667,64 @@ describe("workspace aggregation", () => {
]);
});
test("fetch_workspaces_response emits before cold registration-triggered git work starts", async () => {
const events: string[] = [];
const emitted: Array<{ type: string; payload: any }> = [];
const workspaceGitService = createNoopWorkspaceGitService();
const getSnapshot = vi.fn(async (cwd: string) => {
events.push(`git:${cwd}`);
return createWorkspaceRuntimeSnapshot(cwd);
});
workspaceGitService.getSnapshot = getSnapshot;
workspaceGitService.registerWorkspace = vi.fn((params: { cwd: string }) => {
queueMicrotask(() => {
void getSnapshot(params.cwd);
});
return {
unsubscribe: () => {},
};
});
const session = createSessionForWorkspaceTests({
workspaceGitService,
}) as any;
const project = createPersistedProjectRecord({
projectId: "proj-fetch-boundary",
rootPath: "/tmp/repo",
kind: "git",
displayName: "repo",
createdAt: "2026-03-01T12:00:00.000Z",
updatedAt: "2026-03-01T12:00:00.000Z",
});
const workspace = createPersistedWorkspaceRecord({
workspaceId: "ws-fetch-boundary",
projectId: project.projectId,
cwd: "/tmp/repo",
kind: "local_checkout",
displayName: "main",
createdAt: "2026-03-01T12:00:00.000Z",
updatedAt: "2026-03-01T12:00:00.000Z",
});
session.emit = (message: any) => {
if (message.type === "fetch_workspaces_response") {
events.push("response");
}
emitted.push(message);
};
session.listAgentPayloads = async () => [];
session.projectRegistry.list = async () => [project];
session.workspaceRegistry.list = async () => [workspace];
await session.handleMessage({
type: "fetch_workspaces_request",
requestId: "req-fetch-workspaces-boundary",
subscribe: {},
});
expect(emitted.find((message) => message.type === "fetch_workspaces_response")).toBeDefined();
expect(events[0]).toBe("response");
});
test("workspace_update includes updated runtime fields", async () => {
const emitted: Array<{ type: string; payload: any }> = [];
const runtimeSnapshot = createWorkspaceRuntimeSnapshot("/tmp/repo", {
@@ -2865,6 +2862,7 @@ describe("workspace aggregation", () => {
projectId: gitProject.projectId,
projectDisplayName: gitProject.displayName,
projectRootPath: gitProject.rootPath,
workspaceDirectory: gitWorkspace.cwd,
projectKind: gitProject.kind,
workspaceKind: gitWorkspace.kind,
name: "main",
@@ -2881,6 +2879,7 @@ describe("workspace aggregation", () => {
projectId: directoryProject.projectId,
projectDisplayName: directoryProject.displayName,
projectRootPath: directoryProject.rootPath,
workspaceDirectory: directoryWorkspace.cwd,
projectKind: directoryProject.kind,
workspaceKind: directoryWorkspace.kind,
name: "docs",