Refresh MCP worktree cache after create/archive (#911)
* Fix MCP worktree list cache after create/archive * Fix MCP worktree archive refresh from scoped cwd --------- Co-authored-by: zbl <zbl@zbl-M4Pro.local> Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
co-authored by
zbl
Mohamed Boudra
parent
47d236a299
commit
15cab6014c
@@ -683,8 +683,11 @@ describe("Suite E: Worktree Tools", () => {
|
||||
try {
|
||||
const created = await callToolStructured(topLevelClient, "create_worktree", {
|
||||
cwd: worktreeRepoCwd,
|
||||
branchName,
|
||||
baseBranch: "main",
|
||||
target: {
|
||||
mode: "branch-off",
|
||||
newBranch: branchName,
|
||||
base: "main",
|
||||
},
|
||||
});
|
||||
worktreePath = str(created.worktreePath);
|
||||
|
||||
@@ -711,8 +714,11 @@ describe("Suite E: Worktree Tools", () => {
|
||||
try {
|
||||
const created = await callToolStructured(topLevelClient, "create_worktree", {
|
||||
cwd: worktreeRepoCwd,
|
||||
branchName,
|
||||
baseBranch: "main",
|
||||
target: {
|
||||
mode: "branch-off",
|
||||
newBranch: branchName,
|
||||
base: "main",
|
||||
},
|
||||
});
|
||||
worktreePath = str(created.worktreePath);
|
||||
|
||||
@@ -731,4 +737,49 @@ describe("Suite E: Worktree Tools", () => {
|
||||
await archiveWorktreeIfPresent({ cwd: worktreeRepoCwd, worktreePath });
|
||||
}
|
||||
});
|
||||
|
||||
test("archive_worktree succeeds when caller cwd is inside the archived worktree", async () => {
|
||||
let worktreePath: string | null = null;
|
||||
let worktreeAgentId: string | null = null;
|
||||
let worktreeScopedClient: McpClient | null = null;
|
||||
const branchName = `parity-archive-self-cwd-${Date.now()}`;
|
||||
|
||||
try {
|
||||
const created = await callToolStructured(topLevelClient, "create_worktree", {
|
||||
cwd: worktreeRepoCwd,
|
||||
target: {
|
||||
mode: "branch-off",
|
||||
newBranch: branchName,
|
||||
base: "main",
|
||||
},
|
||||
});
|
||||
worktreePath = str(created.worktreePath);
|
||||
worktreeAgentId = await createTopLevelAgent({
|
||||
cwd: worktreePath,
|
||||
title: "Worktree scoped parity agent",
|
||||
});
|
||||
worktreeScopedClient = await createMcpClient(
|
||||
`http://127.0.0.1:${daemonHandle.port}/mcp/agents?callerAgentId=${encodeURIComponent(
|
||||
worktreeAgentId,
|
||||
)}`,
|
||||
);
|
||||
|
||||
const archived = await callToolStructured(worktreeScopedClient, "archive_worktree", {
|
||||
worktreePath,
|
||||
});
|
||||
expect(archived).toEqual({ success: true });
|
||||
worktreePath = null;
|
||||
worktreeAgentId = null;
|
||||
|
||||
const listed = await callToolStructured(topLevelClient, "list_worktrees", {
|
||||
cwd: worktreeRepoCwd,
|
||||
});
|
||||
const worktrees = recordArr(listed.worktrees);
|
||||
expect(worktrees.map((worktree) => worktree.path)).not.toContain(created.worktreePath);
|
||||
} finally {
|
||||
await worktreeScopedClient?.close();
|
||||
await archiveAgentIfPresent(worktreeAgentId);
|
||||
await archiveWorktreeIfPresent({ cwd: worktreeRepoCwd, worktreePath });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1033,6 +1033,8 @@ describe("create_agent MCP tool", () => {
|
||||
execFileSync("git", ["branch", "-M", "main"], { cwd: repoDir, stdio: "pipe" });
|
||||
const workspaceGitService = {
|
||||
getSnapshot: vi.fn(async () => null),
|
||||
listWorktrees: vi.fn(async () => []),
|
||||
resolveRepoRoot: vi.fn(async () => repoDir),
|
||||
};
|
||||
|
||||
const server = await createAgentMcpServer({
|
||||
@@ -1046,7 +1048,7 @@ describe("create_agent MCP tool", () => {
|
||||
}),
|
||||
workspaceGitService: workspaceGitService as unknown as Pick<
|
||||
WorkspaceGitService,
|
||||
"getSnapshot" | "listWorktrees"
|
||||
"getSnapshot" | "listWorktrees" | "resolveRepoRoot"
|
||||
>,
|
||||
logger,
|
||||
});
|
||||
@@ -1059,6 +1061,10 @@ describe("create_agent MCP tool", () => {
|
||||
expect(response.structuredContent.branchName).toBe("tool-worktree");
|
||||
expect(response.structuredContent.worktreePath).toContain("tool-worktree");
|
||||
expect(workspaceGitService.getSnapshot).not.toHaveBeenCalled();
|
||||
expect(workspaceGitService.listWorktrees).toHaveBeenCalledWith(repoDir, {
|
||||
force: true,
|
||||
reason: "mcp:create-worktree",
|
||||
});
|
||||
expect(setupContinuations).toEqual([undefined]);
|
||||
expect(broadcasts).toHaveLength(1);
|
||||
expect(broadcasts[0]).toContain("tool-worktree");
|
||||
@@ -1093,6 +1099,8 @@ describe("create_agent MCP tool", () => {
|
||||
|
||||
const workspaceGitService = {
|
||||
getSnapshot: vi.fn(async () => null),
|
||||
listWorktrees: vi.fn(async () => []),
|
||||
resolveRepoRoot: vi.fn(async () => repoDir),
|
||||
};
|
||||
const archiveWorkspaceRecord = vi.fn(async () => undefined);
|
||||
const emitWorkspaceUpdatesForWorkspaceIds = vi.fn(async () => undefined);
|
||||
@@ -1106,7 +1114,7 @@ describe("create_agent MCP tool", () => {
|
||||
createPaseoWorktree: createPaseoWorktreeForMcpTest({ paseoHome, broadcasts: [] }),
|
||||
workspaceGitService: workspaceGitService as unknown as Pick<
|
||||
WorkspaceGitService,
|
||||
"getSnapshot" | "listWorktrees"
|
||||
"getSnapshot" | "listWorktrees" | "resolveRepoRoot"
|
||||
>,
|
||||
archiveWorkspaceRecord,
|
||||
emitWorkspaceUpdatesForWorkspaceIds,
|
||||
@@ -1133,6 +1141,11 @@ describe("create_agent MCP tool", () => {
|
||||
force: true,
|
||||
reason: "archive-worktree",
|
||||
});
|
||||
expect(workspaceGitService.resolveRepoRoot).toHaveBeenCalledWith(repoDir);
|
||||
expect(workspaceGitService.listWorktrees).toHaveBeenCalledWith(repoDir, {
|
||||
force: true,
|
||||
reason: "mcp:archive-worktree",
|
||||
});
|
||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(created.structuredContent.worktreePath);
|
||||
expect(markWorkspaceArchiving).toHaveBeenCalledWith(
|
||||
[created.structuredContent.worktreePath],
|
||||
|
||||
@@ -1858,6 +1858,10 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
resolveDefaultBranch: mcpInput.resolveDefaultBranch,
|
||||
});
|
||||
const { worktree } = createdWorktree;
|
||||
await options.workspaceGitService?.listWorktrees?.(repoRoot, {
|
||||
force: true,
|
||||
reason: "mcp:create-worktree",
|
||||
});
|
||||
|
||||
return {
|
||||
content: [],
|
||||
@@ -1887,7 +1891,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
},
|
||||
},
|
||||
async ({ cwd, worktreePath, worktreeSlug }) => {
|
||||
const repoRoot = resolveScopedCwd(cwd, { required: true });
|
||||
const resolvedCwd = resolveScopedCwd(cwd, { required: true });
|
||||
if (!worktreePath && !worktreeSlug) {
|
||||
throw new Error("worktreePath or worktreeSlug is required");
|
||||
}
|
||||
@@ -1912,6 +1916,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
if (!options.emitSessionMessage) {
|
||||
throw new Error("Session message emitter is required to archive worktrees");
|
||||
}
|
||||
const repoRoot = await options.workspaceGitService.resolveRepoRoot(resolvedCwd);
|
||||
|
||||
const targetPath =
|
||||
worktreePath ??
|
||||
@@ -1948,6 +1953,10 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
||||
requestId: "mcp:archive_worktree",
|
||||
},
|
||||
);
|
||||
await options.workspaceGitService.listWorktrees(repoRoot, {
|
||||
force: true,
|
||||
reason: "mcp:archive-worktree",
|
||||
});
|
||||
|
||||
return {
|
||||
content: [],
|
||||
|
||||
Reference in New Issue
Block a user