feat(p10): archivage automatique des sessions terminées (rétention configurable)

- DB: migration #10 (sessions.archived_at + index), helpers archive/unarchive/archiveExpired (soft-archive, jamais de DELETE)
- core/retention-settings.ts: session_retention_days (défaut 30, 0=jamais, 1-3650) + session_purge_days (off)
- core/session-archive.ts: scheduler start/stop/sweep (calqué DiscoveryService), câblé dans runDaemon
- pty-manager.list({includeArchived}) + SessionSummary.archived + emitHistoricalUpdate
- routes: GET /sessions?includeArchived, POST/DELETE /sessions/:id/archive, POST /sessions/archive-now
- protocole additif: message WS session_archived (relayé par la gateway, abonnés 'sessions')
- settings: retentionDays/purgeDays exposés et validés dans PATCH /settings
- web: store sessions (showArchived + archive/unarchive), SessionsListView (toggle/badge/actions), SettingsView (slider rétention), i18n EN+FR
- tests: retention-settings + session-archive (vitest) + settings-routes étendu ; acceptance-p10.mjs (sweep, event WS, resume d'une session archivée → 201, rétention=0)
This commit is contained in:
2026-06-27 13:31:28 +02:00
parent be43911dc0
commit c8dd539571
22 changed files with 818 additions and 42 deletions

View File

@@ -125,6 +125,9 @@ export interface SessionSummary {
// ---- Masquage (additif) ----
/** true = session découverte masquée par l'utilisateur (exclue de la liste sauf includeHidden). */
hidden?: boolean;
// ---- Archivage auto (P10, additif) ----
/** true = session managée auto-archivée par ancienneté (exclue de la liste sauf includeArchived). */
archived?: boolean;
}
// ---- Worktrees & repos (P3) ----
@@ -232,6 +235,9 @@ export type ServerMessage =
| { type: 'control_changed'; channel: number; controlling: boolean }
| { type: 'session_update'; session: SessionSummary }
| { type: 'session_exit'; sessionId: string; exitCode: number | null; signal: number | null }
// P10 — une session managée vient d'être archivée (auto par ancienneté ou manuellement). Signal
// léger : le client met à jour son row (badge archived) et le retire si « Show archived » est off.
| { type: 'session_archived'; sessionId: string }
| { type: 'repo_update'; repo: RepoSummary }
| { type: 'repo_removed'; repoId: string }
| { type: 'worktree_update'; repoId: string; worktree: WorktreeSummary }