P2: découverte & reprise des sessions Claude
Arboretum découvre désormais toutes les sessions Claude de la machine (scan ~/.claude/projects + registre ~/.claude/sessions), distingue vivantes/mortes par pid+procStart, et permet de reprendre une morte (--resume dans son cwd d'origine) ou forker une vivante sans la corrompre. - shared: SessionSummary enrichi (source, claudeSessionId, pid, resumable, attachable, registryStatus) — additif, PROTOCOL_VERSION inchangé ; types REST resume/fork. - db: migration id:2 (claude_session_id, resumed_from). - core: jsonl-discovery (parseur tolérant, scan asynchrone non bloquant), session-registry (vivacité pid+procStart), discovery-service (cache + refresh périodique + diff/broadcast), pty-manager (resume/fork + capture du claudeSessionId via le registre). - routes: /sessions/:id/resume (garde-fou 409 anti-corruption sur session vivante) et /fork ; GET fusionné managées + découvertes ; relais WS. - web: badges managed/discovered + busy/idle/waiting, actions conditionnelles (Open/Observe/Kill vs Fork/View vs Resume/Fork), vue read-only des sessions externes, i18n EN/FR. - tests: jsonl-discovery, session-registry, discovery-service + resume/fork (130 verts) ; acceptation E2E acceptance-p2.mjs (sans quota) ALL GREEN. Conforme aux verdicts S1 (resume dans cwd d'origine, vivacité pid+procStart) et S4 (munge cwd, parseur tête+queue, priorité de titre). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
type SessionSummary,
|
||||
} from '@arboretum/shared';
|
||||
import type { ClientBinding, PtyManager } from '../core/pty-manager.js';
|
||||
import type { DiscoveryService } from '../core/discovery-service.js';
|
||||
|
||||
const HEARTBEAT_MS = 30_000;
|
||||
|
||||
@@ -17,7 +18,12 @@ interface ChannelState {
|
||||
binding: ClientBinding;
|
||||
}
|
||||
|
||||
export function registerWsGateway(app: FastifyInstance, manager: PtyManager, serverVersion: string): void {
|
||||
export function registerWsGateway(
|
||||
app: FastifyInstance,
|
||||
manager: PtyManager,
|
||||
discovery: DiscoveryService,
|
||||
serverVersion: string,
|
||||
): void {
|
||||
app.get('/ws', { websocket: true }, (socket: WebSocket, req) => {
|
||||
// L'auth + le check Origin ont eu lieu dans le preValidation global (app.ts).
|
||||
const channels = new Map<number, ChannelState>();
|
||||
@@ -39,8 +45,13 @@ export function registerWsGateway(app: FastifyInstance, manager: PtyManager, ser
|
||||
const onSessionExit = (e: { sessionId: string; exitCode: number | null; signal: number | null }): void => {
|
||||
if (subscribedSessions) send({ type: 'session_exit', ...e });
|
||||
};
|
||||
// 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 });
|
||||
};
|
||||
manager.on('session_update', onSessionUpdate);
|
||||
manager.on('session_exit', onSessionExit);
|
||||
discovery.on('discovery_update', onDiscoveryUpdate);
|
||||
|
||||
const heartbeat = setInterval(() => {
|
||||
if (!alive) {
|
||||
@@ -148,6 +159,7 @@ export function registerWsGateway(app: FastifyInstance, manager: PtyManager, ser
|
||||
clearInterval(heartbeat);
|
||||
manager.off('session_update', onSessionUpdate);
|
||||
manager.off('session_exit', onSessionExit);
|
||||
discovery.off('discovery_update', onDiscoveryUpdate);
|
||||
for (const [, st] of channels) manager.detach(st.sessionId, st.binding);
|
||||
channels.clear();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user