fix(permissions): tools MCP inter-projets exposés (idea_project_*) + contactable agent/template persisté — update_agent_contactable (application/web-server/app-tauri), defaultContactable TemplateEditor save/reopen, groupes MCP 'IdeA inter-projets' avec fallback, permissions agent Contactable — #267 (QA verte)

This commit is contained in:
2026-09-07 18:13:27 +02:00
parent 9266d121cd
commit f6101a8249
30 changed files with 632 additions and 89 deletions

View File

@ -702,6 +702,24 @@ export class MockAgentGateway implements AgentGateway {
return structuredClone(next);
}
async updateAgentContactable(
projectId: string,
agentId: string,
contactable: boolean,
): Promise<Agent> {
const list = this.getAgents(projectId);
const idx = list.findIndex((a) => a.id === agentId);
if (idx === -1) {
const err: GatewayError = {
code: "NOT_FOUND",
message: `agent ${agentId} not found in project ${projectId}`,
};
throw err;
}
list[idx] = { ...list[idx], contactable };
return structuredClone(list[idx]);
}
// ── Internal helpers for MockTemplateGateway (same-package use only) ──
/**
@ -2232,6 +2250,7 @@ export class MockTemplateGateway implements TemplateGateway {
version: 1,
defaultProfileId: input.defaultProfileId,
defaultAgentName: input.defaultAgentName ?? null,
defaultContactable: input.defaultContactable ?? false,
systemPermissions: input.systemPermissions ?? null,
mcpToolPermissions: input.mcpToolPermissions ?? null,
};
@ -2259,6 +2278,7 @@ export class MockTemplateGateway implements TemplateGateway {
content: input,
defaultProfileId: current.defaultProfileId,
defaultAgentName: current.defaultAgentName ?? null,
defaultContactable: current.defaultContactable ?? false,
systemPermissions: current.systemPermissions ?? null,
mcpToolPermissions: current.mcpToolPermissions ?? null,
}
@ -2269,6 +2289,7 @@ export class MockTemplateGateway implements TemplateGateway {
contentMd: update.content,
defaultProfileId: update.defaultProfileId,
defaultAgentName: update.defaultAgentName ?? null,
defaultContactable: update.defaultContactable ?? false,
systemPermissions: update.systemPermissions ?? null,
mcpToolPermissions: update.mcpToolPermissions ?? null,
version: current.version + 1,
@ -2329,6 +2350,7 @@ export class MockTemplateGateway implements TemplateGateway {
},
synchronized,
skills: [],
contactable: template.defaultContactable ?? false,
};
this.agentGateway._insertAgent(projectId, agent, template.contentMd);
@ -2940,6 +2962,9 @@ export class MockPermissionGateway implements PermissionGateway {
// document from the file/command permissions above. ─────────────────────
private mcpCatalogue: McpToolCatalogue = {
readOnlyTools: [
"idea_project_list",
"idea_project_read_context",
"idea_project_list_agents",
"idea_list_agents",
"idea_context_read",
"idea_memory_read",
@ -2948,9 +2973,15 @@ export class MockPermissionGateway implements PermissionGateway {
"idea_ticket_read",
"idea_ticket_list",
"idea_ticket_read_carnet",
"idea_ticket_attachment_read",
"idea_sprint_list",
"idea_template_list",
"idea_template_read",
"idea_managed_temp_resolve",
],
writeActionTools: [
"idea_project_ask_agent",
"idea_project_cancel_agent",
"idea_ask_agent",
"idea_ask_agents",
"idea_run_in_background",
@ -2958,6 +2989,7 @@ export class MockPermissionGateway implements PermissionGateway {
"idea_stop_agent",
"idea_update_context",
"idea_context_propose",
"idea_context_update",
"idea_memory_write",
"idea_workstate_set",
"idea_create_skill",
@ -2965,14 +2997,30 @@ export class MockPermissionGateway implements PermissionGateway {
"idea_ticket_update",
"idea_ticket_update_status",
"idea_ticket_update_priority",
"idea_ticket_bulk_update_status",
"idea_ticket_bulk_update_priority",
"idea_ticket_bulk_delete",
"idea_ticket_update_carnet",
"idea_ticket_attachment_add",
"idea_ticket_attachment_mark_summarized",
"idea_ticket_link",
"idea_ticket_unlink",
"idea_template_create",
"idea_template_update",
"idea_template_delete",
"idea_managed_temp_allocate",
"idea_managed_temp_release",
"idea_managed_temp_gc",
],
};
private mcpDocs = new Map<string, ProjectMcpToolPermissions>();
setMcpToolCatalogue(catalogue: McpToolCatalogue): void {
this.mcpCatalogue = structuredClone(catalogue);
this.mcpDocs.clear();
}
private mcpDoc(projectId: string): ProjectMcpToolPermissions {
if (!this.mcpDocs.has(projectId)) {
this.mcpDocs.set(projectId, {