import { AppFocusManager, type AppFocusSnapshot } from "@/runtime/app-management/app-focus-manager"; import { AppInstanceManager, type AppInstanceRecord, type AppInstanceSnapshot } from "@/runtime/app-management/app-instance-manager"; import type { AppScope } from "@/runtime/app-management/app-registry"; export type AppWorkspaceSnapshot = { version: 1; instances: AppInstanceSnapshot; focus: AppFocusSnapshot }; /** Coordinates legal transitions and restoration; it never mounts a DOM Host. */ export class AppLifecycleManager { public readonly instances = new AppInstanceManager(); public readonly focus = new AppFocusManager(); public start(input: { instance_id: string; app_scope: AppScope; conversation_id?: string; app_session_id?: string; parent_instance_id?: string; continued_from_app_session_id?: string }, now: string): AppInstanceRecord { return this.instances.create(input, now); } public foreground(instanceID: string, now: string): AppInstanceRecord { const current = this.instances.get(instanceID); if (!current) throw new Error("Unknown App Instance."); const prior = this.focus.foreground(); if (prior && prior !== instanceID) { const record = this.instances.get(prior); if (record?.state === "foreground") this.instances.transition(prior, "background", now); } const next = this.instances.transition(instanceID, "foreground", now); this.focus.push(instanceID); return next; } public background(instanceID: string, now: string): AppInstanceRecord { const next = this.instances.transition(instanceID, "background", now); if (this.focus.foreground() === instanceID) this.focus.remove(instanceID); return next; } public suspend(instanceID: string, now: string): AppInstanceRecord { const next = this.instances.transition(instanceID, "suspended", now); if (this.focus.foreground() === instanceID) this.focus.remove(instanceID); return next; } public close(instanceID: string, now: string, error?: string): AppInstanceRecord | undefined { const current = this.instances.get(instanceID); if (!current || current.state === "stopped" || current.state === "failed") return current; this.instances.transition(instanceID, "stopping", now); const finished = this.instances.transition(instanceID, error ? "failed" : "stopped", now, error); this.focus.remove(instanceID); return finished; } public restore(snapshot: AppWorkspaceSnapshot): void { this.instances.restore(snapshot?.instances); this.focus.restore(snapshot?.focus, id => Boolean(this.instances.get(id))); } public snapshot(): AppWorkspaceSnapshot { return { version: 1, instances: this.instances.snapshot(), focus: this.focus.snapshot() }; } }