fix(web): démarre le serveur MCP custom CLI via idea-serve au lieu de node — #224

This commit is contained in:
2026-08-20 12:49:00 +02:00
parent b25c17c095
commit 9a3ca51f6b
9 changed files with 600 additions and 56 deletions

View File

@ -120,6 +120,51 @@ describe("WebAgentCell", () => {
});
});
it("replays startup MCP activity when the mobile custom CLI launches", async () => {
const { agent, profile, agentId } = await seededAgentGateway(structuredProfile);
const launchChatSpy = vi.spyOn(agent, "launchAgentChat");
const startupScrollback = [
{
kind: "progress" as const,
progress: {
source: "ideaLocal" as const,
kind: "mcp" as const,
stage: "started" as const,
label: "idea_context_read",
toolName: "idea_context_read",
text: "Bootstrap MCP tools",
},
},
{ kind: "final" as const, content: "Custom CLI ready" },
];
const reattachChatSpy = vi
.spyOn(agent, "reattachAgentChat")
.mockImplementation(async (sessionId: string) => ({
sessionId,
scrollback: startupScrollback,
}));
renderCell(agent, profile, agentId, { fullHeight: true });
fireEvent.click(await screen.findByRole("button", { name: "CLI custom" }));
await waitFor(() => expect(launchChatSpy).toHaveBeenCalledTimes(1));
await waitFor(() => expect(reattachChatSpy).toHaveBeenCalledTimes(1));
expect(launchChatSpy.mock.calls[0][2]).toMatchObject({
cwd: "/srv/demo",
nodeId: `web-mobile-${agentId}`,
});
fireEvent.click(screen.getByRole("button", { name: "TUI native" }));
await waitFor(() => expect(screen.queryByTestId("custom-agent-chat-view")).toBeNull());
fireEvent.click(screen.getByRole("button", { name: "CLI custom" }));
await waitFor(() => expect(reattachChatSpy).toHaveBeenCalledTimes(2));
expect(await screen.findByText("MCP")).toBeTruthy();
expect(screen.getByText("idea_context_read")).toBeTruthy();
expect(screen.getByText("Bootstrap MCP tools")).toBeTruthy();
expect(screen.getByText("Custom CLI ready")).toBeTruthy();
});
it("reattaches the mobile custom CLI session when returning to custom mode", async () => {
const { agent, profile, agentId } = await seededAgentGateway(structuredProfile);
const launchChatSpy = vi.spyOn(agent, "launchAgentChat");
@ -138,6 +183,26 @@ describe("WebAgentCell", () => {
expect(launchChatSpy).toHaveBeenCalledTimes(1);
});
it("surfaces a mobile custom CLI launch failure when the runtime cannot find node", async () => {
const { agent, profile, agentId } = await seededAgentGateway(structuredProfile);
const launchChatSpy = vi.spyOn(agent, "launchAgentChat").mockRejectedValueOnce({
code: "PROCESS",
message: "spawn node ENOENT: node is not installed on this runtime",
});
const reattachChatSpy = vi.spyOn(agent, "reattachAgentChat");
renderCell(agent, profile, agentId, { fullHeight: true });
fireEvent.click(await screen.findByRole("button", { name: "CLI custom" }));
await waitFor(() => expect(launchChatSpy).toHaveBeenCalledTimes(1));
expect(launchChatSpy.mock.calls[0][2]).toMatchObject({
cwd: "/srv/demo",
nodeId: `web-mobile-${agentId}`,
});
expect(reattachChatSpy).not.toHaveBeenCalled();
expect((await screen.findByRole("alert")).textContent).toContain("spawn node ENOENT");
});
it("falls back to native TUI when the mobile agent loses custom CLI support", async () => {
const { agent, profile, agentId } = await seededAgentGateway(structuredProfile);
const created = (await agent.listAgents(PROJECT_ID)).find((candidate) => candidate.id === agentId);