feat(engine): allow read of sibling task PROMPT.md/task.json for deps

Agents working on a task that depends on other tasks (e.g. documentation
alignment tasks needing the sibling tasks' specs) were repeatedly
rejected by the worktree boundary when reading .fusion/tasks/FN-NNNN/PROMPT.md,
which also contributed to the malformed-tool-result crash we just fixed.

Add a read-only exception to isWorktreeAllowedPath: the read/glob/grep
tools may access .fusion/tasks/*/PROMPT.md and .fusion/tasks/*/task.json
at the project root. Writes and bash cwd remain restricted.

Update the system-prompt boundary docs (executor.ts) so agents know the
exception exists and stop burning turns re-trying rejected reads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Fusion
2026-04-24 14:07:00 -07:00
committed by gsxdsm
parent 5eba97fc80
commit ad46484126
3 changed files with 33 additions and 8 deletions

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
import { render, screen, waitFor, fireEvent, act } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";
import { AgentDetailView } from "../AgentDetailView";
@@ -825,11 +825,11 @@ describe("AgentDetailView", () => {
});
it("shows loading state while fetching chain of command", async () => {
let resolveChain: ((agents: AgentDetail[]) => void) | undefined;
const resolveChainCalls: Array<(agents: AgentDetail[]) => void> = [];
mockFetchChainOfCommand.mockImplementation(
() =>
new Promise((resolve) => {
resolveChain = resolve;
resolveChainCalls.push(resolve as (agents: AgentDetail[]) => void);
}) as any,
);
@@ -845,7 +845,11 @@ describe("AgentDetailView", () => {
expect(screen.getByText("Loading reporting chain...")).toBeInTheDocument();
});
resolveChain?.([{ id: "agent-001", name: "Test Agent" } as AgentDetail]);
await act(async () => {
for (const resolve of resolveChainCalls) {
resolve([{ id: "agent-001", name: "Test Agent" } as AgentDetail]);
}
});
await waitFor(() => {
expect(screen.queryByText("Loading reporting chain...")).not.toBeInTheDocument();