feat(skill-awareness): T1→T5 — manifeste de skills + outil MCP idea_skill_read

Surface les skills assignés à un agent « à la MCP » : description sur l'entité
Skill (+ effective_description fallback), section « # Skills disponibles » haute
altitude dans le convention-file (mode MCP), outil read-only idea_skill_read
(résolution projet→global), use case ReadSkill (port SkillStore existant), et
câblage au composition root. Dump legacy du corps complet conservé en mode
sans-MCP (zéro régression). Rétro-compat index.json (serde default).

Tests : domain+application+infrastructure 1212 passed / 0 failed (23 ajoutés).
Reste : T6 (champ description front) + T7 (e2e après rebuild AppImage).

NB topologie : commit réalisé par l'orchestrateur car l'agent Git était
injoignable (bug de livraison cold-start) ; à faire relire/rebaser par Git.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 15:08:33 +02:00
parent 7db444a31d
commit 11dc8d7ba3
13 changed files with 758 additions and 27 deletions

View File

@ -51,7 +51,11 @@ pub enum ToolMapError {
pub fn tool_returns_reply(tool: &str) -> bool {
matches!(
tool,
"idea_ask_agent" | "idea_list_agents" | "idea_context_read" | "idea_memory_read"
"idea_ask_agent"
| "idea_list_agents"
| "idea_context_read"
| "idea_memory_read"
| "idea_skill_read"
)
}
@ -201,6 +205,21 @@ pub fn catalogue() -> Vec<ToolDef> {
"additionalProperties": false
}),
},
ToolDef {
name: "idea_skill_read",
description: "Read the full body of an IdeA skill assigned to you, by name — call this \
to actually execute/follow a skill listed in your « Skills disponibles » \
section. Resolves project scope first, then global. Returns the skill's \
Markdown inline.",
input_schema: json!({
"type": "object",
"properties": {
"name": { "type": "string", "description": "Skill name (as listed in your context)." }
},
"required": ["name"],
"additionalProperties": false
}),
},
ToolDef {
name: "idea_create_skill",
description: "Create a reusable IdeA skill (Markdown) in the project or global scope.",
@ -320,6 +339,14 @@ pub fn map_tool_call(
content: s("content"),
..base()
},
"idea_skill_read" => OrchestratorRequest {
request_type: Some("skill.read".to_owned()),
// The requester (handshake identity) is carried for symmetry with the
// other read tools; `validate` derives the requester party from it.
requested_by: Some(requester.to_owned()),
name: s("name"),
..base()
},
"idea_create_skill" => OrchestratorRequest {
request_type: Some("skill.create".to_owned()),
name: s("name"),