feat(wave): #119/#122/#131/#132 verts + sprint plugins ESM/persistance #135/#136/#139

État d'intégration confiné à la branche batch. Les tickets #119 (skills →
capacités agent découvrables), #122 (override permissions par défaut), #131
(effort par agent/presets) et #132 (outil MCP d'édition du contexte projet)
sont verts en périmètre. Le sprint plugins multi-fichiers ESM / persistance
plugin-owned (#135/#136/#139) est co-implémenté dans les MÊMES fichiers de
câblage (frontend/src/ports/index.ts, backend/src/lib.rs, domain/ports.rs,
backend/dto.rs), inséparable sans staging interactif (indisponible ici).

Commit unique volontaire : préserve l'état vert QA sans découpe hunk risquée.
NON mergé vers develop tant que #137 (QA e2e plugins) n'est pas vert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 11:06:23 +02:00
parent 22c6bd803d
commit 171c6c923c
59 changed files with 3654 additions and 291 deletions

View File

@ -48,6 +48,7 @@ import {
WebPluginConfigGateway,
WebPluginEventGateway,
WebPluginGateway,
WebPluginStorageGateway,
WebPluginTaskGateway,
WebPluginToolchainGateway,
WebPluginWorkspaceGateway,
@ -151,6 +152,7 @@ export function createHttpWsGateways(config: HttpWsGatewaysConfig = {}): Gateway
pluginToolchain: new WebPluginToolchainGateway(),
pluginEvents: new WebPluginEventGateway(),
pluginConfig: new WebPluginConfigGateway(),
pluginStorage: new WebPluginStorageGateway(),
};
}

View File

@ -15,7 +15,6 @@ import type {
Agent,
AgentDrift,
AgentProfile,
EffectivePermissions,
EmbedderEngines,
EmbedderProfile,
FirstRunState,
@ -43,6 +42,7 @@ import type {
ProjectSystemPermissions,
ProfileAvailability,
ProfileModelCatalog,
ResolvedAgentPermissions,
ResolvedAgentSystemPermissions,
SystemPermissionSet,
Skill,
@ -286,7 +286,14 @@ export class HttpSkillGateway implements SkillGateway {
}
createSkill(input: CreateSkillInput): Promise<Skill> {
return this.http.invoke<Skill>("create_skill", {
request: { projectId: input.projectId, name: input.name, content: input.content, scope: input.scope },
request: {
projectId: input.projectId,
name: input.name,
description: input.description,
kind: input.kind,
content: input.content,
scope: input.scope,
},
});
}
updateSkill(projectId: string, scope: SkillScope, skillId: string, content: string): Promise<Skill> {
@ -381,8 +388,8 @@ export class HttpPermissionGateway implements PermissionGateway {
request: { projectId, agentId, permissions },
});
}
resolveAgentPermissions(projectId: string, agentId: string): Promise<EffectivePermissions | null> {
return this.http.invoke<EffectivePermissions | null>("resolve_agent_permissions", {
resolveAgentPermissions(projectId: string, agentId: string): Promise<ResolvedAgentPermissions> {
return this.http.invoke<ResolvedAgentPermissions>("resolve_agent_permissions", {
request: { projectId, agentId },
});
}

View File

@ -23,6 +23,7 @@ import type {
Agent,
AppExitWorkGuardState,
DomainEvent,
EffortSelection,
HealthReport,
ReplyChunk,
ResumableAgent,
@ -223,6 +224,15 @@ export class HttpAgentGateway implements AgentGateway {
request: { projectId, agentId, profileId, rows, cols },
});
}
updateAgentEffort(
projectId: string,
agentId: string,
effort: EffortSelection | null,
): Promise<Agent> {
return this.http.invoke<Agent>("update_agent_effort", {
request: { projectId, agentId, effort },
});
}
readContext(projectId: string, agentId: string): Promise<string> {
return this.http.invoke<string>("read_agent_context", { projectId, agentId });
}

View File

@ -12,6 +12,7 @@
import type {
EmbeddedServerStatus,
GatewayError,
JsonValue,
PluginAdmin,
PluginCommandTask,
PluginConfigDocument,
@ -44,6 +45,9 @@ import type {
PluginEventSubscribeInput,
PluginEventUnsubscribeInput,
PluginGateway,
PluginStorageGateway,
PluginStorageGetInput,
PluginStorageSetInput,
PluginProjectStructureQuery,
PluginRunCommandInput,
PluginTaskGateway,
@ -263,3 +267,18 @@ export class WebPluginConfigGateway implements PluginConfigGateway {
return unsupportedOnWeb("Plugin structured config documents");
}
}
/** Web stub: plugin-owned storage is owned by the desktop host app-data. */
export class WebPluginStorageGateway implements PluginStorageGateway {
async get(_input: PluginStorageGetInput): Promise<JsonValue | null> {
return unsupportedOnWeb("Plugin storage");
}
async set(_input: PluginStorageSetInput): Promise<void> {
return unsupportedOnWeb("Plugin storage");
}
async delete(_input: PluginStorageGetInput): Promise<boolean> {
return unsupportedOnWeb("Plugin storage");
}
}