feat(windows): persistance et restauration des fenêtres au redémarrage (#40)

Persiste l'état des fenêtres (layout/position) et le restaure au
relancement de l'application. Découpage hexagonal :
- domaine : modèle et port d'état des fenêtres (layout, ports)
- application : use cases de persistance/restauration
- infrastructure : store window_state (adapter de persistance)
- présentation : câblage app-tauri (state, commands, lib)
Couvert par des tests ciblés domaine/application/infrastructure.

Depend de #39 (fermeture des fenêtres auxiliaires).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 08:00:20 +02:00
parent 55087b5d9b
commit 2eb51d3335
15 changed files with 887 additions and 40 deletions

View File

@ -33,13 +33,14 @@ use application::{
ReadMemoryIndex, ReadProjectContext, ReadSkill, RecallMemory, ReconcileLayouts,
ReconcileLiveState, ReconcileLiveStateInput, RecordTurn, RecordTurnProvider, ReferenceProfiles,
RenameLayout, RenameSprint, ReorderSprints, ResizeTerminal, ResolveAgentPermissions,
ResolveMemoryLinks, RetryBackgroundTask, RotateConversationLog, SaveEmbedderProfile,
SaveModelServer, SaveProfile, SessionLimitService, SetActiveLayout, SnapshotRunningAgents,
SpawnBackgroundCommand, StopLiveAgent, StructuredSessions, SuggestedThisSession,
SyncAgentWithTemplate, TerminalSessions, UnassignSkillFromAgent, UnassignTicketFromSprint,
UnlinkIssues, UpdateAgentContext, UpdateAgentPermissions, UpdateIssue, UpdateIssueCarnet,
UpdateLiveState, UpdateMemory, UpdateProjectContext, UpdateProjectPermissions, UpdateSkill,
UpdateTemplate, WakeSessionProvider, WriteMemory, WriteToTerminal, AGENT_MEMORY_RECALL_BUDGET,
ResolveMemoryLinks, RestoreOpenWindows, RetryBackgroundTask, RotateConversationLog,
SaveEmbedderProfile, SaveModelServer, SaveProfile, SessionLimitService, SetActiveLayout,
SnapshotOpenWindows, SnapshotRunningAgents, SpawnBackgroundCommand, StopLiveAgent,
StructuredSessions, SuggestedThisSession, SyncAgentWithTemplate, TerminalSessions,
UnassignSkillFromAgent, UnassignTicketFromSprint, UnlinkIssues, UpdateAgentContext,
UpdateAgentPermissions, UpdateIssue, UpdateIssueCarnet, UpdateLiveState, UpdateMemory,
UpdateProjectContext, UpdateProjectPermissions, UpdateSkill, UpdateTemplate,
WakeSessionProvider, WriteMemory, WriteToTerminal, AGENT_MEMORY_RECALL_BUDGET,
};
use async_trait::async_trait;
use domain::ports::{
@ -49,7 +50,7 @@ use domain::ports::{
EmbedderPromptStore, EventBus, FileSystem, GitPort, IdGenerator, IssueNumberAllocator,
IssueStore, MemoryRecall, MemoryStore, PermissionStore, ProcessSpawner, ProfileStore,
ProjectStore, PtyPort, ScheduledTask, Scheduler, SkillStore, SprintStore, TemplateStore,
ToolInvoker, WakeError, WakeReason,
ToolInvoker, WakeError, WakeReason, WindowStateStore,
};
use domain::profile::{
AgentProfile, ContextInjection, McpConfigStrategy, McpTransport, StructuredAdapter,
@ -71,13 +72,14 @@ use infrastructure::{
FsEmbedderPromptStore, FsHandoffStore, FsIssueNumberAllocator, FsIssueStore, FsLiveStateStore,
FsMemoryStore, FsModelServerRegistry, FsOrchestratorWatcher, FsPermissionStore, FsProfileStore,
FsProjectStore, FsProviderSessionStore, FsSkillStore, FsSprintStore, FsTemplateStore,
Git2Repository, HeuristicHandoffSummarizer, HttpOpenAiCompatibleProbe, IdeaiContextStore,
InMemoryConversationRegistry, InMemoryMailbox, LlamaCppRuntime, LocalFileSystem,
LocalManagedProcess, LocalProcessSpawner, McpServer, MediatedInbox, NaiveMemoryRecall,
OrchestratorWatchHandle, PortablePtyAdapter, RwFileGuard, StructuredSessionFactory,
SystemClock, SystemMillisClock, TicketToolProvider, TokioBroadcastEventBus, TokioScheduler,
ToolPolicyRegistry, UuidGenerator, VectorMemoryRecall, DEFAULT_OLLAMA_BASE_URL,
ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
FsWindowStateStore, Git2Repository, HeuristicHandoffSummarizer, HttpOpenAiCompatibleProbe,
IdeaiContextStore, InMemoryConversationRegistry, InMemoryMailbox, LlamaCppRuntime,
LocalFileSystem, LocalManagedProcess, LocalProcessSpawner, McpServer, MediatedInbox,
NaiveMemoryRecall, OrchestratorWatchHandle, PortablePtyAdapter, RwFileGuard,
StructuredSessionFactory, SystemClock, SystemMillisClock, TicketToolProvider,
TokioBroadcastEventBus, TokioScheduler, ToolPolicyRegistry, UuidGenerator, VectorMemoryRecall,
DEFAULT_OLLAMA_BASE_URL, ONNX_CACHE_SUBDIR, RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED,
VECTOR_ONNX_ENABLED,
};
use crate::chat::ChatBridge;
@ -900,6 +902,10 @@ pub struct AppState {
// --- Windows (L10) ---
/// Detach a tab into a new OS window (persists the workspace topology).
pub move_tab: Arc<MoveTabToNewWindow>,
/// Persist open Tauri webview-window state on main-window shutdown.
pub snapshot_open_windows: Arc<SnapshotOpenWindows>,
/// Load restorable Tauri webview-window state on startup.
pub restore_open_windows: Arc<RestoreOpenWindows>,
// --- Background tasks (B8) ---
/// Spawn a command-backed first-class background task.
pub spawn_background_command: Arc<SpawnBackgroundCommand>,
@ -1054,10 +1060,15 @@ impl AppState {
Arc::clone(&fs) as Arc<dyn FileSystem>,
app_data_dir.to_string_lossy().into_owned(),
));
let window_state_store = Arc::new(FsWindowStateStore::new(
Arc::clone(&fs) as Arc<dyn FileSystem>,
app_data_dir.to_string_lossy().into_owned(),
));
// Port-typed handles for injection.
let fs_port = Arc::clone(&fs) as Arc<dyn FileSystem>;
let store_port = Arc::clone(&store) as Arc<dyn ProjectStore>;
let window_state_port = Arc::clone(&window_state_store) as Arc<dyn WindowStateStore>;
let events_port = Arc::clone(&event_bus) as Arc<dyn EventBus>;
// --- Use cases (ports injected as Arc<dyn Port>) ---
@ -2211,6 +2222,12 @@ impl AppState {
Arc::clone(&store_port),
Arc::clone(&ids) as Arc<dyn IdGenerator>,
));
let snapshot_open_windows =
Arc::new(SnapshotOpenWindows::new(Arc::clone(&window_state_port)));
let restore_open_windows = Arc::new(RestoreOpenWindows::new(
Arc::clone(&window_state_port),
Arc::clone(&store_port),
));
Self {
health,
@ -2340,6 +2357,8 @@ impl AppState {
fs_port: Arc::clone(&fs_port),
home_dir,
move_tab,
snapshot_open_windows,
restore_open_windows,
spawn_background_command,
cancel_background_task,
retry_background_task,