@soederpop/luca 0.0.26 → 0.0.28

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-23T07:45:56.976Z
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",
@@ -6223,7 +6247,7 @@ setBuildTimeData('features.fs', {
6223
6247
 
6224
6248
  setBuildTimeData('features.ipcSocket', {
6225
6249
  "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' }); ```",
6250
+ "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
6251
  "shortcut": "features.ipcSocket",
6228
6252
  "className": "IpcSocket",
6229
6253
  "methods": {
@@ -6263,61 +6287,127 @@ setBuildTimeData('features.ipcSocket', {
6263
6287
  ]
6264
6288
  },
6265
6289
  "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>\" } ```",
6290
+ "description": "Broadcasts a message to all connected clients (server mode only).",
6267
6291
  "parameters": {
6268
6292
  "message": {
6269
6293
  "type": "any",
6270
- "description": "The message object to broadcast to all clients"
6294
+ "description": "The message object to broadcast"
6295
+ },
6296
+ "exclude": {
6297
+ "type": "string",
6298
+ "description": "Optional client ID to exclude from broadcast"
6271
6299
  }
6272
6300
  },
6273
6301
  "required": [
6274
6302
  "message"
6275
6303
  ],
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() });"
6304
+ "returns": "void"
6305
+ },
6306
+ "sendTo": {
6307
+ "description": "Sends a message to a specific client by ID (server mode only).",
6308
+ "parameters": {
6309
+ "clientId": {
6310
+ "type": "string",
6311
+ "description": "The target client ID"
6312
+ },
6313
+ "message": {
6314
+ "type": "any",
6315
+ "description": "The message to send"
6281
6316
  }
6282
- ]
6317
+ },
6318
+ "required": [
6319
+ "clientId",
6320
+ "message"
6321
+ ],
6322
+ "returns": "boolean"
6283
6323
  },
6284
6324
  "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>\" } ```",
6325
+ "description": "Fire-and-forget: sends a message to the server (client mode only). For server→client, use sendTo() or broadcast().",
6286
6326
  "parameters": {
6287
6327
  "message": {
6288
6328
  "type": "any",
6289
- "description": "The message object to send to the server"
6329
+ "description": "The message to send"
6290
6330
  }
6291
6331
  },
6292
6332
  "required": [
6293
6333
  "message"
6294
6334
  ],
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});"
6335
+ "returns": "void"
6336
+ },
6337
+ "ask": {
6338
+ "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.",
6339
+ "parameters": {
6340
+ "message": {
6341
+ "type": "any",
6342
+ "description": "The message to send"
6343
+ },
6344
+ "options": {
6345
+ "type": "{ clientId?: string; timeoutMs?: number }",
6346
+ "description": "Optional: clientId (server mode target), timeoutMs"
6300
6347
  }
6301
- ]
6348
+ },
6349
+ "required": [
6350
+ "message"
6351
+ ],
6352
+ "returns": "Promise<any>"
6353
+ },
6354
+ "reply": {
6355
+ "description": "Sends a reply to a previous ask() call, correlated by requestId.",
6356
+ "parameters": {
6357
+ "requestId": {
6358
+ "type": "string",
6359
+ "description": "The requestId from the incoming message"
6360
+ },
6361
+ "data": {
6362
+ "type": "any",
6363
+ "description": "The reply payload"
6364
+ },
6365
+ "clientId": {
6366
+ "type": "string",
6367
+ "description": "Target client (server mode; for client mode, omit)"
6368
+ }
6369
+ },
6370
+ "required": [
6371
+ "requestId",
6372
+ "data"
6373
+ ],
6374
+ "returns": "void"
6302
6375
  },
6303
6376
  "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",
