@agimon-ai/po 0.0.0-alpha.10 → 0.0.0-alpha.11

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.
@@ -2,7 +2,7 @@
2
2
  "version": 1,
3
3
  "packages": {
4
4
  "@agimon-ai/po": {
5
- "version": "0.0.0-alpha.10",
5
+ "version": "0.0.0-alpha.11",
6
6
  "dependencies": [
7
7
  "@agimon-ai/po-artifact",
8
8
  "@agimon-ai/po-autostop",
@@ -23,7 +23,7 @@
23
23
  ]
24
24
  },
25
25
  "@agimon-ai/po-artifact": {
26
- "version": "0.0.0-alpha.8",
26
+ "version": "0.0.0-alpha.9",
27
27
  "dependencies": [
28
28
  "@agimon-ai/po-core",
29
29
  "@agimon-ai/po-web-components",
@@ -31,7 +31,7 @@
31
31
  ]
32
32
  },
33
33
  "@agimon-ai/po-author": {
34
- "version": "0.0.0-alpha.9",
34
+ "version": "0.0.0-alpha.10",
35
35
  "dependencies": [
36
36
  "@agimon-ai/po-artifact",
37
37
  "@agimon-ai/po-core",
@@ -41,7 +41,7 @@
41
41
  ]
42
42
  },
43
43
  "@agimon-ai/po-autocompact": {
44
- "version": "0.0.0-alpha.9",
44
+ "version": "0.0.0-alpha.10",
45
45
  "dependencies": [
46
46
  "@agimon-ai/po-config",
47
47
  "@agimon-ai/po-core",
@@ -49,25 +49,25 @@
49
49
  ]
50
50
  },
51
51
  "@agimon-ai/po-autostop": {
52
- "version": "0.0.0-alpha.9",
52
+ "version": "0.0.0-alpha.10",
53
53
  "dependencies": [
54
54
  "@agimon-ai/po-core",
55
55
  "@agimon-ai/po-telemetry"
56
56
  ]
57
57
  },
58
58
  "@agimon-ai/po-browse": {
59
- "version": "0.0.1-alpha.7",
59
+ "version": "0.0.1-alpha.8",
60
60
  "dependencies": [
61
61
  "@agimon-ai/po-core",
62
62
  "@agimon-ai/po-web-components"
63
63
  ]
64
64
  },
65
65
  "@agimon-ai/po-build": {
66
- "version": "0.0.0-alpha.9",
66
+ "version": "0.0.0-alpha.10",
67
67
  "dependencies": []
68
68
  },
69
69
  "@agimon-ai/po-cache": {
70
- "version": "0.0.0-alpha.9",
70
+ "version": "0.0.0-alpha.10",
71
71
  "dependencies": [
72
72
  "@agimon-ai/po-config",
73
73
  "@agimon-ai/po-core",
@@ -75,7 +75,7 @@
75
75
  ]
76
76
  },
77
77
  "@agimon-ai/po-computer-use": {
78
- "version": "0.0.0-alpha.9",
78
+ "version": "0.0.0-alpha.10",
79
79
  "dependencies": [
80
80
  "@agimon-ai/po-config",
81
81
  "@agimon-ai/po-core",
@@ -85,7 +85,7 @@
85
85
  ]
86
86
  },
87
87
  "@agimon-ai/po-config": {
88
- "version": "0.0.0-alpha.9",
88
+ "version": "0.0.0-alpha.10",
89
89
  "dependencies": [
90
90
  "@agimon-ai/po-core",
91
91
  "@agimon-ai/po-telemetry",
@@ -93,14 +93,14 @@
93
93
  ]
94
94
  },
95
95
  "@agimon-ai/po-core": {
96
- "version": "0.0.0-alpha.9",
96
+ "version": "0.0.0-alpha.10",
97
97
  "dependencies": [
98
98
  "@agimon-ai/po-telemetry",
99
99
  "@agimon-ai/po-web-security"
100
100
  ]
101
101
  },
102
102
  "@agimon-ai/po-domain": {
103
- "version": "0.0.0-alpha.9",
103
+ "version": "0.0.0-alpha.10",
104
104
  "dependencies": [
105
105
  "@agimon-ai/po-config",
106
106
  "@agimon-ai/po-core",
@@ -109,7 +109,7 @@
109
109
  ]
110
110
  },
111
111
  "@agimon-ai/po-edit": {
112
- "version": "0.0.0-alpha.9",
112
+ "version": "0.0.0-alpha.10",
113
113
  "dependencies": [
114
114
  "@agimon-ai/po-core",
115
115
  "@agimon-ai/po-hashline",
@@ -118,7 +118,7 @@
118
118
  ]
119
119
  },
120
120
  "@agimon-ai/po-file-edit": {
121
- "version": "0.0.0-alpha.9",
121
+ "version": "0.0.0-alpha.10",
122
122
  "dependencies": [
123
123
  "@agimon-ai/po-config",
124
124
  "@agimon-ai/po-core",
@@ -129,7 +129,7 @@
129
129
  ]
130
130
  },
131
131
  "@agimon-ai/po-git": {
132
- "version": "0.0.0-alpha.9",
132
+ "version": "0.0.0-alpha.10",
133
133
  "dependencies": [
134
134
  "@agimon-ai/po-core",
135
135
  "@agimon-ai/po-session",
@@ -138,7 +138,7 @@
138
138
  ]
139
139
  },
140
140
  "@agimon-ai/po-goal": {
141
- "version": "0.0.0-alpha.9",
141
+ "version": "0.0.0-alpha.10",
142
142
  "dependencies": [
143
143
  "@agimon-ai/po-core",
144
144
  "@agimon-ai/po-minor-mode",
@@ -147,7 +147,7 @@
147
147
  ]
148
148
  },
149
149
  "@agimon-ai/po-grep": {
150
- "version": "0.0.0-alpha.9",
150
+ "version": "0.0.0-alpha.10",
151
151
  "dependencies": [
152
152
  "@agimon-ai/po-core",
153
153
  "@agimon-ai/po-hashline",
@@ -156,11 +156,11 @@
156
156
  ]
157
157
  },
158
158
  "@agimon-ai/po-hashline": {
159
- "version": "0.0.0-alpha.9",
159
+ "version": "0.0.0-alpha.10",
160
160
  "dependencies": []
161
161
  },
162
162
  "@agimon-ai/po-help": {
163
- "version": "0.0.0-alpha.9",
163
+ "version": "0.0.0-alpha.10",
164
164
  "dependencies": [
165
165
  "@agimon-ai/po-core",
166
166
  "@agimon-ai/po-minor-mode",
@@ -168,7 +168,7 @@
168
168
  ]
169
169
  },
170
170
  "@agimon-ai/po-hook": {
171
- "version": "0.0.0-alpha.9",
171
+ "version": "0.0.0-alpha.10",
172
172
  "dependencies": [
173
173
  "@agimon-ai/po-config",
174
174
  "@agimon-ai/po-core",
@@ -176,7 +176,7 @@
176
176
  ]
177
177
  },
178
178
  "@agimon-ai/po-image-gen": {
179
- "version": "0.0.0-alpha.8",
179
+ "version": "0.0.0-alpha.9",
180
180
  "dependencies": [
181
181
  "@agimon-ai/po-core",
182
182
  "@agimon-ai/po-web-components",
@@ -184,7 +184,7 @@
184
184
  ]
185
185
  },
186
186
  "@agimon-ai/po-log": {
187
- "version": "0.0.0-alpha.9",
187
+ "version": "0.0.0-alpha.10",
188
188
  "dependencies": [
189
189
  "@agimon-ai/po-core",
190
190
  "@agimon-ai/po-telemetry",
@@ -193,7 +193,7 @@
193
193
  ]
194
194
  },
195
195
  "@agimon-ai/po-loop": {
196
- "version": "0.0.0-alpha.9",
196
+ "version": "0.0.0-alpha.10",
197
197
  "dependencies": [
198
198
  "@agimon-ai/po-core",
199
199
  "@agimon-ai/po-minor-mode",
@@ -202,7 +202,7 @@
202
202
  ]
203
203
  },
204
204
  "@agimon-ai/po-major-mode": {
205
- "version": "0.0.0-alpha.9",
205
+ "version": "0.0.0-alpha.10",
206
206
  "dependencies": [
207
207
  "@agimon-ai/po-config",
208
208
  "@agimon-ai/po-core",
@@ -211,7 +211,7 @@
211
211
  ]
212
212
  },
213
213
  "@agimon-ai/po-mcp": {
214
- "version": "0.0.0-alpha.9",
214
+ "version": "0.0.0-alpha.10",
215
215
  "dependencies": [
216
216
  "@agimon-ai/po-config",
217
217
  "@agimon-ai/po-core",
@@ -220,33 +220,33 @@
220
220
  ]
221
221
  },
222
222
  "@agimon-ai/po-minor-mode": {
223
- "version": "0.0.0-alpha.9",
223
+ "version": "0.0.0-alpha.10",
224
224
  "dependencies": [
225
225
  "@agimon-ai/po-core",
226
226
  "@agimon-ai/po-telemetry"
227
227
  ]
228
228
  },
229
229
  "@agimon-ai/po-model-guidance": {
230
- "version": "0.0.0-alpha.9",
230
+ "version": "0.0.0-alpha.10",
231
231
  "dependencies": [
232
232
  "@agimon-ai/po-config",
233
233
  "@agimon-ai/po-core"
234
234
  ]
235
235
  },
236
236
  "@agimon-ai/po-native-components": {
237
- "version": "0.0.0-alpha.9",
237
+ "version": "0.0.0-alpha.10",
238
238
  "dependencies": [
239
239
  "@agimon-ai/po-web-components"
240
240
  ]
241
241
  },
242
242
  "@agimon-ai/po-notification": {
243
- "version": "0.0.0-alpha.9",
243
+ "version": "0.0.0-alpha.10",
244
244
  "dependencies": [
245
245
  "@agimon-ai/po-core"
246
246
  ]
247
247
  },
248
248
  "@agimon-ai/po-plan": {
249
- "version": "0.0.0-alpha.9",
249
+ "version": "0.0.0-alpha.10",
250
250
  "dependencies": [
251
251
  "@agimon-ai/po-config",
252
252
  "@agimon-ai/po-core",
@@ -257,7 +257,7 @@
257
257
  ]
258
258
  },
259
259
  "@agimon-ai/po-profile": {
260
- "version": "0.0.0-alpha.9",
260
+ "version": "0.0.0-alpha.10",
261
261
  "dependencies": [
262
262
  "@agimon-ai/po-config",
263
263
  "@agimon-ai/po-core",
@@ -266,7 +266,7 @@
266
266
  ]
267
267
  },
268
268
  "@agimon-ai/po-prompt": {
269
- "version": "0.0.0-alpha.9",
269
+ "version": "0.0.0-alpha.10",
270
270
  "dependencies": [
271
271
  "@agimon-ai/po-core",
272
272
  "@agimon-ai/po-web-components",
@@ -274,7 +274,7 @@
274
274
  ]
275
275
  },
276
276
  "@agimon-ai/po-read": {
277
- "version": "0.0.0-alpha.9",
277
+ "version": "0.0.0-alpha.10",
278
278
  "dependencies": [
279
279
  "@agimon-ai/po-config",
280
280
  "@agimon-ai/po-core",
@@ -284,7 +284,7 @@
284
284
  ]
285
285
  },
286
286
  "@agimon-ai/po-runner": {
287
- "version": "0.0.0-alpha.9",
287
+ "version": "0.0.0-alpha.10",
288
288
  "dependencies": [
289
289
  "@agimon-ai/po-core",
290
290
  "@agimon-ai/po-telemetry",
@@ -294,19 +294,19 @@
294
294
  ]
295
295
  },
296
296
  "@agimon-ai/po-sandbox": {
297
- "version": "0.0.0-alpha.9",
297
+ "version": "0.0.0-alpha.10",
298
298
  "dependencies": [
299
299
  "@agimon-ai/po-core"
300
300
  ]
301
301
  },
302
302
  "@agimon-ai/po-session": {
303
- "version": "0.0.0-alpha.9",
303
+ "version": "0.0.0-alpha.10",
304
304
  "dependencies": [
305
305
  "@agimon-ai/po-core"
306
306
  ]
307
307
  },
308
308
  "@agimon-ai/po-skill": {
309
- "version": "0.0.0-alpha.9",
309
+ "version": "0.0.0-alpha.10",
310
310
  "dependencies": [
311
311
  "@agimon-ai/po-config",
312
312
  "@agimon-ai/po-core",
@@ -316,7 +316,7 @@
316
316
  ]
317
317
  },
318
318
  "@agimon-ai/po-style-system": {
319
- "version": "0.0.0-alpha.9",
319
+ "version": "0.0.0-alpha.10",
320
320
  "dependencies": [
321
321
  "@agimon-ai/po-core",
322
322
  "@agimon-ai/po-web-components",
@@ -324,7 +324,7 @@
324
324
  ]
325
325
  },
326
326
  "@agimon-ai/po-task": {
327
- "version": "0.0.0-alpha.9",
327
+ "version": "0.0.0-alpha.10",
328
328
  "dependencies": [
329
329
  "@agimon-ai/po-core",
330
330
  "@agimon-ai/po-telemetry",
@@ -333,7 +333,7 @@
333
333
  ]
334
334
  },
335
335
  "@agimon-ai/po-team": {
336
- "version": "0.0.0-alpha.9",
336
+ "version": "0.0.0-alpha.10",
337
337
  "dependencies": [
338
338
  "@agimon-ai/po-cache",
339
339
  "@agimon-ai/po-config",
@@ -346,11 +346,11 @@
346
346
  ]
347
347
  },
348
348
  "@agimon-ai/po-telemetry": {
349
- "version": "0.0.0-alpha.9",
349
+ "version": "0.0.0-alpha.10",
350
350
  "dependencies": []
351
351
  },
352
352
  "@agimon-ai/po-template-advanced": {
353
- "version": "0.0.0-alpha.9",
353
+ "version": "0.0.0-alpha.10",
354
354
  "dependencies": [
355
355
  "@agimon-ai/po-core",
356
356
  "@agimon-ai/po-web-components",
@@ -358,7 +358,7 @@
358
358
  ]
359
359
  },
360
360
  "@agimon-ai/po-template-elegant": {
361
- "version": "0.0.0-alpha.9",
361
+ "version": "0.0.0-alpha.10",
362
362
  "dependencies": [
363
363
  "@agimon-ai/po-core",
364
364
  "@agimon-ai/po-web-components",
@@ -366,7 +366,7 @@
366
366
  ]
367
367
  },
368
368
  "@agimon-ai/po-ui": {
369
- "version": "0.0.0-alpha.9",
369
+ "version": "0.0.0-alpha.10",
370
370
  "dependencies": [
371
371
  "@agimon-ai/po-core",
372
372
  "@agimon-ai/po-hashline",
@@ -376,7 +376,7 @@
376
376
  ]
377
377
  },
378
378
  "@agimon-ai/po-user-feedback": {
379
- "version": "0.0.0-alpha.9",
379
+ "version": "0.0.0-alpha.10",
380
380
  "dependencies": [
381
381
  "@agimon-ai/po-core",
382
382
  "@agimon-ai/po-minor-mode",
@@ -384,7 +384,7 @@
384
384
  ]
385
385
  },
386
386
  "@agimon-ai/po-voice": {
387
- "version": "0.0.0-alpha.9",
387
+ "version": "0.0.0-alpha.10",
388
388
  "dependencies": [
389
389
  "@agimon-ai/po-config",
390
390
  "@agimon-ai/po-core",
@@ -397,11 +397,11 @@
397
397
  ]
398
398
  },
399
399
  "@agimon-ai/po-web-components": {
400
- "version": "0.0.0-alpha.9",
400
+ "version": "0.0.0-alpha.10",
401
401
  "dependencies": []
402
402
  },
403
403
  "@agimon-ai/po-web-dashboard": {
404
- "version": "0.0.0-alpha.9",
404
+ "version": "0.0.0-alpha.10",
405
405
  "dependencies": [
406
406
  "@agimon-ai/po-core",
407
407
  "@agimon-ai/po-web-components",
@@ -409,18 +409,18 @@
409
409
  ]
410
410
  },
411
411
  "@agimon-ai/po-web-search": {
412
- "version": "0.0.0-alpha.8",
412
+ "version": "0.0.0-alpha.9",
413
413
  "dependencies": [
414
414
  "@agimon-ai/po-core",
415
415
  "@agimon-ai/po-web-components"
416
416
  ]
417
417
  },
418
418
  "@agimon-ai/po-web-security": {
419
- "version": "0.0.0-alpha.9",
419
+ "version": "0.0.0-alpha.10",
420
420
  "dependencies": []
421
421
  },
422
422
  "@agimon-ai/po-workflow": {
423
- "version": "0.0.0-alpha.9",
423
+ "version": "0.0.0-alpha.10",
424
424
  "dependencies": [
425
425
  "@agimon-ai/po-core",
426
426
  "@agimon-ai/po-minor-mode",
@@ -34,7 +34,7 @@ async function createComputerUseBinding(transport = process, remotePolicy = {})
34
34
  return caller?.locality === "remote" && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true ? caller : void 0;
35
35
  };
36
36
  const notify = (sessionId) => {
37
- for (const [listener, session] of listeners) if (sessionId === void 0 || session === sessionId) listener();
37
+ for (const [listener, session] of listeners) if (sessionId === void 0 || session === void 0 || session === sessionId) listener();
38
38
  };
39
39
  const revoke = (sessionId, retainRecording = false) => {
40
40
  const delegated = delegations.get(sessionId);
@@ -1 +1 @@
1
- {"version":3,"file":"computerUseBinding.cjs","names":["ComputerUseRecordingStore","fs","path","os","timingSafeEqual","poApiCallerFrom","randomUUID"],"sources":["../../../../src/builders/server/computerUseBinding.ts"],"sourcesContent":["import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { PoComputerUseHostBinding } from '@agimon-ai/po-core/hubChannel';\nimport { poApiCallerFrom } from '@agimon-ai/po-core/packageApi';\n\nimport { ComputerUseRecordingStore } from './computerUseRecordings';\n\nconst VERSION = 1;\nconst MAX_BYTES = 8 * 1024 * 1024;\nconst DESKTOP_HEADER = 'x-po-desktop';\ntype Transport = Pick<NodeJS.Process, 'send' | 'connected' | 'on' | 'off'>;\n\n/** The capability is discovered over the inherited Desktop IPC channel, never from environment flags. */\nexport async function createComputerUseBinding(\n transport: Transport = process,\n remotePolicy: {\n isDeviceAuthorized?: (deviceId: string) => boolean;\n stepUpRequired?: () => boolean;\n } = {},\n): Promise<PoComputerUseHostBinding | undefined> {\n if (!transport.send || !transport.connected) return undefined;\n const recordings = new ComputerUseRecordingStore(await fs.mkdtemp(path.join(os.tmpdir(), 'po-recordings-')));\n let available = false;\n let enabled = false;\n let closed = false;\n let token = '';\n let generation: string | undefined;\n const ownedSessions = new Set<string>();\n const revokedSessions = new Set<string>();\n const listeners = new Map<() => void, string | undefined>();\n const delegations = new Map<\n string,\n { deviceId: string; approved: boolean; abort: AbortController; grantId?: string; expiresAt?: number }\n >();\n const nativeAuthorized = (headers: Headers): boolean => {\n const proof = headers.get(DESKTOP_HEADER) ?? '';\n return available && /^[a-f0-9]{64}$/u.test(proof) && timingSafeEqual(Buffer.from(proof), Buffer.from(token));\n };\n const remoteCaller = (headers: Headers) => {\n const caller = poApiCallerFrom(headers);\n return caller?.locality === 'remote' && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true\n ? caller\n : undefined;\n };\n const notify = (sessionId?: string): void => {\n for (const [listener, session] of listeners) if (sessionId === undefined || session === sessionId) listener();\n };\n const revoke = (sessionId: string, retainRecording = false): void => {\n const delegated = delegations.get(sessionId);\n if (delegated === undefined) return;\n if (!retainRecording) delegations.delete(sessionId);\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n revokedSessions.add(sessionId);\n if (delegated.grantId !== undefined && available) {\n void exchange(\n { type: 'po:computer-use:request', sessionId, operation: 'stop', payload: { grantId: delegated.grantId } },\n 30_000,\n )\n .then((result) => recordings.importStop(sessionId, delegated.grantId!, result.result))\n .catch(() => close());\n }\n notify(sessionId);\n };\n const pending = new Map<string, { finish: (value?: Record<string, unknown>, error?: Error) => void }>();\n const send = (value: object): void => {\n if (closed || !transport.connected) throw new Error('Desktop computer use is disconnected.');\n transport.send!(value, (error: Error | null) => {\n if (error) close();\n });\n };\n const close = (): void => {\n if (closed) return;\n closed = true;\n available = false;\n token = '';\n transport.off('message', onMessage);\n transport.off('disconnect', close);\n transport.off('exit', close);\n for (const request of pending.values())\n request.finish(undefined, new Error('Desktop computer use is disconnected.'));\n pending.clear();\n for (const sessionId of delegations.keys()) revoke(sessionId);\n notify();\n listeners.clear();\n void recordings.close().catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep ownership pinned while the server is alive, including after Desktop disconnects.\n };\n const onMessage = (value: unknown): void => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return;\n const message = value as Record<string, unknown>;\n if (message.version !== VERSION) return;\n if (message.type === 'po:computer-use:availability' && typeof message.enabled === 'boolean') {\n enabled = message.enabled;\n // Native stop/expiry also notifies availability without changing the global setting.\n for (const sessionId of delegations.keys()) revoke(sessionId, true);\n notify();\n return;\n }\n if (typeof message.requestId !== 'string') return;\n if (message.type !== 'po:computer-use:ready' && message.type !== 'po:computer-use:response') return;\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES) {\n close();\n return;\n }\n pending.get(message.requestId)?.finish(message);\n };\n transport.on('message', onMessage);\n transport.on('disconnect', close);\n transport.on('exit', close);\n\n const exchange = (\n value: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n ): Promise<Record<string, unknown>> =>\n new Promise((resolve, reject) => {\n signal?.throwIfAborted();\n if (closed || pending.size >= 128) throw new Error('Desktop computer-use transport is unavailable or busy.');\n const requestId = randomUUID();\n const cancel = (): void => {\n try {\n send({ type: 'po:computer-use:cancel', version: VERSION, requestId });\n } catch {\n /* Already disconnected. */\n }\n };\n const finish = (result?: Record<string, unknown>, error?: Error): void => {\n if (!pending.delete(requestId)) return;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(result!);\n };\n const onAbort = (): void => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request was cancelled.'));\n };\n const timer = setTimeout(() => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request timed out.'));\n }, timeoutMs);\n pending.set(requestId, { finish });\n signal?.addEventListener('abort', onAbort, { once: true });\n try {\n const message = { ...value, version: VERSION, requestId };\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES)\n throw new Error('Desktop computer-use request is too large.');\n send(message);\n } catch (error) {\n finish(undefined, error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n try {\n const ready = await exchange({ type: 'po:computer-use:hello' }, 1_500);\n if (\n ready.type !== 'po:computer-use:ready' ||\n typeof ready.token !== 'string' ||\n !/^[a-f0-9]{64}$/u.test(ready.token)\n ) {\n throw new Error('Invalid Desktop capability handshake.');\n }\n token = ready.token;\n available = true;\n enabled = ready.enabled === true;\n } catch {\n close();\n return undefined;\n }\n\n return {\n get available() {\n return available;\n },\n get enabled() {\n return available && enabled;\n },\n authorize: nativeAuthorized,\n readRecording: (scope, artifactId, range) => recordings.read(scope.sessionId, artifactId, range),\n authorizeActivation(headers) {\n if (!available || !enabled) return false;\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n return (\n caller !== undefined &&\n (remotePolicy.stepUpRequired?.() === true ? caller.stepUp === 'verified' : caller.stepUp === 'not-required')\n );\n },\n authorizePending(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated !== undefined &&\n delegated.deviceId === caller.deviceId &&\n delegated.expiresAt === undefined &&\n !delegated.abort.signal.aborted\n );\n },\n authorizeRecording(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available && caller !== undefined && delegated?.approved === true && delegated.deviceId === caller.deviceId\n );\n },\n authorizeSession(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n if (available && enabled && caller !== undefined && !ownedSessions.has(sessionId)) return true;\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated?.approved === true &&\n delegated.expiresAt !== undefined &&\n delegated.expiresAt > Date.now() &&\n delegated.deviceId === caller.deviceId &&\n !delegated.abort.signal.aborted\n );\n },\n claimSession(sessionId, headers) {\n if (!available || !enabled) throw new Error('Desktop computer use is unavailable.');\n const caller = headers === undefined ? undefined : remoteCaller(headers);\n if (caller !== undefined) {\n const previous = delegations.get(sessionId);\n if (previous !== undefined && previous.deviceId !== caller.deviceId)\n throw new Error('This session belongs to another paired device.');\n if (previous?.abort.signal.aborted) {\n previous.abort = new AbortController();\n previous.grantId = undefined;\n }\n if (previous === undefined)\n delegations.set(sessionId, {\n deviceId: caller.deviceId,\n approved: false,\n abort: new AbortController(),\n });\n } else if (headers !== undefined && !nativeAuthorized(headers)) {\n throw new Error('Native or paired authorization is required.');\n }\n revokedSessions.delete(sessionId);\n ownedSessions.add(sessionId);\n },\n revokeDevice(deviceId) {\n for (const [sessionId, delegated] of delegations) if (delegated.deviceId === deviceId) revoke(sessionId);\n },\n ownsSession: (sessionId) => ownedSessions.has(sessionId),\n forgetSession: (sessionId) => {\n revoke(sessionId);\n void recordings\n .forgetSession(sessionId)\n .catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep private history pinned to Desktop, but never replay device approval after restart.\n },\n subscribe(listener, sessionId) {\n listeners.set(listener, sessionId);\n return () => {\n listeners.delete(listener);\n };\n },\n async request(scope, request) {\n if (!available) throw new Error('Desktop computer use is unavailable.');\n if (revokedSessions.has(scope.sessionId) && request.operation !== 'stop' && request.operation !== 'status')\n throw new Error('Computer-use delegation was revoked.');\n if (request.operation !== 'status' && request.operation !== 'targets' && !ownedSessions.has(scope.sessionId)) {\n throw new Error('This session has not been authorized by Desktop.');\n }\n const delegated = delegations.get(scope.sessionId);\n if (delegated !== undefined && remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true) {\n revoke(scope.sessionId);\n if (request.operation !== 'stop') throw new Error('The paired device was revoked.');\n }\n if (request.operation === 'stop' && delegated !== undefined) {\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n }\n const signal =\n delegated === undefined || request.operation === 'stop'\n ? request.signal\n : request.signal === undefined\n ? delegated.abort.signal\n : AbortSignal.any([request.signal, delegated.abort.signal]);\n const result = await exchange(\n {\n type: 'po:computer-use:request',\n sessionId: scope.sessionId,\n operation: request.operation,\n ...(request.payload === undefined ? {} : { payload: request.payload }),\n },\n request.operation === 'activate' ? 120_000 : 30_000,\n signal,\n );\n if (\n typeof result.hostGeneration !== 'string' ||\n (generation !== undefined && generation !== result.hostGeneration)\n ) {\n close();\n throw new Error('Desktop generation changed. Authorize a new session.');\n }\n generation = result.hostGeneration;\n if (result.ok !== true)\n throw new Error(typeof result.error === 'string' ? result.error : 'Desktop request failed.');\n if (request.operation === 'activate' && delegated !== undefined) {\n if (\n delegations.get(scope.sessionId) !== delegated ||\n delegated.abort.signal.aborted ||\n remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true\n )\n throw new Error('The paired activation was revoked.');\n delegated.approved = true;\n const grant = result.result as { grantId?: unknown; expiresAt?: unknown } | undefined;\n if (typeof grant?.expiresAt === 'number') delegated.expiresAt = grant.expiresAt;\n if (typeof grant?.grantId === 'string') delegated.grantId = grant.grantId;\n }\n if (request.operation === 'stop') {\n if (delegated !== undefined) delegated.expiresAt = undefined;\n const grantId = (request.payload as { grantId?: unknown } | undefined)?.grantId;\n if (typeof grantId !== 'string') throw new Error('Recording finalization requires its grant.');\n return recordings.importStop(scope.sessionId, grantId, result.result);\n }\n return result.result;\n },\n close() {\n if (closed) return;\n try {\n send({ type: 'po:computer-use:close', version: VERSION });\n } finally {\n close();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"computerUseBinding.cjs","names":["ComputerUseRecordingStore","fs","path","os","timingSafeEqual","poApiCallerFrom","randomUUID"],"sources":["../../../../src/builders/server/computerUseBinding.ts"],"sourcesContent":["import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { PoComputerUseHostBinding } from '@agimon-ai/po-core/hubChannel';\nimport { poApiCallerFrom } from '@agimon-ai/po-core/packageApi';\n\nimport { ComputerUseRecordingStore } from './computerUseRecordings';\n\nconst VERSION = 1;\nconst MAX_BYTES = 8 * 1024 * 1024;\nconst DESKTOP_HEADER = 'x-po-desktop';\ntype Transport = Pick<NodeJS.Process, 'send' | 'connected' | 'on' | 'off'>;\n\n/** The capability is discovered over the inherited Desktop IPC channel, never from environment flags. */\nexport async function createComputerUseBinding(\n transport: Transport = process,\n remotePolicy: {\n isDeviceAuthorized?: (deviceId: string) => boolean;\n stepUpRequired?: () => boolean;\n } = {},\n): Promise<PoComputerUseHostBinding | undefined> {\n if (!transport.send || !transport.connected) return undefined;\n const recordings = new ComputerUseRecordingStore(await fs.mkdtemp(path.join(os.tmpdir(), 'po-recordings-')));\n let available = false;\n let enabled = false;\n let closed = false;\n let token = '';\n let generation: string | undefined;\n const ownedSessions = new Set<string>();\n const revokedSessions = new Set<string>();\n const listeners = new Map<() => void, string | undefined>();\n const delegations = new Map<\n string,\n { deviceId: string; approved: boolean; abort: AbortController; grantId?: string; expiresAt?: number }\n >();\n const nativeAuthorized = (headers: Headers): boolean => {\n const proof = headers.get(DESKTOP_HEADER) ?? '';\n return available && /^[a-f0-9]{64}$/u.test(proof) && timingSafeEqual(Buffer.from(proof), Buffer.from(token));\n };\n const remoteCaller = (headers: Headers) => {\n const caller = poApiCallerFrom(headers);\n return caller?.locality === 'remote' && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true\n ? caller\n : undefined;\n };\n const notify = (sessionId?: string): void => {\n for (const [listener, session] of listeners)\n if (sessionId === undefined || session === undefined || session === sessionId) listener();\n };\n const revoke = (sessionId: string, retainRecording = false): void => {\n const delegated = delegations.get(sessionId);\n if (delegated === undefined) return;\n if (!retainRecording) delegations.delete(sessionId);\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n revokedSessions.add(sessionId);\n if (delegated.grantId !== undefined && available) {\n void exchange(\n { type: 'po:computer-use:request', sessionId, operation: 'stop', payload: { grantId: delegated.grantId } },\n 30_000,\n )\n .then((result) => recordings.importStop(sessionId, delegated.grantId!, result.result))\n .catch(() => close());\n }\n notify(sessionId);\n };\n const pending = new Map<string, { finish: (value?: Record<string, unknown>, error?: Error) => void }>();\n const send = (value: object): void => {\n if (closed || !transport.connected) throw new Error('Desktop computer use is disconnected.');\n transport.send!(value, (error: Error | null) => {\n if (error) close();\n });\n };\n const close = (): void => {\n if (closed) return;\n closed = true;\n available = false;\n token = '';\n transport.off('message', onMessage);\n transport.off('disconnect', close);\n transport.off('exit', close);\n for (const request of pending.values())\n request.finish(undefined, new Error('Desktop computer use is disconnected.'));\n pending.clear();\n for (const sessionId of delegations.keys()) revoke(sessionId);\n notify();\n listeners.clear();\n void recordings.close().catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep ownership pinned while the server is alive, including after Desktop disconnects.\n };\n const onMessage = (value: unknown): void => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return;\n const message = value as Record<string, unknown>;\n if (message.version !== VERSION) return;\n if (message.type === 'po:computer-use:availability' && typeof message.enabled === 'boolean') {\n enabled = message.enabled;\n // Native stop/expiry also notifies availability without changing the global setting.\n for (const sessionId of delegations.keys()) revoke(sessionId, true);\n notify();\n return;\n }\n if (typeof message.requestId !== 'string') return;\n if (message.type !== 'po:computer-use:ready' && message.type !== 'po:computer-use:response') return;\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES) {\n close();\n return;\n }\n pending.get(message.requestId)?.finish(message);\n };\n transport.on('message', onMessage);\n transport.on('disconnect', close);\n transport.on('exit', close);\n\n const exchange = (\n value: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n ): Promise<Record<string, unknown>> =>\n new Promise((resolve, reject) => {\n signal?.throwIfAborted();\n if (closed || pending.size >= 128) throw new Error('Desktop computer-use transport is unavailable or busy.');\n const requestId = randomUUID();\n const cancel = (): void => {\n try {\n send({ type: 'po:computer-use:cancel', version: VERSION, requestId });\n } catch {\n /* Already disconnected. */\n }\n };\n const finish = (result?: Record<string, unknown>, error?: Error): void => {\n if (!pending.delete(requestId)) return;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(result!);\n };\n const onAbort = (): void => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request was cancelled.'));\n };\n const timer = setTimeout(() => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request timed out.'));\n }, timeoutMs);\n pending.set(requestId, { finish });\n signal?.addEventListener('abort', onAbort, { once: true });\n try {\n const message = { ...value, version: VERSION, requestId };\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES)\n throw new Error('Desktop computer-use request is too large.');\n send(message);\n } catch (error) {\n finish(undefined, error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n try {\n const ready = await exchange({ type: 'po:computer-use:hello' }, 1_500);\n if (\n ready.type !== 'po:computer-use:ready' ||\n typeof ready.token !== 'string' ||\n !/^[a-f0-9]{64}$/u.test(ready.token)\n ) {\n throw new Error('Invalid Desktop capability handshake.');\n }\n token = ready.token;\n available = true;\n enabled = ready.enabled === true;\n } catch {\n close();\n return undefined;\n }\n\n return {\n get available() {\n return available;\n },\n get enabled() {\n return available && enabled;\n },\n authorize: nativeAuthorized,\n readRecording: (scope, artifactId, range) => recordings.read(scope.sessionId, artifactId, range),\n authorizeActivation(headers) {\n if (!available || !enabled) return false;\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n return (\n caller !== undefined &&\n (remotePolicy.stepUpRequired?.() === true ? caller.stepUp === 'verified' : caller.stepUp === 'not-required')\n );\n },\n authorizePending(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated !== undefined &&\n delegated.deviceId === caller.deviceId &&\n delegated.expiresAt === undefined &&\n !delegated.abort.signal.aborted\n );\n },\n authorizeRecording(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available && caller !== undefined && delegated?.approved === true && delegated.deviceId === caller.deviceId\n );\n },\n authorizeSession(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n if (available && enabled && caller !== undefined && !ownedSessions.has(sessionId)) return true;\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated?.approved === true &&\n delegated.expiresAt !== undefined &&\n delegated.expiresAt > Date.now() &&\n delegated.deviceId === caller.deviceId &&\n !delegated.abort.signal.aborted\n );\n },\n claimSession(sessionId, headers) {\n if (!available || !enabled) throw new Error('Desktop computer use is unavailable.');\n const caller = headers === undefined ? undefined : remoteCaller(headers);\n if (caller !== undefined) {\n const previous = delegations.get(sessionId);\n if (previous !== undefined && previous.deviceId !== caller.deviceId)\n throw new Error('This session belongs to another paired device.');\n if (previous?.abort.signal.aborted) {\n previous.abort = new AbortController();\n previous.grantId = undefined;\n }\n if (previous === undefined)\n delegations.set(sessionId, {\n deviceId: caller.deviceId,\n approved: false,\n abort: new AbortController(),\n });\n } else if (headers !== undefined && !nativeAuthorized(headers)) {\n throw new Error('Native or paired authorization is required.');\n }\n revokedSessions.delete(sessionId);\n ownedSessions.add(sessionId);\n },\n revokeDevice(deviceId) {\n for (const [sessionId, delegated] of delegations) if (delegated.deviceId === deviceId) revoke(sessionId);\n },\n ownsSession: (sessionId) => ownedSessions.has(sessionId),\n forgetSession: (sessionId) => {\n revoke(sessionId);\n void recordings\n .forgetSession(sessionId)\n .catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep private history pinned to Desktop, but never replay device approval after restart.\n },\n subscribe(listener, sessionId) {\n listeners.set(listener, sessionId);\n return () => {\n listeners.delete(listener);\n };\n },\n async request(scope, request) {\n if (!available) throw new Error('Desktop computer use is unavailable.');\n if (revokedSessions.has(scope.sessionId) && request.operation !== 'stop' && request.operation !== 'status')\n throw new Error('Computer-use delegation was revoked.');\n if (request.operation !== 'status' && request.operation !== 'targets' && !ownedSessions.has(scope.sessionId)) {\n throw new Error('This session has not been authorized by Desktop.');\n }\n const delegated = delegations.get(scope.sessionId);\n if (delegated !== undefined && remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true) {\n revoke(scope.sessionId);\n if (request.operation !== 'stop') throw new Error('The paired device was revoked.');\n }\n if (request.operation === 'stop' && delegated !== undefined) {\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n }\n const signal =\n delegated === undefined || request.operation === 'stop'\n ? request.signal\n : request.signal === undefined\n ? delegated.abort.signal\n : AbortSignal.any([request.signal, delegated.abort.signal]);\n const result = await exchange(\n {\n type: 'po:computer-use:request',\n sessionId: scope.sessionId,\n operation: request.operation,\n ...(request.payload === undefined ? {} : { payload: request.payload }),\n },\n request.operation === 'activate' ? 120_000 : 30_000,\n signal,\n );\n if (\n typeof result.hostGeneration !== 'string' ||\n (generation !== undefined && generation !== result.hostGeneration)\n ) {\n close();\n throw new Error('Desktop generation changed. Authorize a new session.');\n }\n generation = result.hostGeneration;\n if (result.ok !== true)\n throw new Error(typeof result.error === 'string' ? result.error : 'Desktop request failed.');\n if (request.operation === 'activate' && delegated !== undefined) {\n if (\n delegations.get(scope.sessionId) !== delegated ||\n delegated.abort.signal.aborted ||\n remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true\n )\n throw new Error('The paired activation was revoked.');\n delegated.approved = true;\n const grant = result.result as { grantId?: unknown; expiresAt?: unknown } | undefined;\n if (typeof grant?.expiresAt === 'number') delegated.expiresAt = grant.expiresAt;\n if (typeof grant?.grantId === 'string') delegated.grantId = grant.grantId;\n }\n if (request.operation === 'stop') {\n if (delegated !== undefined) delegated.expiresAt = undefined;\n const grantId = (request.payload as { grantId?: unknown } | undefined)?.grantId;\n if (typeof grantId !== 'string') throw new Error('Recording finalization requires its grant.');\n return recordings.importStop(scope.sessionId, grantId, result.result);\n }\n return result.result;\n },\n close() {\n if (closed) return;\n try {\n send({ type: 'po:computer-use:close', version: VERSION });\n } finally {\n close();\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -30,7 +30,7 @@ async function createComputerUseBinding(transport = process, remotePolicy = {})
30
30
  return caller?.locality === "remote" && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true ? caller : void 0;
31
31
  };
32
32
  const notify = (sessionId) => {
33
- for (const [listener, session] of listeners) if (sessionId === void 0 || session === sessionId) listener();
33
+ for (const [listener, session] of listeners) if (sessionId === void 0 || session === void 0 || session === sessionId) listener();
34
34
  };
35
35
  const revoke = (sessionId, retainRecording = false) => {
36
36
  const delegated = delegations.get(sessionId);
@@ -1 +1 @@
1
- {"version":3,"file":"computerUseBinding.mjs","names":[],"sources":["../../../../src/builders/server/computerUseBinding.ts"],"sourcesContent":["import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { PoComputerUseHostBinding } from '@agimon-ai/po-core/hubChannel';\nimport { poApiCallerFrom } from '@agimon-ai/po-core/packageApi';\n\nimport { ComputerUseRecordingStore } from './computerUseRecordings';\n\nconst VERSION = 1;\nconst MAX_BYTES = 8 * 1024 * 1024;\nconst DESKTOP_HEADER = 'x-po-desktop';\ntype Transport = Pick<NodeJS.Process, 'send' | 'connected' | 'on' | 'off'>;\n\n/** The capability is discovered over the inherited Desktop IPC channel, never from environment flags. */\nexport async function createComputerUseBinding(\n transport: Transport = process,\n remotePolicy: {\n isDeviceAuthorized?: (deviceId: string) => boolean;\n stepUpRequired?: () => boolean;\n } = {},\n): Promise<PoComputerUseHostBinding | undefined> {\n if (!transport.send || !transport.connected) return undefined;\n const recordings = new ComputerUseRecordingStore(await fs.mkdtemp(path.join(os.tmpdir(), 'po-recordings-')));\n let available = false;\n let enabled = false;\n let closed = false;\n let token = '';\n let generation: string | undefined;\n const ownedSessions = new Set<string>();\n const revokedSessions = new Set<string>();\n const listeners = new Map<() => void, string | undefined>();\n const delegations = new Map<\n string,\n { deviceId: string; approved: boolean; abort: AbortController; grantId?: string; expiresAt?: number }\n >();\n const nativeAuthorized = (headers: Headers): boolean => {\n const proof = headers.get(DESKTOP_HEADER) ?? '';\n return available && /^[a-f0-9]{64}$/u.test(proof) && timingSafeEqual(Buffer.from(proof), Buffer.from(token));\n };\n const remoteCaller = (headers: Headers) => {\n const caller = poApiCallerFrom(headers);\n return caller?.locality === 'remote' && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true\n ? caller\n : undefined;\n };\n const notify = (sessionId?: string): void => {\n for (const [listener, session] of listeners) if (sessionId === undefined || session === sessionId) listener();\n };\n const revoke = (sessionId: string, retainRecording = false): void => {\n const delegated = delegations.get(sessionId);\n if (delegated === undefined) return;\n if (!retainRecording) delegations.delete(sessionId);\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n revokedSessions.add(sessionId);\n if (delegated.grantId !== undefined && available) {\n void exchange(\n { type: 'po:computer-use:request', sessionId, operation: 'stop', payload: { grantId: delegated.grantId } },\n 30_000,\n )\n .then((result) => recordings.importStop(sessionId, delegated.grantId!, result.result))\n .catch(() => close());\n }\n notify(sessionId);\n };\n const pending = new Map<string, { finish: (value?: Record<string, unknown>, error?: Error) => void }>();\n const send = (value: object): void => {\n if (closed || !transport.connected) throw new Error('Desktop computer use is disconnected.');\n transport.send!(value, (error: Error | null) => {\n if (error) close();\n });\n };\n const close = (): void => {\n if (closed) return;\n closed = true;\n available = false;\n token = '';\n transport.off('message', onMessage);\n transport.off('disconnect', close);\n transport.off('exit', close);\n for (const request of pending.values())\n request.finish(undefined, new Error('Desktop computer use is disconnected.'));\n pending.clear();\n for (const sessionId of delegations.keys()) revoke(sessionId);\n notify();\n listeners.clear();\n void recordings.close().catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep ownership pinned while the server is alive, including after Desktop disconnects.\n };\n const onMessage = (value: unknown): void => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return;\n const message = value as Record<string, unknown>;\n if (message.version !== VERSION) return;\n if (message.type === 'po:computer-use:availability' && typeof message.enabled === 'boolean') {\n enabled = message.enabled;\n // Native stop/expiry also notifies availability without changing the global setting.\n for (const sessionId of delegations.keys()) revoke(sessionId, true);\n notify();\n return;\n }\n if (typeof message.requestId !== 'string') return;\n if (message.type !== 'po:computer-use:ready' && message.type !== 'po:computer-use:response') return;\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES) {\n close();\n return;\n }\n pending.get(message.requestId)?.finish(message);\n };\n transport.on('message', onMessage);\n transport.on('disconnect', close);\n transport.on('exit', close);\n\n const exchange = (\n value: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n ): Promise<Record<string, unknown>> =>\n new Promise((resolve, reject) => {\n signal?.throwIfAborted();\n if (closed || pending.size >= 128) throw new Error('Desktop computer-use transport is unavailable or busy.');\n const requestId = randomUUID();\n const cancel = (): void => {\n try {\n send({ type: 'po:computer-use:cancel', version: VERSION, requestId });\n } catch {\n /* Already disconnected. */\n }\n };\n const finish = (result?: Record<string, unknown>, error?: Error): void => {\n if (!pending.delete(requestId)) return;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(result!);\n };\n const onAbort = (): void => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request was cancelled.'));\n };\n const timer = setTimeout(() => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request timed out.'));\n }, timeoutMs);\n pending.set(requestId, { finish });\n signal?.addEventListener('abort', onAbort, { once: true });\n try {\n const message = { ...value, version: VERSION, requestId };\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES)\n throw new Error('Desktop computer-use request is too large.');\n send(message);\n } catch (error) {\n finish(undefined, error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n try {\n const ready = await exchange({ type: 'po:computer-use:hello' }, 1_500);\n if (\n ready.type !== 'po:computer-use:ready' ||\n typeof ready.token !== 'string' ||\n !/^[a-f0-9]{64}$/u.test(ready.token)\n ) {\n throw new Error('Invalid Desktop capability handshake.');\n }\n token = ready.token;\n available = true;\n enabled = ready.enabled === true;\n } catch {\n close();\n return undefined;\n }\n\n return {\n get available() {\n return available;\n },\n get enabled() {\n return available && enabled;\n },\n authorize: nativeAuthorized,\n readRecording: (scope, artifactId, range) => recordings.read(scope.sessionId, artifactId, range),\n authorizeActivation(headers) {\n if (!available || !enabled) return false;\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n return (\n caller !== undefined &&\n (remotePolicy.stepUpRequired?.() === true ? caller.stepUp === 'verified' : caller.stepUp === 'not-required')\n );\n },\n authorizePending(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated !== undefined &&\n delegated.deviceId === caller.deviceId &&\n delegated.expiresAt === undefined &&\n !delegated.abort.signal.aborted\n );\n },\n authorizeRecording(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available && caller !== undefined && delegated?.approved === true && delegated.deviceId === caller.deviceId\n );\n },\n authorizeSession(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n if (available && enabled && caller !== undefined && !ownedSessions.has(sessionId)) return true;\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated?.approved === true &&\n delegated.expiresAt !== undefined &&\n delegated.expiresAt > Date.now() &&\n delegated.deviceId === caller.deviceId &&\n !delegated.abort.signal.aborted\n );\n },\n claimSession(sessionId, headers) {\n if (!available || !enabled) throw new Error('Desktop computer use is unavailable.');\n const caller = headers === undefined ? undefined : remoteCaller(headers);\n if (caller !== undefined) {\n const previous = delegations.get(sessionId);\n if (previous !== undefined && previous.deviceId !== caller.deviceId)\n throw new Error('This session belongs to another paired device.');\n if (previous?.abort.signal.aborted) {\n previous.abort = new AbortController();\n previous.grantId = undefined;\n }\n if (previous === undefined)\n delegations.set(sessionId, {\n deviceId: caller.deviceId,\n approved: false,\n abort: new AbortController(),\n });\n } else if (headers !== undefined && !nativeAuthorized(headers)) {\n throw new Error('Native or paired authorization is required.');\n }\n revokedSessions.delete(sessionId);\n ownedSessions.add(sessionId);\n },\n revokeDevice(deviceId) {\n for (const [sessionId, delegated] of delegations) if (delegated.deviceId === deviceId) revoke(sessionId);\n },\n ownsSession: (sessionId) => ownedSessions.has(sessionId),\n forgetSession: (sessionId) => {\n revoke(sessionId);\n void recordings\n .forgetSession(sessionId)\n .catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep private history pinned to Desktop, but never replay device approval after restart.\n },\n subscribe(listener, sessionId) {\n listeners.set(listener, sessionId);\n return () => {\n listeners.delete(listener);\n };\n },\n async request(scope, request) {\n if (!available) throw new Error('Desktop computer use is unavailable.');\n if (revokedSessions.has(scope.sessionId) && request.operation !== 'stop' && request.operation !== 'status')\n throw new Error('Computer-use delegation was revoked.');\n if (request.operation !== 'status' && request.operation !== 'targets' && !ownedSessions.has(scope.sessionId)) {\n throw new Error('This session has not been authorized by Desktop.');\n }\n const delegated = delegations.get(scope.sessionId);\n if (delegated !== undefined && remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true) {\n revoke(scope.sessionId);\n if (request.operation !== 'stop') throw new Error('The paired device was revoked.');\n }\n if (request.operation === 'stop' && delegated !== undefined) {\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n }\n const signal =\n delegated === undefined || request.operation === 'stop'\n ? request.signal\n : request.signal === undefined\n ? delegated.abort.signal\n : AbortSignal.any([request.signal, delegated.abort.signal]);\n const result = await exchange(\n {\n type: 'po:computer-use:request',\n sessionId: scope.sessionId,\n operation: request.operation,\n ...(request.payload === undefined ? {} : { payload: request.payload }),\n },\n request.operation === 'activate' ? 120_000 : 30_000,\n signal,\n );\n if (\n typeof result.hostGeneration !== 'string' ||\n (generation !== undefined && generation !== result.hostGeneration)\n ) {\n close();\n throw new Error('Desktop generation changed. Authorize a new session.');\n }\n generation = result.hostGeneration;\n if (result.ok !== true)\n throw new Error(typeof result.error === 'string' ? result.error : 'Desktop request failed.');\n if (request.operation === 'activate' && delegated !== undefined) {\n if (\n delegations.get(scope.sessionId) !== delegated ||\n delegated.abort.signal.aborted ||\n remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true\n )\n throw new Error('The paired activation was revoked.');\n delegated.approved = true;\n const grant = result.result as { grantId?: unknown; expiresAt?: unknown } | undefined;\n if (typeof grant?.expiresAt === 'number') delegated.expiresAt = grant.expiresAt;\n if (typeof grant?.grantId === 'string') delegated.grantId = grant.grantId;\n }\n if (request.operation === 'stop') {\n if (delegated !== undefined) delegated.expiresAt = undefined;\n const grantId = (request.payload as { grantId?: unknown } | undefined)?.grantId;\n if (typeof grantId !== 'string') throw new Error('Recording finalization requires its grant.');\n return recordings.importStop(scope.sessionId, grantId, result.result);\n }\n return result.result;\n },\n close() {\n if (closed) return;\n try {\n send({ type: 'po:computer-use:close', version: VERSION });\n } finally {\n close();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"computerUseBinding.mjs","names":[],"sources":["../../../../src/builders/server/computerUseBinding.ts"],"sourcesContent":["import { randomUUID, timingSafeEqual } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { PoComputerUseHostBinding } from '@agimon-ai/po-core/hubChannel';\nimport { poApiCallerFrom } from '@agimon-ai/po-core/packageApi';\n\nimport { ComputerUseRecordingStore } from './computerUseRecordings';\n\nconst VERSION = 1;\nconst MAX_BYTES = 8 * 1024 * 1024;\nconst DESKTOP_HEADER = 'x-po-desktop';\ntype Transport = Pick<NodeJS.Process, 'send' | 'connected' | 'on' | 'off'>;\n\n/** The capability is discovered over the inherited Desktop IPC channel, never from environment flags. */\nexport async function createComputerUseBinding(\n transport: Transport = process,\n remotePolicy: {\n isDeviceAuthorized?: (deviceId: string) => boolean;\n stepUpRequired?: () => boolean;\n } = {},\n): Promise<PoComputerUseHostBinding | undefined> {\n if (!transport.send || !transport.connected) return undefined;\n const recordings = new ComputerUseRecordingStore(await fs.mkdtemp(path.join(os.tmpdir(), 'po-recordings-')));\n let available = false;\n let enabled = false;\n let closed = false;\n let token = '';\n let generation: string | undefined;\n const ownedSessions = new Set<string>();\n const revokedSessions = new Set<string>();\n const listeners = new Map<() => void, string | undefined>();\n const delegations = new Map<\n string,\n { deviceId: string; approved: boolean; abort: AbortController; grantId?: string; expiresAt?: number }\n >();\n const nativeAuthorized = (headers: Headers): boolean => {\n const proof = headers.get(DESKTOP_HEADER) ?? '';\n return available && /^[a-f0-9]{64}$/u.test(proof) && timingSafeEqual(Buffer.from(proof), Buffer.from(token));\n };\n const remoteCaller = (headers: Headers) => {\n const caller = poApiCallerFrom(headers);\n return caller?.locality === 'remote' && remotePolicy.isDeviceAuthorized?.(caller.deviceId) === true\n ? caller\n : undefined;\n };\n const notify = (sessionId?: string): void => {\n for (const [listener, session] of listeners)\n if (sessionId === undefined || session === undefined || session === sessionId) listener();\n };\n const revoke = (sessionId: string, retainRecording = false): void => {\n const delegated = delegations.get(sessionId);\n if (delegated === undefined) return;\n if (!retainRecording) delegations.delete(sessionId);\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n revokedSessions.add(sessionId);\n if (delegated.grantId !== undefined && available) {\n void exchange(\n { type: 'po:computer-use:request', sessionId, operation: 'stop', payload: { grantId: delegated.grantId } },\n 30_000,\n )\n .then((result) => recordings.importStop(sessionId, delegated.grantId!, result.result))\n .catch(() => close());\n }\n notify(sessionId);\n };\n const pending = new Map<string, { finish: (value?: Record<string, unknown>, error?: Error) => void }>();\n const send = (value: object): void => {\n if (closed || !transport.connected) throw new Error('Desktop computer use is disconnected.');\n transport.send!(value, (error: Error | null) => {\n if (error) close();\n });\n };\n const close = (): void => {\n if (closed) return;\n closed = true;\n available = false;\n token = '';\n transport.off('message', onMessage);\n transport.off('disconnect', close);\n transport.off('exit', close);\n for (const request of pending.values())\n request.finish(undefined, new Error('Desktop computer use is disconnected.'));\n pending.clear();\n for (const sessionId of delegations.keys()) revoke(sessionId);\n notify();\n listeners.clear();\n void recordings.close().catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep ownership pinned while the server is alive, including after Desktop disconnects.\n };\n const onMessage = (value: unknown): void => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return;\n const message = value as Record<string, unknown>;\n if (message.version !== VERSION) return;\n if (message.type === 'po:computer-use:availability' && typeof message.enabled === 'boolean') {\n enabled = message.enabled;\n // Native stop/expiry also notifies availability without changing the global setting.\n for (const sessionId of delegations.keys()) revoke(sessionId, true);\n notify();\n return;\n }\n if (typeof message.requestId !== 'string') return;\n if (message.type !== 'po:computer-use:ready' && message.type !== 'po:computer-use:response') return;\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES) {\n close();\n return;\n }\n pending.get(message.requestId)?.finish(message);\n };\n transport.on('message', onMessage);\n transport.on('disconnect', close);\n transport.on('exit', close);\n\n const exchange = (\n value: Record<string, unknown>,\n timeoutMs: number,\n signal?: AbortSignal,\n ): Promise<Record<string, unknown>> =>\n new Promise((resolve, reject) => {\n signal?.throwIfAborted();\n if (closed || pending.size >= 128) throw new Error('Desktop computer-use transport is unavailable or busy.');\n const requestId = randomUUID();\n const cancel = (): void => {\n try {\n send({ type: 'po:computer-use:cancel', version: VERSION, requestId });\n } catch {\n /* Already disconnected. */\n }\n };\n const finish = (result?: Record<string, unknown>, error?: Error): void => {\n if (!pending.delete(requestId)) return;\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n if (error) reject(error);\n else resolve(result!);\n };\n const onAbort = (): void => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request was cancelled.'));\n };\n const timer = setTimeout(() => {\n cancel();\n finish(undefined, new Error('Desktop computer-use request timed out.'));\n }, timeoutMs);\n pending.set(requestId, { finish });\n signal?.addEventListener('abort', onAbort, { once: true });\n try {\n const message = { ...value, version: VERSION, requestId };\n if (Buffer.byteLength(JSON.stringify(message)) > MAX_BYTES)\n throw new Error('Desktop computer-use request is too large.');\n send(message);\n } catch (error) {\n finish(undefined, error instanceof Error ? error : new Error(String(error)));\n }\n });\n\n try {\n const ready = await exchange({ type: 'po:computer-use:hello' }, 1_500);\n if (\n ready.type !== 'po:computer-use:ready' ||\n typeof ready.token !== 'string' ||\n !/^[a-f0-9]{64}$/u.test(ready.token)\n ) {\n throw new Error('Invalid Desktop capability handshake.');\n }\n token = ready.token;\n available = true;\n enabled = ready.enabled === true;\n } catch {\n close();\n return undefined;\n }\n\n return {\n get available() {\n return available;\n },\n get enabled() {\n return available && enabled;\n },\n authorize: nativeAuthorized,\n readRecording: (scope, artifactId, range) => recordings.read(scope.sessionId, artifactId, range),\n authorizeActivation(headers) {\n if (!available || !enabled) return false;\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n return (\n caller !== undefined &&\n (remotePolicy.stepUpRequired?.() === true ? caller.stepUp === 'verified' : caller.stepUp === 'not-required')\n );\n },\n authorizePending(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated !== undefined &&\n delegated.deviceId === caller.deviceId &&\n delegated.expiresAt === undefined &&\n !delegated.abort.signal.aborted\n );\n },\n authorizeRecording(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n return (\n available && caller !== undefined && delegated?.approved === true && delegated.deviceId === caller.deviceId\n );\n },\n authorizeSession(sessionId, headers) {\n if (nativeAuthorized(headers)) return true;\n const caller = remoteCaller(headers);\n const delegated = delegations.get(sessionId);\n if (available && enabled && caller !== undefined && !ownedSessions.has(sessionId)) return true;\n return (\n available &&\n enabled &&\n caller !== undefined &&\n delegated?.approved === true &&\n delegated.expiresAt !== undefined &&\n delegated.expiresAt > Date.now() &&\n delegated.deviceId === caller.deviceId &&\n !delegated.abort.signal.aborted\n );\n },\n claimSession(sessionId, headers) {\n if (!available || !enabled) throw new Error('Desktop computer use is unavailable.');\n const caller = headers === undefined ? undefined : remoteCaller(headers);\n if (caller !== undefined) {\n const previous = delegations.get(sessionId);\n if (previous !== undefined && previous.deviceId !== caller.deviceId)\n throw new Error('This session belongs to another paired device.');\n if (previous?.abort.signal.aborted) {\n previous.abort = new AbortController();\n previous.grantId = undefined;\n }\n if (previous === undefined)\n delegations.set(sessionId, {\n deviceId: caller.deviceId,\n approved: false,\n abort: new AbortController(),\n });\n } else if (headers !== undefined && !nativeAuthorized(headers)) {\n throw new Error('Native or paired authorization is required.');\n }\n revokedSessions.delete(sessionId);\n ownedSessions.add(sessionId);\n },\n revokeDevice(deviceId) {\n for (const [sessionId, delegated] of delegations) if (delegated.deviceId === deviceId) revoke(sessionId);\n },\n ownsSession: (sessionId) => ownedSessions.has(sessionId),\n forgetSession: (sessionId) => {\n revoke(sessionId);\n void recordings\n .forgetSession(sessionId)\n .catch(() => process.emitWarning('Computer-use recording cleanup failed.'));\n // Keep private history pinned to Desktop, but never replay device approval after restart.\n },\n subscribe(listener, sessionId) {\n listeners.set(listener, sessionId);\n return () => {\n listeners.delete(listener);\n };\n },\n async request(scope, request) {\n if (!available) throw new Error('Desktop computer use is unavailable.');\n if (revokedSessions.has(scope.sessionId) && request.operation !== 'stop' && request.operation !== 'status')\n throw new Error('Computer-use delegation was revoked.');\n if (request.operation !== 'status' && request.operation !== 'targets' && !ownedSessions.has(scope.sessionId)) {\n throw new Error('This session has not been authorized by Desktop.');\n }\n const delegated = delegations.get(scope.sessionId);\n if (delegated !== undefined && remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true) {\n revoke(scope.sessionId);\n if (request.operation !== 'stop') throw new Error('The paired device was revoked.');\n }\n if (request.operation === 'stop' && delegated !== undefined) {\n delegated.expiresAt = undefined;\n delegated.abort.abort();\n }\n const signal =\n delegated === undefined || request.operation === 'stop'\n ? request.signal\n : request.signal === undefined\n ? delegated.abort.signal\n : AbortSignal.any([request.signal, delegated.abort.signal]);\n const result = await exchange(\n {\n type: 'po:computer-use:request',\n sessionId: scope.sessionId,\n operation: request.operation,\n ...(request.payload === undefined ? {} : { payload: request.payload }),\n },\n request.operation === 'activate' ? 120_000 : 30_000,\n signal,\n );\n if (\n typeof result.hostGeneration !== 'string' ||\n (generation !== undefined && generation !== result.hostGeneration)\n ) {\n close();\n throw new Error('Desktop generation changed. Authorize a new session.');\n }\n generation = result.hostGeneration;\n if (result.ok !== true)\n throw new Error(typeof result.error === 'string' ? result.error : 'Desktop request failed.');\n if (request.operation === 'activate' && delegated !== undefined) {\n if (\n delegations.get(scope.sessionId) !== delegated ||\n delegated.abort.signal.aborted ||\n remotePolicy.isDeviceAuthorized?.(delegated.deviceId) !== true\n )\n throw new Error('The paired activation was revoked.');\n delegated.approved = true;\n const grant = result.result as { grantId?: unknown; expiresAt?: unknown } | undefined;\n if (typeof grant?.expiresAt === 'number') delegated.expiresAt = grant.expiresAt;\n if (typeof grant?.grantId === 'string') delegated.grantId = grant.grantId;\n }\n if (request.operation === 'stop') {\n if (delegated !== undefined) delegated.expiresAt = undefined;\n const grantId = (request.payload as { grantId?: unknown } | undefined)?.grantId;\n if (typeof grantId !== 'string') throw new Error('Recording finalization requires its grant.');\n return recordings.importStop(scope.sessionId, grantId, result.result);\n }\n return result.result;\n },\n close() {\n if (closed) return;\n try {\n send({ type: 'po:computer-use:close', version: VERSION });\n } finally {\n close();\n }\n },\n };\n}\n"],"mappings":"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"}