feat(plugins): paramètres projet plugins + attribution skills/tools aux agents — #282 (manifeste accepte contributes.skills IdeA-native multi-harness; store .ideai/project-plugins.json v1: enable plugin par projet + assignments skills/tools par agent; refs + use cases settings/assign/unassign; resolver skills pour idea_skill_read et injection catalogue lancement agent; permissions MCP dynamiques projetées par harness Claude Code/Codex/OpenCode; tombstones uninstall, hot reload recalcule catalogue et marque assignments cassés; frontend: Settings projet Plugins, détail capabilities, attribution agent, catalogue permissions; bump pointeur IdeaSDK 6eb8db3; QA verte: cargo test -p application, project_plugin_settings 3/3, dto_plugins 2/2, structured_launch_d3 26/26, catalogue mcp 7/7, frontend 5 tests ProjectPluginSettings/plugin, npm build frontend)
This commit is contained in:
105
frontend/src/features/plugins/ProjectPluginSettings.test.tsx
Normal file
105
frontend/src/features/plugins/ProjectPluginSettings.test.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { DIProvider } from "@/app/di";
|
||||
import { createMockGateways, MockPluginGateway } from "@/adapters/mock";
|
||||
import type { ProjectPluginManifest } from "@/domain";
|
||||
import { AgentPluginCapabilities } from "./AgentPluginCapabilities";
|
||||
import { ProjectPluginsPanel } from "./ProjectPluginsPanel";
|
||||
|
||||
function manifest(): ProjectPluginManifest {
|
||||
return {
|
||||
ideaPluginManifestVersion: 1,
|
||||
id: "dev.acme.unity",
|
||||
displayName: "Unity Plugin",
|
||||
publisher: "Acme",
|
||||
version: "1.2.3",
|
||||
main: "dist/index.js",
|
||||
trustLevel: "full",
|
||||
capabilities: ["ui", "mcp"],
|
||||
activationScope: "app",
|
||||
contributes: {
|
||||
skills: [{
|
||||
id: "unity.debug",
|
||||
name: "unity-debug",
|
||||
description: "Diagnostiquer les builds Unity.",
|
||||
kind: "workflow",
|
||||
path: "skills/unity-debug/SKILL.md",
|
||||
}],
|
||||
menus: [],
|
||||
menuItems: [],
|
||||
layouts: [],
|
||||
mcpServers: [{ id: "unity-tools", displayName: "Unity Tools", transport: "stdio" }],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function gatewaysWithPlugin() {
|
||||
const plugin = new MockPluginGateway();
|
||||
plugin._seedProjectPluginManifest(manifest());
|
||||
return { ...createMockGateways(), plugin };
|
||||
}
|
||||
|
||||
describe("project plugin settings #282", () => {
|
||||
it("lists globally installed plugins, details their capabilities and toggles project activation", async () => {
|
||||
const gateways = gatewaysWithPlugin();
|
||||
render(
|
||||
<DIProvider gateways={gateways}>
|
||||
<ProjectPluginsPanel projectId="project-1" />
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
expect(await screen.findByText("Unity Plugin")).toBeTruthy();
|
||||
expect(screen.getByText("Installé globalement")).toBeTruthy();
|
||||
fireEvent.click(screen.getByText("Voir les capabilities"));
|
||||
expect(screen.getByText("unity-debug")).toBeTruthy();
|
||||
expect(screen.getByText("Unity Tools")).toBeTruthy();
|
||||
|
||||
const toggle = screen.getByRole("checkbox", { name: "Activé pour ce projet" });
|
||||
fireEvent.click(toggle);
|
||||
await waitFor(() => expect((toggle as HTMLInputElement).checked).toBe(true));
|
||||
expect((await gateways.plugin.listProjectSettings("project-1")).settings.plugins).toEqual([
|
||||
{ pluginId: "dev.acme.unity", enabled: true },
|
||||
]);
|
||||
});
|
||||
|
||||
it("assigns plugin skills and MCP tools to an agent and keeps stale references removable", async () => {
|
||||
const gateways = gatewaysWithPlugin();
|
||||
gateways.plugin._seedProjectPluginSettings("project-1", {
|
||||
version: 1,
|
||||
plugins: [{ pluginId: "dev.acme.unity", enabled: true }],
|
||||
agents: [{
|
||||
agentId: "agent-1",
|
||||
skills: [{ pluginId: "missing.plugin", skillId: "removed-skill" }],
|
||||
tools: [],
|
||||
}],
|
||||
});
|
||||
render(
|
||||
<DIProvider gateways={gateways}>
|
||||
<AgentPluginCapabilities projectId="project-1" agentId="agent-1" agentName="Dev" />
|
||||
</DIProvider>,
|
||||
);
|
||||
|
||||
const skill = await screen.findByRole("checkbox", { name: /unity-debug/ });
|
||||
fireEvent.click(skill);
|
||||
await waitFor(() => expect((skill as HTMLInputElement).checked).toBe(true));
|
||||
expect(screen.getByText(/removed-skill/).textContent).toContain("Obsolète ou manquant");
|
||||
|
||||
fireEvent.click(screen.getByLabelText("serveur MCP de plugin"));
|
||||
fireEvent.click(screen.getByRole("option", { name: "Unity Plugin — Unity Tools" }));
|
||||
fireEvent.change(screen.getByLabelText("nom du tool MCP"), {
|
||||
target: { value: "unity_build" },
|
||||
});
|
||||
fireEvent.click(screen.getByRole("button", { name: "Attribuer" }));
|
||||
expect(await screen.findByText("unity_build")).toBeTruthy();
|
||||
|
||||
const settings = (await gateways.plugin.listProjectSettings("project-1")).settings;
|
||||
const agent = settings.agents.find((entry) => entry.agentId === "agent-1");
|
||||
expect(agent?.skills).toContainEqual({ pluginId: "dev.acme.unity", skillId: "unity.debug" });
|
||||
expect(agent?.tools).toContainEqual({
|
||||
pluginId: "dev.acme.unity",
|
||||
serverId: "unity-tools",
|
||||
toolName: "unity_build",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user