feat(workstate): UI des actions contrôlées (Lot D frontend)

Câble les actions contrôlées dans ProjectWorkStatePanel : port et adaptateur
agent étendus aux nouvelles commandes, adaptateur mock aligné.

Tests verts : workstate + projects (25), agent (8), singletonAgent +
agentAlreadyRunning (9), tsc --noEmit OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 19:51:52 +02:00
parent 3408c96974
commit 1c6441bb35
8 changed files with 611 additions and 33 deletions

View File

@ -103,7 +103,7 @@ describe("R0d — launch refused with AGENT_ALREADY_RUNNING", () => {
// The live set reports the agent already hosted in cell B (the host).
vi.spyOn(agentGateway, "listLiveAgents").mockResolvedValue([
{ agentId: agent.id, nodeId: bId, sessionId: "s-1" },
{ agentId: agent.id, nodeId: bId, sessionId: "s-1", kind: "pty" },
]);
// The launch from cell A is refused by the backend (singleton invariant).
vi.spyOn(agentGateway, "launchAgent").mockRejectedValue({

View File

@ -70,6 +70,7 @@ describe("singleton agent — mock gateway guard (T5)", () => {
agentId: a.id,
nodeId: "node-A",
sessionId: "mock-agent-session-1",
kind: "pty",
},
]);
});
@ -146,6 +147,7 @@ describe("singleton agent — dropdown guard (T6)", () => {
agentId: a.id,
nodeId: leafId,
sessionId: "mock-agent-session-1",
kind: "pty",
},
]);
});
@ -156,7 +158,7 @@ describe("singleton agent — dropdown guard (T6)", () => {
const a = await agent.createAgent("p1", { name: "Busy", profileId: "p" });
vi.spyOn(agent, "listLiveAgents").mockResolvedValue([
{ agentId: a.id, nodeId: "some-other-node" },
{ agentId: a.id, nodeId: "some-other-node" } as LiveAgent,
]);
renderGrid(layout, agent);
@ -190,7 +192,7 @@ describe("singleton agent — dropdown guard (T6)", () => {
// The agent is live in THIS very cell (same node id as the leaf).
vi.spyOn(agent, "listLiveAgents").mockResolvedValue([
{ agentId: a.id, nodeId: leafId },
{ agentId: a.id, nodeId: leafId, sessionId: "s-own", kind: "pty" },
]);
renderGrid(layout, agent);
@ -239,7 +241,7 @@ describe("R0d — dropdown disables agents live elsewhere + go-to-cell", () => {
// The agent is live in cell B (a currently-visible leaf).
vi.spyOn(agent, "listLiveAgents").mockResolvedValue([
{ agentId: ag.id, nodeId: b, sessionId: "s-1" },
{ agentId: ag.id, nodeId: b, sessionId: "s-1", kind: "pty" },
]);
renderGrid(layout, agent);