/** * Connector registry (F4 Phase 1). * * A tiny extensible registry so connector implementations (Phase 2: tmux, * Discord, Matrix) register a factory by kind and fleet core resolves one from * roster config without branching on kind. Phase 1 ships the registry + the * config→kind resolution; the connector factories land in Phase 2. */ import { type ConnectorConfig, type ConnectorKind, type OrchestratorConnector, DEFAULT_CONNECTOR_KIND, } from './types.js'; /** The set of connector kinds the framework recognizes. */ export const KNOWN_CONNECTOR_KINDS: readonly ConnectorKind[] = ['tmux', 'discord', 'matrix']; /** Type guard: is `value` a known connector kind? */ export function isKnownConnectorKind(value: unknown): value is ConnectorKind { return typeof value === 'string' && (KNOWN_CONNECTOR_KINDS as readonly string[]).includes(value); } /** * Resolve the connector kind from roster config. Absent config ⇒ the default * (tmux) so existing rosters keep working unchanged (back-compat). */ export function resolveConnectorKind(config?: ConnectorConfig): ConnectorKind { return config?.kind ?? DEFAULT_CONNECTOR_KIND; } /** A factory builds a live connector from its validated config. */ export type ConnectorFactory = (config: ConnectorConfig) => OrchestratorConnector; /** Thrown when no factory is registered for a requested kind. */ export class ConnectorNotImplementedError extends Error { constructor(public readonly kind: ConnectorKind) { super( `Connector "${kind}" is not implemented yet. ` + `Register a factory via registerConnector('${kind}', …) (F4 Phase 2).`, ); this.name = 'ConnectorNotImplementedError'; } } const registry = new Map(); /** Register a connector factory for a kind (idempotent — last registration wins). */ export function registerConnector(kind: ConnectorKind, factory: ConnectorFactory): void { registry.set(kind, factory); } /** True when a factory is registered for `kind`. */ export function hasConnector(kind: ConnectorKind): boolean { return registry.has(kind); } /** * Build a connector from roster config. Throws `ConnectorNotImplementedError` * when no factory is registered for the resolved kind (the Phase-1 default for * every kind until Phase 2 registers them). */ export function createConnector(config?: ConnectorConfig): OrchestratorConnector { const kind = resolveConnectorKind(config); const factory = registry.get(kind); if (!factory) { throw new ConnectorNotImplementedError(kind); } return factory(config ?? { kind }); } /** Test/runtime helper: drop all registrations. */ export function _resetConnectorRegistry(): void { registry.clear(); }