/** * RuntimeRegistry — Strict single-active-account enforcement * * Prevents concurrent accounts from running. * Registry.register() throws if another account is already active. * This replaces the old shared.js singleton pattern. * * See §1.1 of refactoring-plan.md. */ import { logger } from '../util/logger.js'; import type { AccountRuntime } from './account.js'; export class RuntimeRegistry { private _active: AccountRuntime | null = null; /** * Register an AccountRuntime as the active instance. * @throws Error if another account is already active */ register(runtime: AccountRuntime): void { if (this._active && this._active !== runtime) { throw new Error( `Cannot start account '${runtime.accountId}': ` + `account '${this._active.accountId}' is already running. ` + `Stop it first.` ); } this._active = runtime; logger.info(`[registry] Registered account '${runtime.accountId}'`); } /** * Unregister the active runtime. */ unregister(runtime: AccountRuntime): void { if (this._active === runtime) { logger.info(`[registry] Unregistered account '${runtime.accountId}'`); this._active = null; } } /** * Get the currently active runtime. * Returns null if no account is running. */ getActive(): AccountRuntime | null { return this._active; } /** * Get the default (only) runtime. * In single-active-account mode, this is the same as getActive(). */ getDefault(): AccountRuntime | null { return this._active; } /** * Check if any account is currently running. */ hasActive(): boolean { return this._active !== null; } } /** * Global registry instance. * Shared by channel adapter, tools, and hooks. */ export const registry = new RuntimeRegistry();