Files
IdeA/frontend/src/features/permissions/mcpToolGroups.ts

206 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { McpToolCatalogue } from "@/domain";
/**
* Presentational grouping of the MCP tool catalogue (ticket #82).
*
* Purely a frontend display concern: which domain a tool "belongs to" for the
* grouped/collapsible editor, and its short French label. The read/write
* classification stays backend-canonical — always read from the
* {@link McpToolCatalogue} the API returns, never re-derived here.
*/
export interface McpToolGroupDef {
id: string;
label: string;
description?: string;
tools: string[];
}
type Tr = (french: string, english: string) => string;
const fr: Tr = (french) => french;
/** Domain groups, in display order (carnet #82 — Conception UX/F). */
export const MCP_TOOL_GROUPS: McpToolGroupDef[] = [
{
id: "workspace",
label: "Outils du projet",
description: "Permet à l’agent d’explorer, rechercher et lire les fichiers du projet.",
tools: [
"idea_workspace_map",
"idea_workspace_list",
"idea_workspace_read",
"idea_workspace_search",
],
},
{
id: "crossProject",
label: "IdeA inter-projets",
tools: [
"idea_project_list",
"idea_project_read_context",
"idea_project_list_agents",
"idea_project_ask_agent",
"idea_project_cancel_agent",
],
},
{
id: "readProject",
label: "Lecture projet",
tools: [
"idea_list_agents",
"idea_context_read",
"idea_memory_read",
"idea_skill_read",
"idea_workstate_read",
],
},
{
id: "readTickets",
label: "Lecture tickets",
tools: [
"idea_ticket_read",
"idea_ticket_list",
"idea_ticket_read_carnet",
"idea_sprint_list",
],
},
{
id: "delegation",
label: "Délégation agents",
tools: [
"idea_ask_agent",
"idea_ask_agents",
"idea_launch_agent",
"idea_stop_agent",
],
},
{
id: "contextMemory",
label: "Contexte et mémoire",
tools: ["idea_update_context", "idea_context_propose", "idea_memory_write"],
},
{
id: "tickets",
label: "Tickets",
tools: [
"idea_ticket_create",
"idea_ticket_update",
"idea_ticket_update_status",
"idea_ticket_update_priority",
"idea_ticket_update_carnet",
"idea_ticket_link",
"idea_ticket_unlink",
],
},
{
id: "work",
label: "Travail et exécution",
tools: ["idea_run_in_background", "idea_workstate_set"],
},
{
id: "skills",
label: "Skills",
tools: ["idea_create_skill"],
},
];
/** Short, human French label per exact MCP tool name. */
export const MCP_TOOL_LABELS: Record<string, string> = {
idea_workspace_map: "Cartographier le projet",
idea_workspace_list: "Lister les éléments du projet",
idea_workspace_read: "Lire un élément du projet",
idea_workspace_search: "Rechercher dans le projet",
idea_project_list: "Lister les projets IdeA",
idea_project_read_context: "Lire le contexte d'un autre projet",
idea_project_list_agents: "Lister les agents d'un autre projet",
idea_project_ask_agent: "Demander à un agent d'un autre projet",
idea_project_cancel_agent: "Annuler une demande inter-projet",
idea_list_agents: "Lister les agents",
idea_context_read: "Lire le contexte d'un agent",
idea_memory_read: "Lire la mémoire projet",
idea_skill_read: "Lire un skill",
idea_workstate_read: "Lire l'état de travail",
idea_ticket_read: "Lire un ticket",
idea_ticket_list: "Lister les tickets",
idea_ticket_read_carnet: "Lire le carnet d'un ticket",
idea_sprint_list: "Lister les sprints",
idea_ask_agent: "Déléguer à un agent",
idea_ask_agents: "Solliciter plusieurs agents",
idea_launch_agent: "Lancer un agent",
idea_stop_agent: "Arrêter un agent",
idea_update_context: "Modifier le contexte d'un agent",
idea_context_propose: "Proposer un contexte",
idea_memory_write: "Écrire la mémoire projet",
idea_workstate_set: "Écrire l'état de travail",
idea_create_skill: "Créer un skill",
idea_ticket_create: "Créer un ticket",
idea_ticket_update: "Modifier un ticket",
idea_ticket_update_status: "Modifier le statut d'un ticket",
idea_ticket_update_priority: "Modifier la priorité d'un ticket",
idea_ticket_update_carnet: "Modifier le carnet d'un ticket",
idea_ticket_link: "Lier des tickets",
idea_ticket_unlink: "Délier des tickets",
idea_run_in_background: "Exécuter une commande en arrière-plan",
};
const MCP_TOOL_LABELS_EN: Record<string, string> = {
idea_workspace_map: "Map the project", idea_workspace_list: "List project items", idea_workspace_read: "Read a project item", idea_workspace_search: "Search the project",
idea_project_list: "List IdeA projects", idea_project_read_context: "Read another project's context", idea_project_list_agents: "List agents in another project", idea_project_ask_agent: "Ask an agent in another project", idea_project_cancel_agent: "Cancel a cross-project request",
idea_list_agents: "List agents", idea_context_read: "Read an agent's context", idea_memory_read: "Read project memory", idea_skill_read: "Read a skill", idea_workstate_read: "Read work state", idea_ticket_read: "Read a ticket", idea_ticket_list: "List tickets", idea_ticket_read_carnet: "Read ticket notes", idea_sprint_list: "List sprints",
idea_ask_agent: "Delegate to an agent", idea_ask_agents: "Ask several agents", idea_launch_agent: "Launch an agent", idea_stop_agent: "Stop an agent", idea_update_context: "Update an agent's context", idea_context_propose: "Propose context", idea_memory_write: "Write project memory", idea_workstate_set: "Write work state", idea_create_skill: "Create a skill",
idea_ticket_create: "Create a ticket", idea_ticket_update: "Update a ticket", idea_ticket_update_status: "Update ticket status", idea_ticket_update_priority: "Update ticket priority", idea_ticket_update_carnet: "Update ticket notes", idea_ticket_link: "Link tickets", idea_ticket_unlink: "Unlink tickets", idea_run_in_background: "Run a command in the background",
};
export function mcpToolGroupLabel(group: McpToolGroupDef, tr: Tr = fr): string {
const english: Record<string, string> = { workspace: "Project tools", crossProject: "IdeA cross-project", readProject: "Project read", readTickets: "Ticket read", delegation: "Agent delegation", contextMemory: "Context and memory", tickets: "Tickets", work: "Work and execution", skills: "Skills", other: "Other" };
return tr(group.label, english[group.id] ?? group.label);
}
export function mcpToolGroupDescription(
group: McpToolGroupDef,
tr: Tr = fr,
): string | undefined {
if (!group.description) return undefined;
if (group.id === "workspace") {
return tr(
group.description,
"Lets the agent explore, search, and read project files.",
);
}
return group.description;
}
/** Short human label for `tool`, falling back to the exact name if unmapped. */
export function mcpToolLabel(tool: string, tr: Tr = fr): string {
const french = MCP_TOOL_LABELS[tool];
return french ? tr(french, MCP_TOOL_LABELS_EN[tool] ?? french) : tool;
}
/** The group a tool belongs to, or `undefined` if not locally mapped. */
export function mcpToolGroupId(tool: string): string | undefined {
return MCP_TOOL_GROUPS.find((group) => group.tools.includes(tool))?.id;
}
/**
* Builds the exhaustive presentation groups from the backend catalogue.
* Local groups only choose placement/labels; every catalogued tool remains
* configurable, with unmapped names collected under the visible fallback.
*/
export function mcpToolGroupsForCatalogue(
catalogue: McpToolCatalogue,
): McpToolGroupDef[] {
const catalogued = Array.from(
new Set([...catalogue.readOnlyTools, ...catalogue.writeActionTools]),
);
const cataloguedSet = new Set(catalogued);
const mapped = new Set<string>();
const groups = MCP_TOOL_GROUPS.flatMap((group) => {
const tools = group.tools.filter((tool) => cataloguedSet.has(tool));
tools.forEach((tool) => mapped.add(tool));
return tools.length > 0 ? [{ ...group, tools }] : [];
});
const otherTools = catalogued.filter((tool) => !mapped.has(tool));
return otherTools.length > 0
? [...groups, { id: "other", label: "Autres", tools: otherTools }]
: groups;
}