feat(workstate): UI live-state des conversations/délégations (Lot A frontend)

Ajoute le port et l'adaptateur workState (+ mock) côté frontend, le type domaine
associé, et la feature `workstate` (panneau ProjectWorkStatePanel + hook
useProjectWorkState) consommant le read-model live exposé par le backend.
Intègre le panneau dans ProjectsView. Tests verts (workstate + projects).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:06:28 +02:00
parent aae18499a9
commit 17685a08e1
11 changed files with 397 additions and 1 deletions

View File

@ -31,6 +31,7 @@ import type {
PermissionSet,
Project,
ProjectPermissions,
ProjectWorkState,
ProfileAvailability,
ResumableAgent,
Skill,
@ -64,6 +65,7 @@ import type {
TemplateGateway,
TerminalGateway,
TerminalHandle,
WorkStateGateway,
} from "@/ports";
import { applyOperation, singleLeafTree } from "@/features/layout/layout";
@ -1648,6 +1650,19 @@ export class MockPermissionGateway implements PermissionGateway {
}
}
export class MockWorkStateGateway implements WorkStateGateway {
private states = new Map<string, ProjectWorkState>();
/** Seeds the read-model returned for a project (deterministic tests/dev). */
_setProjectWorkState(projectId: string, state: ProjectWorkState): void {
this.states.set(projectId, structuredClone(state));
}
async getProjectWorkState(projectId: string): Promise<ProjectWorkState> {
return structuredClone(this.states.get(projectId) ?? { agents: [] });
}
}
function mostRestrictive(
project?: PermissionSet["fallback"],
agent?: PermissionSet["fallback"],
@ -1676,6 +1691,7 @@ export function createMockGateways(): Gateways {
memory: new MockMemoryGateway(),
embedder: new MockEmbedderGateway(),
permission: new MockPermissionGateway(),
workState: new MockWorkStateGateway(),
};
}