export interface DaemonInfo { larkAppId: string; botName: string; /** CLI adapter id from bots.json, e.g. codex / claude-code / traex. */ cliId?: string; /** Lark app avatar URL (from /bot/v3/info); absent until the open_id probe lands. */ botAvatarUrl?: string; botIndex: number; ipcPort: number; pid: number; startedAt: number; /** Random per-process audience for authenticated Workflow v3 mutations. */ bootInstanceId?: string; /** Auth protocol advertised atomically with the boot identity. */ workflowIpcProtocol?: string; lastHeartbeat: number; /** * open_ids of users the bot's allowedUsers list was resolved to (post-email * resolution). Used by dashboard's "Create new group" flow to pick a creator * bot whose scope contains the operator. Emails are stripped — only resolved * open_ids appear here. May be empty for bots with no allowlist configured. */ resolvedAllowedUsers?: string[]; } export type RegistryListener = (online: DaemonInfo[]) => void; /** * Stable roster fingerprint used to tell a real roster change (bot added / * removed / renamed / re-indexed) apart from the 15s no-op poll and the 30s * heartbeat rewrites. Only fields the dashboard's Bot 配置 list keys off of are * included — a pure heartbeat bump (lastHeartbeat) must NOT change it, or the * `/events` bots.changed emitter would fire every poll. Order-independent. */ export declare function botsRosterSignature(online: DaemonInfo[]): string; export interface DaemonRegistryOptions { refreshIntervalMs?: number; } /** * Watches the dashboard-daemons descriptor directory and exposes the * currently-online daemons (filtered by 90s heartbeat staleness). */ export declare class DaemonRegistry { private dir; private items; private listeners; private watcher?; private poller?; private refreshIntervalMs; constructor(dir: string, options?: DaemonRegistryOptions); start(): Promise; stop(): void; list(): DaemonInfo[]; getByAppId(id: string): DaemonInfo | undefined; on(fn: RegistryListener): () => void; private refresh; } //# sourceMappingURL=registry.d.ts.map