6377
+ "description": "Connects to an IPC server at the specified socket path (client mode).",
6305
6378
  "parameters": {
6306
6379
  "socketPath": {
6307
6380
  "type": "string",
6308
- "description": "The file system path to the server's Unix domain socket"
6381
+ "description": "Path to the server's Unix domain socket"
6382
+ },
6383
+ "options": {
6384
+ "type": "{ reconnect?: boolean; name?: string }",
6385
+ "description": "Optional: reconnect (enable auto-reconnect), name (identify this client)"
6309
6386
  }
6310
6387
  },
6311
6388
  "required": [
6312
6389
  "socketPath"
6313
6390
  ],
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' });"
6391
+ "returns": "Promise<Socket>"
6392
+ },
6393
+ "disconnect": {
6394
+ "description": "Disconnects the client and stops any reconnection attempts.",
6395
+ "parameters": {},
6396
+ "required": [],
6397
+ "returns": "void"
6398
+ },
6399
+ "probeSocket": {
6400
+ "description": "Probe an existing socket to see if a live listener is behind it. Attempts a quick connect — if it succeeds, someone is listening.",
6401
+ "parameters": {
6402
+ "socketPath": {
6403
+ "type": "string",
6404
+ "description": "Parameter socketPath"
6319
6405
  }
6320
- ]
6406
+ },
6407
+ "required": [
6408
+ "socketPath"
6409
+ ],
6410
+ "returns": "Promise<boolean>"
6321
6411
  }
6322
6412
  },
