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:
@@ -13,6 +13,7 @@ import {
|
||||
} from '@arboretum/shared';
|
||||
import type { ClientBinding, PtyManager } from '../core/pty-manager.js';
|
||||
import type { DiscoveryService } from '../core/discovery-service.js';
|
||||
import type { SessionArchiveService } from '../core/session-archive.js';
|
||||
import type { WorktreeManager } from '../core/worktree-manager.js';
|
||||
import type { GroupManager } from '../core/group-manager.js';
|
||||
|
||||
@@ -27,6 +28,7 @@ export function registerWsGateway(
|
||||
app: FastifyInstance,
|
||||
manager: PtyManager,
|
||||
discovery: DiscoveryService,
|
||||
sessionArchive: SessionArchiveService,
|
||||
worktrees: WorktreeManager,
|
||||
groups: GroupManager,
|
||||
serverVersion: string,
|
||||
@@ -57,6 +59,10 @@ export function registerWsGateway(
|
||||
const onSessionExit = (e: { sessionId: string; exitCode: number | null; signal: number | null }): void => {
|
||||
if (subscribedSessions) send({ type: 'session_exit', ...e });
|
||||
};
|
||||
// P10 — une session managée vient d'être archivée (auto par ancienneté ou manuellement).
|
||||
const onSessionArchived = (e: { id: string; archivedAt: string }): void => {
|
||||
if (subscribedSessions) send({ type: 'session_archived', sessionId: e.id });
|
||||
};
|
||||
// Les sessions découvertes (DiscoveryService) sont relayées sur le même flux que les managées.
|
||||
const onDiscoveryUpdate = (session: SessionSummary): void => {
|
||||
if (subscribedSessions) send({ type: 'session_update', session });
|
||||
@@ -85,6 +91,7 @@ export function registerWsGateway(
|
||||
};
|
||||
manager.on('session_update', onSessionUpdate);
|
||||
manager.on('session_exit', onSessionExit);
|
||||
sessionArchive.on('session_archived', onSessionArchived);
|
||||
discovery.on('discovery_update', onDiscoveryUpdate);
|
||||
worktrees.on('repo_update', onRepoUpdate);
|
||||
worktrees.on('repo_removed', onRepoRemoved);
|
||||
@@ -234,6 +241,7 @@ export function registerWsGateway(
|
||||
clearInterval(heartbeat);
|
||||
manager.off('session_update', onSessionUpdate);
|
||||
manager.off('session_exit', onSessionExit);
|
||||
sessionArchive.off('session_archived', onSessionArchived);
|
||||
discovery.off('discovery_update', onDiscoveryUpdate);
|
||||
worktrees.off('repo_update', onRepoUpdate);
|
||||
worktrees.off('repo_removed', onRepoRemoved);
|
||||
|
||||
Reference in New Issue
Block a user