206 lines
8.1 KiB
TypeScript
206 lines
8.1 KiB
TypeScript
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;
|
||
}
|