6323
6413
  "getters": {
@@ -6329,12 +6419,25 @@ setBuildTimeData('features.ipcSocket', {
6329
6419
  "description": "Checks if the IPC socket is operating in server mode.",
6330
6420
  "returns": "any"
6331
6421
  },
6422
+ "clientCount": {
6423
+ "description": "Returns the number of currently connected clients (server mode).",
6424
+ "returns": "any"
6425
+ },
6426
+ "connectedClients": {
6427
+ "description": "Returns info about all connected clients (server mode).",
6428
+ "returns": "Array<{ id: string; name?: string; connectedAt: number }>"
6429
+ },
6332
6430
  "connection": {
6333
6431
  "description": "Gets the current client connection socket.",
6334
6432
  "returns": "any"
6335
6433
  }
6336
6434
  },
6337
6435
  "events": {
6436
+ "disconnection": {
6437
+ "name": "disconnection",
6438
+ "description": "Event emitted by IpcSocket",
6439
+ "arguments": {}
6440
+ },
6338
6441
  "connection": {
6339
6442
  "name": "connection",
6340
6443
  "description": "Event emitted by IpcSocket",
@@ -7255,10 +7358,68 @@ setBuildTimeData('features.packageFinder', {
7255
7358
 
7256
7359
  setBuildTimeData('features.processManager', {
7257
7360
  "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.",
7361
+ "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
7362
  "shortcut": "features.processManager",
7260
7363
  "className": "ProcessManager",
7261
7364
  "methods": {
7365
+ "spawnProcess": {
7366
+ "description": "Tool handler: spawn a long-running background process.",
7367
+ "parameters": {
7368
+ "args": {
7369
+ "type": "{ command: string; args?: string; tag?: string; cwd?: string }",
7370
+ "description": "Parameter args"
7371
+ }
7372
+ },
7373
+ "required": [
7374
+ "args"
7375
+ ],
7376
+ "returns": "void"
7377
+ },
7378
+ "runCommand": {
7379
+ "description": "Tool handler: run a command to completion and return its output.",
7380
+ "parameters": {
7381
+ "args": {
7382
+ "type": "{ command: string; cwd?: string }",
7383
+ "description": "Parameter args"
7384
+ }
7385
+ },
7386
+ "required": [
7387
+ "args"
7388
+ ],
7389
+ "returns": "void"
7390
+ },
7391
+ "listProcesses": {
7392
+ "description": "Tool handler: list all tracked processes.",
7393
+ "parameters": {},
7394
+ "required": [],
7395
+ "returns": "void"
7396
+ },
7397
+ "getProcessOutput": {
7398
+ "description": "Tool handler: peek at a process's buffered output.",
7399
+ "parameters": {
7400
+ "args": {
7401
+ "type": "{ id?: string; tag?: string; stream?: string }",
7402
+ "description": "Parameter args"
7403
+ }
7404
+ },
7405
+ "required": [
7406
+ "args"
7407
+ ],
7408
+ "returns": "void"
7409
+ },
7410
+ "killProcess": {
7411
+ "description": "Tool handler: kill a process by ID or tag.",
7412
+ "parameters": {
7413
+ "args": {
7414
+ "type": "{ id?: string; tag?: string; signal?: string }",
7415
+ "description": "Parameter args"
7416
+ }
7417
+ },
7418
+ "required": [
7419
+ "args"
7420
+ ],
7421
+ "returns": "void"
7422
+ },
7262
7423
  "spawn": {
7263
7424
  "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
7425
  "parameters": {
@@ -7436,7 +7597,7 @@ setBuildTimeData('features.processManager', {
7436
7597
  "examples": [
7437
7598
  {
7438
7599
  "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"
7600
+ "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
7601
  }
7441
7602
  ]
7442
7603
  });
@@ -9805,7 +9966,7 @@ setBuildTimeData('clients.rest', {
9805
9966
 
9806
9967
  setBuildTimeData('clients.websocket', {
9807
9968
  "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)",
9969
+ "description": "WebSocketClient helper",
9809
9970
  "shortcut": "clients.websocket",
9810
9971
  "className": "WebSocketClient",
9811
9972
  "methods": {
@@ -9828,6 +9989,59 @@ setBuildTimeData('clients.websocket', {
9828
9989
  ],
9829
9990
  "returns": "Promise<void>"
9830
9991
  },
9992
+ "ask": {
9993
+ "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.",
9994
+ "parameters": {
9995
+ "type": {
9996
+ "type": "string",
9997
+ "description": "A string identifying the request type"
9998
+ },
9999
+ "data": {
10000
+ "type": "any",
10001
+ "description": "Optional payload to include with the request"
10002
+ },
10003
+ "timeout": {
10004
+ "type": "any",
10005
+ "description": "How long to wait for a response (default 10 000 ms)"
10006
+ }
10007
+ },
10008
+ "required": [
10009
+ "type"
10010
+ ],
10011
+ "returns": "Promise<R>",
10012
+ "examples": [
10013
+ {
10014
+ "language": "ts",
10015
+ "code": "const result = await ws.ask('getUser', { id: 42 })"
10016
+ }
10017
+ ]
10018
+ },
10019
+ "_handleReply": {
10020
+ "description": "",
10021
+ "parameters": {
10022
+ "message": {
10023
+ "type": "any",
10024
+ "description": "Parameter message"
10025
+ }
10026
+ },
10027
+ "required": [
10028
+ "message"
10029
+ ],
10030
+ "returns": "boolean"
10031
+ },
10032
+ "_rejectAllPending": {
10033
+ "description": "",
10034
+ "parameters": {
10035
+ "reason": {
10036
+ "type": "string",
10037
+ "description": "Parameter reason"
10038
+ }
10039
+ },
10040
+ "required": [
10041
+ "reason"
10042
+ ],
10043
+ "returns": "void"
10044
+ },
9831
10045
  "disconnect": {
9832
10046
  "description": "Gracefully close the WebSocket connection. Suppresses auto-reconnect and updates connection state to disconnected.",
9833
10047
  "parameters": {},
@@ -9870,13 +10084,7 @@ setBuildTimeData('clients.websocket', {
9870
10084
  },
9871
10085
  "state": {},
9872
10086
  "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
- ]
10087
+ "envVars": []
9880
10088
  });
9881
10089
 
9882
10090
  setBuildTimeData('clients.openai', {
@@ -11081,7 +11289,7 @@ setBuildTimeData('servers.express', {
11081
11289
 
11082
11290
  setBuildTimeData('servers.websocket', {
11083
11291
  "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.",
11292
+ "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
11293
  "shortcut": "servers.websocket",
11086
11294
  "className": "WebsocketServer",
11087
11295
  "methods": {
@@ -11116,6 +11324,64 @@ setBuildTimeData('servers.websocket', {
11116
11324
  ],
11117
11325
  "returns": "void"
11118
11326
  },
11327
+ "ask": {
11328
+ "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.",
11329
+ "parameters": {
11330
+ "ws": {
11331
+ "type": "any",
11332
+ "description": "The WebSocket client to ask"
11333
+ },
11334
+ "type": {
11335
+ "type": "string",
11336
+ "description": "A string identifying the request type"
11337
+ },
11338
+ "data": {
11339
+ "type": "any",
11340
+ "description": "Optional payload"
11341
+ },
11342
+ "timeout": {
11343
+ "type": "any",
11344
+ "description": "How long to wait (default 10 000 ms)"
11345
+ }
11346
+ },
11347
+ "required": [
11348
+ "ws",
11349
+ "type"
11350
+ ],
11351
+ "returns": "Promise<R>",
11352
+ "examples": [
11353
+ {
11354
+ "language": "ts",
11355
+ "code": "ws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
11356
+ }
11357
+ ]
11358
+ },
11359
+ "_handleReply": {
11360
+ "description": "",
11361
+ "parameters": {
11362
+ "message": {
11363
+ "type": "any",
11364
+ "description": "Parameter message"
11365
+ }
11366
+ },
11367
+ "required": [
11368
+ "message"
11369
+ ],
11370
+ "returns": "boolean"
11371
+ },
11372
+ "_rejectAllPending": {
11373
+ "description": "",
11374
+ "parameters": {
11375
+ "reason": {
11376
+ "type": "string",
11377
+ "description": "Parameter reason"
11378
+ }
11379
+ },
11380
+ "required": [
11381
+ "reason"
11382
+ ],
11383
+ "returns": "void"
11384
+ },
11119
11385
  "start": {
11120
11386
  "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
11387
  "parameters": {
@@ -11162,7 +11428,7 @@ setBuildTimeData('servers.websocket', {
11162
11428
  "examples": [
11163
11429
  {
11164
11430
  "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})"
11431
+ "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
11432
  }
11167
11433
  ]
11168
11434
  });
@@ -13118,7 +13384,7 @@ export const introspectionData = [
13118
13384
  },
13119
13385
  {
13120
13386
  "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",
13387
+ "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
13388
  "shortcut": "features.windowManager",
13123
13389
  "className": "WindowManager",
13124
13390
  "methods": {
@@ -13134,7 +13400,18 @@ export const introspectionData = [
13134
13400
  "returns": "Promise<this>"
13135
13401
  },
13136
13402
  "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.",
13403
+ "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.",
13404
+ "parameters": {
13405
+ "socketPath": {
13406
+ "type": "string",
13407
+ "description": "Override the configured app socket path"
13408
+ }
13409
+ },
13410
+ "required": [],
13411
+ "returns": "Promise<this>"
13412
+ },
13413
+ "cleanupSocket": {
13414
+ "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
13415
  "parameters": {
13139
13416
  "socketPath": {
13140
13417
  "type": "string",
@@ -13142,10 +13419,10 @@ export const introspectionData = [
13142
13419
  }
13143
13420
  },
13144
13421
  "required": [],
13145
- "returns": "this"
13422
+ "returns": "Promise<boolean>"
13146
13423
  },
13147
13424
  "stop": {
13148
- "description": "Stop the IPC server and clean up all connections. Rejects any pending window operation requests.",
13425
+ "description": "Stop the window manager and clean up all connections. Rejects any pending window operation requests.",
13149
13426
  "parameters": {},
13150
13427
  "required": [],
13151
13428
  "returns": "Promise<this>"
@@ -13418,7 +13695,7 @@ export const introspectionData = [
13418
13695
  ]
13419
13696
  },
13420
13697
  "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.",
13698
+ "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
13699
  "parameters": {
13423
13700
  "msg": {
13424
13701
  "type": "Record<string, any>",
@@ -13432,12 +13709,20 @@ export const introspectionData = [
13432
13709
  }
13433
13710
  },
13434
13711
  "getters": {
13712
+ "isBroker": {
13713
+ "description": "Whether this instance is acting as the broker.",
13714
+ "returns": "boolean"
13715
+ },
13716
+ "isProducer": {
13717
+ "description": "Whether this instance is acting as a producer.",
13718
+ "returns": "boolean"
13719
+ },
13435
13720
  "isListening": {
13436
- "description": "Whether the IPC server is currently listening.",
13721
+ "description": "Whether the IPC server is currently listening (broker) or connected to broker (producer).",
13437
13722
  "returns": "boolean"
13438
13723
  },
13439
13724
  "isClientConnected": {
13440
- "description": "Whether the native app client is currently connected.",
13725
+ "description": "Whether the native app client is currently connected (only meaningful for broker).",
13441
13726
  "returns": "boolean"
13442
13727
  }
13443
13728
  },
@@ -13472,6 +13757,11 @@ export const introspectionData = [
13472
13757
  "description": "Event emitted by WindowManager",
13473
13758
  "arguments": {}
13474
13759
  },
13760
+ "windowFocus": {
13761
+ "name": "windowFocus",
13762
+ "description": "Event emitted by WindowManager",
13763
+ "arguments": {}
13764
+ },
13475
13765
  "message": {
13476
13766
  "name": "message",
13477
13767
  "description": "Event emitted by WindowManager",
@@ -17795,7 +18085,7 @@ export const introspectionData = [
17795
18085
  },
17796
18086
  {
17797
18087
  "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' }); ```",
18088
+ "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
18089
  "shortcut": "features.ipcSocket",
17800
18090
  "className": "IpcSocket",
17801
18091
  "methods": {
@@ -17835,61 +18125,127 @@ export const introspectionData = [
17835
18125
  ]
17836
18126
  },
17837
18127
  "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>\" } ```",
18128
+ "description": "Broadcasts a message to all connected clients (server mode only).",
17839
18129
  "parameters": {
17840
18130
  "message": {
17841
18131
  "type": "any",
17842
- "description": "The message object to broadcast to all clients"
18132
+ "description": "The message object to broadcast"
18133
+ },
18134
+ "exclude": {
18135
+ "type": "string",
18136
+ "description": "Optional client ID to exclude from broadcast"
17843
18137
  }
17844
18138
  },
17845
18139
  "required": [
17846
18140
  "message"
17847
18141
  ],
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() });"
18142
+ "returns": "void"
18143
+ },
18144
+ "sendTo": {
18145
+ "description": "Sends a message to a specific client by ID (server mode only).",
18146
+ "parameters": {
18147
+ "clientId": {
18148
+ "type": "string",
18149
+ "description": "The target client ID"
18150
+ },
18151
+ "message": {
18152
+ "type": "any",
18153
+ "description": "The message to send"
17853
18154
  }
17854
- ]
18155
+ },
18156
+ "required": [
18157
+ "clientId",
18158
+ "message"
18159
+ ],
18160
+ "returns": "boolean"
17855
18161
  },
17856
18162
  "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>\" } ```",
18163
+ "description": "Fire-and-forget: sends a message to the server (client mode only). For server→client, use sendTo() or broadcast().",
17858
18164
  "parameters": {
17859
18165
  "message": {
17860
18166
  "type": "any",
17861
- "description": "The message object to send to the server"
18167
+ "description": "The message to send"
17862
18168
  }
17863
18169
  },
17864
18170
  "required": [
17865
18171
  "message"
17866
18172
  ],
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});"
18173
+ "returns": "void"
18174
+ },
18175
+ "ask": {
18176
+ "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.",
18177
+ "parameters": {
18178
+ "message": {
18179
+ "type": "any",
18180
+ "description": "The message to send"
18181
+ },
18182
+ "options": {
18183
+ "type": "{ clientId?: string; timeoutMs?: number }",
18184
+ "description": "Optional: clientId (server mode target), timeoutMs"
17872
18185
  }
17873
- ]
18186
+ },
18187
+ "required": [
18188
+ "message"
18189
+ ],
18190
+ "returns": "Promise<any>"
18191
+ },
18192
+ "reply": {
18193
+ "description": "Sends a reply to a previous ask() call, correlated by requestId.",
18194
+ "parameters": {
18195
+ "requestId": {
18196
+ "type": "string",
18197
+ "description": "The requestId from the incoming message"
18198
+ },
18199
+ "data": {
18200
+ "type": "any",
18201
+ "description": "The reply payload"
18202
+ },
18203
+ "clientId": {
18204
+ "type": "string",
18205
+ "description": "Target client (server mode; for client mode, omit)"
18206
+ }
18207
+ },
18208
+ "required": [
18209
+ "requestId",
18210
+ "data"
18211
+ ],
18212
+ "returns": "void"
17874
18213
  },
17875
18214
  "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",
18215
+ "description": "Connects to an IPC server at the specified socket path (client mode).",
17877
18216
  "parameters": {
17878
18217
  "socketPath": {
17879
18218
  "type": "string",
17880
- "description": "The file system path to the server's Unix domain socket"
18219
+ "description": "Path to the server's Unix domain socket"
18220
+ },
18221
+ "options": {
18222
+ "type": "{ reconnect?: boolean; name?: string }",
18223
+ "description": "Optional: reconnect (enable auto-reconnect), name (identify this client)"
17881
18224
  }
17882
18225
  },
17883
18226
  "required": [
17884
18227
  "socketPath"
17885
18228
  ],
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' });"
18229
+ "returns": "Promise<Socket>"
18230
+ },
18231
+ "disconnect": {
18232
+ "description": "Disconnects the client and stops any reconnection attempts.",
18233
+ "parameters": {},
18234
+ "required": [],
18235
+ "returns": "void"
18236
+ },
18237
+ "probeSocket": {
18238
+ "description": "Probe an existing socket to see if a live listener is behind it. Attempts a quick connect — if it succeeds, someone is listening.",
18239
+ "parameters": {
18240
+ "socketPath": {
18241
+ "type": "string",
18242
+ "description": "Parameter socketPath"
17891
18243
  }
17892
- ]
18244
+ },
18245
+ "required": [
18246
+ "socketPath"
18247
+ ],
18248
+ "returns": "Promise<boolean>"
17893
18249
  }
17894
18250
  },
17895
18251
  "getters": {
@@ -17901,12 +18257,25 @@ export const introspectionData = [
17901
18257
  "description": "Checks if the IPC socket is operating in server mode.",
17902
18258
  "returns": "any"
17903
18259
  },
18260
+ "clientCount": {
18261
+ "description": "Returns the number of currently connected clients (server mode).",
18262
+ "returns": "any"
18263
+ },
18264
+ "connectedClients": {
18265
+ "description": "Returns info about all connected clients (server mode).",
18266
+ "returns": "Array<{ id: string; name?: string; connectedAt: number }>"
18267
+ },
17904
18268
  "connection": {
17905
18269
  "description": "Gets the current client connection socket.",
17906
18270
  "returns": "any"
17907
18271
  }
17908
18272
  },
17909
18273
  "events": {
18274
+ "disconnection": {
18275
+ "name": "disconnection",
18276
+ "description": "Event emitted by IpcSocket",
18277
+ "arguments": {}
18278
+ },
17910
18279
  "connection": {
17911
18280
  "name": "connection",
17912
18281
  "description": "Event emitted by IpcSocket",
@@ -18821,10 +19190,68 @@ export const introspectionData = [
18821
19190
  },
18822
19191
  {
18823
19192
  "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.",
19193
+ "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
19194
  "shortcut": "features.processManager",
18826
19195
  "className": "ProcessManager",
18827
19196
  "methods": {
19197
+ "spawnProcess": {
19198
+ "description": "Tool handler: spawn a long-running background process.",
19199
+ "parameters": {
19200
+ "args": {
19201
+ "type": "{ command: string; args?: string; tag?: string; cwd?: string }",
19202
+ "description": "Parameter args"
19203
+ }
19204
+ },
19205
+ "required": [
19206
+ "args"
19207
+ ],
19208
+ "returns": "void"
19209
+ },
19210
+ "runCommand": {
19211
+ "description": "Tool handler: run a command to completion and return its output.",
19212
+ "parameters": {
19213
+ "args": {
19214
+ "type": "{ command: string; cwd?: string }",
19215
+ "description": "Parameter args"
19216
+ }
19217
+ },
19218
+ "required": [
19219
+ "args"
19220
+ ],
19221
+ "returns": "void"
19222
+ },
19223
+ "listProcesses": {
19224
+ "description": "Tool handler: list all tracked processes.",
19225
+ "parameters": {},
19226
+ "required": [],
19227
+ "returns": "void"
19228
+ },
19229
+ "getProcessOutput": {
19230
+ "description": "Tool handler: peek at a process's buffered output.",
19231
+ "parameters": {
19232
+ "args": {
19233
+ "type": "{ id?: string; tag?: string; stream?: string }",
19234
+ "description": "Parameter args"
19235
+ }
19236
+ },
19237
+ "required": [
19238
+ "args"
19239
+ ],
19240
+ "returns": "void"
19241
+ },
19242
+ "killProcess": {
19243
+ "description": "Tool handler: kill a process by ID or tag.",
19244
+ "parameters": {
19245
+ "args": {
19246
+ "type": "{ id?: string; tag?: string; signal?: string }",
19247
+ "description": "Parameter args"
19248
+ }
19249
+ },
19250
+ "required": [
19251
+ "args"
19252
+ ],
19253
+ "returns": "void"
19254
+ },
18828
19255
  "spawn": {
18829
19256
  "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
19257
  "parameters": {
@@ -19002,7 +19429,7 @@ export const introspectionData = [
19002
19429
  "examples": [
19003
19430
  {
19004
19431
  "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"
19432
+ "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
19433
  }
19007
19434
  ]
19008
19435
  },
@@ -21360,7 +21787,7 @@ export const introspectionData = [
21360
21787
  },
21361
21788
  {
21362
21789
  "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)",
21790
+ "description": "WebSocketClient helper",
21364
21791
  "shortcut": "clients.websocket",
21365
21792
  "className": "WebSocketClient",
21366
21793
  "methods": {
@@ -21383,6 +21810,59 @@ export const introspectionData = [
21383
21810
  ],
21384
21811
  "returns": "Promise<void>"
21385
21812
  },
21813
+ "ask": {
21814
+ "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.",
21815
+ "parameters": {
21816
+ "type": {
21817
+ "type": "string",
21818
+ "description": "A string identifying the request type"
21819
+ },
21820
+ "data": {
21821
+ "type": "any",
21822
+ "description": "Optional payload to include with the request"
21823
+ },
21824
+ "timeout": {
21825
+ "type": "any",
21826
+ "description": "How long to wait for a response (default 10 000 ms)"
21827
+ }
21828
+ },
21829
+ "required": [
21830
+ "type"
21831
+ ],
21832
+ "returns": "Promise<R>",
21833
+ "examples": [
21834
+ {
21835
+ "language": "ts",
21836
+ "code": "const result = await ws.ask('getUser', { id: 42 })"
21837
+ }
21838
+ ]
21839
+ },
21840
+ "_handleReply": {
21841
+ "description": "",
21842
+ "parameters": {
21843
+ "message": {
21844
+ "type": "any",
21845
+ "description": "Parameter message"
21846
+ }
21847
+ },
21848
+ "required": [
21849
+ "message"
21850
+ ],
21851
+ "returns": "boolean"
21852
+ },
21853
+ "_rejectAllPending": {
21854
+ "description": "",
21855
+ "parameters": {
21856
+ "reason": {
21857
+ "type": "string",
21858
+ "description": "Parameter reason"
21859
+ }
21860
+ },
21861
+ "required": [
21862
+ "reason"
21863
+ ],
21864
+ "returns": "void"
21865
+ },
21386
21866
  "disconnect": {
21387
21867
  "description": "Gracefully close the WebSocket connection. Suppresses auto-reconnect and updates connection state to disconnected.",
21388
21868
  "parameters": {},
@@ -21425,13 +21905,7 @@ export const introspectionData = [
21425
21905
  },
21426
21906
  "state": {},
21427
21907
  "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
- ]
21908
+ "envVars": []
21435
21909
  },
21436
21910
  {
21437
21911
  "id": "clients.openai",
@@ -22629,7 +23103,7 @@ export const introspectionData = [
22629
23103
  },
22630
23104
  {
22631
23105
  "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.",
23106
+ "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
23107
  "shortcut": "servers.websocket",
22634
23108
  "className": "WebsocketServer",
22635
23109
  "methods": {
@@ -22664,6 +23138,64 @@ export const introspectionData = [
22664
23138
  ],
22665
23139
  "returns": "void"
22666
23140
  },
23141
+ "ask": {
23142
+ "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.",
23143
+ "parameters": {
23144
+ "ws": {
23145
+ "type": "any",
23146
+ "description": "The WebSocket client to ask"
23147
+ },
23148
+ "type": {
23149
+ "type": "string",
23150
+ "description": "A string identifying the request type"
23151
+ },
23152
+ "data": {
23153
+ "type": "any",
23154
+ "description": "Optional payload"
23155
+ },
23156
+ "timeout": {
23157
+ "type": "any",
23158
+ "description": "How long to wait (default 10 000 ms)"
23159
+ }
23160
+ },
23161
+ "required": [
23162
+ "ws",
23163
+ "type"
23164
+ ],
23165
+ "returns": "Promise<R>",
23166
+ "examples": [
23167
+ {
23168
+ "language": "ts",
23169
+ "code": "ws.on('connection', async (client) => {\n const info = await ws.ask(client, 'identify')\n console.log('Client says:', info)\n})"
23170
+ }
23171
+ ]
23172
+ },
23173
+ "_handleReply": {
23174
+ "description": "",
23175
+ "parameters": {
23176
+ "message": {
23177
+ "type": "any",
23178
+ "description": "Parameter message"
23179
+ }
23180
+ },
23181
+ "required": [
23182
+ "message"
23183
+ ],
23184
+ "returns": "boolean"
23185
+ },
23186
+ "_rejectAllPending": {
23187
+ "description": "",
23188
+ "parameters": {
23189
+ "reason": {
23190
+ "type": "string",
23191
+ "description": "Parameter reason"
23192
+ }
23193
+ },
23194
+ "required": [
23195
+ "reason"
23196
+ ],
23197
+ "returns": "void"
23198
+ },
22667
23199
  "start": {
22668
23200
  "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
23201
  "parameters": {
@@ -22710,7 +23242,7 @@ export const introspectionData = [
22710
23242
  "examples": [
22711
23243
  {
22712
23244
  "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})"
23245
+ "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
23246
  }
22715
23247
  ]
22716
23248
  }