@soederpop/luca 0.0.26 → 0.0.29

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.
@@ -1,7 +1,7 @@
1
1
  import { setBuildTimeData, setContainerBuildTimeData } from './index.js';
2
2
 
3
3
  // Auto-generated introspection registry data
4
- // Generated at: 2026-03-22T20:57:23.101Z
4
+ // Generated at: 2026-03-24T01:41:39.147Z
5
5
 
6
6
  setBuildTimeData('features.googleDocs', {
7
7
  "id": "features.googleDocs",
@@ -1525,7 +1525,7 @@ setBuildTimeData('features.downloader', {
1525
1525
 
1526
1526
  setBuildTimeData('features.windowManager', {
1527
1527
  "id": "features.windowManager",
1528
- "description": "WindowManager Feature — Native window control via LucaVoiceLauncher Acts as an IPC server that the native macOS launcher app connects to. Communicates over a Unix domain socket using NDJSON (newline-delimited JSON). **Protocol:** - Bun listens on a Unix domain socket; the native app connects as a client - Window dispatch commands are sent as NDJSON with a `window` field - The app executes window commands and sends back `windowAck` messages - Any non-windowAck message from the app is emitted as a `message` event - Other features can use `send()` to write arbitrary NDJSON to the app **Capabilities:** - Spawn native browser windows with configurable chrome - Navigate, focus, close, and eval JavaScript in windows - Automatic socket file cleanup and fallback paths",
1528
+ "description": "WindowManager Feature — Native window control via LucaVoiceLauncher Uses a broker/producer architecture so multiple luca processes can trigger window operations without competing for the same Unix socket. **Architecture:** - The first process to call `listen()` becomes the **broker**. It owns the app-facing socket (`ipc-window.sock`) and a control socket (`ipc-window-control.sock`). - Subsequent processes detect the broker and become **producers**. They connect to the control socket and route commands through the broker. - The broker forwards producer commands to the native app and routes acks and lifecycle events back to the originating producer. **Protocol:** - Bun listens on a Unix domain socket; the native app connects as a client - Window dispatch commands are sent as NDJSON with a `window` field - The app executes window commands and sends back `windowAck` messages - Any non-windowAck message from the app is emitted as a `message` event - Other features can use `send()` to write arbitrary NDJSON to the app **Capabilities:** - Spawn native browser windows with configurable chrome - Navigate, focus, close, and eval JavaScript in windows - Multiple luca processes can trigger window operations simultaneously - Automatic broker detection and producer fallback Observable state includes `windows` (open window metadata), `pendingOperations` (in-flight command ids), and `producerCount` (broker). Sockets, promises, and `WindowHandle` instances stay internal. **Producer state:** The broker pushes `windowStateSync` on the control socket when a producer connects and whenever the window roster changes, so every process sees the same `windows` / `windowCount` / `clientConnected` as the broker (not only its own acks).",
1529
1529
  "shortcut": "features.windowManager",
1530
1530
  "className": "WindowManager",
1531
1531
  "methods": {
@@ -1541,7 +1541,18 @@ setBuildTimeData('features.windowManager', {
1541
1541
  "returns": "Promise<this>"
1542
1542
  },
1543
1543
  "listen": {
1544
- "description": "Start listening on the Unix domain socket for the native app to connect. Fire-and-forget binds the socket and returns immediately. Sits quietly until the native app connects; does nothing visible if it never does.",
1544
+ "description": "Start the window manager. Automatically detects whether a broker already exists and either becomes the broker or connects as a producer. - If no broker is running: becomes the broker, binds the app socket and a control socket for producers. - If a broker is already running: connects as a producer through the control socket.",
1545
+ "parameters": {
1546
+ "socketPath": {
1547
+ "type": "string",
1548
+ "description": "Override the configured app socket path"
1549
+ }
1550
+ },
1551
+ "required": [],
1552
+ "returns": "Promise<this>"
1553
+ },
1554
+ "cleanupSocket": {
1555
+ "description": "Remove stale socket files without starting or stopping the server. Useful when a previous process crashed and left dead sockets behind. Will not remove sockets that have live listeners.",
1545
1556
  "parameters": {
1546
1557
  "socketPath": {
1547
1558
  "type": "string",
@@ -1549,10 +1560,10 @@ setBuildTimeData('features.windowManager', {
1549
1560
  }
1550
1561
  },
1551
1562
  "required": [],
1552
- "returns": "this"
1563
+ "returns": "Promise<boolean>"
1553
1564
  },
1554
1565
  "stop": {
1555
- "description": "Stop the IPC server and clean up all connections. Rejects any pending window operation requests.",
1566
+ "description": "Stop the window manager and clean up all connections. Rejects any pending window operation requests.",
1556
1567
  "parameters": {},
1557
1568
  "required": [],
1558
1569
  "returns": "Promise<this>"
@@ -1825,7 +1836,7 @@ setBuildTimeData('features.windowManager', {
1825
1836
  ]
1826
1837
  },
1827
1838
  "send": {
1828
- "description": "Write an NDJSON message to the connected app client. Public so other features can send arbitrary protocol messages over the same socket.",
1839
+ "description": "Write an NDJSON message to the connected app client. In producer mode, routes through the broker. Public so other features can send arbitrary protocol messages over the same socket.",
1829
1840
  "parameters": {
1830
1841
  "msg": {
1831
1842
  "type": "Record<string, any>",
@@ -1839,12 +1850,20 @@ setBuildTimeData('features.windowManager', {
1839
1850
  }
1840
1851
  },
1841
1852
  "getters": {
1853
+ "isBroker": {
1854
+ "description": "Whether this instance is acting as the broker.",
1855
+ "returns": "boolean"
1856
+ },
1857
+ "isProducer": {
1858
+ "description": "Whether this instance is acting as a producer.",
1859
+ "returns": "boolean"
1860
+ },
1842
1861
  "isListening": {
1843
- "description": "Whether the IPC server is currently listening.",
1862
+ "description": "Whether the IPC server is currently listening (broker) or connected to broker (producer).",
1844
1863
  "returns": "boolean"
1845
1864
  },
1846
1865
  "isClientConnected": {
1847
- "description": "Whether the native app client is currently connected.",
1866
+ "description": "Whether the native app client is currently connected (only meaningful for broker).",
1848
1867
  "returns": "boolean"
1849
1868
  }
1850
1869
  },
@@ -1879,6 +1898,11 @@ setBuildTimeData('features.windowManager', {
1879
1898
  "description": "Event emitted by WindowManager",
1880
1899
  "arguments": {}
1881
1900
  },
1901
+ "windowFocus": {
1902
+ "name": "windowFocus",
1903
+ "description": "Event emitted by WindowManager",
1904
+ "arguments": {}
1905
+ },
1882
1906
  "message": {
1883
1907
  "name": "message",
1884
1908
  "description": "Event emitted by WindowManager",
@@ -5749,6 +5773,32 @@ setBuildTimeData('features.fs', {
5749
5773
  }
5750
5774
  ]
5751
5775
  },
5776
+ "isSymlink": {
5777
+ "description": "Checks if a path is a symbolic link.",
5778
+ "parameters": {
5779
+ "path": {
5780
+ "type": "string",
5781
+ "description": "The path to check"
5782
+ }
5783
+ },
5784
+ "required": [
5785
+ "path"
5786
+ ],
5787
+ "returns": "boolean"
5788
+ },
5789
+ "realpath": {
5790
+ "description": "Resolves a symlink to its real path. Returns the resolved path as-is if not a symlink.",
5791
+ "parameters": {
5792
+ "path": {
5793
+ "type": "string",
5794
+ "description": "The path to resolve"
5795
+ }
5796
+ },
5797
+ "required": [
5798
+ "path"
5799
+ ],
5800
+ "returns": "string"
5801
+ },
5752
5802
  "stat": {
5753
5803
  "description": "Synchronously returns the stat object for a file or directory.",
5754
5804
  "parameters": {
@@ -6223,7 +6273,7 @@ setBuildTimeData('features.fs', {
6223
6273
 
6224
6274
  setBuildTimeData('features.ipcSocket', {
6225
6275
  "id": "features.ipcSocket",
6226
- "description": "IpcSocket Feature - Inter-Process Communication via Unix Domain Sockets This feature provides robust IPC (Inter-Process Communication) capabilities using Unix domain sockets. It supports both server and client modes, allowing processes to communicate efficiently through file system-based socket connections. **Key Features:** - Dual-mode operation: server and client functionality - JSON message serialization/deserialization - Multiple client connection support (server mode) - Event-driven message handling - Automatic socket cleanup and management - Broadcast messaging to all connected clients - Lock file management for socket paths **Communication Pattern:** - Messages are automatically JSON-encoded with unique IDs - Both server and client emit 'message' events for incoming data - Server can broadcast to all connected clients - Client maintains single connection to server **Socket Management:** - Automatic cleanup of stale socket files - Connection tracking and management - Graceful shutdown procedures - Lock file protection against conflicts **Usage Examples:** **Server Mode:** ```typescript const ipc = container.feature('ipcSocket'); await ipc.listen('/tmp/myapp.sock', true); // removeLock=true ipc.on('connection', (socket) => { console.log('Client connected'); }); ipc.on('message', (data) => { console.log('Received:', data); ipc.broadcast({ reply: 'ACK', original: data }); }); ``` **Client Mode:** ```typescript const ipc = container.feature('ipcSocket'); await ipc.connect('/tmp/myapp.sock'); ipc.on('message', (data) => { console.log('Server says:', data); }); await ipc.send({ type: 'request', payload: 'hello' }); ```",
6276
+ "description": "IpcSocket Feature - Inter-Process Communication via Unix Domain Sockets This feature provides robust IPC (Inter-Process Communication) capabilities using Unix domain sockets. It supports both server and client modes, allowing processes to communicate efficiently through file system-based socket connections. **Key Features:** - Hub-and-spoke: one server, many named clients with identity tracking - Targeted messaging: sendTo(clientId), broadcast(msg, excludeId) - Request/reply: ask() + reply() with timeout-based correlation - Auto-reconnect: clients reconnect with exponential backoff - Stale socket detection: probeSocket() before listen() - Clean shutdown: stopServer() removes socket file **Server (Hub):** ```typescript const ipc = container.feature('ipcSocket'); await ipc.listen('/tmp/hub.sock', true); ipc.on('connection', (clientId, socket) => { console.log('Client joined:', clientId); }); ipc.on('message', (data, clientId) => { console.log(`From ${clientId}:`, data); // Reply to sender, or ask and wait ipc.sendTo(clientId, { ack: true }); }); ``` **Client (Spoke):** ```typescript const ipc = container.feature('ipcSocket'); await ipc.connect('/tmp/hub.sock', { reconnect: true, name: 'worker-1' }); // Fire and forget await ipc.send({ type: 'status', ready: true }); // Request/reply ipc.on('message', (data) => { if (data.requestId) ipc.reply(data.requestId, { result: 42 }); }); ```",
6227
6277
  "shortcut": "features.ipcSocket",
6228
6278
  "className": "IpcSocket",
6229
6279
  "methods": {
@@ -6263,61 +6313,127 @@ setBuildTimeData('features.ipcSocket', {
6263
6313
  ]
6264
6314
  },
6265
6315
  "broadcast": {
6266
- "description": "Broadcasts a message to all connected clients (server mode only). This method sends a JSON-encoded message with a unique ID to every client currently connected to the server. Each message is automatically wrapped with metadata including a UUID for tracking. **Message Format:** Messages are automatically wrapped in the format: ```json { \"data\": <your_message>, \"id\": \"<uuid>\" } ```",
6316
+ "description": "Broadcasts a message to all connected clients (server mode only).",
6267
6317
  "parameters": {
6268
6318
  "message": {
6269
6319
  "type": "any",
6270
- "description": "The message object to broadcast to all clients"
6320
+ "description": "The message object to broadcast"
6321
+ },
6322
+ "exclude": {
6323
+ "type": "string",
6324
+ "description": "Optional client ID to exclude from broadcast"
6271
6325
  }
6272
6326
  },
6273
6327
  "required": [
6274
6328
  "message"
6275
6329
  ],
6276
- "returns": "void",
6277
- "examples": [
6278
- {
6279
- "language": "ts",
6280
- "code": "// Broadcast to all connected clients\nipc.broadcast({ \n type: 'notification',\n message: 'Server is shutting down in 30 seconds',\n timestamp: Date.now()\n});\n\n// Chain multiple operations\nipc.broadcast({ status: 'ready' })\n .broadcast({ time: new Date().toISOString() });"
6330
+ "returns": "void"
6331
+ },
6332
+ "sendTo": {
6333
+ "description": "Sends a message to a specific client by ID (server mode only).",
6334
+ "parameters": {
6335
+ "clientId": {
6336
+ "type": "string",
6337
+ "description": "The target client ID"
6338
+ },
6339
+ "message": {
6340
+ "type": "any",
6341
+ "description": "The message to send"
6281
6342
  }
6282
- ]
6343
+ },
6344
+ "required": [
6345
+ "clientId",
6346
+ "message"
6347
+ ],
6348
+ "returns": "boolean"
6283
6349
  },
6284
6350
  "send": {
6285
- "description": "Sends a message to the server (client mode only). This method sends a JSON-encoded message with a unique ID to the connected server. The message is automatically wrapped with metadata for tracking purposes. **Message Format:** Messages are automatically wrapped in the format: ```json { \"data\": <your_message>, \"id\": \"<uuid>\" } ```",
6351
+ "description": "Fire-and-forget: sends a message to the server (client mode only). For server→client, use sendTo() or broadcast().",
6286
6352
  "parameters": {
6287
6353
  "message": {
6288
6354
  "type": "any",
6289
- "description": "The message object to send to the server"
6355
+ "description": "The message to send"
6290
6356
  }
6291
6357
  },
6292
6358
  "required": [
6293
6359
  "message"
6294
6360
  ],
6295
- "returns": "void",
6296
- "examples": [
6297
- {
6298
- "language": "ts",
6299
- "code": "// Send a simple message\nawait ipc.send({ type: 'ping' });\n\n// Send complex data\nawait ipc.send({\n type: 'data_update',\n payload: { users: [...], timestamp: Date.now() }\n});"
6361
+ "returns": "void"
6362
+ },
6363
+ "ask": {
6364
+ "description": "Sends a message and waits for a correlated reply. Works in both client and server mode. The recipient should call `reply(requestId, response)` to respond.",
6365
+ "parameters": {
6366
+ "message": {
6367
+ "type": "any",
6368
+ "description": "The message to send"
6369
+ },
6370
+ "options": {
6371
+ "type": "{ clientId?: string; timeoutMs?: number }",
6372
+ "description": "Optional: clientId (server mode target), timeoutMs"
6300
6373
  }
6301
- ]
6374
+ },
6375
+ "required": [
6376
+ "message"
6377
+ ],
6378
+ "returns": "Promise<any>"
6379
+ },
6380
+ "reply": {
6381
+ "description": "Sends a reply to a previous ask() call, correlated by requestId.",
6382
+ "parameters": {
6383
+ "requestId": {
6384
+ "type": "string",
6385
+ "description": "The requestId from the incoming message"
6386
+ },
6387
+ "data": {
6388
+ "type": "any",
6389
+ "description": "The reply payload"
6390
+ },
6391
+ "clientId": {
6392
+ "type": "string",
6393
+ "description": "Target client (server mode; for client mode, omit)"
6394
+ }
6395
+ },
6396
+ "required": [
6397
+ "requestId",
6398
+ "data"
6399
+ ],
6400
+ "returns": "void"
6302
6401
  },
6303
6402
  "connect": {
6304
- "description": "Connects to an IPC server at the specified socket path (client mode). This method establishes a client connection to an existing IPC server. Once connected, the client can send messages to the server and receive responses. The connection is maintained until explicitly closed or the server terminates. **Connection Behavior:** - Sets the socket mode to 'client' - Returns existing connection if already connected - Automatically handles connection events and cleanup - JSON-parses incoming messages and emits 'message' events - Cleans up connection reference when socket closes **Error Handling:** - Throws error if already in server mode - Rejects promise on connection failures - Automatically cleans up on connection close",
6403
+ "description": "Connects to an IPC server at the specified socket path (client mode).",
6305
6404
  "parameters": {
6306
6405
  "socketPath": {
6307
6406
  "type": "string",
6308
- "description": "The file system path to the server's Unix domain socket"
6407
+ "description": "Path to the server's Unix domain socket"
6408
+ },
6409
+ "options": {
6410
+ "type": "{ reconnect?: boolean; name?: string }",
6411
+ "description": "Optional: reconnect (enable auto-reconnect), name (identify this client)"
6309
6412
  }
6310
6413
  },
6311
6414
  "required": [
6312
6415
  "socketPath"
6313
6416
  ],
6314
- "returns": "Promise<Socket>",
6315
- "examples": [
6316
- {
6317
- "language": "ts",
6318
- "code": "// Connect to server\nconst socket = await ipc.connect('/tmp/myapp.sock');\nconsole.log('Connected to IPC server');\n\n// Handle incoming messages\nipc.on('message', (data) => {\n console.log('Server message:', data);\n});\n\n// Send messages\nawait ipc.send({ type: 'hello', client_id: 'client_001' });"
6417
+ "returns": "Promise<Socket>"
6418
+ },
6419
+ "disconnect": {
6420
+ "description": "Disconnects the client and stops any reconnection attempts.",
6421
+ "parameters": {},
6422
+ "required": [],
6423
+ "returns": "void"
6424
+ },
6425
+ "probeSocket": {
6426
+ "description": "Probe an existing socket to see if a live listener is behind it. Attempts a quick connect — if it succeeds, someone is listening.",
6427
+ "parameters": {
6428
+ "socketPath": {
6429
+ "type": "string",
6430
+ "description": "Parameter socketPath"
6319
6431
  }
6320
- ]
6432
+ },
6433
+ "required": [
6434
+ "socketPath"
6435
+ ],
6436
+ "returns": "Promise<boolean>"
6321
6437
  }
6322
6438
  },
6323
6439
  "getters": {
@@ -6329,12 +6445,25 @@ setBuildTimeData('features.ipcSocket', {
6329
6445
  "description": "Checks if the IPC socket is operating in server mode.",
6330
6446
  "returns": "any"
6331
6447
  },
6448
+ "clientCount": {
6449
+ "description": "Returns the number of currently connected clients (server mode).",
6450
+ "returns": "any"
6451
+ },
6452
+ "connectedClients": {
6453
+ "description": "Returns info about all connected clients (server mode).",
6454
+ "returns": "Array<{ id: string; name?: string; connectedAt: number }>"
6455
+ },
6332
6456
  "connection": {
6333
6457
  "description": "Gets the current client connection socket.",
6334
6458
  "returns": "any"
6335
6459
  }
6336
6460
  },
6337
6461
  "events": {
6462
+ "disconnection": {
6463
+ "name": "disconnection",
6464
+ "description": "Event emitted by IpcSocket",
6465
+ "arguments": {}
6466
+ },
6338
6467
  "connection": {
6339
6468
  "name": "connection",
6340
6469
  "description": "Event emitted by IpcSocket",
@@ -7255,10 +7384,68 @@ setBuildTimeData('features.packageFinder', {
7255
7384
 
7256
7385
  setBuildTimeData('features.processManager', {
7257
7386
  "id": "features.processManager",
7258
- "description": "Manages long-running child processes with tracking, events, and automatic cleanup. Unlike the `proc` feature whose spawn methods block until the child exits, ProcessManager returns a SpawnHandler immediately — a handle object with its own state, events, and lifecycle methods. The feature tracks all spawned processes, maintains observable state, and can automatically kill them on parent exit.",
7387
+ "description": "Manages long-running child processes with tracking, events, and automatic cleanup. Unlike the `proc` feature whose spawn methods block until the child exits, ProcessManager returns a SpawnHandler immediately — a handle object with its own state, events, and lifecycle methods. The feature tracks all spawned processes, maintains observable state, and can automatically kill them on parent exit. Each handler maintains a memory-efficient output buffer: the first 20 lines (head) and last 50 lines (tail) of stdout/stderr are kept, everything in between is discarded.",
7259
7388
  "shortcut": "features.processManager",
7260
7389
  "className": "ProcessManager",
7261
7390
  "methods": {
7391
+ "spawnProcess": {
7392
+ "description": "Tool handler: spawn a long-running background process.",
7393
+ "parameters": {
7394
+ "args": {
7395
+ "type": "{ command: string; args?: string; tag?: string; cwd?: string }",
7396
+ "description": "Parameter args"
7397
+ }
7398
+ },
7399
+ "required": [
7400
+ "args"
7401
+ ],
7402
+ "returns": "void"
7403
+ },
7404
+ "runCommand": {
7405
+ "description": "Tool handler: run a command to completion and return its output.",
7406
+ "parameters": {
7407
+ "args": {
7408
+ "type": "{ command: string; cwd?: string }",
7409
+ "description": "Parameter args"
7410
+ }
7411
+ },
7412
+ "required": [
7413
+ "args"
7414
+ ],
7415
+ "returns": "void"
7416
+ },
7417
+ "listProcesses": {
7418
+ "description": "Tool handler: list all tracked processes.",
7419
+ "parameters": {},
7420
+ "required": [],
7421
+ "returns": "void"
7422
+ },
7423
+ "getProcessOutput": {
7424
+ "description": "Tool handler: peek at a process's buffered output.",
7425
+ "parameters": {
7426
+ "args": {
7427
+ "type": "{ id?: string; tag?: string; stream?: string }",
7428
+ "description": "Parameter args"
7429
+ }
7430
+ },
7431
+ "required": [
7432
+ "args"
7433
+ ],
7434
+ "returns": "void"
7435
+ },
7436
+ "killProcess": {
7437
+ "description": "Tool handler: kill a process by ID or tag.",
7438
+ "parameters": {
7439
+ "args": {
7440
+ "type": "{ id?: string; tag?: string; signal?: string }",
7441
+ "description": "Parameter args"
7442
+ }
7443
+ },
7444
+ "required": [
7445
+ "args"
7446
+ ],
7447
+ "returns": "void"
7448
+ },
7262
7449
  "spawn": {
7263
7450
  "description": "Spawn a long-running process and return a handle immediately. The returned SpawnHandler provides events for stdout/stderr streaming, exit/crash notifications, and methods to kill or await the process.",
7264
7451
  "parameters": {
@@ -7436,7 +7623,7 @@ setBuildTimeData('features.processManager', {
7436
7623
  "examples": [
7437
7624
  {
7438
7625
  "language": "ts",
7439
- "code": "const pm = container.feature('processManager', { enable: true })\n\nconst server = pm.spawn('node', ['server.js'], { tag: 'api', cwd: '/app' })\nserver.on('stdout', (data) => console.log('[api]', data))\nserver.on('crash', (code) => console.error('API crashed:', code))\n\n// Kill one\nserver.kill()\n\n// Kill all tracked processes\npm.killAll()\n\n// List and lookup\npm.list() // SpawnHandler[]\npm.getByTag('api') // SpawnHandler | undefined"
7626
+ "code": "const pm = container.feature('processManager', { enable: true })\n\nconst server = pm.spawn('node', ['server.js'], { tag: 'api', cwd: '/app' })\nserver.on('stdout', (data) => console.log('[api]', data))\nserver.on('crash', (code) => console.error('API crashed:', code))\n\n// Peek at buffered output\nconst { head, tail } = server.peek()\n\n// Kill one\nserver.kill()\n\n// Kill all tracked processes\npm.killAll()\n\n// List and lookup\npm.list() // SpawnHandler[]\npm.getByTag('api') // SpawnHandler | undefined"
7440
7627
  }
7441
7628
  ]
7442
7629
  });
@@ -9805,7 +9992,7 @@ setBuildTimeData('clients.rest', {
9805
9992
 
9806
9993
  setBuildTimeData('clients.websocket', {
9807
9994
  "id": "clients.websocket",
9808
- "description": "WebSocket client that bridges raw WebSocket events to Luca's Helper event bus, providing a clean interface for sending/receiving messages, tracking connection state, and optional auto-reconnection with exponential backoff. Events emitted: - `open` — connection established - `message` — message received (JSON-parsed when possible) - `close` — connection closed (with code and reason) - `error` — connection error - `reconnecting` — attempting reconnection (with attempt number)",
9995
+ "description": "WebSocketClient helper",
9809
9996
  "shortcut": "clients.websocket",
9810
9997
  "className": "WebSocketClient",
9811
9998
  "methods": {
@@ -9828,6 +10015,59 @@ setBuildTimeData('clients.websocket', {
9828
10015
  ],
9829
10016
  "returns": "Promise<void>"
9830
10017
  },
10018
+ "ask": {
10019
+ "description": "Send a request and wait for a correlated response. The message is sent with a unique `requestId`; the remote side is expected to reply with a message containing `replyTo` set to that same ID.",
10020
+ "parameters": {
10021
+ "type": {
10022
+ "type": "string",
10023
+ "description": "A string identifying the request type"
10024
+ },
10025
+ "data": {
10026
+ "type": "any",
10027
+ "description": "Optional payload to include with the request"
10028
+ },
10029
+ "timeout": {
10030
+ "type": "any",
10031
+ "description": "How long to wait for a response (default 10 000 ms)"
10032
+ }
10033
+ },
10034
+ "required": [
10035
+ "type"
10036
+ ],
10037
+ "returns": "Promise<R>",
10038
+ "examples": [
10039
+ {
10040
+ "language": "ts",
10041
+ "code": "const result = await ws.ask('getUser', { id: 42 })"
10042
+ }
10043
+ ]
10044
+ },
10045
+ "_handleReply": {
10046
+ "description": "",
10047
+ "parameters": {
10048
+ "message": {
10049
+ "type": "any",
10050
+ "description": "Parameter message"
10051
+ }
10052
+ },
10053
+ "required": [
10054
+ "message"
10055
+ ],
10056
+ "returns": "boolean"
10057
+ },
10058
+ "_rejectAllPending": {
10059
+ "description": "",
10060
+ "parameters": {
10061
+ "reason": {
10062
+ "type": "string",
10063
+ "description": "Parameter reason"
10064
+ }
10065
+ },
10066
+ "required": [
10067
+ "reason"
10068
+ ],
10069
+ "returns": "void"
10070
+ },
9831
10071
  "disconnect": {
9832
10072
  "description": "Gracefully close the WebSocket connection. Suppresses auto-reconnect and updates connection state to disconnected.",
9833
10073
  "parameters": {},
@@ -9870,13 +10110,7 @@ setBuildTimeData('clients.websocket', {
9870
10110
  },
9871
10111
  "state": {},
9872
10112
  "options": {},
9873
- "envVars": [],
9874
- "examples": [
9875
- {
9876
- "language": "ts",
9877
- "code": "const ws = container.client('websocket', {\n baseURL: 'ws://localhost:8080',\n reconnect: true,\n maxReconnectAttempts: 5\n})\nws.on('message', (data) => console.log('Received:', data))\nawait ws.connect()\nawait ws.send({ type: 'hello' })"
9878
- }
9879
- ]
10113
+ "envVars": []
9880
10114
  });
9881
10115
 
9882
10116
  setBuildTimeData('clients.openai', {
@@ -10147,220 +10381,18 @@ setBuildTimeData('clients.openai', {
10147
10381
  ]
10148
10382
  });
10149
10383
 
10150
- setBuildTimeData('clients.elevenlabs', {
10151
- "id": "clients.elevenlabs",
10152
- "description": "ElevenLabs client text-to-speech synthesis via the ElevenLabs REST API. Provides methods for listing voices, listing models, and generating speech audio. Audio is returned as a Buffer; use `say()` for a convenience method that writes to disk.",
10153
- "shortcut": "clients.elevenlabs",
10154
- "className": "ElevenLabsClient",
10384
+ setBuildTimeData('clients.supabase', {
10385
+ "id": "clients.supabase",
10386
+ "description": "Supabase client for the Luca container system. Wraps the official `@supabase/supabase-js` SDK and exposes it through Luca's typed state, events, and introspection system. The SDK is isomorphic so this single implementation works in both Node and browser containers. Use `client.sdk` for full SDK access, or use the convenience wrappers for common operations (auth, database queries, storage, edge functions, realtime).",
10387
+ "shortcut": "clients.supabase",
10388
+ "className": "SupabaseClient",
10155
10389
  "methods": {
10156
- "beforeRequest": {
10157
- "description": "Inject the xi-api-key header before each request.",
10158
- "parameters": {},
10159
- "required": [],
10160
- "returns": "void"
10161
- },
10162
- "connect": {
10163
- "description": "Validate the API key by listing available models.",
10164
- "parameters": {},
10165
- "required": [],
10166
- "returns": "Promise<this>",
10167
- "examples": [
10168
- {
10169
- "language": "ts",
10170
- "code": "await el.connect()"
10171
- }
10172
- ]
10173
- },
10174
- "listVoices": {
10175
- "description": "List available voices with optional search and filtering.",
10390
+ "from": {
10391
+ "description": "Start a query on a Postgres table or view.",
10176
10392
  "parameters": {
10177
- "options": {
10178
- "type": "{\n search?: string\n category?: string\n voice_type?: string\n page_size?: number\n next_page_token?: string\n }",
10179
- "description": "Query parameters for filtering voices"
10180
- }
10181
- },
10182
- "required": [],
10183
- "returns": "Promise<any>",
10184
- "examples": [
10185
- {
10186
- "language": "ts",
10187
- "code": "const voices = await el.listVoices()\nconst premade = await el.listVoices({ category: 'premade' })"
10188
- }
10189
- ]
10190
- },
10191
- "getVoice": {
10192
- "description": "Get details for a single voice.",
10193
- "parameters": {
10194
- "voiceId": {
10195
- "type": "string",
10196
- "description": "The voice ID to look up"
10197
- }
10198
- },
10199
- "required": [
10200
- "voiceId"
10201
- ],
10202
- "returns": "Promise<any>",
10203
- "examples": [
10204
- {
10205
- "language": "ts",
10206
- "code": "const voice = await el.getVoice('21m00Tcm4TlvDq8ikWAM')\nconsole.log(voice.name, voice.settings)"
10207
- }
10208
- ]
10209
- },
10210
- "listModels": {
10211
- "description": "List available TTS models.",
10212
- "parameters": {},
10213
- "required": [],
10214
- "returns": "Promise<any[]>",
10215
- "examples": [
10216
- {
10217
- "language": "ts",
10218
- "code": "const models = await el.listModels()\nconsole.log(models.map(m => m.model_id))"
10219
- }
10220
- ]
10221
- },
10222
- "synthesize": {
10223
- "description": "Synthesize speech from text, returning audio as a Buffer.",
10224
- "parameters": {
10225
- "text": {
10226
- "type": "string",
10227
- "description": "The text to convert to speech"
10228
- },
10229
- "options": {
10230
- "type": "SynthesizeOptions",
10231
- "description": "Voice, model, format, and voice settings overrides",
10232
- "properties": {
10233
- "voiceId": {
10234
- "type": "string",
10235
- "description": ""
10236
- },
10237
- "modelId": {
10238
- "type": "string",
10239
- "description": ""
10240
- },
10241
- "outputFormat": {
10242
- "type": "string",
10243
- "description": ""
10244
- },
10245
- "voiceSettings": {
10246
- "type": "ElevenLabsVoiceSettings",
10247
- "description": ""
10248
- },
10249
- "disableCache": {
10250
- "type": "boolean",
10251
- "description": ""
10252
- }
10253
- }
10254
- }
10255
- },
10256
- "required": [
10257
- "text"
10258
- ],
10259
- "returns": "Promise<Buffer>",
10260
- "examples": [
10261
- {
10262
- "language": "ts",
10263
- "code": "const audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data\n\nconst custom = await el.synthesize('Hello', {\n voiceId: '21m00Tcm4TlvDq8ikWAM',\n voiceSettings: { stability: 0.5, similarityBoost: 0.8 }\n})"
10264
- }
10265
- ]
10266
- },
10267
- "say": {
10268
- "description": "Synthesize speech and write the audio to a file.",
10269
- "parameters": {
10270
- "text": {
10271
- "type": "string",
10272
- "description": "The text to convert to speech"
10273
- },
10274
- "outputPath": {
10275
- "type": "string",
10276
- "description": "File path to write the audio to"
10277
- },
10278
- "options": {
10279
- "type": "SynthesizeOptions",
10280
- "description": "Voice, model, format, and voice settings overrides",
10281
- "properties": {
10282
- "voiceId": {
10283
- "type": "string",
10284
- "description": ""
10285
- },
10286
- "modelId": {
10287
- "type": "string",
10288
- "description": ""
10289
- },
10290
- "outputFormat": {
10291
- "type": "string",
10292
- "description": ""
10293
- },
10294
- "voiceSettings": {
10295
- "type": "ElevenLabsVoiceSettings",
10296
- "description": ""
10297
- },
10298
- "disableCache": {
10299
- "type": "boolean",
10300
- "description": ""
10301
- }
10302
- }
10303
- }
10304
- },
10305
- "required": [
10306
- "text",
10307
- "outputPath"
10308
- ],
10309
- "returns": "Promise<string>",
10310
- "examples": [
10311
- {
10312
- "language": "ts",
10313
- "code": "const path = await el.say('Hello world', './hello.mp3')\nconsole.log(`Audio saved to ${path}`)"
10314
- }
10315
- ]
10316
- }
10317
- },
10318
- "getters": {
10319
- "apiKey": {
10320
- "description": "The resolved API key from options or environment.",
10321
- "returns": "string"
10322
- }
10323
- },
10324
- "events": {
10325
- "failure": {
10326
- "name": "failure",
10327
- "description": "Event emitted by ElevenLabsClient",
10328
- "arguments": {}
10329
- },
10330
- "voices": {
10331
- "name": "voices",
10332
- "description": "Event emitted by ElevenLabsClient",
10333
- "arguments": {}
10334
- },
10335
- "speech": {
10336
- "name": "speech",
10337
- "description": "Event emitted by ElevenLabsClient",
10338
- "arguments": {}
10339
- }
10340
- },
10341
- "state": {},
10342
- "options": {},
10343
- "envVars": [],
10344
- "examples": [
10345
- {
10346
- "language": "ts",
10347
- "code": "const el = container.client('elevenlabs')\nawait el.connect()\nconst voices = await el.listVoices()\nconst audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data"
10348
- }
10349
- ]
10350
- });
10351
-
10352
- setBuildTimeData('clients.supabase', {
10353
- "id": "clients.supabase",
10354
- "description": "Supabase client for the Luca container system. Wraps the official `@supabase/supabase-js` SDK and exposes it through Luca's typed state, events, and introspection system. The SDK is isomorphic so this single implementation works in both Node and browser containers. Use `client.sdk` for full SDK access, or use the convenience wrappers for common operations (auth, database queries, storage, edge functions, realtime).",
10355
- "shortcut": "clients.supabase",
10356
- "className": "SupabaseClient",
10357
- "methods": {
10358
- "from": {
10359
- "description": "Start a query on a Postgres table or view.",
10360
- "parameters": {
10361
- "table": {
10362
- "type": "string",
10363
- "description": "The table or view name to query"
10393
+ "table": {
10394
+ "type": "string",
10395
+ "description": "The table or view name to query"
10364
10396
  }
10365
10397
  },
10366
10398
  "required": [
@@ -10740,49 +10772,251 @@ setBuildTimeData('clients.comfyui', {
10740
10772
  }
10741
10773
  },
10742
10774
  "getters": {
10743
- "clientId": {
10744
- "description": "The unique client ID used for WebSocket session tracking.",
10745
- "returns": "string"
10746
- },
10747
- "wsURL": {
10748
- "description": "The WebSocket URL derived from baseURL or overridden via options.",
10775
+ "clientId": {
10776
+ "description": "The unique client ID used for WebSocket session tracking.",
10777
+ "returns": "string"
10778
+ },
10779
+ "wsURL": {
10780
+ "description": "The WebSocket URL derived from baseURL or overridden via options.",
10781
+ "returns": "string"
10782
+ }
10783
+ },
10784
+ "events": {
10785
+ "execution_start": {
10786
+ "name": "execution_start",
10787
+ "description": "Event emitted by ComfyUIClient",
10788
+ "arguments": {}
10789
+ },
10790
+ "execution_complete": {
10791
+ "name": "execution_complete",
10792
+ "description": "Event emitted by ComfyUIClient",
10793
+ "arguments": {}
10794
+ },
10795
+ "executing": {
10796
+ "name": "executing",
10797
+ "description": "Event emitted by ComfyUIClient",
10798
+ "arguments": {}
10799
+ },
10800
+ "progress": {
10801
+ "name": "progress",
10802
+ "description": "Event emitted by ComfyUIClient",
10803
+ "arguments": {}
10804
+ },
10805
+ "executed": {
10806
+ "name": "executed",
10807
+ "description": "Event emitted by ComfyUIClient",
10808
+ "arguments": {}
10809
+ },
10810
+ "execution_cached": {
10811
+ "name": "execution_cached",
10812
+ "description": "Event emitted by ComfyUIClient",
10813
+ "arguments": {}
10814
+ },
10815
+ "execution_error": {
10816
+ "name": "execution_error",
10817
+ "description": "Event emitted by ComfyUIClient",
10818
+ "arguments": {}
10819
+ }
10820
+ },
10821
+ "state": {},
10822
+ "options": {},
10823
+ "envVars": [],
10824
+ "examples": [
10825
+ {
10826
+ "language": "ts",
10827
+ "code": "const comfy = container.client('comfyui', { baseURL: 'http://localhost:8188' })\nconst result = await comfy.runWorkflow(workflow, {\n '6': { text: 'a beautiful sunset' }\n})\nconsole.log(result.images)"
10828
+ }
10829
+ ]
10830
+ });
10831
+
10832
+ setBuildTimeData('clients.elevenlabs', {
10833
+ "id": "clients.elevenlabs",
10834
+ "description": "ElevenLabs client — text-to-speech synthesis via the ElevenLabs REST API. Provides methods for listing voices, listing models, and generating speech audio. Audio is returned as a Buffer; use `say()` for a convenience method that writes to disk.",
10835
+ "shortcut": "clients.elevenlabs",
10836
+ "className": "ElevenLabsClient",
10837
+ "methods": {
10838
+ "beforeRequest": {
10839
+ "description": "Inject the xi-api-key header before each request.",
10840
+ "parameters": {},
10841
+ "required": [],
10842
+ "returns": "void"
10843
+ },
10844
+ "connect": {
10845
+ "description": "Validate the API key by listing available models.",
10846
+ "parameters": {},
10847
+ "required": [],
10848
+ "returns": "Promise<this>",
10849
+ "examples": [
10850
+ {
10851
+ "language": "ts",
10852
+ "code": "await el.connect()"
10853
+ }
10854
+ ]
10855
+ },
10856
+ "listVoices": {
10857
+ "description": "List available voices with optional search and filtering.",
10858
+ "parameters": {
10859
+ "options": {
10860
+ "type": "{\n search?: string\n category?: string\n voice_type?: string\n page_size?: number\n next_page_token?: string\n }",
10861
+ "description": "Query parameters for filtering voices"
10862
+ }
10863
+ },
10864
+ "required": [],
10865
+ "returns": "Promise<any>",
10866
+ "examples": [
10867
+ {
10868
+ "language": "ts",
10869
+ "code": "const voices = await el.listVoices()\nconst premade = await el.listVoices({ category: 'premade' })"
10870
+ }
10871
+ ]
10872
+ },
10873
+ "getVoice": {
10874
+ "description": "Get details for a single voice.",
10875
+ "parameters": {
10876
+ "voiceId": {
10877
+ "type": "string",
10878
+ "description": "The voice ID to look up"
10879
+ }
10880
+ },
10881
+ "required": [
10882
+ "voiceId"
10883
+ ],
10884
+ "returns": "Promise<any>",
10885
+ "examples": [
10886
+ {
10887
+ "language": "ts",
10888
+ "code": "const voice = await el.getVoice('21m00Tcm4TlvDq8ikWAM')\nconsole.log(voice.name, voice.settings)"
10889
+ }
10890
+ ]
10891
+ },
10892
+ "listModels": {
10893
+ "description": "List available TTS models.",
10894
+ "parameters": {},
10895
+ "required": [],
10896
+ "returns": "Promise<any[]>",
10897
+ "examples": [
10898
+ {
10899
+ "language": "ts",
10900
+ "code": "const models = await el.listModels()\nconsole.log(models.map(m => m.model_id))"
10901
+ }
10902
+ ]
10903
+ },
10904
+ "synthesize": {
10905
+ "description": "Synthesize speech from text, returning audio as a Buffer.",
10906
+ "parameters": {
10907
+ "text": {
10908
+ "type": "string",
10909
+ "description": "The text to convert to speech"
10910
+ },
10911
+ "options": {
10912
+ "type": "SynthesizeOptions",
10913
+ "description": "Voice, model, format, and voice settings overrides",
10914
+ "properties": {
10915
+ "voiceId": {
10916
+ "type": "string",
10917
+ "description": ""
10918
+ },
10919
+ "modelId": {
10920
+ "type": "string",
10921
+ "description": ""
10922
+ },
10923
+ "outputFormat": {
10924
+ "type": "string",
10925
+ "description": ""
10926
+ },
10927
+ "voiceSettings": {
10928
+ "type": "ElevenLabsVoiceSettings",
10929
+ "description": ""
10930
+ },
10931
+ "disableCache": {
10932
+ "type": "boolean",
10933
+ "description": ""
10934
+ }
10935
+ }
10936
+ }
10937
+ },
10938
+ "required": [
10939
+ "text"
10940
+ ],
10941
+ "returns": "Promise<Buffer>",
10942
+ "examples": [
10943
+ {
10944
+ "language": "ts",
10945
+ "code": "const audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data\n\nconst custom = await el.synthesize('Hello', {\n voiceId: '21m00Tcm4TlvDq8ikWAM',\n voiceSettings: { stability: 0.5, similarityBoost: 0.8 }\n})"
10946
+ }
10947
+ ]
10948
+ },
10949
+ "say": {
10950
+ "description": "Synthesize speech and write the audio to a file.",
10951
+ "parameters": {
10952
+ "text": {
10953
+ "type": "string",
10954
+ "description": "The text to convert to speech"
10955
+ },
10956
+ "outputPath": {
10957
+ "type": "string",
10958
+ "description": "File path to write the audio to"
10959
+ },
10960
+ "options": {
10961
+ "type": "SynthesizeOptions",
10962
+ "description": "Voice, model, format, and voice settings overrides",
10963
+ "properties": {
10964
+ "voiceId": {
10965
+ "type": "string",
10966
+ "description": ""
10967
+ },
10968
+ "modelId": {
10969
+ "type": "string",
10970
+ "description": ""
10971
+ },
10972
+ "outputFormat": {
10973
+ "type": "string",
10974
+ "description": ""
10975
+ },
10976
+ "voiceSettings": {
10977
+ "type": "ElevenLabsVoiceSettings",
10978
+ "description": ""
10979
+ },
10980
+ "disableCache": {
10981
+ "type": "boolean",
10982
+ "description": ""
10983
+ }
10984
+ }
10985
+ }
10986
+ },
10987
+ "required": [
10988
+ "text",
10989
+ "outputPath"
10990
+ ],
10991
+ "returns": "Promise<string>",
10992
+ "examples": [
10993
+ {
10994
+ "language": "ts",
10995
+ "code": "const path = await el.say('Hello world', './hello.mp3')\nconsole.log(`Audio saved to ${path}`)"
10996
+ }
10997
+ ]
10998
+ }
10999
+ },
11000
+ "getters": {
11001
+ "apiKey": {
11002
+ "description": "The resolved API key from options or environment.",
10749
11003
  "returns": "string"
10750
11004
  }
10751
11005
  },
10752
11006
  "events": {
10753
- "execution_start": {
10754
- "name": "execution_start",
10755
- "description": "Event emitted by ComfyUIClient",
10756
- "arguments": {}
10757
- },
10758
- "execution_complete": {
10759
- "name": "execution_complete",
10760
- "description": "Event emitted by ComfyUIClient",
10761
- "arguments": {}
10762
- },
10763
- "executing": {
10764
- "name": "executing",
10765
- "description": "Event emitted by ComfyUIClient",
10766
- "arguments": {}
10767
- },
10768
- "progress": {
10769
- "name": "progress",
10770
- "description": "Event emitted by ComfyUIClient",
10771
- "arguments": {}
10772
- },
10773
- "executed": {
10774
- "name": "executed",
10775
- "description": "Event emitted by ComfyUIClient",
11007
+ "failure": {
11008
+ "name": "failure",
11009
+ "description": "Event emitted by ElevenLabsClient",
10776
11010
  "arguments": {}
10777
11011
  },
10778
- "execution_cached": {
10779
- "name": "execution_cached",
10780
- "description": "Event emitted by ComfyUIClient",
11012
+ "voices": {
11013
+ "name": "voices",
11014
+ "description": "Event emitted by ElevenLabsClient",
10781
11015
  "arguments": {}
10782
11016
  },
10783
- "execution_error": {
10784
- "name": "execution_error",
10785
- "description": "Event emitted by ComfyUIClient",
11017
+ "speech": {
11018
+ "name": "speech",
11019
+ "description": "Event emitted by ElevenLabsClient",
10786
11020
  "arguments": {}
10787
11021
  }
10788
11022
  },
@@ -10792,7 +11026,7 @@ setBuildTimeData('clients.comfyui', {
10792
11026
  "examples": [
10793
11027
  {
10794
11028
  "language": "ts",
10795
- "code": "const comfy = container.client('comfyui', { baseURL: 'http://localhost:8188' })\nconst result = await comfy.runWorkflow(workflow, {\n '6': { text: 'a beautiful sunset' }\n})\nconsole.log(result.images)"
11029
+ "code": "const el = container.client('elevenlabs')\nawait el.connect()\nconst voices = await el.listVoices()\nconst audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data"
10796
11030
  }
10797
11031
  ]
10798
11032
  });
@@ -11081,7 +11315,7 @@ setBuildTimeData('servers.express', {
11081
11315
 
11082
11316
  setBuildTimeData('servers.websocket', {
11083
11317
  "id": "servers.websocket",
11084
- "description": "WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety.",
11318
+ "description": "WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety. Supports ask/reply semantics when paired with the Luca WebSocket client. The server can `ask(ws, type, data)` a connected client and await a typed response, or handle incoming asks from clients by listening for messages with a `requestId` and replying via `send(ws, { replyTo, data })`. Requests time out if no reply arrives within the configurable window.",
11085
11319
  "shortcut": "servers.websocket",
11086
11320
  "className": "WebsocketServer",
11087
11321
  "methods": {
@@ -11116,6 +11350,64 @@ setBuildTimeData('servers.websocket', {
11116
11350
  ],
11117
11351
  "returns": "void"
11118
11352
  },
11353
+ "ask": {
11354
+ "description": "Send a request to a specific client and wait for a correlated response. The client is expected to reply with a message whose `replyTo` matches the `requestId` of this message.",
11355
+ "parameters": {
11356
+ "ws": {
11357
+ "type": "any",
11358
+ "description": "The WebSocket client to ask"
11359
+ },
11360
+ "type": {
11361
+ "type": "string",
11362
+ "description": "A string identifying the request type"
11363
+ },
11364
+ "data": {
11365
+ "type": "any",
11366
+ "description": "Optional payload"
11367
+ },
11368
+ "timeout": {
11369
+ "type": "any",
11370
+ "description": "How long to wait (default 10 000 ms)"
11371
+ }
11372
+ },
11373
+ "required": [
11374
+ "ws",
11375
+ "type"
11376
+ ],
11377
+ "returns": "Promise<R>",
11378
+ "examples": [
11379
+ {
11380
+ "language": "ts",
11381
+ "code": "ws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
11382
+ }
11383
+ ]
11384
+ },
11385
+ "_handleReply": {
11386
+ "description": "",
11387
+ "parameters": {
11388
+ "message": {
11389
+ "type": "any",
11390
+ "description": "Parameter message"
11391
+ }
11392
+ },
11393
+ "required": [
11394
+ "message"
11395
+ ],
11396
+ "returns": "boolean"
11397
+ },
11398
+ "_rejectAllPending": {
11399
+ "description": "",
11400
+ "parameters": {
11401
+ "reason": {
11402
+ "type": "string",
11403
+ "description": "Parameter reason"
11404
+ }
11405
+ },
11406
+ "required": [
11407
+ "reason"
11408
+ ],
11409
+ "returns": "void"
11410
+ },
11119
11411
  "start": {
11120
11412
  "description": "Start the WebSocket server. A runtime `port` overrides the constructor option and is written to state before the underlying `ws.Server` is created, so the server binds to the correct port.",
11121
11413
  "parameters": {
@@ -11162,7 +11454,7 @@ setBuildTimeData('servers.websocket', {
11162
11454
  "examples": [
11163
11455
  {
11164
11456
  "language": "ts",
11165
- "code": "const ws = container.server('websocket', { json: true })\nawait ws.start({ port: 8080 })\n\nws.on('message', (data, client) => {\n console.log('Received:', data)\n ws.broadcast({ echo: data })\n})"
11457
+ "code": "const ws = container.server('websocket', { json: true })\nawait ws.start({ port: 8080 })\n\nws.on('message', (data, client) => {\n console.log('Received:', data)\n ws.broadcast({ echo: data })\n})\n\n// ask/reply: request info from a connected client\nws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
11166
11458
  }
11167
11459
  ]
11168
11460
  });
@@ -13118,7 +13410,7 @@ export const introspectionData = [
13118
13410
  },
13119
13411
  {
13120
13412
  "id": "features.windowManager",
13121
- "description": "WindowManager Feature — Native window control via LucaVoiceLauncher Acts as an IPC server that the native macOS launcher app connects to. Communicates over a Unix domain socket using NDJSON (newline-delimited JSON). **Protocol:** - Bun listens on a Unix domain socket; the native app connects as a client - Window dispatch commands are sent as NDJSON with a `window` field - The app executes window commands and sends back `windowAck` messages - Any non-windowAck message from the app is emitted as a `message` event - Other features can use `send()` to write arbitrary NDJSON to the app **Capabilities:** - Spawn native browser windows with configurable chrome - Navigate, focus, close, and eval JavaScript in windows - Automatic socket file cleanup and fallback paths",
13413
+ "description": "WindowManager Feature — Native window control via LucaVoiceLauncher Uses a broker/producer architecture so multiple luca processes can trigger window operations without competing for the same Unix socket. **Architecture:** - The first process to call `listen()` becomes the **broker**. It owns the app-facing socket (`ipc-window.sock`) and a control socket (`ipc-window-control.sock`). - Subsequent processes detect the broker and become **producers**. They connect to the control socket and route commands through the broker. - The broker forwards producer commands to the native app and routes acks and lifecycle events back to the originating producer. **Protocol:** - Bun listens on a Unix domain socket; the native app connects as a client - Window dispatch commands are sent as NDJSON with a `window` field - The app executes window commands and sends back `windowAck` messages - Any non-windowAck message from the app is emitted as a `message` event - Other features can use `send()` to write arbitrary NDJSON to the app **Capabilities:** - Spawn native browser windows with configurable chrome - Navigate, focus, close, and eval JavaScript in windows - Multiple luca processes can trigger window operations simultaneously - Automatic broker detection and producer fallback Observable state includes `windows` (open window metadata), `pendingOperations` (in-flight command ids), and `producerCount` (broker). Sockets, promises, and `WindowHandle` instances stay internal. **Producer state:** The broker pushes `windowStateSync` on the control socket when a producer connects and whenever the window roster changes, so every process sees the same `windows` / `windowCount` / `clientConnected` as the broker (not only its own acks).",
13122
13414
  "shortcut": "features.windowManager",
13123
13415
  "className": "WindowManager",
13124
13416
  "methods": {
@@ -13134,7 +13426,18 @@ export const introspectionData = [
13134
13426
  "returns": "Promise<this>"
13135
13427
  },
13136
13428
  "listen": {
13137
- "description": "Start listening on the Unix domain socket for the native app to connect. Fire-and-forget binds the socket and returns immediately. Sits quietly until the native app connects; does nothing visible if it never does.",
13429
+ "description": "Start the window manager. Automatically detects whether a broker already exists and either becomes the broker or connects as a producer. - If no broker is running: becomes the broker, binds the app socket and a control socket for producers. - If a broker is already running: connects as a producer through the control socket.",
13430
+ "parameters": {
13431
+ "socketPath": {
13432
+ "type": "string",
13433
+ "description": "Override the configured app socket path"
13434
+ }
13435
+ },
13436
+ "required": [],
13437
+ "returns": "Promise<this>"
13438
+ },
13439
+ "cleanupSocket": {
13440
+ "description": "Remove stale socket files without starting or stopping the server. Useful when a previous process crashed and left dead sockets behind. Will not remove sockets that have live listeners.",
13138
13441
  "parameters": {
13139
13442
  "socketPath": {
13140
13443
  "type": "string",
@@ -13142,10 +13445,10 @@ export const introspectionData = [
13142
13445
  }
13143
13446
  },
13144
13447
  "required": [],
13145
- "returns": "this"
13448
+ "returns": "Promise<boolean>"
13146
13449
  },
13147
13450
  "stop": {
13148
- "description": "Stop the IPC server and clean up all connections. Rejects any pending window operation requests.",
13451
+ "description": "Stop the window manager and clean up all connections. Rejects any pending window operation requests.",
13149
13452
  "parameters": {},
13150
13453
  "required": [],
13151
13454
  "returns": "Promise<this>"
@@ -13418,7 +13721,7 @@ export const introspectionData = [
13418
13721
  ]
13419
13722
  },
13420
13723
  "send": {
13421
- "description": "Write an NDJSON message to the connected app client. Public so other features can send arbitrary protocol messages over the same socket.",
13724
+ "description": "Write an NDJSON message to the connected app client. In producer mode, routes through the broker. Public so other features can send arbitrary protocol messages over the same socket.",
13422
13725
  "parameters": {
13423
13726
  "msg": {
13424
13727
  "type": "Record<string, any>",
@@ -13432,12 +13735,20 @@ export const introspectionData = [
13432
13735
  }
13433
13736
  },
13434
13737
  "getters": {
13738
+ "isBroker": {
13739
+ "description": "Whether this instance is acting as the broker.",
13740
+ "returns": "boolean"
13741
+ },
13742
+ "isProducer": {
13743
+ "description": "Whether this instance is acting as a producer.",
13744
+ "returns": "boolean"
13745
+ },
13435
13746
  "isListening": {
13436
- "description": "Whether the IPC server is currently listening.",
13747
+ "description": "Whether the IPC server is currently listening (broker) or connected to broker (producer).",
13437
13748
  "returns": "boolean"
13438
13749
  },
13439
13750
  "isClientConnected": {
13440
- "description": "Whether the native app client is currently connected.",
13751
+ "description": "Whether the native app client is currently connected (only meaningful for broker).",
13441
13752
  "returns": "boolean"
13442
13753
  }
13443
13754
  },
@@ -13472,6 +13783,11 @@ export const introspectionData = [
13472
13783
  "description": "Event emitted by WindowManager",
13473
13784
  "arguments": {}
13474
13785
  },
13786
+ "windowFocus": {
13787
+ "name": "windowFocus",
13788
+ "description": "Event emitted by WindowManager",
13789
+ "arguments": {}
13790
+ },
13475
13791
  "message": {
13476
13792
  "name": "message",
13477
13793
  "description": "Event emitted by WindowManager",
@@ -17322,6 +17638,32 @@ export const introspectionData = [
17322
17638
  }
17323
17639
  ]
17324
17640
  },
17641
+ "isSymlink": {
17642
+ "description": "Checks if a path is a symbolic link.",
17643
+ "parameters": {
17644
+ "path": {
17645
+ "type": "string",
17646
+ "description": "The path to check"
17647
+ }
17648
+ },
17649
+ "required": [
17650
+ "path"
17651
+ ],
17652
+ "returns": "boolean"
17653
+ },
17654
+ "realpath": {
17655
+ "description": "Resolves a symlink to its real path. Returns the resolved path as-is if not a symlink.",
17656
+ "parameters": {
17657
+ "path": {
17658
+ "type": "string",
17659
+ "description": "The path to resolve"
17660
+ }
17661
+ },
17662
+ "required": [
17663
+ "path"
17664
+ ],
17665
+ "returns": "string"
17666
+ },
17325
17667
  "stat": {
17326
17668
  "description": "Synchronously returns the stat object for a file or directory.",
17327
17669
  "parameters": {
@@ -17795,7 +18137,7 @@ export const introspectionData = [
17795
18137
  },
17796
18138
  {
17797
18139
  "id": "features.ipcSocket",
17798
- "description": "IpcSocket Feature - Inter-Process Communication via Unix Domain Sockets This feature provides robust IPC (Inter-Process Communication) capabilities using Unix domain sockets. It supports both server and client modes, allowing processes to communicate efficiently through file system-based socket connections. **Key Features:** - Dual-mode operation: server and client functionality - JSON message serialization/deserialization - Multiple client connection support (server mode) - Event-driven message handling - Automatic socket cleanup and management - Broadcast messaging to all connected clients - Lock file management for socket paths **Communication Pattern:** - Messages are automatically JSON-encoded with unique IDs - Both server and client emit 'message' events for incoming data - Server can broadcast to all connected clients - Client maintains single connection to server **Socket Management:** - Automatic cleanup of stale socket files - Connection tracking and management - Graceful shutdown procedures - Lock file protection against conflicts **Usage Examples:** **Server Mode:** ```typescript const ipc = container.feature('ipcSocket'); await ipc.listen('/tmp/myapp.sock', true); // removeLock=true ipc.on('connection', (socket) => { console.log('Client connected'); }); ipc.on('message', (data) => { console.log('Received:', data); ipc.broadcast({ reply: 'ACK', original: data }); }); ``` **Client Mode:** ```typescript const ipc = container.feature('ipcSocket'); await ipc.connect('/tmp/myapp.sock'); ipc.on('message', (data) => { console.log('Server says:', data); }); await ipc.send({ type: 'request', payload: 'hello' }); ```",
18140
+ "description": "IpcSocket Feature - Inter-Process Communication via Unix Domain Sockets This feature provides robust IPC (Inter-Process Communication) capabilities using Unix domain sockets. It supports both server and client modes, allowing processes to communicate efficiently through file system-based socket connections. **Key Features:** - Hub-and-spoke: one server, many named clients with identity tracking - Targeted messaging: sendTo(clientId), broadcast(msg, excludeId) - Request/reply: ask() + reply() with timeout-based correlation - Auto-reconnect: clients reconnect with exponential backoff - Stale socket detection: probeSocket() before listen() - Clean shutdown: stopServer() removes socket file **Server (Hub):** ```typescript const ipc = container.feature('ipcSocket'); await ipc.listen('/tmp/hub.sock', true); ipc.on('connection', (clientId, socket) => { console.log('Client joined:', clientId); }); ipc.on('message', (data, clientId) => { console.log(`From ${clientId}:`, data); // Reply to sender, or ask and wait ipc.sendTo(clientId, { ack: true }); }); ``` **Client (Spoke):** ```typescript const ipc = container.feature('ipcSocket'); await ipc.connect('/tmp/hub.sock', { reconnect: true, name: 'worker-1' }); // Fire and forget await ipc.send({ type: 'status', ready: true }); // Request/reply ipc.on('message', (data) => { if (data.requestId) ipc.reply(data.requestId, { result: 42 }); }); ```",
17799
18141
  "shortcut": "features.ipcSocket",
17800
18142
  "className": "IpcSocket",
17801
18143
  "methods": {
@@ -17835,61 +18177,127 @@ export const introspectionData = [
17835
18177
  ]
17836
18178
  },
17837
18179
  "broadcast": {
17838
- "description": "Broadcasts a message to all connected clients (server mode only). This method sends a JSON-encoded message with a unique ID to every client currently connected to the server. Each message is automatically wrapped with metadata including a UUID for tracking. **Message Format:** Messages are automatically wrapped in the format: ```json { \"data\": <your_message>, \"id\": \"<uuid>\" } ```",
18180
+ "description": "Broadcasts a message to all connected clients (server mode only).",
17839
18181
  "parameters": {
17840
18182
  "message": {
17841
18183
  "type": "any",
17842
- "description": "The message object to broadcast to all clients"
18184
+ "description": "The message object to broadcast"
18185
+ },
18186
+ "exclude": {
18187
+ "type": "string",
18188
+ "description": "Optional client ID to exclude from broadcast"
17843
18189
  }
17844
18190
  },
17845
18191
  "required": [
17846
18192
  "message"
17847
18193
  ],
17848
- "returns": "void",
17849
- "examples": [
17850
- {
17851
- "language": "ts",
17852
- "code": "// Broadcast to all connected clients\nipc.broadcast({ \n type: 'notification',\n message: 'Server is shutting down in 30 seconds',\n timestamp: Date.now()\n});\n\n// Chain multiple operations\nipc.broadcast({ status: 'ready' })\n .broadcast({ time: new Date().toISOString() });"
18194
+ "returns": "void"
18195
+ },
18196
+ "sendTo": {
18197
+ "description": "Sends a message to a specific client by ID (server mode only).",
18198
+ "parameters": {
18199
+ "clientId": {
18200
+ "type": "string",
18201
+ "description": "The target client ID"
18202
+ },
18203
+ "message": {
18204
+ "type": "any",
18205
+ "description": "The message to send"
17853
18206
  }
17854
- ]
18207
+ },
18208
+ "required": [
18209
+ "clientId",
18210
+ "message"
18211
+ ],
18212
+ "returns": "boolean"
17855
18213
  },
17856
18214
  "send": {
17857
- "description": "Sends a message to the server (client mode only). This method sends a JSON-encoded message with a unique ID to the connected server. The message is automatically wrapped with metadata for tracking purposes. **Message Format:** Messages are automatically wrapped in the format: ```json { \"data\": <your_message>, \"id\": \"<uuid>\" } ```",
18215
+ "description": "Fire-and-forget: sends a message to the server (client mode only). For server→client, use sendTo() or broadcast().",
17858
18216
  "parameters": {
17859
18217
  "message": {
17860
18218
  "type": "any",
17861
- "description": "The message object to send to the server"
18219
+ "description": "The message to send"
17862
18220
  }
17863
18221
  },
17864
18222
  "required": [
17865
18223
  "message"
17866
18224
  ],
17867
- "returns": "void",
17868
- "examples": [
17869
- {
17870
- "language": "ts",
17871
- "code": "// Send a simple message\nawait ipc.send({ type: 'ping' });\n\n// Send complex data\nawait ipc.send({\n type: 'data_update',\n payload: { users: [...], timestamp: Date.now() }\n});"
18225
+ "returns": "void"
18226
+ },
18227
+ "ask": {
18228
+ "description": "Sends a message and waits for a correlated reply. Works in both client and server mode. The recipient should call `reply(requestId, response)` to respond.",
18229
+ "parameters": {
18230
+ "message": {
18231
+ "type": "any",
18232
+ "description": "The message to send"
18233
+ },
18234
+ "options": {
18235
+ "type": "{ clientId?: string; timeoutMs?: number }",
18236
+ "description": "Optional: clientId (server mode target), timeoutMs"
17872
18237
  }
17873
- ]
18238
+ },
18239
+ "required": [
18240
+ "message"
18241
+ ],
18242
+ "returns": "Promise<any>"
18243
+ },
18244
+ "reply": {
18245
+ "description": "Sends a reply to a previous ask() call, correlated by requestId.",
18246
+ "parameters": {
18247
+ "requestId": {
18248
+ "type": "string",
18249
+ "description": "The requestId from the incoming message"
18250
+ },
18251
+ "data": {
18252
+ "type": "any",
18253
+ "description": "The reply payload"
18254
+ },
18255
+ "clientId": {
18256
+ "type": "string",
18257
+ "description": "Target client (server mode; for client mode, omit)"
18258
+ }
18259
+ },
18260
+ "required": [
18261
+ "requestId",
18262
+ "data"
18263
+ ],
18264
+ "returns": "void"
17874
18265
  },
17875
18266
  "connect": {
17876
- "description": "Connects to an IPC server at the specified socket path (client mode). This method establishes a client connection to an existing IPC server. Once connected, the client can send messages to the server and receive responses. The connection is maintained until explicitly closed or the server terminates. **Connection Behavior:** - Sets the socket mode to 'client' - Returns existing connection if already connected - Automatically handles connection events and cleanup - JSON-parses incoming messages and emits 'message' events - Cleans up connection reference when socket closes **Error Handling:** - Throws error if already in server mode - Rejects promise on connection failures - Automatically cleans up on connection close",
18267
+ "description": "Connects to an IPC server at the specified socket path (client mode).",
17877
18268
  "parameters": {
17878
18269
  "socketPath": {
17879
18270
  "type": "string",
17880
- "description": "The file system path to the server's Unix domain socket"
18271
+ "description": "Path to the server's Unix domain socket"
18272
+ },
18273
+ "options": {
18274
+ "type": "{ reconnect?: boolean; name?: string }",
18275
+ "description": "Optional: reconnect (enable auto-reconnect), name (identify this client)"
17881
18276
  }
17882
18277
  },
17883
18278
  "required": [
17884
18279
  "socketPath"
17885
18280
  ],
17886
- "returns": "Promise<Socket>",
17887
- "examples": [
17888
- {
17889
- "language": "ts",
17890
- "code": "// Connect to server\nconst socket = await ipc.connect('/tmp/myapp.sock');\nconsole.log('Connected to IPC server');\n\n// Handle incoming messages\nipc.on('message', (data) => {\n console.log('Server message:', data);\n});\n\n// Send messages\nawait ipc.send({ type: 'hello', client_id: 'client_001' });"
18281
+ "returns": "Promise<Socket>"
18282
+ },
18283
+ "disconnect": {
18284
+ "description": "Disconnects the client and stops any reconnection attempts.",
18285
+ "parameters": {},
18286
+ "required": [],
18287
+ "returns": "void"
18288
+ },
18289
+ "probeSocket": {
18290
+ "description": "Probe an existing socket to see if a live listener is behind it. Attempts a quick connect — if it succeeds, someone is listening.",
18291
+ "parameters": {
18292
+ "socketPath": {
18293
+ "type": "string",
18294
+ "description": "Parameter socketPath"
17891
18295
  }
17892
- ]
18296
+ },
18297
+ "required": [
18298
+ "socketPath"
18299
+ ],
18300
+ "returns": "Promise<boolean>"
17893
18301
  }
17894
18302
  },
17895
18303
  "getters": {
@@ -17901,12 +18309,25 @@ export const introspectionData = [
17901
18309
  "description": "Checks if the IPC socket is operating in server mode.",
17902
18310
  "returns": "any"
17903
18311
  },
18312
+ "clientCount": {
18313
+ "description": "Returns the number of currently connected clients (server mode).",
18314
+ "returns": "any"
18315
+ },
18316
+ "connectedClients": {
18317
+ "description": "Returns info about all connected clients (server mode).",
18318
+ "returns": "Array<{ id: string; name?: string; connectedAt: number }>"
18319
+ },
17904
18320
  "connection": {
17905
18321
  "description": "Gets the current client connection socket.",
17906
18322
  "returns": "any"
17907
18323
  }
17908
18324
  },
17909
18325
  "events": {
18326
+ "disconnection": {
18327
+ "name": "disconnection",
18328
+ "description": "Event emitted by IpcSocket",
18329
+ "arguments": {}
18330
+ },
17910
18331
  "connection": {
17911
18332
  "name": "connection",
17912
18333
  "description": "Event emitted by IpcSocket",
@@ -18821,10 +19242,68 @@ export const introspectionData = [
18821
19242
  },
18822
19243
  {
18823
19244
  "id": "features.processManager",
18824
- "description": "Manages long-running child processes with tracking, events, and automatic cleanup. Unlike the `proc` feature whose spawn methods block until the child exits, ProcessManager returns a SpawnHandler immediately — a handle object with its own state, events, and lifecycle methods. The feature tracks all spawned processes, maintains observable state, and can automatically kill them on parent exit.",
19245
+ "description": "Manages long-running child processes with tracking, events, and automatic cleanup. Unlike the `proc` feature whose spawn methods block until the child exits, ProcessManager returns a SpawnHandler immediately — a handle object with its own state, events, and lifecycle methods. The feature tracks all spawned processes, maintains observable state, and can automatically kill them on parent exit. Each handler maintains a memory-efficient output buffer: the first 20 lines (head) and last 50 lines (tail) of stdout/stderr are kept, everything in between is discarded.",
18825
19246
  "shortcut": "features.processManager",
18826
19247
  "className": "ProcessManager",
18827
19248
  "methods": {
19249
+ "spawnProcess": {
19250
+ "description": "Tool handler: spawn a long-running background process.",
19251
+ "parameters": {
19252
+ "args": {
19253
+ "type": "{ command: string; args?: string; tag?: string; cwd?: string }",
19254
+ "description": "Parameter args"
19255
+ }
19256
+ },
19257
+ "required": [
19258
+ "args"
19259
+ ],
19260
+ "returns": "void"
19261
+ },
19262
+ "runCommand": {
19263
+ "description": "Tool handler: run a command to completion and return its output.",
19264
+ "parameters": {
19265
+ "args": {
19266
+ "type": "{ command: string; cwd?: string }",
19267
+ "description": "Parameter args"
19268
+ }
19269
+ },
19270
+ "required": [
19271
+ "args"
19272
+ ],
19273
+ "returns": "void"
19274
+ },
19275
+ "listProcesses": {
19276
+ "description": "Tool handler: list all tracked processes.",
19277
+ "parameters": {},
19278
+ "required": [],
19279
+ "returns": "void"
19280
+ },
19281
+ "getProcessOutput": {
19282
+ "description": "Tool handler: peek at a process's buffered output.",
19283
+ "parameters": {
19284
+ "args": {
19285
+ "type": "{ id?: string; tag?: string; stream?: string }",
19286
+ "description": "Parameter args"
19287
+ }
19288
+ },
19289
+ "required": [
19290
+ "args"
19291
+ ],
19292
+ "returns": "void"
19293
+ },
19294
+ "killProcess": {
19295
+ "description": "Tool handler: kill a process by ID or tag.",
19296
+ "parameters": {
19297
+ "args": {
19298
+ "type": "{ id?: string; tag?: string; signal?: string }",
19299
+ "description": "Parameter args"
19300
+ }
19301
+ },
19302
+ "required": [
19303
+ "args"
19304
+ ],
19305
+ "returns": "void"
19306
+ },
18828
19307
  "spawn": {
18829
19308
  "description": "Spawn a long-running process and return a handle immediately. The returned SpawnHandler provides events for stdout/stderr streaming, exit/crash notifications, and methods to kill or await the process.",
18830
19309
  "parameters": {
@@ -19002,7 +19481,7 @@ export const introspectionData = [
19002
19481
  "examples": [
19003
19482
  {
19004
19483
  "language": "ts",
19005
- "code": "const pm = container.feature('processManager', { enable: true })\n\nconst server = pm.spawn('node', ['server.js'], { tag: 'api', cwd: '/app' })\nserver.on('stdout', (data) => console.log('[api]', data))\nserver.on('crash', (code) => console.error('API crashed:', code))\n\n// Kill one\nserver.kill()\n\n// Kill all tracked processes\npm.killAll()\n\n// List and lookup\npm.list() // SpawnHandler[]\npm.getByTag('api') // SpawnHandler | undefined"
19484
+ "code": "const pm = container.feature('processManager', { enable: true })\n\nconst server = pm.spawn('node', ['server.js'], { tag: 'api', cwd: '/app' })\nserver.on('stdout', (data) => console.log('[api]', data))\nserver.on('crash', (code) => console.error('API crashed:', code))\n\n// Peek at buffered output\nconst { head, tail } = server.peek()\n\n// Kill one\nserver.kill()\n\n// Kill all tracked processes\npm.killAll()\n\n// List and lookup\npm.list() // SpawnHandler[]\npm.getByTag('api') // SpawnHandler | undefined"
19006
19485
  }
19007
19486
  ]
19008
19487
  },
@@ -21360,7 +21839,7 @@ export const introspectionData = [
21360
21839
  },
21361
21840
  {
21362
21841
  "id": "clients.websocket",
21363
- "description": "WebSocket client that bridges raw WebSocket events to Luca's Helper event bus, providing a clean interface for sending/receiving messages, tracking connection state, and optional auto-reconnection with exponential backoff. Events emitted: - `open` — connection established - `message` — message received (JSON-parsed when possible) - `close` — connection closed (with code and reason) - `error` — connection error - `reconnecting` — attempting reconnection (with attempt number)",
21842
+ "description": "WebSocketClient helper",
21364
21843
  "shortcut": "clients.websocket",
21365
21844
  "className": "WebSocketClient",
21366
21845
  "methods": {
@@ -21383,6 +21862,59 @@ export const introspectionData = [
21383
21862
  ],
21384
21863
  "returns": "Promise<void>"
21385
21864
  },
21865
+ "ask": {
21866
+ "description": "Send a request and wait for a correlated response. The message is sent with a unique `requestId`; the remote side is expected to reply with a message containing `replyTo` set to that same ID.",
21867
+ "parameters": {
21868
+ "type": {
21869
+ "type": "string",
21870
+ "description": "A string identifying the request type"
21871
+ },
21872
+ "data": {
21873
+ "type": "any",
21874
+ "description": "Optional payload to include with the request"
21875
+ },
21876
+ "timeout": {
21877
+ "type": "any",
21878
+ "description": "How long to wait for a response (default 10 000 ms)"
21879
+ }
21880
+ },
21881
+ "required": [
21882
+ "type"
21883
+ ],
21884
+ "returns": "Promise<R>",
21885
+ "examples": [
21886
+ {
21887
+ "language": "ts",
21888
+ "code": "const result = await ws.ask('getUser', { id: 42 })"
21889
+ }
21890
+ ]
21891
+ },
21892
+ "_handleReply": {
21893
+ "description": "",
21894
+ "parameters": {
21895
+ "message": {
21896
+ "type": "any",
21897
+ "description": "Parameter message"
21898
+ }
21899
+ },
21900
+ "required": [
21901
+ "message"
21902
+ ],
21903
+ "returns": "boolean"
21904
+ },
21905
+ "_rejectAllPending": {
21906
+ "description": "",
21907
+ "parameters": {
21908
+ "reason": {
21909
+ "type": "string",
21910
+ "description": "Parameter reason"
21911
+ }
21912
+ },
21913
+ "required": [
21914
+ "reason"
21915
+ ],
21916
+ "returns": "void"
21917
+ },
21386
21918
  "disconnect": {
21387
21919
  "description": "Gracefully close the WebSocket connection. Suppresses auto-reconnect and updates connection state to disconnected.",
21388
21920
  "parameters": {},
@@ -21425,13 +21957,7 @@ export const introspectionData = [
21425
21957
  },
21426
21958
  "state": {},
21427
21959
  "options": {},
21428
- "envVars": [],
21429
- "examples": [
21430
- {
21431
- "language": "ts",
21432
- "code": "const ws = container.client('websocket', {\n baseURL: 'ws://localhost:8080',\n reconnect: true,\n maxReconnectAttempts: 5\n})\nws.on('message', (data) => console.log('Received:', data))\nawait ws.connect()\nawait ws.send({ type: 'hello' })"
21433
- }
21434
- ]
21960
+ "envVars": []
21435
21961
  },
21436
21962
  {
21437
21963
  "id": "clients.openai",
@@ -21684,210 +22210,9 @@ export const introspectionData = [
21684
22210
  "description": "Event emitted by OpenAIClient",
21685
22211
  "arguments": {}
21686
22212
  },
21687
- "models": {
21688
- "name": "models",
21689
- "description": "Event emitted by OpenAIClient",
21690
- "arguments": {}
21691
- }
21692
- },
21693
- "state": {},
21694
- "options": {},
21695
- "envVars": [],
21696
- "examples": [
21697
- {
21698
- "language": "ts",
21699
- "code": "const openai = container.client('openai', { defaultModel: 'gpt-4o' })\nconst answer = await openai.ask('What is the meaning of life?')\nconsole.log(answer)"
21700
- }
21701
- ]
21702
- },
21703
- {
21704
- "id": "clients.elevenlabs",
21705
- "description": "ElevenLabs client — text-to-speech synthesis via the ElevenLabs REST API. Provides methods for listing voices, listing models, and generating speech audio. Audio is returned as a Buffer; use `say()` for a convenience method that writes to disk.",
21706
- "shortcut": "clients.elevenlabs",
21707
- "className": "ElevenLabsClient",
21708
- "methods": {
21709
- "beforeRequest": {
21710
- "description": "Inject the xi-api-key header before each request.",
21711
- "parameters": {},
21712
- "required": [],
21713
- "returns": "void"
21714
- },
21715
- "connect": {
21716
- "description": "Validate the API key by listing available models.",
21717
- "parameters": {},
21718
- "required": [],
21719
- "returns": "Promise<this>",
21720
- "examples": [
21721
- {
21722
- "language": "ts",
21723
- "code": "await el.connect()"
21724
- }
21725
- ]
21726
- },
21727
- "listVoices": {
21728
- "description": "List available voices with optional search and filtering.",
21729
- "parameters": {
21730
- "options": {
21731
- "type": "{\n search?: string\n category?: string\n voice_type?: string\n page_size?: number\n next_page_token?: string\n }",
21732
- "description": "Query parameters for filtering voices"
21733
- }
21734
- },
21735
- "required": [],
21736
- "returns": "Promise<any>",
21737
- "examples": [
21738
- {
21739
- "language": "ts",
21740
- "code": "const voices = await el.listVoices()\nconst premade = await el.listVoices({ category: 'premade' })"
21741
- }
21742
- ]
21743
- },
21744
- "getVoice": {
21745
- "description": "Get details for a single voice.",
21746
- "parameters": {
21747
- "voiceId": {
21748
- "type": "string",
21749
- "description": "The voice ID to look up"
21750
- }
21751
- },
21752
- "required": [
21753
- "voiceId"
21754
- ],
21755
- "returns": "Promise<any>",
21756
- "examples": [
21757
- {
21758
- "language": "ts",
21759
- "code": "const voice = await el.getVoice('21m00Tcm4TlvDq8ikWAM')\nconsole.log(voice.name, voice.settings)"
21760
- }
21761
- ]
21762
- },
21763
- "listModels": {
21764
- "description": "List available TTS models.",
21765
- "parameters": {},
21766
- "required": [],
21767
- "returns": "Promise<any[]>",
21768
- "examples": [
21769
- {
21770
- "language": "ts",
21771
- "code": "const models = await el.listModels()\nconsole.log(models.map(m => m.model_id))"
21772
- }
21773
- ]
21774
- },
21775
- "synthesize": {
21776
- "description": "Synthesize speech from text, returning audio as a Buffer.",
21777
- "parameters": {
21778
- "text": {
21779
- "type": "string",
21780
- "description": "The text to convert to speech"
21781
- },
21782
- "options": {
21783
- "type": "SynthesizeOptions",
21784
- "description": "Voice, model, format, and voice settings overrides",
21785
- "properties": {
21786
- "voiceId": {
21787
- "type": "string",
21788
- "description": ""
21789
- },
21790
- "modelId": {
21791
- "type": "string",
21792
- "description": ""
21793
- },
21794
- "outputFormat": {
21795
- "type": "string",
21796
- "description": ""
21797
- },
21798
- "voiceSettings": {
21799
- "type": "ElevenLabsVoiceSettings",
21800
- "description": ""
21801
- },
21802
- "disableCache": {
21803
- "type": "boolean",
21804
- "description": ""
21805
- }
21806
- }
21807
- }
21808
- },
21809
- "required": [
21810
- "text"
21811
- ],
21812
- "returns": "Promise<Buffer>",
21813
- "examples": [
21814
- {
21815
- "language": "ts",
21816
- "code": "const audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data\n\nconst custom = await el.synthesize('Hello', {\n voiceId: '21m00Tcm4TlvDq8ikWAM',\n voiceSettings: { stability: 0.5, similarityBoost: 0.8 }\n})"
21817
- }
21818
- ]
21819
- },
21820
- "say": {
21821
- "description": "Synthesize speech and write the audio to a file.",
21822
- "parameters": {
21823
- "text": {
21824
- "type": "string",
21825
- "description": "The text to convert to speech"
21826
- },
21827
- "outputPath": {
21828
- "type": "string",
21829
- "description": "File path to write the audio to"
21830
- },
21831
- "options": {
21832
- "type": "SynthesizeOptions",
21833
- "description": "Voice, model, format, and voice settings overrides",
21834
- "properties": {
21835
- "voiceId": {
21836
- "type": "string",
21837
- "description": ""
21838
- },
21839
- "modelId": {
21840
- "type": "string",
21841
- "description": ""
21842
- },
21843
- "outputFormat": {
21844
- "type": "string",
21845
- "description": ""
21846
- },
21847
- "voiceSettings": {
21848
- "type": "ElevenLabsVoiceSettings",
21849
- "description": ""
21850
- },
21851
- "disableCache": {
21852
- "type": "boolean",
21853
- "description": ""
21854
- }
21855
- }
21856
- }
21857
- },
21858
- "required": [
21859
- "text",
21860
- "outputPath"
21861
- ],
21862
- "returns": "Promise<string>",
21863
- "examples": [
21864
- {
21865
- "language": "ts",
21866
- "code": "const path = await el.say('Hello world', './hello.mp3')\nconsole.log(`Audio saved to ${path}`)"
21867
- }
21868
- ]
21869
- }
21870
- },
21871
- "getters": {
21872
- "apiKey": {
21873
- "description": "The resolved API key from options or environment.",
21874
- "returns": "string"
21875
- }
21876
- },
21877
- "events": {
21878
- "failure": {
21879
- "name": "failure",
21880
- "description": "Event emitted by ElevenLabsClient",
21881
- "arguments": {}
21882
- },
21883
- "voices": {
21884
- "name": "voices",
21885
- "description": "Event emitted by ElevenLabsClient",
21886
- "arguments": {}
21887
- },
21888
- "speech": {
21889
- "name": "speech",
21890
- "description": "Event emitted by ElevenLabsClient",
22213
+ "models": {
22214
+ "name": "models",
22215
+ "description": "Event emitted by OpenAIClient",
21891
22216
  "arguments": {}
21892
22217
  }
21893
22218
  },
@@ -21897,7 +22222,7 @@ export const introspectionData = [
21897
22222
  "examples": [
21898
22223
  {
21899
22224
  "language": "ts",
21900
- "code": "const el = container.client('elevenlabs')\nawait el.connect()\nconst voices = await el.listVoices()\nconst audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data"
22225
+ "code": "const openai = container.client('openai', { defaultModel: 'gpt-4o' })\nconst answer = await openai.ask('What is the meaning of life?')\nconsole.log(answer)"
21901
22226
  }
21902
22227
  ]
21903
22228
  },
@@ -22347,6 +22672,207 @@ export const introspectionData = [
22347
22672
  }
22348
22673
  ]
22349
22674
  },
22675
+ {
22676
+ "id": "clients.elevenlabs",
22677
+ "description": "ElevenLabs client — text-to-speech synthesis via the ElevenLabs REST API. Provides methods for listing voices, listing models, and generating speech audio. Audio is returned as a Buffer; use `say()` for a convenience method that writes to disk.",
22678
+ "shortcut": "clients.elevenlabs",
22679
+ "className": "ElevenLabsClient",
22680
+ "methods": {
22681
+ "beforeRequest": {
22682
+ "description": "Inject the xi-api-key header before each request.",
22683
+ "parameters": {},
22684
+ "required": [],
22685
+ "returns": "void"
22686
+ },
22687
+ "connect": {
22688
+ "description": "Validate the API key by listing available models.",
22689
+ "parameters": {},
22690
+ "required": [],
22691
+ "returns": "Promise<this>",
22692
+ "examples": [
22693
+ {
22694
+ "language": "ts",
22695
+ "code": "await el.connect()"
22696
+ }
22697
+ ]
22698
+ },
22699
+ "listVoices": {
22700
+ "description": "List available voices with optional search and filtering.",
22701
+ "parameters": {
22702
+ "options": {
22703
+ "type": "{\n search?: string\n category?: string\n voice_type?: string\n page_size?: number\n next_page_token?: string\n }",
22704
+ "description": "Query parameters for filtering voices"
22705
+ }
22706
+ },
22707
+ "required": [],
22708
+ "returns": "Promise<any>",
22709
+ "examples": [
22710
+ {
22711
+ "language": "ts",
22712
+ "code": "const voices = await el.listVoices()\nconst premade = await el.listVoices({ category: 'premade' })"
22713
+ }
22714
+ ]
22715
+ },
22716
+ "getVoice": {
22717
+ "description": "Get details for a single voice.",
22718
+ "parameters": {
22719
+ "voiceId": {
22720
+ "type": "string",
22721
+ "description": "The voice ID to look up"
22722
+ }
22723
+ },
22724
+ "required": [
22725
+ "voiceId"
22726
+ ],
22727
+ "returns": "Promise<any>",
22728
+ "examples": [
22729
+ {
22730
+ "language": "ts",
22731
+ "code": "const voice = await el.getVoice('21m00Tcm4TlvDq8ikWAM')\nconsole.log(voice.name, voice.settings)"
22732
+ }
22733
+ ]
22734
+ },
22735
+ "listModels": {
22736
+ "description": "List available TTS models.",
22737
+ "parameters": {},
22738
+ "required": [],
22739
+ "returns": "Promise<any[]>",
22740
+ "examples": [
22741
+ {
22742
+ "language": "ts",
22743
+ "code": "const models = await el.listModels()\nconsole.log(models.map(m => m.model_id))"
22744
+ }
22745
+ ]
22746
+ },
22747
+ "synthesize": {
22748
+ "description": "Synthesize speech from text, returning audio as a Buffer.",
22749
+ "parameters": {
22750
+ "text": {
22751
+ "type": "string",
22752
+ "description": "The text to convert to speech"
22753
+ },
22754
+ "options": {
22755
+ "type": "SynthesizeOptions",
22756
+ "description": "Voice, model, format, and voice settings overrides",
22757
+ "properties": {
22758
+ "voiceId": {
22759
+ "type": "string",
22760
+ "description": ""
22761
+ },
22762
+ "modelId": {
22763
+ "type": "string",
22764
+ "description": ""
22765
+ },
22766
+ "outputFormat": {
22767
+ "type": "string",
22768
+ "description": ""
22769
+ },
22770
+ "voiceSettings": {
22771
+ "type": "ElevenLabsVoiceSettings",
22772
+ "description": ""
22773
+ },
22774
+ "disableCache": {
22775
+ "type": "boolean",
22776
+ "description": ""
22777
+ }
22778
+ }
22779
+ }
22780
+ },
22781
+ "required": [
22782
+ "text"
22783
+ ],
22784
+ "returns": "Promise<Buffer>",
22785
+ "examples": [
22786
+ {
22787
+ "language": "ts",
22788
+ "code": "const audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data\n\nconst custom = await el.synthesize('Hello', {\n voiceId: '21m00Tcm4TlvDq8ikWAM',\n voiceSettings: { stability: 0.5, similarityBoost: 0.8 }\n})"
22789
+ }
22790
+ ]
22791
+ },
22792
+ "say": {
22793
+ "description": "Synthesize speech and write the audio to a file.",
22794
+ "parameters": {
22795
+ "text": {
22796
+ "type": "string",
22797
+ "description": "The text to convert to speech"
22798
+ },
22799
+ "outputPath": {
22800
+ "type": "string",
22801
+ "description": "File path to write the audio to"
22802
+ },
22803
+ "options": {
22804
+ "type": "SynthesizeOptions",
22805
+ "description": "Voice, model, format, and voice settings overrides",
22806
+ "properties": {
22807
+ "voiceId": {
22808
+ "type": "string",
22809
+ "description": ""
22810
+ },
22811
+ "modelId": {
22812
+ "type": "string",
22813
+ "description": ""
22814
+ },
22815
+ "outputFormat": {
22816
+ "type": "string",
22817
+ "description": ""
22818
+ },
22819
+ "voiceSettings": {
22820
+ "type": "ElevenLabsVoiceSettings",
22821
+ "description": ""
22822
+ },
22823
+ "disableCache": {
22824
+ "type": "boolean",
22825
+ "description": ""
22826
+ }
22827
+ }
22828
+ }
22829
+ },
22830
+ "required": [
22831
+ "text",
22832
+ "outputPath"
22833
+ ],
22834
+ "returns": "Promise<string>",
22835
+ "examples": [
22836
+ {
22837
+ "language": "ts",
22838
+ "code": "const path = await el.say('Hello world', './hello.mp3')\nconsole.log(`Audio saved to ${path}`)"
22839
+ }
22840
+ ]
22841
+ }
22842
+ },
22843
+ "getters": {
22844
+ "apiKey": {
22845
+ "description": "The resolved API key from options or environment.",
22846
+ "returns": "string"
22847
+ }
22848
+ },
22849
+ "events": {
22850
+ "failure": {
22851
+ "name": "failure",
22852
+ "description": "Event emitted by ElevenLabsClient",
22853
+ "arguments": {}
22854
+ },
22855
+ "voices": {
22856
+ "name": "voices",
22857
+ "description": "Event emitted by ElevenLabsClient",
22858
+ "arguments": {}
22859
+ },
22860
+ "speech": {
22861
+ "name": "speech",
22862
+ "description": "Event emitted by ElevenLabsClient",
22863
+ "arguments": {}
22864
+ }
22865
+ },
22866
+ "state": {},
22867
+ "options": {},
22868
+ "envVars": [],
22869
+ "examples": [
22870
+ {
22871
+ "language": "ts",
22872
+ "code": "const el = container.client('elevenlabs')\nawait el.connect()\nconst voices = await el.listVoices()\nconst audio = await el.synthesize('Hello world')\n// audio is a Buffer of mp3 data"
22873
+ }
22874
+ ]
22875
+ },
22350
22876
  {
22351
22877
  "id": "servers.mcp",
22352
22878
  "description": "MCP (Model Context Protocol) server for exposing tools, resources, and prompts to AI clients like Claude Code. Uses the low-level MCP SDK Server class directly with Zod 4 native JSON Schema conversion. Register tools, resources, and prompts programmatically, then start the server over stdio (for CLI integration) or HTTP (for remote access).",
@@ -22629,7 +23155,7 @@ export const introspectionData = [
22629
23155
  },
22630
23156
  {
22631
23157
  "id": "servers.websocket",
22632
- "description": "WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety.",
23158
+ "description": "WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety. Supports ask/reply semantics when paired with the Luca WebSocket client. The server can `ask(ws, type, data)` a connected client and await a typed response, or handle incoming asks from clients by listening for messages with a `requestId` and replying via `send(ws, { replyTo, data })`. Requests time out if no reply arrives within the configurable window.",
22633
23159
  "shortcut": "servers.websocket",
22634
23160
  "className": "WebsocketServer",
22635
23161
  "methods": {
@@ -22664,6 +23190,64 @@ export const introspectionData = [
22664
23190
  ],
22665
23191
  "returns": "void"
22666
23192
  },
23193
+ "ask": {
23194
+ "description": "Send a request to a specific client and wait for a correlated response. The client is expected to reply with a message whose `replyTo` matches the `requestId` of this message.",
23195
+ "parameters": {
23196
+ "ws": {
23197
+ "type": "any",
23198
+ "description": "The WebSocket client to ask"
23199
+ },
23200
+ "type": {
23201
+ "type": "string",
23202
+ "description": "A string identifying the request type"
23203
+ },
23204
+ "data": {
23205
+ "type": "any",
23206
+ "description": "Optional payload"
23207
+ },
23208
+ "timeout": {
23209
+ "type": "any",
23210
+ "description": "How long to wait (default 10 000 ms)"
23211
+ }
23212
+ },
23213
+ "required": [
23214
+ "ws",
23215
+ "type"
23216
+ ],
23217
+ "returns": "Promise<R>",
23218
+ "examples": [
23219
+ {
23220
+ "language": "ts",
23221
+ "code": "ws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
23222
+ }
23223
+ ]
23224
+ },
23225
+ "_handleReply": {
23226
+ "description": "",
23227
+ "parameters": {
23228
+ "message": {
23229
+ "type": "any",
23230
+ "description": "Parameter message"
23231
+ }
23232
+ },
23233
+ "required": [
23234
+ "message"
23235
+ ],
23236
+ "returns": "boolean"
23237
+ },
23238
+ "_rejectAllPending": {
23239
+ "description": "",
23240
+ "parameters": {
23241
+ "reason": {
23242
+ "type": "string",
23243
+ "description": "Parameter reason"
23244
+ }
23245
+ },
23246
+ "required": [
23247
+ "reason"
23248
+ ],
23249
+ "returns": "void"
23250
+ },
22667
23251
  "start": {
22668
23252
  "description": "Start the WebSocket server. A runtime `port` overrides the constructor option and is written to state before the underlying `ws.Server` is created, so the server binds to the correct port.",
22669
23253
  "parameters": {
@@ -22710,7 +23294,7 @@ export const introspectionData = [
22710
23294
  "examples": [
22711
23295
  {
22712
23296
  "language": "ts",
22713
- "code": "const ws = container.server('websocket', { json: true })\nawait ws.start({ port: 8080 })\n\nws.on('message', (data, client) => {\n console.log('Received:', data)\n ws.broadcast({ echo: data })\n})"
23297
+ "code": "const ws = container.server('websocket', { json: true })\nawait ws.start({ port: 8080 })\n\nws.on('message', (data, client) => {\n console.log('Received:', data)\n ws.broadcast({ echo: data })\n})\n\n// ask/reply: request info from a connected client\nws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
22714
23298
  }
22715
23299
  ]
22716
23300
  }