@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/client.ts","../src/config.ts","../src/protocol.ts"],"sourcesContent":["/**\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 * 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}"],"mappings":"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","names":["msg"]}
@@ -0,0 +1,7 @@
1
+ import {
2
+ Client
3
+ } from "./chunk-OMAC7LA7.js";
4
+ export {
5
+ Client
6
+ };
7
+ //# sourceMappingURL=client-QS23U6WX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}