@mirasoth/soothe-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/protocol.ts","../src/client.ts","../src/index.ts","../src/errors.ts","../src/verbosity.ts","../src/events.ts","../src/helpers.ts","../src/session.ts"],"sourcesContent":["/**\n * Client configuration for connecting to the Soothe daemon.\n */\n\nimport type { VerbosityLevel } from './verbosity.js';\n\nexport interface Config {\n /** WebSocket URL for Soothe daemon */\n daemonURL: string;\n /** Event verbosity: quiet/minimal/normal/detailed/debug */\n verbosityLevel: VerbosityLevel;\n /** Maximum connection retry attempts */\n maxRetries: number;\n /** Initial reconnect delay in ms */\n reconnectDelay: number;\n /** Application-level heartbeat interval in ms */\n heartbeatInterval: number;\n /** Handshake: wait for daemon_ready in ms */\n daemonReadyTimeout: number;\n /** Bootstrap: wait for status with loop_id in ms */\n loopStatusTimeout: number;\n /** After loop_subscribe: wait for confirmation in ms */\n subscriptionTimeout: number;\n}\n\n/** Returns default configuration. */\nexport function defaultConfig(): Config {\n return {\n daemonURL: 'ws://localhost:8765',\n verbosityLevel: 'normal',\n maxRetries: 5,\n reconnectDelay: 2000,\n heartbeatInterval: 30000,\n daemonReadyTimeout: 20000,\n loopStatusTimeout: 60000,\n subscriptionTimeout: 10000,\n };\n}\n\n/** Loads configuration from environment variables. */\nexport function loadConfigFromEnv(): Config {\n const config = defaultConfig();\n\n if (typeof process === 'undefined') return config;\n\n const url = process.env.SOOTHE_DAEMON_URL;\n if (url) config.daemonURL = url;\n\n const verbosity = process.env.SOOTHE_VERBOSITY;\n if (verbosity) config.verbosityLevel = verbosity as VerbosityLevel;\n\n const retries = process.env.SOOTHE_MAX_RETRIES;\n if (retries) {\n const val = parseInt(retries, 10);\n if (!isNaN(val)) config.maxRetries = val;\n }\n\n const readyTimeout = process.env.SOOTHE_DAEMON_READY_TIMEOUT_SEC;\n if (readyTimeout) {\n const val = parseInt(readyTimeout, 10);\n if (val > 0) config.daemonReadyTimeout = val * 1000;\n }\n\n const statusTimeout = process.env.SOOTHE_LOOP_STATUS_TIMEOUT_SEC;\n if (statusTimeout) {\n const val = parseInt(statusTimeout, 10);\n if (val > 0) config.loopStatusTimeout = val * 1000;\n }\n\n const subTimeout = process.env.SOOTHE_SUBSCRIPTION_TIMEOUT_SEC;\n if (subTimeout) {\n const val = parseInt(subTimeout, 10);\n if (val > 0) config.subscriptionTimeout = val * 1000;\n }\n\n return config;\n}\n","/**\n * Message types, encode/decode, NDJSON splitting, and factory functions\n * for the Soothe daemon wire protocol.\n */\n\nimport { randomUUID } from 'node:crypto';\n\n// ---------------------------------------------------------------------------\n// Base types\n// ---------------------------------------------------------------------------\n\nexport interface BaseMessage {\n type: string;\n request_id?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client → Daemon messages (Loop-first architecture, RFC-503)\n// ---------------------------------------------------------------------------\n\n/** Loop-scoped user input. */\nexport interface LoopInputMessage extends BaseMessage {\n type: 'loop_input';\n loop_id: string;\n content: string;\n autonomous?: boolean;\n max_iterations?: number;\n preferred_subagent?: string;\n interactive?: boolean;\n model?: string;\n model_params?: Record<string, unknown>;\n attachments?: Record<string, unknown>[];\n}\n\nexport interface CommandMessage extends BaseMessage {\n type: 'command';\n cmd: string;\n}\n\nexport interface DaemonStatusMessage extends BaseMessage {\n type: 'daemon_status';\n}\n\nexport interface DaemonShutdownMessage extends BaseMessage {\n type: 'daemon_shutdown';\n}\n\nexport interface ConfigGetMessage extends BaseMessage {\n type: 'config_get';\n section: string;\n}\n\n// Loop lifecycle messages (RFC-503)\n\nexport interface LoopNewMessage extends BaseMessage {\n type: 'loop_new';\n /** Project directory; runner uses this path directly when set. */\n client_workspace?: string;\n /** Stable scope for persisted sandbox when client_workspace is unset. */\n client_workspace_id?: string;\n /** User segment under $SOOTHE_HOME/workspaces/ (empty → anonymous). */\n user_id?: string;\n /** When true, loop execution data is GC'd after idle period (workspace retained). */\n is_ephemeral?: boolean;\n /**\n * @deprecated Use `client_workspace`. Still accepted by the daemon as an alias.\n */\n workspace?: string;\n}\n\n/** Options for `loop_new` workspace fields. */\nexport interface LoopNewOptions {\n client_workspace?: string;\n client_workspace_id?: string;\n user_id?: string;\n is_ephemeral?: boolean;\n /** @deprecated Use `client_workspace`. */\n workspace?: string;\n}\n\nexport interface LoopSubscribeMessage extends BaseMessage {\n type: 'loop_subscribe';\n loop_id: string;\n verbosity: string;\n stream_delivery?: 'batch' | 'streaming'; // RFC-614 stream shaping\n}\n\nexport interface LoopDetachMessage extends BaseMessage {\n type: 'loop_detach';\n loop_id: string;\n}\n\n// Loop management RPC messages (RFC-504)\n\nexport interface LoopListMessage extends BaseMessage {\n type: 'loop_list';\n filter?: Record<string, unknown>;\n limit?: number;\n}\n\nexport interface LoopGetMessage extends BaseMessage {\n type: 'loop_get';\n loop_id: string;\n verbose?: boolean;\n}\n\nexport interface LoopTreeMessage extends BaseMessage {\n type: 'loop_tree';\n loop_id: string;\n format?: string;\n}\n\nexport interface LoopPruneMessage extends BaseMessage {\n type: 'loop_prune';\n loop_id: string;\n retention_days?: number;\n dry_run?: boolean;\n}\n\nexport interface LoopDeleteMessage extends BaseMessage {\n type: 'loop_delete';\n loop_id: string;\n}\n\nexport interface LoopReattachMessage extends BaseMessage {\n type: 'loop_reattach';\n loop_id: string;\n}\n\n// Other messages\n\nexport interface SkillsListMessage extends BaseMessage {\n type: 'skills_list';\n}\n\nexport interface ModelsListMessage extends BaseMessage {\n type: 'models_list';\n}\n\nexport interface InvokeSkillMessage extends BaseMessage {\n type: 'invoke_skill';\n skill: string;\n args?: string;\n}\n\nexport interface DetachMessage extends BaseMessage {\n type: 'detach';\n}\n\n// ---------------------------------------------------------------------------\n// Daemon → Client messages\n// ---------------------------------------------------------------------------\n\nexport interface EventMessage extends BaseMessage {\n type: 'event';\n loop_id?: string;\n namespace: string;\n data: Record<string, unknown>;\n timestamp?: string;\n}\n\nexport interface StatusResponse extends BaseMessage {\n type: 'status';\n state: string;\n loop_id?: string;\n workspace: string;\n input_history?: string[];\n conversation_history?: unknown[];\n}\n\nexport interface SubscriptionConfirmedResponse extends BaseMessage {\n type: 'subscription_confirmed';\n loop_id?: string;\n client_id: string;\n verbosity: string;\n}\n\nexport interface ErrorResponse extends BaseMessage {\n type: 'error';\n code: string;\n message: string;\n}\n\nexport interface DaemonReadyResponse extends BaseMessage {\n type: 'daemon_ready';\n state: string;\n message?: string;\n}\n\nexport interface DaemonStatusResponse extends BaseMessage {\n type: 'daemon_status_response';\n running: boolean;\n port_live: boolean;\n active_loops: number;\n}\n\nexport interface ShutdownAckResponse extends BaseMessage {\n type: 'shutdown_ack';\n status: string;\n}\n\n// Loop lifecycle responses (RFC-503)\n\nexport interface LoopNewResponse extends BaseMessage {\n type: 'loop_new_response';\n loop_id: string;\n success?: boolean;\n is_ephemeral?: boolean;\n}\n\nexport interface LoopSubscribeResponse extends BaseMessage {\n type: 'loop_subscribe_response';\n loop_id?: string;\n success: boolean;\n message?: string;\n}\n\nexport interface LoopDetachResponse extends BaseMessage {\n type: 'loop_detach_response';\n loop_id?: string;\n success: boolean;\n}\n\n// Loop management responses (RFC-504)\n\nexport interface LoopListResponse extends BaseMessage {\n type: 'loop_list_response';\n loops?: Record<string, unknown>[];\n total?: number;\n}\n\nexport interface LoopGetResponse extends BaseMessage {\n type: 'loop_get_response';\n loop?: Record<string, unknown>;\n}\n\nexport interface LoopTreeResponse extends BaseMessage {\n type: 'loop_tree_response';\n tree?: Record<string, unknown>;\n}\n\nexport interface LoopPruneResponse extends BaseMessage {\n type: 'loop_prune_response';\n result?: Record<string, unknown>;\n}\n\nexport interface LoopDeleteResponse extends BaseMessage {\n type: 'loop_delete_response';\n success: boolean;\n message?: string;\n}\n\nexport interface LoopReattachResponse extends BaseMessage {\n type: 'loop_reattach_response';\n loop_id?: string;\n success?: boolean;\n}\n\n// History replay messages (RFC-411)\n\nexport interface HistoryReplayMessage extends BaseMessage {\n type: 'history_replay';\n loop_id?: string;\n events?: Record<string, unknown>[];\n total_events?: number;\n}\n\nexport interface HistoryReplayCompleteMessage extends BaseMessage {\n type: 'history_replay_complete';\n loop_id?: string;\n}\n\nexport interface ReplayCompleteMessage extends BaseMessage {\n type: 'replay_complete';\n loop_id?: string;\n event_count?: number;\n}\n\nexport interface LoopReattachedWireMessage extends BaseMessage {\n type: 'loop_reattached';\n loop_id?: string;\n timestamp?: string;\n}\n\n// Other responses\n\nexport interface SkillsListResponse extends BaseMessage {\n type: 'skills_list_response';\n skills?: Record<string, unknown>[];\n}\n\nexport interface ModelsListResponse extends BaseMessage {\n type: 'models_list_response';\n models?: Record<string, unknown>[];\n}\n\n// Discriminated union for all decoded messages\nexport type DecodedMessage =\n | LoopInputMessage\n | CommandMessage\n | DaemonStatusMessage\n | DaemonShutdownMessage\n | ConfigGetMessage\n | LoopNewMessage\n | LoopSubscribeMessage\n | LoopDetachMessage\n | LoopListMessage\n | LoopGetMessage\n | LoopTreeMessage\n | LoopPruneMessage\n | LoopDeleteMessage\n | LoopReattachMessage\n | SkillsListMessage\n | ModelsListMessage\n | InvokeSkillMessage\n | DetachMessage\n | EventMessage\n | StatusResponse\n | SubscriptionConfirmedResponse\n | ErrorResponse\n | DaemonReadyResponse\n | DaemonStatusResponse\n | ShutdownAckResponse\n | LoopNewResponse\n | LoopSubscribeResponse\n | LoopDetachResponse\n | LoopListResponse\n | LoopGetResponse\n | LoopTreeResponse\n | LoopPruneResponse\n | LoopDeleteResponse\n | LoopReattachResponse\n | HistoryReplayMessage\n | HistoryReplayCompleteMessage\n | ReplayCompleteMessage\n | LoopReattachedWireMessage\n | SkillsListResponse\n | ModelsListResponse\n | Record<string, unknown>;\n\n// ---------------------------------------------------------------------------\n// Encode / Decode\n// ---------------------------------------------------------------------------\n\n/** Encodes a message as JSON with newline delimiter. */\nexport function encodeMessage(msg: unknown): string {\n return JSON.stringify(msg) + '\\n';\n}\n\n/** Decodes a JSON message and returns a typed object. Unknown types return a raw map. */\nexport function decodeMessage(data: string): DecodedMessage | null {\n if (!data || data.length === 0) return null;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(data);\n } catch {\n throw new Error(`invalid JSON: ${data}`);\n }\n\n const type = parsed.type as string | undefined;\n if (!type) return parsed;\n\n switch (type) {\n // Client → Daemon (loop-first)\n case 'loop_input': return { ...parsed } as unknown as LoopInputMessage;\n case 'command': return { ...parsed } as unknown as CommandMessage;\n case 'daemon_status': return { ...parsed } as unknown as DaemonStatusMessage;\n case 'daemon_shutdown': return { ...parsed } as unknown as DaemonShutdownMessage;\n case 'config_get': return { ...parsed } as unknown as ConfigGetMessage;\n case 'loop_new': return { ...parsed } as unknown as LoopNewMessage;\n case 'loop_subscribe': return { ...parsed } as unknown as LoopSubscribeMessage;\n case 'loop_detach': return { ...parsed } as unknown as LoopDetachMessage;\n case 'loop_list': return { ...parsed } as unknown as LoopListMessage;\n case 'loop_get': return { ...parsed } as unknown as LoopGetMessage;\n case 'loop_tree': return { ...parsed } as unknown as LoopTreeMessage;\n case 'loop_prune': return { ...parsed } as unknown as LoopPruneMessage;\n case 'loop_delete': return { ...parsed } as unknown as LoopDeleteMessage;\n case 'loop_reattach': return { ...parsed } as unknown as LoopReattachMessage;\n case 'skills_list': return { ...parsed } as unknown as SkillsListMessage;\n case 'models_list': return { ...parsed } as unknown as ModelsListMessage;\n case 'invoke_skill': return { ...parsed } as unknown as InvokeSkillMessage;\n case 'detach': return { ...parsed } as unknown as DetachMessage;\n\n // Daemon → Client\n case 'event': return { ...parsed } as unknown as EventMessage;\n case 'status': {\n const msg = { ...parsed } as unknown as StatusResponse;\n if (!msg.loop_id && parsed.loopId && typeof parsed.loopId === 'string') {\n msg.loop_id = parsed.loopId;\n }\n return msg;\n }\n case 'subscription_confirmed': return { ...parsed } as unknown as SubscriptionConfirmedResponse;\n case 'error': return { ...parsed } as unknown as ErrorResponse;\n case 'daemon_ready': return { ...parsed } as unknown as DaemonReadyResponse;\n case 'daemon_status_response': return { ...parsed } as unknown as DaemonStatusResponse;\n case 'shutdown_ack': return { ...parsed } as unknown as ShutdownAckResponse;\n case 'loop_new_response': return { ...parsed } as unknown as LoopNewResponse;\n case 'loop_subscribe_response': return { ...parsed } as unknown as LoopSubscribeResponse;\n case 'loop_detach_response': return { ...parsed } as unknown as LoopDetachResponse;\n case 'loop_list_response': return { ...parsed } as unknown as LoopListResponse;\n case 'loop_get_response': return { ...parsed } as unknown as LoopGetResponse;\n case 'loop_tree_response': return { ...parsed } as unknown as LoopTreeResponse;\n case 'loop_prune_response': return { ...parsed } as unknown as LoopPruneResponse;\n case 'loop_delete_response': return { ...parsed } as unknown as LoopDeleteResponse;\n case 'loop_reattach_response': return { ...parsed } as unknown as LoopReattachResponse;\n case 'history_replay': return { ...parsed } as unknown as HistoryReplayMessage;\n case 'history_replay_complete':\n case 'replay_complete':\n return { ...parsed } as unknown as ReplayCompleteMessage;\n case 'loop_reattached':\n return { ...parsed } as unknown as LoopReattachedWireMessage;\n case 'config_get_response':\n case 'invoke_skill_response':\n return parsed;\n case 'skills_list_response': return { ...parsed } as unknown as SkillsListResponse;\n case 'models_list_response': return { ...parsed } as unknown as ModelsListResponse;\n\n default:\n return parsed;\n }\n}\n\n// ---------------------------------------------------------------------------\n// NDJSON splitting\n// ---------------------------------------------------------------------------\n\n/** Splits a single WebSocket text payload into individual JSON lines. */\nexport function splitWirePayload(data: string): string[] {\n const trimmed = data.trim();\n if (trimmed === '') return [];\n\n const lines = trimmed.split('\\n').map(l => l.trim()).filter(l => l !== '');\n return lines.length > 0 ? lines : [data];\n}\n\n/**\n * Returns the AgentLoop id when present in a message.\n * Prefers loop_id field.\n */\nexport function extractSootheLoopID(msg: unknown): [string, boolean] {\n if (!msg || typeof msg !== 'object') return ['', false];\n const m = msg as Record<string, unknown>;\n\n if (m.type === 'status') {\n const id = m.loop_id as string | undefined;\n if (id && id !== '') return [id, true];\n return ['', false];\n }\n\n if (m.type === 'event') {\n const top = m.loop_id as string | undefined;\n if (top && top !== '') return [top, true];\n\n const data = m.data as Record<string, unknown> | undefined;\n if (data && typeof data === 'object') {\n const dataId = (data['loop_id'] ?? data['loopId']) as string | undefined;\n if (dataId && dataId !== '') return [dataId, true];\n }\n }\n\n const generic = (m['loop_id'] ?? m['loopId']) as string | undefined;\n if (generic && generic !== '') return [generic, true];\n\n return ['', false];\n}\n\n// ---------------------------------------------------------------------------\n// Message factory functions\n// ---------------------------------------------------------------------------\n\n/** Generates a new UUID request ID. */\nexport function newRequestID(): string {\n return randomUUID();\n}\n\n/** Creates a loop_input message with required fields. */\nexport function newLoopInputMessage(loopID: string, content: string): LoopInputMessage {\n return {\n request_id: newRequestID(),\n type: 'loop_input',\n loop_id: loopID,\n content,\n autonomous: false,\n };\n}\n\n/** Creates a loop_new message. */\nexport function newLoopNewMessage(opts?: LoopNewOptions | string): LoopNewMessage {\n const options: LoopNewOptions =\n typeof opts === 'string' ? { client_workspace: opts } : opts ?? {};\n const clientWorkspace = options.client_workspace ?? options.workspace;\n const msg: LoopNewMessage = {\n request_id: newRequestID(),\n type: 'loop_new',\n };\n if (clientWorkspace?.trim()) {\n msg.client_workspace = clientWorkspace.trim();\n }\n if (options.user_id?.trim()) {\n msg.user_id = options.user_id.trim();\n }\n if (options.client_workspace_id?.trim()) {\n msg.client_workspace_id = options.client_workspace_id.trim();\n }\n if (options.is_ephemeral) {\n msg.is_ephemeral = true;\n }\n return msg;\n}\n\n/** Creates a loop_subscribe message. */\nexport function newLoopSubscribeMessage(loopID: string, verbosity: string, streamDelivery?: 'batch' | 'streaming'): LoopSubscribeMessage {\n const msg: LoopSubscribeMessage = {\n request_id: newRequestID(),\n type: 'loop_subscribe',\n loop_id: loopID,\n verbosity,\n };\n if (streamDelivery) {\n msg.stream_delivery = streamDelivery;\n }\n return msg;\n}","/**\n * Client manages a WebSocket session with the Soothe daemon.\n * After close(), a new Client must be created to reconnect.\n */\n\nimport { EventEmitter } from 'node:events';\nimport WebSocket from 'ws';\nimport type { Config } from './config.js';\nimport { defaultConfig } from './config.js';\nimport {\n decodeMessage,\n splitWirePayload,\n newRequestID,\n newLoopNewMessage,\n newLoopSubscribeMessage,\n type DecodedMessage,\n type LoopNewOptions,\n} from './protocol.js';\n\nexport interface InputOptions {\n /** Subscribed AgentLoop id (required for loop_input). */\n loopID?: string;\n autonomous?: boolean;\n maxIterations?: number;\n subagent?: string;\n interactive?: boolean;\n model?: string;\n modelParams?: Record<string, unknown>;\n attachments?: Record<string, unknown>[];\n}\n\nexport class Client extends EventEmitter {\n private url: string;\n private config: Config;\n private ws: WebSocket | null = null;\n private messageBuffer: DecodedMessage[] = [];\n private resolvers: Array<(value: DecodedMessage | null) => void> = [];\n\n constructor(url: string, config?: Config) {\n super();\n this.url = url;\n this.config = config ?? defaultConfig();\n }\n\n // ---------------------------------------------------------------------------\n // Connection lifecycle\n // ---------------------------------------------------------------------------\n\n /** Dials the Soothe daemon WebSocket. No WS-level ping/pong (RFC-0013). */\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n const ws = new WebSocket(this.url, {\n handshakeTimeout: 10_000,\n });\n\n ws.on('open', () => {\n this.ws = ws;\n resolve();\n });\n\n ws.on('error', err => {\n if (!this.ws) {\n reject(new Error(`soothe dial: ${err.message}`));\n }\n });\n\n ws.on('message', (data: WebSocket.RawData) => {\n const text = data.toString();\n for (const frame of splitWirePayload(text)) {\n try {\n const msg = decodeMessage(frame);\n if (msg !== null) {\n this.messageBuffer.push(msg);\n this.emit('message', msg);\n // Resolve pending readEvent calls\n const resolver = this.resolvers.shift();\n if (resolver) resolver(msg);\n }\n } catch {\n // skip malformed messages\n }\n }\n });\n\n ws.on('close', () => {\n this.ws = null;\n this.emit('close');\n // Resolve any pending readEvent calls with null\n for (const resolver of this.resolvers) {\n resolver(null);\n }\n this.resolvers = [];\n });\n });\n }\n\n /** Shuts down the WebSocket connection. */\n close(): void {\n if (!this.ws) return;\n try {\n this.ws.close(1000, '');\n } catch {\n // ignore close errors\n }\n this.ws = null;\n }\n\n /** Returns whether the client has an active WebSocket connection. */\n isConnected(): boolean {\n return this.ws !== null && this.ws.readyState === WebSocket.OPEN;\n }\n\n // ---------------------------------------------------------------------------\n // Core messaging\n // ---------------------------------------------------------------------------\n\n /** Serializes msg as JSON and sends it as a WebSocket text frame. */\n sendMessage(msg: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.ws) {\n reject(new Error('soothe: not connected'));\n return;\n }\n const payload = JSON.stringify(msg);\n this.ws.send(payload, err => {\n if (err) reject(err);\n else resolve();\n });\n });\n }\n\n /** Returns an async iterable of decoded messages. Ends when connection closes. */\n async *receiveMessages(signal?: AbortSignal): AsyncGenerator<DecodedMessage> {\n while (true) {\n if (signal?.aborted) return;\n\n // Drain buffer first\n while (this.messageBuffer.length > 0) {\n const msg = this.messageBuffer.shift()!;\n yield msg;\n }\n\n // Wait for next message or close\n const msg = await new Promise<DecodedMessage | null>(resolve => {\n if (!this.ws) {\n resolve(null);\n return;\n }\n this.resolvers.push(resolve);\n });\n\n if (msg === null) return;\n yield msg;\n }\n }\n\n /** Reads a single event from the daemon. Returns null on connection close. */\n async readEvent(): Promise<Record<string, unknown> | null> {\n // Check buffer first\n if (this.messageBuffer.length > 0) {\n const msg = this.messageBuffer.shift()!;\n return msg as Record<string, unknown>;\n }\n\n if (!this.ws) return null;\n\n const msg = await new Promise<DecodedMessage | null>(resolve => {\n this.resolvers.push(resolve);\n });\n\n if (msg === null) return null;\n return msg as Record<string, unknown>;\n }\n\n /** Reads a single event with a timeout. Returns null on timeout or connection close. */\n readEventWithTimeout(timeout: number): Promise<Record<string, unknown> | null> {\n // Check buffer first\n if (this.messageBuffer.length > 0) {\n const msg = this.messageBuffer.shift()!;\n return Promise.resolve(msg as Record<string, unknown>);\n }\n\n if (!this.ws) return Promise.resolve(null);\n\n return new Promise<Record<string, unknown> | null>(resolve => {\n const timer = setTimeout(() => {\n const idx = this.resolvers.indexOf(resolver);\n if (idx >= 0) this.resolvers.splice(idx, 1);\n resolve(null);\n }, timeout);\n\n const resolver = (val: DecodedMessage | null) => {\n clearTimeout(timer);\n resolve(val as Record<string, unknown> | null);\n };\n\n this.resolvers.push(resolver);\n });\n }\n\n // ---------------------------------------------------------------------------\n // High-level API methods (Loop-first, RFC-503)\n // ---------------------------------------------------------------------------\n\n /** Sends user input to the daemon (loop_input; requires loopID). */\n sendInput(text: string, options?: InputOptions): Promise<void> {\n const loopId = (options?.loopID ?? '').trim();\n if (!loopId) {\n return Promise.reject(new Error('sendInput requires options.loopID'));\n }\n const payload: Record<string, unknown> = {\n type: 'loop_input',\n loop_id: loopId,\n content: text,\n autonomous: options?.autonomous ?? false,\n };\n if (options?.maxIterations !== undefined) payload.max_iterations = options.maxIterations;\n if (options?.subagent) payload.preferred_subagent = options.subagent;\n if (options?.interactive) payload.interactive = true;\n if (options?.model) payload.model = options.model;\n if (options?.modelParams) payload.model_params = options.modelParams;\n if (options?.attachments) payload.attachments = options.attachments;\n return this.sendMessage(payload);\n }\n\n /** Sends a slash command to the daemon. */\n sendCommand(cmd: string): Promise<void> {\n return this.sendMessage({ type: 'command', cmd });\n }\n\n // ---------------------------------------------------------------------------\n // Loop lifecycle methods (RFC-503)\n // ---------------------------------------------------------------------------\n\n /** Requests the daemon to create a new AgentLoop. */\n sendLoopNew(opts?: LoopNewOptions | string): Promise<void> {\n return this.sendMessage(newLoopNewMessage(opts));\n }\n\n /** Subscribes to events for a loop. */\n sendLoopSubscribe(loopID: string, verbosity: string, streamDelivery?: 'batch' | 'streaming'): Promise<void> {\n const msg = newLoopSubscribeMessage(loopID, verbosity);\n if (streamDelivery) {\n (msg as unknown as Record<string, unknown>).stream_delivery = streamDelivery;\n }\n return this.sendMessage(msg);\n }\n\n /** Detaches from a loop (keeps loop running). */\n sendLoopDetach(loopID: string, requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'loop_detach',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Notifies the daemon that this client is detaching. */\n sendDetach(): Promise<void> {\n return this.sendMessage({ type: 'detach' });\n }\n\n /** Sends the daemon_ready handshake message. */\n sendDaemonReady(): Promise<void> {\n return this.sendMessage({ type: 'daemon_ready' });\n }\n\n /** Requests daemon status check. */\n sendDaemonStatus(requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'daemon_status',\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Requests daemon shutdown. */\n sendDaemonShutdown(requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'daemon_shutdown',\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Requests a config section from the daemon. */\n sendConfigGet(section: string, requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'config_get',\n section,\n request_id: requestID ?? newRequestID(),\n });\n }\n\n // ---------------------------------------------------------------------------\n // Loop management RPC methods (RFC-504)\n // ---------------------------------------------------------------------------\n\n /** Requests the persisted loop list. */\n sendLoopList(filter?: Record<string, unknown>, limit?: number, requestID?: string): Promise<void> {\n const msg: Record<string, unknown> = {\n type: 'loop_list',\n request_id: requestID ?? newRequestID(),\n };\n if (filter) msg.filter = filter;\n if (limit !== undefined) msg.limit = limit;\n return this.sendMessage(msg);\n }\n\n /** Requests detailed loop metadata. */\n sendLoopGet(loopID: string, verbose?: boolean, requestID?: string): Promise<void> {\n const msg: Record<string, unknown> = {\n type: 'loop_get',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n };\n if (verbose) msg.verbose = verbose;\n return this.sendMessage(msg);\n }\n\n /** Requests loop tree visualization. */\n sendLoopTree(loopID: string, format?: string, requestID?: string): Promise<void> {\n const msg: Record<string, unknown> = {\n type: 'loop_tree',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n };\n if (format) msg.format = format;\n return this.sendMessage(msg);\n }\n\n /** Requests pruning of old failed branches. */\n sendLoopPrune(loopID: string, retentionDays?: number, dryRun?: boolean, requestID?: string): Promise<void> {\n const msg: Record<string, unknown> = {\n type: 'loop_prune',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n };\n if (retentionDays !== undefined) msg.retention_days = retentionDays;\n if (dryRun !== undefined) msg.dry_run = dryRun;\n return this.sendMessage(msg);\n }\n\n /** Requests loop deletion. */\n sendLoopDelete(loopID: string, requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'loop_delete',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Requests reattachment to a loop with history replay. */\n sendLoopReattach(loopID: string, requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'loop_reattach',\n loop_id: loopID,\n request_id: requestID ?? newRequestID(),\n });\n }\n\n // ---------------------------------------------------------------------------\n // Skills and models\n // ---------------------------------------------------------------------------\n\n /** Requests the skills catalog (RFC-400). */\n sendSkillsList(requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'skills_list',\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Requests the models catalog (RFC-400). */\n sendModelsList(requestID?: string): Promise<void> {\n return this.sendMessage({\n type: 'models_list',\n request_id: requestID ?? newRequestID(),\n });\n }\n\n /** Invokes a skill on the daemon (RFC-400). */\n sendInvokeSkill(skill: string, args?: string, requestID?: string): Promise<void> {\n const msg: Record<string, unknown> = {\n type: 'invoke_skill',\n skill,\n request_id: requestID ?? newRequestID(),\n };\n if (args) msg.args = args;\n return this.sendMessage(msg);\n }\n\n // ---------------------------------------------------------------------------\n // Request-Response pattern\n // ---------------------------------------------------------------------------\n\n /** Sends a request with a unique request_id and waits for a matching response. */\n async requestResponse(\n payload: Record<string, unknown>,\n responseType: string,\n timeout: number,\n ): Promise<Record<string, unknown>> {\n const rid = newRequestID();\n payload.request_id = rid;\n\n await this.sendMessage(payload);\n\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n\n const ev = await this.readEventWithTimeout(remaining);\n if (ev === null) {\n break; // timeout or connection closed\n }\n\n const evRid = ev.request_id as string | undefined;\n if (evRid !== rid) continue;\n\n const typ = ev.type as string;\n if (typ === 'error') {\n const msg = (ev.message as string) ?? 'unknown error';\n throw new Error(`daemon error: ${msg}`);\n }\n if (typ === responseType) {\n return ev;\n }\n }\n\n throw new Error(`timeout after ${timeout}ms waiting for ${responseType}`);\n }\n\n // ---------------------------------------------------------------------------\n // Convenience RPC methods\n // ---------------------------------------------------------------------------\n\n /** Requests the skills catalog and waits for the response. */\n listSkills(timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'skills_list' }, 'skills_list_response', timeout ?? 15_000);\n }\n\n /** Requests the models catalog and waits for the response. */\n listModels(timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'models_list' }, 'models_list_response', timeout ?? 15_000);\n }\n\n /** Invokes a skill on the daemon host and receives echo (RFC-400). */\n invokeSkill(skill: string, args?: string, timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'invoke_skill', skill, args }, 'invoke_skill_response', timeout ?? 120_000);\n }\n\n /** Requests loop list and waits for response. */\n listLoops(timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'loop_list' }, 'loop_list_response', timeout ?? 15_000);\n }\n\n /** Requests loop details and waits for response. */\n getLoop(loopID: string, timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'loop_get', loop_id: loopID }, 'loop_get_response', timeout ?? 15_000);\n }\n\n /** Requests loop tree and waits for response. */\n getLoopTree(loopID: string, timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'loop_tree', loop_id: loopID }, 'loop_tree_response', timeout ?? 15_000);\n }\n\n /** Requests loop deletion and waits for response. */\n deleteLoop(loopID: string, timeout?: number): Promise<Record<string, unknown>> {\n return this.requestResponse({ type: 'loop_delete', loop_id: loopID }, 'loop_delete_response', timeout ?? 15_000);\n }\n\n // ---------------------------------------------------------------------------\n // Wait helpers\n // ---------------------------------------------------------------------------\n\n /** Reads events until a daemon_ready with state == \"ready\". */\n async waitForDaemonReady(timeout?: number): Promise<Record<string, unknown>> {\n const t = timeout ?? 10_000;\n const deadline = Date.now() + t;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = await this.readEventWithTimeout(remaining);\n if (ev === null) break;\n if (ev.type !== 'daemon_ready') continue;\n if (ev.state === 'ready') return ev;\n const msg = (ev.message as string) ?? `daemon state is ${ev.state}`;\n throw new Error(`daemon not ready: ${msg}`);\n }\n throw new Error(`timeout after ${t}ms waiting for daemon_ready`);\n }\n\n /** Waits for subscription confirmation matching loop id. */\n async waitForSubscriptionConfirmed(loopID: string, _verbosity: string, timeout?: number): Promise<void> {\n const t = timeout ?? 5_000;\n const deadline = Date.now() + t;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = await this.readEventWithTimeout(remaining);\n if (ev === null) break;\n if (ev.type === 'loop_subscribe_response' && ev.success === true) {\n if (String(ev.loop_id ?? '') === loopID) return;\n continue;\n }\n if (ev.type !== 'subscription_confirmed') continue;\n const lid = String((ev as { loop_id?: string }).loop_id ?? '');\n if (lid === loopID) return;\n }\n throw new Error(`timeout after ${t}ms waiting for subscription_confirmed`);\n }\n}","/**\n * Soothe WebSocket Client - TypeScript\n *\n * A WebSocket client for the Soothe daemon, providing typed message\n * protocol, session bootstrap, and convenience RPC helpers.\n */\n\n// Errors\nexport { ConnectionError, DaemonError, TimeoutError } from './errors.js';\n\n// Verbosity\nexport { VerbosityTier, shouldShow, isValidVerbosityLevel } from './verbosity.js';\nexport type { VerbosityLevel } from './verbosity.js';\n\n// Config\nexport { defaultConfig, loadConfigFromEnv } from './config.js';\nexport type { Config } from './config.js';\n\n// Protocol\nexport {\n encodeMessage,\n decodeMessage,\n splitWirePayload,\n extractSootheLoopID,\n newRequestID,\n newLoopInputMessage,\n newLoopNewMessage,\n newLoopSubscribeMessage,\n} from './protocol.js';\nexport type {\n BaseMessage,\n LoopInputMessage,\n CommandMessage,\n DaemonStatusMessage,\n DaemonShutdownMessage,\n ConfigGetMessage,\n LoopNewMessage,\n LoopNewOptions,\n LoopSubscribeMessage,\n LoopDetachMessage,\n LoopListMessage,\n LoopGetMessage,\n LoopTreeMessage,\n LoopPruneMessage,\n LoopDeleteMessage,\n LoopReattachMessage,\n SkillsListMessage,\n ModelsListMessage,\n InvokeSkillMessage,\n DetachMessage,\n EventMessage,\n StatusResponse,\n SubscriptionConfirmedResponse,\n ErrorResponse,\n DaemonReadyResponse,\n DaemonStatusResponse,\n ShutdownAckResponse,\n LoopNewResponse,\n LoopSubscribeResponse,\n LoopDetachResponse,\n LoopListResponse,\n LoopGetResponse,\n LoopTreeResponse,\n LoopPruneResponse,\n LoopDeleteResponse,\n LoopReattachResponse,\n HistoryReplayMessage,\n HistoryReplayCompleteMessage,\n SkillsListResponse,\n ModelsListResponse,\n DecodedMessage,\n} from './protocol.js';\n\n// Events\nexport {\n EventPlanCreated,\n EventExploreStarted,\n EventExploreMilestone,\n EventExploreStepCompleted,\n EventExploreCompleted,\n EventTacitusStarted,\n EventTacitusGatherSummary,\n EventTacitusCompleted,\n EventReplayComplete,\n EventLoopReattachedWire,\n EventAgentLoopReasoned,\n EventToolStarted,\n EventToolCompleted,\n EventToolError,\n EventStreamToolCallUpdate,\n EventToolCallUpdatesBatch,\n EventAgentLoopStarted,\n EventAgentLoopIterated,\n EventAgentLoopCompleted,\n EventMessageReceived,\n EventMessageSent,\n EventFinalReport,\n EventGeneralFailed,\n parseNamespace,\n classifyEventVerbosity,\n isCompletionEvent,\n isSubagentProgressEvent,\n ESSENTIAL_EVENT_TYPES,\n} from './events.js';\n\n// Client\nexport { Client } from './client.js';\nexport type { InputOptions } from './client.js';\n\n// Helpers\nexport {\n checkDaemonStatus,\n isDaemonLive,\n requestDaemonShutdown,\n fetchSkillsCatalog,\n fetchConfigSection,\n} from './helpers.js';\n\n// Session\nexport {\n bootstrapLoopSession,\n waitDaemonReady,\n waitLoopStatusWithID,\n waitSubscriptionConfirmed,\n connectWithRetries,\n} from './session.js';","/**\n * Custom error types for the Soothe client.\n */\n\n/** Represents a WebSocket connection failure. */\nexport class ConnectionError extends Error {\n readonly url: string;\n readonly attempt: number;\n readonly cause: Error;\n\n constructor(url: string, attempt: number, cause: Error) {\n super(`connection error to ${url} (attempt ${attempt}): ${cause.message}`);\n this.name = 'ConnectionError';\n this.url = url;\n this.attempt = attempt;\n this.cause = cause;\n }\n}\n\n/** Represents an error reported by the Soothe daemon. */\nexport class DaemonError extends Error {\n readonly code: string;\n /** The daemon's error message text. */\n readonly daemonMessage: string;\n\n constructor(code: string, message: string) {\n super(`daemon error [${code}]: ${message}`);\n this.name = 'DaemonError';\n this.code = code;\n this.daemonMessage = message;\n }\n}\n\n/** Represents a timeout waiting for a daemon response. */\nexport class TimeoutError extends Error {\n readonly operation: string;\n readonly duration: string;\n\n constructor(operation: string, duration: string) {\n super(`timeout after ${duration} waiting for ${operation}`);\n this.name = 'TimeoutError';\n this.operation = operation;\n this.duration = duration;\n }\n}\n","/**\n * Verbosity levels and tiers for event filtering.\n */\n\n/** User-configurable verbosity setting. */\nexport type VerbosityLevel = 'quiet' | 'normal' | 'debug';\n\n/** Minimum verbosity level at which content is visible. */\nexport enum VerbosityTier {\n /** Always visible (errors, assistant text, final reports) */\n Quiet = 0,\n /** Standard progress (plan updates, milestones, agentic loop) */\n Normal = 1,\n /** Detailed internals (protocol events, tool calls, subagent activity) */\n Detailed = 2,\n /** Everything including internals (thinking, heartbeats) */\n Debug = 3,\n /** Never shown at any level (implementation details) */\n Internal = 99,\n}\n\nconst verbosityLevelValues: Record<VerbosityLevel, number> = {\n quiet: 0,\n normal: 1,\n debug: 3,\n};\n\n/** Returns true if content at the given tier is visible at the given verbosity. */\nexport function shouldShow(tier: VerbosityTier, verbosity: VerbosityLevel): boolean {\n if (tier === VerbosityTier.Internal) {\n return false;\n }\n const level = verbosityLevelValues[verbosity] ?? 1; // default to normal\n return tier <= level;\n}\n\n/** Checks whether a string is a valid verbosity level. */\nexport function isValidVerbosityLevel(s: string): s is VerbosityLevel {\n return s in verbosityLevelValues;\n}\n","/**\n * Client-facing event namespace constants for the Soothe daemon wire protocol.\n *\n * Internal catalog types (`soothe.internal.*`) are server-only and are never\n * broadcast to WebSocket clients. Do not add them here.\n *\n * Format: soothe.<domain>.<component>.<action>\n */\n\nimport { VerbosityTier } from './verbosity.js';\n\n// Plan events (client UX)\nexport const EventPlanCreated = 'soothe.cognition.plan.created';\n\n// Explore subagent events (built-in wire, IG-339)\nexport const EventExploreStarted = 'soothe.subagent.explore.started';\nexport const EventExploreMilestone = 'soothe.subagent.explore.milestone';\nexport const EventExploreStepCompleted = 'soothe.subagent.explore.step.completed';\nexport const EventExploreCompleted = 'soothe.subagent.explore.completed';\n\n// Tacitus subagent events (built-in wire, IG-339)\nexport const EventTacitusStarted = 'soothe.subagent.tacitus.started';\nexport const EventTacitusGatherSummary = 'soothe.subagent.tacitus.gather.summary';\nexport const EventTacitusCompleted = 'soothe.subagent.tacitus.completed';\n\n// Control-plane wire envelopes (not soothe.* catalog events)\nexport const EventReplayComplete = 'replay_complete';\nexport const EventLoopReattachedWire = 'loop_reattached';\n\n// Tool events\nexport const EventToolStarted = 'soothe.tool.execution.started';\nexport const EventToolCompleted = 'soothe.tool.execution.completed';\nexport const EventToolError = 'soothe.tool.execution.error';\n\n// Stream tool call events (RFC-450, IG-416)\nexport const EventStreamToolCallUpdate = 'soothe.stream.tool_call.update';\nexport const EventToolCallUpdatesBatch = 'tool_call_updates_batch';\n\n// Agent loop events (cognition domain)\nexport const EventAgentLoopStarted = 'soothe.cognition.agent_loop.started';\nexport const EventAgentLoopIterated = 'soothe.cognition.agent_loop.iterated';\nexport const EventAgentLoopCompleted = 'soothe.cognition.agent_loop.completed';\nexport const EventAgentLoopReasoned = 'soothe.cognition.agent_loop.reasoned';\n\n// Message protocol events (client stream metadata)\nexport const EventMessageReceived = 'soothe.protocol.message.received';\nexport const EventMessageSent = 'soothe.protocol.message.sent';\n\n// Output events\nexport const EventFinalReport = 'soothe.output.autonomous.final_report.reported';\n\n// Error events\nexport const EventGeneralFailed = 'soothe.error.general.failed';\n\n// ---------------------------------------------------------------------------\n// Namespace parsing\n// ---------------------------------------------------------------------------\n\n/** Splits a 4-segment event namespace into domain, component, and action. */\nexport function parseNamespace(ns: string): { domain: string; component: string; action: string } | null {\n const parts = splitNamespace(ns);\n if (parts.length < 4 || parts[0] !== 'soothe') {\n return null;\n }\n if (parts[1] === 'internal') {\n return null;\n }\n return { domain: parts[1], component: parts[2], action: parts[3] };\n}\n\nfunction splitNamespace(ns: string): string[] {\n const parts: string[] = [];\n let start = 0;\n for (let i = 0; i < ns.length; i++) {\n if (ns[i] === '.') {\n parts.push(ns.slice(start, i));\n start = i + 1;\n }\n }\n parts.push(ns.slice(start));\n return parts;\n}\n\n// ---------------------------------------------------------------------------\n// Classification\n// ---------------------------------------------------------------------------\n\n/** Returns the VerbosityTier for a given event type string. */\nexport function classifyEventVerbosity(eventTypeOrNamespace: string): VerbosityTier {\n const parsed = parseNamespace(eventTypeOrNamespace);\n if (!parsed) {\n return classifyByEventTypeString(eventTypeOrNamespace);\n }\n return classifyByDomainAndComponent(parsed.domain, parsed.component, eventTypeOrNamespace);\n}\n\nfunction classifyByDomainAndComponent(domain: string, _component: string, full: string): VerbosityTier {\n switch (domain) {\n case 'cognition':\n return VerbosityTier.Normal;\n case 'protocol':\n return VerbosityTier.Detailed;\n case 'tool':\n return VerbosityTier.Internal;\n case 'subagent':\n return classifySubagentEvent(full);\n case 'output':\n case 'error':\n return VerbosityTier.Quiet;\n default:\n return VerbosityTier.Normal;\n }\n}\n\nfunction classifySubagentEvent(full: string): VerbosityTier {\n const parsed = parseNamespace(full);\n if (!parsed) return VerbosityTier.Normal;\n switch (parsed.action) {\n case 'started':\n case 'completed':\n return VerbosityTier.Normal;\n default:\n return VerbosityTier.Detailed;\n }\n}\n\nfunction classifyByEventTypeString(eventType: string): VerbosityTier {\n if (eventType === EventFinalReport || eventType === EventGeneralFailed) {\n return VerbosityTier.Quiet;\n }\n if (eventType === EventToolStarted) {\n return VerbosityTier.Internal;\n }\n return VerbosityTier.Normal;\n}\n\n// ---------------------------------------------------------------------------\n// Event classification helpers\n// ---------------------------------------------------------------------------\n\n/** Event types that represent completion milestones. */\nexport function isCompletionEvent(eventType: string): boolean {\n return (\n eventType.endsWith('.completed') ||\n eventType.endsWith('.failed') ||\n eventType === EventGeneralFailed\n );\n}\n\n/** Lifecycle subagent events (started/completed) for progress UI. */\nexport function isSubagentProgressEvent(eventType: string): boolean {\n const parsed = parseNamespace(eventType);\n if (!parsed || parsed.domain !== 'subagent') {\n return false;\n }\n return parsed.action === 'started' || parsed.action === 'completed';\n}\n\n/** Essential progress event types for minimal UI surfaces. */\nexport const ESSENTIAL_EVENT_TYPES: ReadonlySet<string> = new Set([\n EventAgentLoopStarted,\n EventAgentLoopCompleted,\n EventAgentLoopReasoned,\n EventPlanCreated,\n EventExploreStarted,\n EventExploreCompleted,\n EventTacitusStarted,\n EventTacitusCompleted,\n EventGeneralFailed,\n]);\n","/**\n * Convenience RPC helper functions for the Soothe client.\n */\n\nimport type { Client } from './client.js';\nimport { defaultConfig } from './config.js';\n\n/** Checks daemon status via RPC. */\nexport async function checkDaemonStatus(client: Client, timeout?: number): Promise<Record<string, unknown>> {\n return client.requestResponse({ type: 'daemon_status' }, 'daemon_status_response', timeout ?? 5_000);\n}\n\n/** Performs a composite health check: connect + status RPC. */\nexport async function isDaemonLive(wsURL: string, timeout?: number): Promise<boolean> {\n const { Client } = await import('./client.js');\n const t = timeout ?? 5_000;\n const client = new Client(wsURL, defaultConfig());\n\n try {\n await client.connect();\n } catch {\n return false;\n }\n\n try {\n await checkDaemonStatus(client, t);\n return true;\n } catch {\n return false;\n } finally {\n client.close();\n }\n}\n\n/** Requests daemon shutdown via RPC. */\nexport async function requestDaemonShutdown(client: Client, timeout?: number): Promise<void> {\n const resp = await client.requestResponse({ type: 'daemon_shutdown' }, 'shutdown_ack', timeout ?? 10_000);\n if (resp.status !== 'acknowledged') {\n throw new Error(`shutdown not acknowledged: ${JSON.stringify(resp)}`);\n }\n}\n\n/** Fetches the skills catalog via RPC. */\nexport async function fetchSkillsCatalog(client: Client, timeout?: number): Promise<Record<string, unknown>[]> {\n const resp = await client.requestResponse({ type: 'skills_list' }, 'skills_list_response', timeout ?? 15_000);\n const skillsRaw = resp.skills;\n if (!skillsRaw || !Array.isArray(skillsRaw)) return [];\n return skillsRaw.filter((s): s is Record<string, unknown> => typeof s === 'object' && s !== null);\n}\n\n/** Fetches a daemon config section via RPC. */\nexport async function fetchConfigSection(client: Client, section: string, timeout?: number): Promise<Record<string, unknown>> {\n const resp = await client.requestResponse({ type: 'config_get', section }, 'config_get_response', timeout ?? 5_000);\n const sec = resp[section];\n if (sec && typeof sec === 'object') {\n return sec as Record<string, unknown>;\n }\n return resp;\n}\n","/**\n * Session bootstrap flows, wait helpers, and connect-with-retries.\n */\n\nimport type { Client } from './client.js';\nimport type { Config } from './config.js';\nimport { defaultConfig } from './config.js';\nimport type { DecodedMessage, LoopNewOptions, StatusResponse, ErrorResponse } from './protocol.js';\nimport { newLoopNewMessage } from './protocol.js';\n\n// ---------------------------------------------------------------------------\n// Bootstrap flows (loop-first, RFC-503)\n// ---------------------------------------------------------------------------\n\n/** Daemon ready → loop_new (or reuse id) → loop_subscribe; returns loop id. */\nexport async function bootstrapLoopSession(\n client: Client,\n resumeLoopId: string | null | undefined,\n config?: Config,\n loopNew?: LoopNewOptions,\n): Promise<string> {\n const cfg = config ?? defaultConfig();\n\n await client.sendMessage({ type: 'daemon_ready' });\n await waitDaemonReady(client, cfg.daemonReadyTimeout);\n\n let loopId = (resumeLoopId ?? '').trim();\n if (!loopId) {\n const newResp = await client.requestResponse(\n newLoopNewMessage(loopNew) as unknown as Record<string, unknown>,\n 'loop_new_response',\n cfg.loopStatusTimeout,\n );\n loopId = String(newResp.loop_id ?? '').trim();\n if (!loopId) {\n throw new Error('loop_new_response missing loop_id');\n }\n }\n\n const subResp = await client.requestResponse(\n { type: 'loop_subscribe', loop_id: loopId, verbosity: cfg.verbosityLevel },\n 'loop_subscribe_response',\n cfg.subscriptionTimeout,\n );\n if (subResp.success === false) {\n throw new Error(String(subResp.message ?? 'loop_subscribe failed'));\n }\n\n return loopId;\n}\n\n// ---------------------------------------------------------------------------\n// Wait helpers (use client's readEventWithTimeout internally)\n// ---------------------------------------------------------------------------\n\n/** Blocks until a daemon_ready message with state == \"ready\". */\nexport async function waitDaemonReady(\n client: Client,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === 'daemon_ready') {\n if (ev.state === 'ready') return;\n throw new Error(\n `daemon not ready: state=${JSON.stringify(ev.state)} message=${JSON.stringify(ev.message ?? '')}`,\n );\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for daemon_ready (state=ready)`);\n}\n\n/** Waits for daemon_ready using messages from an ``AsyncIterable`` (e.g. ``receiveMessages()``). */\nexport async function waitDaemonReadyFromStream(\n eventStream: AsyncIterable<DecodedMessage>,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n for await (const msg of eventStream) {\n if (msg && typeof msg === 'object') {\n const m = msg as Record<string, unknown>;\n if (m.type === 'daemon_ready') {\n if (m.state === 'ready') return;\n throw new Error(\n `daemon not ready: state=${JSON.stringify(m.state)} message=${JSON.stringify(m.message ?? '')}`,\n );\n }\n }\n if (Date.now() >= deadline) break;\n }\n throw new Error(`timeout after ${timeout}ms waiting for daemon_ready (state=ready)`);\n}\n\n/** Waits for a status message with a non-empty ``loop_id``. */\nexport async function waitLoopStatusWithID(\n client: Client,\n timeout: number,\n): Promise<StatusResponse> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n\n if (ev.type === 'error') {\n const errResp = ev as unknown as ErrorResponse;\n throw new Error(`daemon error: ${errResp.code}: ${errResp.message}`);\n }\n\n if (ev.type === 'status') {\n const status = ev as unknown as StatusResponse;\n const lid = status.loop_id;\n if (lid && lid !== '') {\n return status;\n }\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for status with loop_id`);\n}\n\n/** Waits for subscription_confirmed or loop_subscribe_response matching loop id. */\nexport async function waitSubscriptionConfirmed(\n client: Client,\n wantLoopID: string,\n _wantVerbosity: string,\n timeout: number,\n): Promise<void> {\n const deadline = Date.now() + timeout;\n while (Date.now() < deadline) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const ev = (await client.readEventWithTimeout(remaining)) as Record<string, unknown> | null;\n if (ev === null) break;\n if (ev.type === 'loop_subscribe_response' && ev.success === true) {\n if (String(ev.loop_id ?? '') === wantLoopID) return;\n }\n if (ev.type === 'subscription_confirmed') {\n const lid = String((ev as { loop_id?: string }).loop_id ?? '');\n if (lid === wantLoopID) return;\n }\n }\n throw new Error(`timeout after ${timeout}ms waiting for subscription_confirmed`);\n}\n\n// ---------------------------------------------------------------------------\n// Connect with retries\n// ---------------------------------------------------------------------------\n\n/** Attempts to connect to the Soothe daemon with bounded retries. */\nexport async function connectWithRetries(\n client: Client,\n maxRetries?: number,\n retryDelay?: number,\n): Promise<void> {\n const retries = maxRetries && maxRetries > 0 ? maxRetries : 40;\n const delay = retryDelay && retryDelay > 0 ? retryDelay : 250;\n\n let lastErr: Error | null = null;\n for (let attempt = 0; attempt < retries; attempt++) {\n try {\n await client.connect();\n return;\n } catch (err) {\n lastErr = err as Error;\n }\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n throw new Error(`failed to connect after ${retries} attempts: ${lastErr?.message ?? 'unknown error'}`);\n}"],"mappings":"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","names":["WebSocket","msg","VerbosityTier","Client"]}