@soederpop/luca 0.0.28 → 0.0.30
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.
- package/commands/try-all-challenges.ts +1 -1
- package/docs/TABLE-OF-CONTENTS.md +0 -3
- package/docs/examples/structured-output-with-assistants.md +144 -0
- package/docs/tutorials/20-browser-esm.md +234 -0
- package/package.json +1 -1
- package/src/agi/container.server.ts +4 -0
- package/src/agi/features/assistant.ts +132 -2
- package/src/agi/features/browser-use.ts +623 -0
- package/src/agi/features/conversation.ts +135 -45
- package/src/agi/lib/interceptor-chain.ts +79 -0
- package/src/bootstrap/generated.ts +381 -308
- package/src/cli/build-info.ts +2 -2
- package/src/clients/rest.ts +7 -7
- package/src/commands/chat.ts +22 -0
- package/src/commands/describe.ts +67 -2
- package/src/commands/prompt.ts +23 -3
- package/src/container.ts +411 -113
- package/src/helper.ts +189 -5
- package/src/introspection/generated.agi.ts +17664 -11568
- package/src/introspection/generated.node.ts +4891 -1860
- package/src/introspection/generated.web.ts +379 -291
- package/src/introspection/index.ts +7 -0
- package/src/introspection/scan.ts +224 -7
- package/src/node/container.ts +31 -10
- package/src/node/features/content-db.ts +7 -7
- package/src/node/features/disk-cache.ts +11 -11
- package/src/node/features/esbuild.ts +3 -3
- package/src/node/features/file-manager.ts +37 -16
- package/src/node/features/fs.ts +64 -25
- package/src/node/features/git.ts +10 -10
- package/src/node/features/helpers.ts +25 -18
- package/src/node/features/ink.ts +13 -13
- package/src/node/features/ipc-socket.ts +8 -8
- package/src/node/features/networking.ts +3 -3
- package/src/node/features/os.ts +7 -7
- package/src/node/features/package-finder.ts +15 -15
- package/src/node/features/proc.ts +1 -1
- package/src/node/features/ui.ts +13 -13
- package/src/node/features/vm.ts +4 -4
- package/src/scaffolds/generated.ts +1 -1
- package/src/servers/express.ts +6 -6
- package/src/servers/mcp.ts +4 -4
- package/src/servers/socket.ts +6 -6
- package/test/interceptor-chain.test.ts +61 -0
- package/docs/apis/features/node/window-manager.md +0 -445
- package/docs/examples/window-manager-layouts.md +0 -180
- package/docs/examples/window-manager.md +0 -125
- package/docs/window-manager-fix.md +0 -249
- package/scripts/test-window-manager-lifecycle.ts +0 -86
- package/scripts/test-window-manager.ts +0 -43
- package/src/node/features/window-manager.ts +0 -1603
package/src/servers/socket.ts
CHANGED
|
@@ -65,7 +65,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
65
65
|
|
|
66
66
|
_wss?: BaseServer
|
|
67
67
|
|
|
68
|
-
get wss() {
|
|
68
|
+
get wss(): BaseServer {
|
|
69
69
|
if (this._wss) {
|
|
70
70
|
return this._wss
|
|
71
71
|
}
|
|
@@ -78,7 +78,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
78
78
|
connections : Set<any> = new Set()
|
|
79
79
|
_pending = new Map<string, PendingRequest>()
|
|
80
80
|
|
|
81
|
-
async broadcast(message: any) {
|
|
81
|
+
async broadcast(message: any): Promise<this> {
|
|
82
82
|
for(const ws of this.connections) {
|
|
83
83
|
await ws.send(JSON.stringify(message))
|
|
84
84
|
}
|
|
@@ -86,7 +86,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
86
86
|
return this
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
async send(ws: any, message: any) {
|
|
89
|
+
async send(ws: any, message: any): Promise<this> {
|
|
90
90
|
await ws.send(JSON.stringify(message))
|
|
91
91
|
return this
|
|
92
92
|
}
|
|
@@ -158,7 +158,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
158
158
|
*
|
|
159
159
|
* @param options - Optional runtime overrides for port and host
|
|
160
160
|
*/
|
|
161
|
-
override async start(options?: StartOptions) {
|
|
161
|
+
override async start(options?: StartOptions): Promise<this> {
|
|
162
162
|
if (this.isListening) {
|
|
163
163
|
return this
|
|
164
164
|
}
|
|
@@ -209,7 +209,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
209
209
|
return this
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
override async stop() {
|
|
212
|
+
override async stop(): Promise<this> {
|
|
213
213
|
if (this.isStopped) {
|
|
214
214
|
return this
|
|
215
215
|
}
|
|
@@ -250,7 +250,7 @@ export class WebsocketServer<T extends ServerState = ServerState, K extends Sock
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/** The port this server will bind to. Defaults to 8081 if not set via constructor options or start(). */
|
|
253
|
-
override get port() {
|
|
253
|
+
override get port(): number {
|
|
254
254
|
return this.state.get('port') || this.options.port || 8081
|
|
255
255
|
}
|
|
256
256
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, it, expect } from 'bun:test'
|
|
2
|
+
import { InterceptorChain } from '../src/agi/lib/interceptor-chain'
|
|
3
|
+
|
|
4
|
+
describe('InterceptorChain', () => {
|
|
5
|
+
it('runs interceptors in order then the final', async () => {
|
|
6
|
+
const chain = new InterceptorChain<{ log: string[] }>()
|
|
7
|
+
chain.add(async (ctx, next) => { ctx.log.push('a'); await next() })
|
|
8
|
+
chain.add(async (ctx, next) => { ctx.log.push('b'); await next() })
|
|
9
|
+
|
|
10
|
+
const ctx = { log: [] as string[] }
|
|
11
|
+
await chain.run(ctx, async () => { ctx.log.push('final') })
|
|
12
|
+
|
|
13
|
+
expect(ctx.log).toEqual(['a', 'b', 'final'])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('skips the final when an interceptor does not call next', async () => {
|
|
17
|
+
const chain = new InterceptorChain<{ log: string[] }>()
|
|
18
|
+
chain.add(async (ctx, _next) => { ctx.log.push('blocker') })
|
|
19
|
+
chain.add(async (ctx, next) => { ctx.log.push('never'); await next() })
|
|
20
|
+
|
|
21
|
+
const ctx = { log: [] as string[] }
|
|
22
|
+
await chain.run(ctx, async () => { ctx.log.push('final') })
|
|
23
|
+
|
|
24
|
+
expect(ctx.log).toEqual(['blocker'])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('allows interceptors to mutate ctx before and after next', async () => {
|
|
28
|
+
const chain = new InterceptorChain<{ value: number }>()
|
|
29
|
+
chain.add(async (ctx, next) => {
|
|
30
|
+
ctx.value *= 2
|
|
31
|
+
await next()
|
|
32
|
+
ctx.value += 100
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const ctx = { value: 5 }
|
|
36
|
+
await chain.run(ctx, async () => { ctx.value += 1 })
|
|
37
|
+
|
|
38
|
+
expect(ctx.value).toBe(111) // (5*2)=10, final +1=11, after +100=111
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('reports hasInterceptors and size', () => {
|
|
42
|
+
const chain = new InterceptorChain<{}>()
|
|
43
|
+
expect(chain.hasInterceptors).toBe(false)
|
|
44
|
+
expect(chain.size).toBe(0)
|
|
45
|
+
|
|
46
|
+
const fn = async (_ctx: {}, next: () => Promise<void>) => { await next() }
|
|
47
|
+
chain.add(fn)
|
|
48
|
+
expect(chain.hasInterceptors).toBe(true)
|
|
49
|
+
expect(chain.size).toBe(1)
|
|
50
|
+
|
|
51
|
+
chain.remove(fn)
|
|
52
|
+
expect(chain.hasInterceptors).toBe(false)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('runs just the final when no interceptors are registered', async () => {
|
|
56
|
+
const chain = new InterceptorChain<{ ran: boolean }>()
|
|
57
|
+
const ctx = { ran: false }
|
|
58
|
+
await chain.run(ctx, async () => { ctx.ran = true })
|
|
59
|
+
expect(ctx.ran).toBe(true)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
# WindowManager (features.windowManager)
|
|
2
|
-
|
|
3
|
-
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
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
container.feature('windowManager', {
|
|
9
|
-
// Path to the Unix domain socket the server listens on
|
|
10
|
-
socketPath,
|
|
11
|
-
// Automatically start listening when the feature is enabled
|
|
12
|
-
autoListen,
|
|
13
|
-
// Per-request timeout in milliseconds for window operations
|
|
14
|
-
requestTimeoutMs,
|
|
15
|
-
})
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Options (Zod v4 schema)
|
|
19
|
-
|
|
20
|
-
| Property | Type | Description |
|
|
21
|
-
|----------|------|-------------|
|
|
22
|
-
| `socketPath` | `string` | Path to the Unix domain socket the server listens on |
|
|
23
|
-
| `autoListen` | `boolean` | Automatically start listening when the feature is enabled |
|
|
24
|
-
| `requestTimeoutMs` | `number` | Per-request timeout in milliseconds for window operations |
|
|
25
|
-
|
|
26
|
-
## Methods
|
|
27
|
-
|
|
28
|
-
### enable
|
|
29
|
-
|
|
30
|
-
**Parameters:**
|
|
31
|
-
|
|
32
|
-
| Name | Type | Required | Description |
|
|
33
|
-
|------|------|----------|-------------|
|
|
34
|
-
| `options` | `any` | | Parameter options |
|
|
35
|
-
|
|
36
|
-
**Returns:** `Promise<this>`
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
### listen
|
|
41
|
-
|
|
42
|
-
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.
|
|
43
|
-
|
|
44
|
-
**Parameters:**
|
|
45
|
-
|
|
46
|
-
| Name | Type | Required | Description |
|
|
47
|
-
|------|------|----------|-------------|
|
|
48
|
-
| `socketPath` | `string` | | Override the configured socket path |
|
|
49
|
-
|
|
50
|
-
**Returns:** `this`
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
### stop
|
|
55
|
-
|
|
56
|
-
Stop the IPC server and clean up all connections. Rejects any pending window operation requests.
|
|
57
|
-
|
|
58
|
-
**Returns:** `Promise<this>`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### spawn
|
|
63
|
-
|
|
64
|
-
Spawn a new native browser window. Sends a window dispatch to the app and waits for the ack.
|
|
65
|
-
|
|
66
|
-
**Parameters:**
|
|
67
|
-
|
|
68
|
-
| Name | Type | Required | Description |
|
|
69
|
-
|------|------|----------|-------------|
|
|
70
|
-
| `opts` | `SpawnOptions` | | Window configuration (url, dimensions, chrome options) |
|
|
71
|
-
|
|
72
|
-
`SpawnOptions` properties:
|
|
73
|
-
|
|
74
|
-
| Property | Type | Description |
|
|
75
|
-
|----------|------|-------------|
|
|
76
|
-
| `url` | `string` | |
|
|
77
|
-
| `width` | `DimensionValue` | |
|
|
78
|
-
| `height` | `DimensionValue` | |
|
|
79
|
-
| `x` | `DimensionValue` | |
|
|
80
|
-
| `y` | `DimensionValue` | |
|
|
81
|
-
| `alwaysOnTop` | `boolean` | |
|
|
82
|
-
| `window` | `{
|
|
83
|
-
decorations?: 'normal' | 'hiddenTitleBar' | 'none'
|
|
84
|
-
transparent?: boolean
|
|
85
|
-
shadow?: boolean
|
|
86
|
-
alwaysOnTop?: boolean
|
|
87
|
-
opacity?: number
|
|
88
|
-
clickThrough?: boolean
|
|
89
|
-
}` | |
|
|
90
|
-
|
|
91
|
-
**Returns:** `Promise<WindowHandle>`
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
### spawnTTY
|
|
96
|
-
|
|
97
|
-
Spawn a native terminal window running a command. The terminal is read-only — stdout/stderr are rendered with ANSI support. Closing the window terminates the process.
|
|
98
|
-
|
|
99
|
-
**Parameters:**
|
|
100
|
-
|
|
101
|
-
| Name | Type | Required | Description |
|
|
102
|
-
|------|------|----------|-------------|
|
|
103
|
-
| `opts` | `SpawnTTYOptions` | ✓ | Terminal configuration (command, args, cwd, dimensions, etc.) |
|
|
104
|
-
|
|
105
|
-
`SpawnTTYOptions` properties:
|
|
106
|
-
|
|
107
|
-
| Property | Type | Description |
|
|
108
|
-
|----------|------|-------------|
|
|
109
|
-
| `command` | `string` | Executable name or path (required). |
|
|
110
|
-
| `args` | `string[]` | Arguments passed after the command. |
|
|
111
|
-
| `cwd` | `string` | Working directory for the process. |
|
|
112
|
-
| `env` | `Record<string, string>` | Environment variable overrides. |
|
|
113
|
-
| `cols` | `number` | Initial terminal columns. |
|
|
114
|
-
| `rows` | `number` | Initial terminal rows. |
|
|
115
|
-
| `title` | `string` | Window title. |
|
|
116
|
-
| `width` | `DimensionValue` | Window width in points. |
|
|
117
|
-
| `height` | `DimensionValue` | Window height in points. |
|
|
118
|
-
| `x` | `DimensionValue` | Window x position. |
|
|
119
|
-
| `y` | `DimensionValue` | Window y position. |
|
|
120
|
-
| `window` | `SpawnOptions['window']` | Chrome options (decorations, alwaysOnTop, etc.) |
|
|
121
|
-
|
|
122
|
-
**Returns:** `Promise<WindowHandle>`
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
### focus
|
|
127
|
-
|
|
128
|
-
Bring a window to the front.
|
|
129
|
-
|
|
130
|
-
**Parameters:**
|
|
131
|
-
|
|
132
|
-
| Name | Type | Required | Description |
|
|
133
|
-
|------|------|----------|-------------|
|
|
134
|
-
| `windowId` | `string` | | The window ID. If omitted, the app uses the most recent window. |
|
|
135
|
-
|
|
136
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
### close
|
|
141
|
-
|
|
142
|
-
Close a window.
|
|
143
|
-
|
|
144
|
-
**Parameters:**
|
|
145
|
-
|
|
146
|
-
| Name | Type | Required | Description |
|
|
147
|
-
|------|------|----------|-------------|
|
|
148
|
-
| `windowId` | `string` | | The window ID. If omitted, the app closes the most recent window. |
|
|
149
|
-
|
|
150
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
### navigate
|
|
155
|
-
|
|
156
|
-
Navigate a window to a new URL.
|
|
157
|
-
|
|
158
|
-
**Parameters:**
|
|
159
|
-
|
|
160
|
-
| Name | Type | Required | Description |
|
|
161
|
-
|------|------|----------|-------------|
|
|
162
|
-
| `windowId` | `string` | ✓ | The window ID |
|
|
163
|
-
| `url` | `string` | ✓ | The URL to navigate to |
|
|
164
|
-
|
|
165
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
### eval
|
|
170
|
-
|
|
171
|
-
Evaluate JavaScript in a window's web view.
|
|
172
|
-
|
|
173
|
-
**Parameters:**
|
|
174
|
-
|
|
175
|
-
| Name | Type | Required | Description |
|
|
176
|
-
|------|------|----------|-------------|
|
|
177
|
-
| `windowId` | `string` | ✓ | The window ID |
|
|
178
|
-
| `code` | `string` | ✓ | JavaScript code to evaluate |
|
|
179
|
-
| `opts` | `{ timeoutMs?: number; returnJson?: boolean }` | | timeoutMs (default 5000), returnJson (default true) |
|
|
180
|
-
|
|
181
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
### screengrab
|
|
186
|
-
|
|
187
|
-
Capture a PNG screenshot from a window.
|
|
188
|
-
|
|
189
|
-
**Parameters:**
|
|
190
|
-
|
|
191
|
-
| Name | Type | Required | Description |
|
|
192
|
-
|------|------|----------|-------------|
|
|
193
|
-
| `opts` | `WindowScreenGrabOptions` | ✓ | Window target and output path |
|
|
194
|
-
|
|
195
|
-
`WindowScreenGrabOptions` properties:
|
|
196
|
-
|
|
197
|
-
| Property | Type | Description |
|
|
198
|
-
|----------|------|-------------|
|
|
199
|
-
| `windowId` | `string` | Window ID. If omitted, the launcher uses the most recent window. |
|
|
200
|
-
| `path` | `string` | Output file path for the PNG image. |
|
|
201
|
-
|
|
202
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
### video
|
|
207
|
-
|
|
208
|
-
Record a video from a window to disk.
|
|
209
|
-
|
|
210
|
-
**Parameters:**
|
|
211
|
-
|
|
212
|
-
| Name | Type | Required | Description |
|
|
213
|
-
|------|------|----------|-------------|
|
|
214
|
-
| `opts` | `WindowVideoOptions` | ✓ | Window target, output path, and optional duration |
|
|
215
|
-
|
|
216
|
-
`WindowVideoOptions` properties:
|
|
217
|
-
|
|
218
|
-
| Property | Type | Description |
|
|
219
|
-
|----------|------|-------------|
|
|
220
|
-
| `windowId` | `string` | Window ID. If omitted, the launcher uses the most recent window. |
|
|
221
|
-
| `path` | `string` | Output file path for the video file. |
|
|
222
|
-
| `durationMs` | `number` | Recording duration in milliseconds. |
|
|
223
|
-
|
|
224
|
-
**Returns:** `Promise<WindowAckResult>`
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
### window
|
|
229
|
-
|
|
230
|
-
Get a WindowHandle for chainable operations on a specific window. Returns the tracked handle if one exists, otherwise creates a new one.
|
|
231
|
-
|
|
232
|
-
**Parameters:**
|
|
233
|
-
|
|
234
|
-
| Name | Type | Required | Description |
|
|
235
|
-
|------|------|----------|-------------|
|
|
236
|
-
| `windowId` | `string` | ✓ | The window ID |
|
|
237
|
-
|
|
238
|
-
**Returns:** `WindowHandle`
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
### spawnLayout
|
|
243
|
-
|
|
244
|
-
Spawn multiple windows in parallel from a layout configuration. Returns handles in the same order as the config entries.
|
|
245
|
-
|
|
246
|
-
**Parameters:**
|
|
247
|
-
|
|
248
|
-
| Name | Type | Required | Description |
|
|
249
|
-
|------|------|----------|-------------|
|
|
250
|
-
| `config` | `LayoutEntry[]` | ✓ | Array of layout entries (window or tty) |
|
|
251
|
-
|
|
252
|
-
**Returns:** `Promise<WindowHandle[]>`
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
const handles = await wm.spawnLayout([
|
|
256
|
-
{ type: 'window', url: 'https://google.com', width: 800, height: 600 },
|
|
257
|
-
{ type: 'tty', command: 'htop' },
|
|
258
|
-
{ url: 'https://github.com' }, // defaults to window
|
|
259
|
-
])
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
### spawnLayouts
|
|
265
|
-
|
|
266
|
-
Spawn multiple layouts sequentially. Each layout's windows spawn in parallel, but the next layout waits for the previous one to fully complete.
|
|
267
|
-
|
|
268
|
-
**Parameters:**
|
|
269
|
-
|
|
270
|
-
| Name | Type | Required | Description |
|
|
271
|
-
|------|------|----------|-------------|
|
|
272
|
-
| `configs` | `LayoutEntry[][]` | ✓ | Array of layout configurations |
|
|
273
|
-
|
|
274
|
-
**Returns:** `Promise<WindowHandle[][]>`
|
|
275
|
-
|
|
276
|
-
```ts
|
|
277
|
-
const [firstBatch, secondBatch] = await wm.spawnLayouts([
|
|
278
|
-
[{ url: 'https://google.com' }, { url: 'https://github.com' }],
|
|
279
|
-
[{ type: 'tty', command: 'htop' }],
|
|
280
|
-
])
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
### send
|
|
286
|
-
|
|
287
|
-
Write an NDJSON message to the connected app client. Public so other features can send arbitrary protocol messages over the same socket.
|
|
288
|
-
|
|
289
|
-
**Parameters:**
|
|
290
|
-
|
|
291
|
-
| Name | Type | Required | Description |
|
|
292
|
-
|------|------|----------|-------------|
|
|
293
|
-
| `msg` | `Record<string, any>` | ✓ | The message object to send (will be JSON-serialized + newline) |
|
|
294
|
-
|
|
295
|
-
**Returns:** `boolean`
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
## Getters
|
|
300
|
-
|
|
301
|
-
| Property | Type | Description |
|
|
302
|
-
|----------|------|-------------|
|
|
303
|
-
| `isListening` | `boolean` | Whether the IPC server is currently listening. |
|
|
304
|
-
| `isClientConnected` | `boolean` | Whether the native app client is currently connected. |
|
|
305
|
-
|
|
306
|
-
## Events (Zod v4 schema)
|
|
307
|
-
|
|
308
|
-
### listening
|
|
309
|
-
|
|
310
|
-
Emitted when the IPC server starts listening
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
### clientConnected
|
|
315
|
-
|
|
316
|
-
Emitted when the native app connects
|
|
317
|
-
|
|
318
|
-
**Event Arguments:**
|
|
319
|
-
|
|
320
|
-
| Name | Type | Description |
|
|
321
|
-
|------|------|-------------|
|
|
322
|
-
| `arg0` | `any` | The client socket |
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
### clientDisconnected
|
|
327
|
-
|
|
328
|
-
Emitted when the native app disconnects
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
### windowAck
|
|
333
|
-
|
|
334
|
-
Emitted when a window ack is received from the app
|
|
335
|
-
|
|
336
|
-
**Event Arguments:**
|
|
337
|
-
|
|
338
|
-
| Name | Type | Description |
|
|
339
|
-
|------|------|-------------|
|
|
340
|
-
| `arg0` | `any` | The window ack payload |
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
### windowClosed
|
|
345
|
-
|
|
346
|
-
Emitted when the native app reports a window closed event
|
|
347
|
-
|
|
348
|
-
**Event Arguments:**
|
|
349
|
-
|
|
350
|
-
| Name | Type | Description |
|
|
351
|
-
|------|------|-------------|
|
|
352
|
-
| `arg0` | `any` | Window lifecycle payload emitted when a window closes |
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
### terminalExited
|
|
357
|
-
|
|
358
|
-
Emitted when the native app reports a terminal process exit event
|
|
359
|
-
|
|
360
|
-
**Event Arguments:**
|
|
361
|
-
|
|
362
|
-
| Name | Type | Description |
|
|
363
|
-
|------|------|-------------|
|
|
364
|
-
| `arg0` | `any` | Terminal lifecycle payload emitted when a terminal process exits |
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
### message
|
|
369
|
-
|
|
370
|
-
Emitted for any incoming message that is not a windowAck
|
|
371
|
-
|
|
372
|
-
**Event Arguments:**
|
|
373
|
-
|
|
374
|
-
| Name | Type | Description |
|
|
375
|
-
|------|------|-------------|
|
|
376
|
-
| `arg0` | `any` | The parsed message object |
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
### error
|
|
381
|
-
|
|
382
|
-
Emitted on error
|
|
383
|
-
|
|
384
|
-
**Event Arguments:**
|
|
385
|
-
|
|
386
|
-
| Name | Type | Description |
|
|
387
|
-
|------|------|-------------|
|
|
388
|
-
| `arg0` | `any` | The error |
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
## State (Zod v4 schema)
|
|
393
|
-
|
|
394
|
-
| Property | Type | Description |
|
|
395
|
-
|----------|------|-------------|
|
|
396
|
-
| `enabled` | `boolean` | Whether this feature is currently enabled |
|
|
397
|
-
| `listening` | `boolean` | Whether the IPC server is listening |
|
|
398
|
-
| `clientConnected` | `boolean` | Whether the native launcher app is connected |
|
|
399
|
-
| `socketPath` | `string` | The socket path in use |
|
|
400
|
-
| `windowCount` | `number` | Number of tracked windows |
|
|
401
|
-
| `lastError` | `string` | Last error message |
|
|
402
|
-
|
|
403
|
-
## Examples
|
|
404
|
-
|
|
405
|
-
**features.windowManager**
|
|
406
|
-
|
|
407
|
-
```ts
|
|
408
|
-
const wm = container.feature('windowManager', { enable: true, autoListen: true })
|
|
409
|
-
|
|
410
|
-
const handle = await wm.spawn({ url: 'https://google.com', width: 800, height: 600 })
|
|
411
|
-
handle.on('close', (msg) => console.log('window closed'))
|
|
412
|
-
await handle.navigate('https://news.ycombinator.com')
|
|
413
|
-
const title = await handle.eval('document.title')
|
|
414
|
-
await handle.close()
|
|
415
|
-
|
|
416
|
-
// Other features can listen for non-window messages
|
|
417
|
-
wm.on('message', (msg) => console.log('App says:', msg))
|
|
418
|
-
|
|
419
|
-
// Other features can write raw NDJSON to the app
|
|
420
|
-
wm.send({ id: 'abc', status: 'processing', speech: 'Working on it' })
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
**spawnLayout**
|
|
426
|
-
|
|
427
|
-
```ts
|
|
428
|
-
const handles = await wm.spawnLayout([
|
|
429
|
-
{ type: 'window', url: 'https://google.com', width: 800, height: 600 },
|
|
430
|
-
{ type: 'tty', command: 'htop' },
|
|
431
|
-
{ url: 'https://github.com' }, // defaults to window
|
|
432
|
-
])
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
**spawnLayouts**
|
|
438
|
-
|
|
439
|
-
```ts
|
|
440
|
-
const [firstBatch, secondBatch] = await wm.spawnLayouts([
|
|
441
|
-
[{ url: 'https://google.com' }, { url: 'https://github.com' }],
|
|
442
|
-
[{ type: 'tty', command: 'htop' }],
|
|
443
|
-
])
|
|
444
|
-
```
|
|
445
|
-
|