feat(FN-3867): add changeset for paused scope exclusion feature

Completes Step 4 by adding a patch changeset for `@runfusion/fusion`, signaling that the FN-3864 scope-exclusion work is ready for the next release.

Fusion-Task-Id: FN-3867
This commit is contained in:
Fusion
2026-05-09 11:47:33 -07:00
committed by gsxdsm
parent 8f5cf45e77
commit 06d9de791d
3 changed files with 84 additions and 2 deletions

View File

@@ -793,6 +793,80 @@ describe("Scheduler", () => {
expect(updateTask).not.toHaveBeenCalledWith("FN-002", { status: "queued", blockedBy: "FN-001" });
});
it("excludes paused in-review tasks from active scopes", async () => {
vi.mocked(existsSync).mockReturnValue(true);
vi.mocked(readFile).mockResolvedValue("# Task\nDo something");
const tasks = [
createMockTask({ id: "FN-001", column: "in-review", paused: true, worktree: "/test/project/.worktrees/fn-001" }),
createMockTask({ id: "FN-002", column: "todo" }),
];
const parseScopeMock = vi.fn(async (taskId: string): Promise<string[]> => {
if (taskId === "FN-001") return ["src/foo.ts"];
if (taskId === "FN-002") return ["src/foo.ts"];
return [];
});
const updateTask = vi.fn().mockResolvedValue(undefined);
const moveTask = vi.fn().mockResolvedValue(undefined);
const store = createMockStore({
listTasks: vi.fn().mockResolvedValue(tasks),
getSettings: vi.fn().mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
groupOverlappingFiles: true,
}),
parseFileScopeFromPrompt: parseScopeMock,
updateTask,
moveTask,
});
const scheduler = new Scheduler(store);
(scheduler as any).running = true;
await scheduler.schedule();
expect(moveTask).toHaveBeenCalledWith("FN-002", "in-progress", expect.objectContaining({ allocateWorktree: expect.any(Function) }));
expect(updateTask).not.toHaveBeenCalledWith("FN-002", { status: "queued", blockedBy: "FN-001" });
});
it("blocks todo when overlapping in-review task is not paused", async () => {
vi.mocked(existsSync).mockReturnValue(true);
vi.mocked(readFile).mockResolvedValue("# Task\nDo something");
const tasks = [
createMockTask({ id: "FN-001", column: "in-review", worktree: "/test/project/.worktrees/fn-001" }),
createMockTask({ id: "FN-002", column: "todo" }),
];
const parseScopeMock = vi.fn(async (taskId: string): Promise<string[]> => {
if (taskId === "FN-001") return ["src/foo.ts"];
if (taskId === "FN-002") return ["src/foo.ts"];
return [];
});
const updateTask = vi.fn().mockResolvedValue(undefined);
const moveTask = vi.fn().mockResolvedValue(undefined);
const store = createMockStore({
listTasks: vi.fn().mockResolvedValue(tasks),
getSettings: vi.fn().mockResolvedValue({
maxConcurrent: 2,
maxWorktrees: 4,
groupOverlappingFiles: true,
}),
parseFileScopeFromPrompt: parseScopeMock,
updateTask,
moveTask,
});
const scheduler = new Scheduler(store);
(scheduler as any).running = true;
await scheduler.schedule();
expect(updateTask).toHaveBeenCalledWith("FN-002", { status: "queued", blockedBy: "FN-001" });
expect(moveTask).not.toHaveBeenCalledWith("FN-002", "in-progress");
});
it("still blocks overlap for non-ignored paths", async () => {
vi.mocked(existsSync).mockReturnValue(true);
vi.mocked(readFile).mockResolvedValue("# Task\nDo something");