@chatroomcp/chatroom 0.1.7 → 0.2.1

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.
Files changed (51) hide show
  1. package/dist/app/application.d.ts +1 -0
  2. package/dist/app/application.js +4 -0
  3. package/dist/app/event-bus.d.ts +4 -0
  4. package/dist/auth/ingress-policy.d.ts +2 -0
  5. package/dist/auth/ingress-policy.js +7 -1
  6. package/dist/infrastructure/database/app-database.js +7 -0
  7. package/dist/infrastructure/http/http-server.js +5 -1
  8. package/dist/mcp/server/plugin-mcp-registrar.d.ts +6 -1
  9. package/dist/mcp/server/plugin-mcp-registrar.js +4 -4
  10. package/dist/mcp/server/request-context.d.ts +3 -0
  11. package/dist/mcp/server/request-context.js +8 -0
  12. package/dist/mcp/server/tool-support.d.ts +1 -1
  13. package/dist/mcp/server/tool-support.js +3 -1
  14. package/dist/native/linux/chatroom-computer-helper +0 -0
  15. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/Info.plist +14 -0
  16. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
  17. package/dist/native/macos/ChatRoomComputerHelper.app/Contents/_CodeSignature/CodeResources +115 -0
  18. package/dist/native/windows/chatroom-computer-helper.exe +0 -0
  19. package/dist/plugins/computer/audit.d.ts +34 -0
  20. package/dist/plugins/computer/audit.js +42 -0
  21. package/dist/plugins/computer/computer-native-backend.d.ts +11 -0
  22. package/dist/plugins/computer/computer-native-backend.js +58 -0
  23. package/dist/plugins/computer/computer-native-host.d.ts +27 -0
  24. package/dist/plugins/computer/computer-native-host.js +335 -0
  25. package/dist/plugins/computer/computer-protocol.d.ts +21 -0
  26. package/dist/plugins/computer/computer-protocol.js +72 -0
  27. package/dist/plugins/computer/computer-schemas.d.ts +318 -0
  28. package/dist/plugins/computer/computer-schemas.js +152 -0
  29. package/dist/plugins/computer/computer-service.d.ts +27 -0
  30. package/dist/plugins/computer/computer-service.js +108 -0
  31. package/dist/plugins/computer/computer-settings-repository.d.ts +8 -0
  32. package/dist/plugins/computer/computer-settings-repository.js +41 -0
  33. package/dist/plugins/computer/mcp.d.ts +3 -0
  34. package/dist/plugins/computer/mcp.js +126 -0
  35. package/dist/plugins/computer/plugin.d.ts +4 -0
  36. package/dist/plugins/computer/plugin.js +29 -0
  37. package/dist/plugins/computer/types.d.ts +174 -0
  38. package/dist/plugins/computer/types.js +1 -0
  39. package/dist/plugins/web/api-types.d.ts +15 -1
  40. package/dist/plugins/web/http/api-router.js +2 -0
  41. package/dist/plugins/web/http/computer-api-router.d.ts +5 -0
  42. package/dist/plugins/web/http/computer-api-router.js +68 -0
  43. package/dist/plugins/web/plugin.js +3 -1
  44. package/dist/plugins/web/runtime.d.ts +3 -1
  45. package/dist/plugins/web/runtime.js +3 -1
  46. package/dist/web/assets/index-B4vO7wVS.css +1 -0
  47. package/dist/web/assets/index-BU7LCgKB.js +26 -0
  48. package/dist/web/index.html +2 -2
  49. package/package.json +6 -3
  50. package/dist/web/assets/index-B7jL3mhD.css +0 -1
  51. package/dist/web/assets/index-L4-YdZVN.js +0 -26
@@ -0,0 +1,318 @@
1
+ import { z } from "zod";
2
+ export declare const computerPermissionStateSchema: z.ZodEnum<{
3
+ granted: "granted";
4
+ denied: "denied";
5
+ unknown: "unknown";
6
+ "not-required": "not-required";
7
+ }>;
8
+ export declare const computerDisplaySchema: z.ZodObject<{
9
+ id: z.ZodString;
10
+ name: z.ZodString;
11
+ width: z.ZodNumber;
12
+ height: z.ZodNumber;
13
+ scale: z.ZodNumber;
14
+ primary: z.ZodBoolean;
15
+ }, z.core.$strip>;
16
+ export declare const computerElementSchema: z.ZodObject<{
17
+ id: z.ZodNumber;
18
+ role: z.ZodString;
19
+ name: z.ZodNullable<z.ZodString>;
20
+ value: z.ZodNullable<z.ZodString>;
21
+ enabled: z.ZodBoolean;
22
+ focused: z.ZodBoolean;
23
+ selected: z.ZodBoolean;
24
+ sensitive: z.ZodBoolean;
25
+ bounds: z.ZodNullable<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
26
+ actions: z.ZodArray<z.ZodString>;
27
+ }, z.core.$strip>;
28
+ export declare const computerScreenshotSchema: z.ZodObject<{
29
+ mimeType: z.ZodEnum<{
30
+ "image/jpeg": "image/jpeg";
31
+ "image/png": "image/png";
32
+ }>;
33
+ data: z.ZodString;
34
+ }, z.core.$strip>;
35
+ export declare const computerNativeStatusSchema: z.ZodObject<{
36
+ platform: z.ZodEnum<{
37
+ macos: "macos";
38
+ windows: "windows";
39
+ linux: "linux";
40
+ unsupported: "unsupported";
41
+ }>;
42
+ helper: z.ZodEnum<{
43
+ running: "running";
44
+ stopped: "stopped";
45
+ unavailable: "unavailable";
46
+ }>;
47
+ permissions: z.ZodObject<{
48
+ accessibility: z.ZodEnum<{
49
+ granted: "granted";
50
+ denied: "denied";
51
+ unknown: "unknown";
52
+ "not-required": "not-required";
53
+ }>;
54
+ screenRecording: z.ZodEnum<{
55
+ granted: "granted";
56
+ denied: "denied";
57
+ unknown: "unknown";
58
+ "not-required": "not-required";
59
+ }>;
60
+ }, z.core.$strip>;
61
+ displays: z.ZodArray<z.ZodObject<{
62
+ id: z.ZodString;
63
+ name: z.ZodString;
64
+ width: z.ZodNumber;
65
+ height: z.ZodNumber;
66
+ scale: z.ZodNumber;
67
+ primary: z.ZodBoolean;
68
+ }, z.core.$strip>>;
69
+ }, z.core.$strip>;
70
+ export declare const computerSnapshotSchema: z.ZodObject<{
71
+ snapshotId: z.ZodString;
72
+ revision: z.ZodNumber;
73
+ display: z.ZodNullable<z.ZodObject<{
74
+ id: z.ZodString;
75
+ name: z.ZodString;
76
+ width: z.ZodNumber;
77
+ height: z.ZodNumber;
78
+ scale: z.ZodNumber;
79
+ primary: z.ZodBoolean;
80
+ }, z.core.$strip>>;
81
+ activeApp: z.ZodNullable<z.ZodString>;
82
+ activeWindow: z.ZodNullable<z.ZodString>;
83
+ cursor: z.ZodNullable<z.ZodObject<{
84
+ x: z.ZodNumber;
85
+ y: z.ZodNumber;
86
+ }, z.core.$strip>>;
87
+ elements: z.ZodArray<z.ZodObject<{
88
+ id: z.ZodNumber;
89
+ role: z.ZodString;
90
+ name: z.ZodNullable<z.ZodString>;
91
+ value: z.ZodNullable<z.ZodString>;
92
+ enabled: z.ZodBoolean;
93
+ focused: z.ZodBoolean;
94
+ selected: z.ZodBoolean;
95
+ sensitive: z.ZodBoolean;
96
+ bounds: z.ZodNullable<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
97
+ actions: z.ZodArray<z.ZodString>;
98
+ }, z.core.$strip>>;
99
+ screenshot: z.ZodOptional<z.ZodObject<{
100
+ mimeType: z.ZodEnum<{
101
+ "image/jpeg": "image/jpeg";
102
+ "image/png": "image/png";
103
+ }>;
104
+ data: z.ZodString;
105
+ }, z.core.$strip>>;
106
+ }, z.core.$strip>;
107
+ export declare const computerSnapshotMetadataSchema: z.ZodObject<{
108
+ display: z.ZodNullable<z.ZodObject<{
109
+ id: z.ZodString;
110
+ name: z.ZodString;
111
+ width: z.ZodNumber;
112
+ height: z.ZodNumber;
113
+ scale: z.ZodNumber;
114
+ primary: z.ZodBoolean;
115
+ }, z.core.$strip>>;
116
+ snapshotId: z.ZodString;
117
+ revision: z.ZodNumber;
118
+ activeApp: z.ZodNullable<z.ZodString>;
119
+ activeWindow: z.ZodNullable<z.ZodString>;
120
+ cursor: z.ZodNullable<z.ZodObject<{
121
+ x: z.ZodNumber;
122
+ y: z.ZodNumber;
123
+ }, z.core.$strip>>;
124
+ elements: z.ZodArray<z.ZodObject<{
125
+ id: z.ZodNumber;
126
+ role: z.ZodString;
127
+ name: z.ZodNullable<z.ZodString>;
128
+ value: z.ZodNullable<z.ZodString>;
129
+ enabled: z.ZodBoolean;
130
+ focused: z.ZodBoolean;
131
+ selected: z.ZodBoolean;
132
+ sensitive: z.ZodBoolean;
133
+ bounds: z.ZodNullable<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
134
+ actions: z.ZodArray<z.ZodString>;
135
+ }, z.core.$strip>>;
136
+ }, z.core.$strip>;
137
+ export declare const computerActionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
138
+ type: z.ZodLiteral<"move">;
139
+ x: z.ZodNumber;
140
+ y: z.ZodNumber;
141
+ }, z.core.$strip>, z.ZodObject<{
142
+ type: z.ZodLiteral<"click">;
143
+ x: z.ZodOptional<z.ZodNumber>;
144
+ y: z.ZodOptional<z.ZodNumber>;
145
+ elementId: z.ZodOptional<z.ZodNumber>;
146
+ }, z.core.$strip>, z.ZodObject<{
147
+ type: z.ZodLiteral<"double_click">;
148
+ x: z.ZodOptional<z.ZodNumber>;
149
+ y: z.ZodOptional<z.ZodNumber>;
150
+ elementId: z.ZodOptional<z.ZodNumber>;
151
+ }, z.core.$strip>, z.ZodObject<{
152
+ type: z.ZodLiteral<"right_click">;
153
+ x: z.ZodOptional<z.ZodNumber>;
154
+ y: z.ZodOptional<z.ZodNumber>;
155
+ elementId: z.ZodOptional<z.ZodNumber>;
156
+ }, z.core.$strip>, z.ZodObject<{
157
+ type: z.ZodLiteral<"drag">;
158
+ from: z.ZodObject<{
159
+ x: z.ZodNumber;
160
+ y: z.ZodNumber;
161
+ }, z.core.$strip>;
162
+ to: z.ZodObject<{
163
+ x: z.ZodNumber;
164
+ y: z.ZodNumber;
165
+ }, z.core.$strip>;
166
+ durationMs: z.ZodOptional<z.ZodNumber>;
167
+ }, z.core.$strip>, z.ZodObject<{
168
+ type: z.ZodLiteral<"scroll">;
169
+ deltaX: z.ZodOptional<z.ZodNumber>;
170
+ deltaY: z.ZodNumber;
171
+ elementId: z.ZodOptional<z.ZodNumber>;
172
+ }, z.core.$strip>, z.ZodObject<{
173
+ type: z.ZodLiteral<"keypress">;
174
+ keys: z.ZodArray<z.ZodString>;
175
+ }, z.core.$strip>, z.ZodObject<{
176
+ type: z.ZodLiteral<"type_text">;
177
+ text: z.ZodString;
178
+ elementId: z.ZodOptional<z.ZodNumber>;
179
+ }, z.core.$strip>, z.ZodObject<{
180
+ type: z.ZodLiteral<"invoke">;
181
+ elementId: z.ZodNumber;
182
+ }, z.core.$strip>, z.ZodObject<{
183
+ type: z.ZodLiteral<"set_value">;
184
+ elementId: z.ZodNumber;
185
+ value: z.ZodString;
186
+ }, z.core.$strip>, z.ZodObject<{
187
+ type: z.ZodLiteral<"select_text">;
188
+ elementId: z.ZodNumber;
189
+ start: z.ZodNumber;
190
+ length: z.ZodNumber;
191
+ }, z.core.$strip>, z.ZodObject<{
192
+ type: z.ZodLiteral<"activate_app">;
193
+ app: z.ZodString;
194
+ }, z.core.$strip>, z.ZodObject<{
195
+ type: z.ZodLiteral<"activate_window">;
196
+ elementId: z.ZodNumber;
197
+ }, z.core.$strip>, z.ZodObject<{
198
+ type: z.ZodLiteral<"move_window">;
199
+ elementId: z.ZodNumber;
200
+ x: z.ZodNumber;
201
+ y: z.ZodNumber;
202
+ }, z.core.$strip>, z.ZodObject<{
203
+ type: z.ZodLiteral<"resize_window">;
204
+ elementId: z.ZodNumber;
205
+ width: z.ZodNumber;
206
+ height: z.ZodNumber;
207
+ }, z.core.$strip>, z.ZodObject<{
208
+ type: z.ZodLiteral<"wait">;
209
+ ms: z.ZodNumber;
210
+ }, z.core.$strip>], "type">;
211
+ export declare const computerActionResultSchema: z.ZodObject<{
212
+ success: z.ZodLiteral<true>;
213
+ revision: z.ZodNumber;
214
+ snapshot: z.ZodOptional<z.ZodObject<{
215
+ snapshotId: z.ZodString;
216
+ revision: z.ZodNumber;
217
+ display: z.ZodNullable<z.ZodObject<{
218
+ id: z.ZodString;
219
+ name: z.ZodString;
220
+ width: z.ZodNumber;
221
+ height: z.ZodNumber;
222
+ scale: z.ZodNumber;
223
+ primary: z.ZodBoolean;
224
+ }, z.core.$strip>>;
225
+ activeApp: z.ZodNullable<z.ZodString>;
226
+ activeWindow: z.ZodNullable<z.ZodString>;
227
+ cursor: z.ZodNullable<z.ZodObject<{
228
+ x: z.ZodNumber;
229
+ y: z.ZodNumber;
230
+ }, z.core.$strip>>;
231
+ elements: z.ZodArray<z.ZodObject<{
232
+ id: z.ZodNumber;
233
+ role: z.ZodString;
234
+ name: z.ZodNullable<z.ZodString>;
235
+ value: z.ZodNullable<z.ZodString>;
236
+ enabled: z.ZodBoolean;
237
+ focused: z.ZodBoolean;
238
+ selected: z.ZodBoolean;
239
+ sensitive: z.ZodBoolean;
240
+ bounds: z.ZodNullable<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
241
+ actions: z.ZodArray<z.ZodString>;
242
+ }, z.core.$strip>>;
243
+ screenshot: z.ZodOptional<z.ZodObject<{
244
+ mimeType: z.ZodEnum<{
245
+ "image/jpeg": "image/jpeg";
246
+ "image/png": "image/png";
247
+ }>;
248
+ data: z.ZodString;
249
+ }, z.core.$strip>>;
250
+ }, z.core.$strip>>;
251
+ executionMode: z.ZodEnum<{
252
+ semantic: "semantic";
253
+ background: "background";
254
+ foreground: "foreground";
255
+ mixed: "mixed";
256
+ }>;
257
+ focusChanged: z.ZodBoolean;
258
+ }, z.core.$strip>;
259
+ export declare const computerActionMetadataSchema: z.ZodObject<{
260
+ success: z.ZodLiteral<true>;
261
+ revision: z.ZodNumber;
262
+ executionMode: z.ZodEnum<{
263
+ semantic: "semantic";
264
+ background: "background";
265
+ foreground: "foreground";
266
+ mixed: "mixed";
267
+ }>;
268
+ focusChanged: z.ZodBoolean;
269
+ snapshot: z.ZodOptional<z.ZodObject<{
270
+ display: z.ZodNullable<z.ZodObject<{
271
+ id: z.ZodString;
272
+ name: z.ZodString;
273
+ width: z.ZodNumber;
274
+ height: z.ZodNumber;
275
+ scale: z.ZodNumber;
276
+ primary: z.ZodBoolean;
277
+ }, z.core.$strip>>;
278
+ snapshotId: z.ZodString;
279
+ revision: z.ZodNumber;
280
+ activeApp: z.ZodNullable<z.ZodString>;
281
+ activeWindow: z.ZodNullable<z.ZodString>;
282
+ cursor: z.ZodNullable<z.ZodObject<{
283
+ x: z.ZodNumber;
284
+ y: z.ZodNumber;
285
+ }, z.core.$strip>>;
286
+ elements: z.ZodArray<z.ZodObject<{
287
+ id: z.ZodNumber;
288
+ role: z.ZodString;
289
+ name: z.ZodNullable<z.ZodString>;
290
+ value: z.ZodNullable<z.ZodString>;
291
+ enabled: z.ZodBoolean;
292
+ focused: z.ZodBoolean;
293
+ selected: z.ZodBoolean;
294
+ sensitive: z.ZodBoolean;
295
+ bounds: z.ZodNullable<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
296
+ actions: z.ZodArray<z.ZodString>;
297
+ }, z.core.$strip>>;
298
+ }, z.core.$strip>>;
299
+ }, z.core.$strip>;
300
+ export declare const computerSnapshotTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
301
+ type: z.ZodLiteral<"desktop">;
302
+ }, z.core.$strip>, z.ZodObject<{
303
+ type: z.ZodLiteral<"display">;
304
+ displayId: z.ZodOptional<z.ZodString>;
305
+ }, z.core.$strip>, z.ZodObject<{
306
+ type: z.ZodLiteral<"app">;
307
+ app: z.ZodString;
308
+ }, z.core.$strip>, z.ZodObject<{
309
+ type: z.ZodLiteral<"window">;
310
+ elementId: z.ZodNumber;
311
+ }, z.core.$strip>, z.ZodObject<{
312
+ type: z.ZodLiteral<"region">;
313
+ displayId: z.ZodOptional<z.ZodString>;
314
+ x: z.ZodNumber;
315
+ y: z.ZodNumber;
316
+ width: z.ZodNumber;
317
+ height: z.ZodNumber;
318
+ }, z.core.$strip>], "type">;
@@ -0,0 +1,152 @@
1
+ import { z } from "zod";
2
+ export const computerPermissionStateSchema = z.enum([
3
+ "granted",
4
+ "denied",
5
+ "unknown",
6
+ "not-required",
7
+ ]);
8
+ export const computerDisplaySchema = z.object({
9
+ id: z.string(),
10
+ name: z.string(),
11
+ width: z.number(),
12
+ height: z.number(),
13
+ scale: z.number(),
14
+ primary: z.boolean(),
15
+ });
16
+ export const computerElementSchema = z.object({
17
+ id: z.number().int(),
18
+ role: z.string(),
19
+ name: z.string().nullable(),
20
+ value: z.string().nullable(),
21
+ enabled: z.boolean(),
22
+ focused: z.boolean(),
23
+ selected: z.boolean(),
24
+ sensitive: z.boolean(),
25
+ bounds: z.tuple([z.number(), z.number(), z.number(), z.number()]).nullable(),
26
+ actions: z.array(z.string()),
27
+ });
28
+ export const computerScreenshotSchema = z.object({
29
+ mimeType: z.enum(["image/jpeg", "image/png"]),
30
+ data: z.string(),
31
+ });
32
+ export const computerNativeStatusSchema = z.object({
33
+ platform: z.enum(["macos", "windows", "linux", "unsupported"]),
34
+ helper: z.enum(["running", "stopped", "unavailable"]),
35
+ permissions: z.object({
36
+ accessibility: computerPermissionStateSchema,
37
+ screenRecording: computerPermissionStateSchema,
38
+ }),
39
+ displays: z.array(computerDisplaySchema),
40
+ });
41
+ export const computerSnapshotSchema = z.object({
42
+ snapshotId: z.string().min(1),
43
+ revision: z.number().int(),
44
+ display: computerDisplaySchema.nullable(),
45
+ activeApp: z.string().nullable(),
46
+ activeWindow: z.string().nullable(),
47
+ cursor: z.object({ x: z.number(), y: z.number() }).nullable(),
48
+ elements: z.array(computerElementSchema),
49
+ screenshot: computerScreenshotSchema.optional(),
50
+ });
51
+ export const computerSnapshotMetadataSchema = computerSnapshotSchema.omit({
52
+ screenshot: true,
53
+ });
54
+ export const computerActionSchema = z.discriminatedUnion("type", [
55
+ z.object({ type: z.literal("move"), x: z.number(), y: z.number() }),
56
+ z.object({
57
+ type: z.literal("click"),
58
+ x: z.number().optional(),
59
+ y: z.number().optional(),
60
+ elementId: z.number().int().optional(),
61
+ }),
62
+ z.object({
63
+ type: z.literal("double_click"),
64
+ x: z.number().optional(),
65
+ y: z.number().optional(),
66
+ elementId: z.number().int().optional(),
67
+ }),
68
+ z.object({
69
+ type: z.literal("right_click"),
70
+ x: z.number().optional(),
71
+ y: z.number().optional(),
72
+ elementId: z.number().int().optional(),
73
+ }),
74
+ z.object({
75
+ type: z.literal("drag"),
76
+ from: z.object({ x: z.number(), y: z.number() }),
77
+ to: z.object({ x: z.number(), y: z.number() }),
78
+ durationMs: z.number().int().min(0).max(10_000).optional(),
79
+ }),
80
+ z.object({
81
+ type: z.literal("scroll"),
82
+ deltaX: z.number().optional(),
83
+ deltaY: z.number(),
84
+ elementId: z.number().int().optional(),
85
+ }),
86
+ z.object({
87
+ type: z.literal("keypress"),
88
+ keys: z.array(z.string().min(1)).min(1).max(8),
89
+ }),
90
+ z.object({
91
+ type: z.literal("type_text"),
92
+ text: z.string().max(100_000),
93
+ elementId: z.number().int().optional(),
94
+ }),
95
+ z.object({ type: z.literal("invoke"), elementId: z.number().int() }),
96
+ z.object({
97
+ type: z.literal("set_value"),
98
+ elementId: z.number().int(),
99
+ value: z.string().max(100_000),
100
+ }),
101
+ z.object({
102
+ type: z.literal("select_text"),
103
+ elementId: z.number().int(),
104
+ start: z.number().int().min(0),
105
+ length: z.number().int().min(0),
106
+ }),
107
+ z.object({ type: z.literal("activate_app"), app: z.string().min(1) }),
108
+ z.object({ type: z.literal("activate_window"), elementId: z.number().int() }),
109
+ z.object({
110
+ type: z.literal("move_window"),
111
+ elementId: z.number().int(),
112
+ x: z.number(),
113
+ y: z.number(),
114
+ }),
115
+ z.object({
116
+ type: z.literal("resize_window"),
117
+ elementId: z.number().int(),
118
+ width: z.number().positive(),
119
+ height: z.number().positive(),
120
+ }),
121
+ z.object({
122
+ type: z.literal("wait"),
123
+ ms: z.number().int().min(0).max(30_000),
124
+ }),
125
+ ]);
126
+ export const computerActionResultSchema = z.object({
127
+ success: z.literal(true),
128
+ revision: z.number().int(),
129
+ snapshot: computerSnapshotSchema.optional(),
130
+ executionMode: z.enum(["semantic", "background", "foreground", "mixed"]),
131
+ focusChanged: z.boolean(),
132
+ });
133
+ export const computerActionMetadataSchema = computerActionResultSchema.extend({
134
+ snapshot: computerSnapshotMetadataSchema.optional(),
135
+ });
136
+ export const computerSnapshotTargetSchema = z.discriminatedUnion("type", [
137
+ z.object({ type: z.literal("desktop") }),
138
+ z.object({
139
+ type: z.literal("display"),
140
+ displayId: z.string().optional(),
141
+ }),
142
+ z.object({ type: z.literal("app"), app: z.string().min(1) }),
143
+ z.object({ type: z.literal("window"), elementId: z.number().int() }),
144
+ z.object({
145
+ type: z.literal("region"),
146
+ displayId: z.string().optional(),
147
+ x: z.number(),
148
+ y: z.number(),
149
+ width: z.number().positive(),
150
+ height: z.number().positive(),
151
+ }),
152
+ ]);
@@ -0,0 +1,27 @@
1
+ import type { RuntimeEventBus } from "../../app/event-bus.js";
2
+ import type { ComputerSettingsRepository } from "./computer-settings-repository.js";
3
+ import type { ComputerAccessScope, ComputerActionRequest, ComputerActionResult, ComputerBackend, ComputerPermission, ComputerSettings, ComputerSnapshot, ComputerSnapshotRequest, ComputerStatus } from "./types.js";
4
+ type ComputerSettingsStore = Pick<ComputerSettingsRepository, "get" | "set">;
5
+ export declare class ComputerService {
6
+ private readonly backend;
7
+ private readonly settingsRepository;
8
+ private readonly events;
9
+ private revision;
10
+ private currentSnapshotId;
11
+ private latestSnapshotValue;
12
+ private queue;
13
+ constructor(backend: ComputerBackend, settingsRepository: ComputerSettingsStore, events: RuntimeEventBus);
14
+ settings(): ComputerSettings;
15
+ latestSnapshot(scope: ComputerAccessScope): ComputerSnapshot | null;
16
+ requestPermission(permission: ComputerPermission): Promise<ComputerStatus>;
17
+ status(): Promise<ComputerStatus>;
18
+ setSettings(patch: Partial<Pick<ComputerSettings, "enabled" | "remoteAccess">>): ComputerSettings;
19
+ snapshot(scope: ComputerAccessScope, request: ComputerSnapshotRequest): Promise<ComputerSnapshot>;
20
+ action(scope: ComputerAccessScope, request: ComputerActionRequest): Promise<ComputerActionResult>;
21
+ shutdown(): Promise<void>;
22
+ private assertActionBudget;
23
+ private assertAllowed;
24
+ private assertScopeAllowed;
25
+ private serial;
26
+ }
27
+ export {};
@@ -0,0 +1,108 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { ChatRoomError } from "../../core/errors/chatroom-error.js";
3
+ export class ComputerService {
4
+ backend;
5
+ settingsRepository;
6
+ events;
7
+ revision = 0;
8
+ currentSnapshotId = null;
9
+ latestSnapshotValue = null;
10
+ queue = Promise.resolve();
11
+ constructor(backend, settingsRepository, events) {
12
+ this.backend = backend;
13
+ this.settingsRepository = settingsRepository;
14
+ this.events = events;
15
+ }
16
+ settings() {
17
+ return this.settingsRepository.get();
18
+ }
19
+ latestSnapshot(scope) {
20
+ const settings = this.settings();
21
+ if (!settings.enabled)
22
+ return null;
23
+ this.assertScopeAllowed(scope, settings);
24
+ return this.latestSnapshotValue;
25
+ }
26
+ requestPermission(permission) {
27
+ return this.serial(async () => {
28
+ const base = await this.backend.requestPermission(permission);
29
+ return { ...base, settings: this.settings() };
30
+ });
31
+ }
32
+ async status() {
33
+ const base = await this.backend.status();
34
+ return { ...base, settings: this.settings() };
35
+ }
36
+ setSettings(patch) {
37
+ const next = this.settingsRepository.set({ ...this.settings(), ...patch });
38
+ if (!next.enabled) {
39
+ this.currentSnapshotId = null;
40
+ this.latestSnapshotValue = null;
41
+ void this.backend.dispose().catch(() => undefined);
42
+ }
43
+ this.events.emit({ type: "computer-settings", settings: next });
44
+ return next;
45
+ }
46
+ snapshot(scope, request) {
47
+ return this.serial(async () => {
48
+ this.assertAllowed(scope);
49
+ this.currentSnapshotId = null;
50
+ const value = await this.backend.snapshot(request, this.revision);
51
+ this.currentSnapshotId = value.snapshotId || `snap_${randomUUID()}`;
52
+ value.snapshotId = this.currentSnapshotId;
53
+ value.revision = this.revision;
54
+ this.latestSnapshotValue = value;
55
+ return value;
56
+ });
57
+ }
58
+ action(scope, request) {
59
+ return this.serial(async () => {
60
+ this.assertAllowed(scope);
61
+ this.assertActionBudget(request);
62
+ const referencesElements = request.actions.some((action) => "elementId" in action && action.elementId !== undefined);
63
+ if (referencesElements && !request.snapshotId)
64
+ throw new ChatRoomError("CONFLICT", "Actions using elementId require the latest snapshotId");
65
+ if (request.snapshotId && request.snapshotId !== this.currentSnapshotId)
66
+ throw new ChatRoomError("CONFLICT", "Computer snapshot is stale; take a new snapshot before acting");
67
+ this.currentSnapshotId = null;
68
+ const result = await this.backend.action(request, ++this.revision);
69
+ this.currentSnapshotId = result.snapshot?.snapshotId ?? null;
70
+ if (result.snapshot)
71
+ this.latestSnapshotValue = result.snapshot;
72
+ return result;
73
+ });
74
+ }
75
+ async shutdown() {
76
+ this.currentSnapshotId = null;
77
+ this.latestSnapshotValue = null;
78
+ await this.backend.dispose();
79
+ }
80
+ assertActionBudget(request) {
81
+ const durationMs = request.actions.reduce((total, action) => {
82
+ if (action.type === "wait")
83
+ return total + action.ms;
84
+ if (action.type === "drag")
85
+ return total + (action.durationMs ?? 0);
86
+ return total;
87
+ }, 0);
88
+ if (durationMs > 30_000)
89
+ throw new ChatRoomError("INVALID_INPUT", "Computer action batch exceeds the 30 second execution budget");
90
+ }
91
+ assertAllowed(scope) {
92
+ const settings = this.settings();
93
+ if (!settings.enabled)
94
+ throw new ChatRoomError("FORBIDDEN", "Computer Use is disabled");
95
+ this.assertScopeAllowed(scope, settings);
96
+ }
97
+ assertScopeAllowed(scope, settings) {
98
+ if (scope === "remote" && !settings.remoteAccess)
99
+ throw new ChatRoomError("FORBIDDEN", "Remote Computer Use is disabled", {
100
+ reason: "remote_computer_disabled",
101
+ });
102
+ }
103
+ serial(action) {
104
+ const next = this.queue.then(action, action);
105
+ this.queue = next.then(() => undefined, () => undefined);
106
+ return next;
107
+ }
108
+ }
@@ -0,0 +1,8 @@
1
+ import type { AppDatabase } from "../../infrastructure/database/app-database.js";
2
+ import type { ComputerSettings } from "./types.js";
3
+ export declare class ComputerSettingsRepository {
4
+ private readonly database;
5
+ constructor(database: AppDatabase);
6
+ get(): ComputerSettings;
7
+ set(value: Omit<ComputerSettings, "updatedAt"> | ComputerSettings): ComputerSettings;
8
+ }
@@ -0,0 +1,41 @@
1
+ export class ComputerSettingsRepository {
2
+ database;
3
+ constructor(database) {
4
+ this.database = database;
5
+ }
6
+ get() {
7
+ const row = this.database.raw
8
+ .prepare("SELECT enabled, remote_access, updated_at FROM computer_settings WHERE id = 1")
9
+ .get();
10
+ if (row)
11
+ return fromRow(row);
12
+ const value = {
13
+ enabled: false,
14
+ remoteAccess: true,
15
+ updatedAt: new Date().toISOString(),
16
+ };
17
+ this.set(value);
18
+ return value;
19
+ }
20
+ set(value) {
21
+ const updatedAt = new Date().toISOString();
22
+ this.database.raw
23
+ .prepare(`
24
+ INSERT INTO computer_settings(id, enabled, remote_access, updated_at)
25
+ VALUES(1, ?, ?, ?)
26
+ ON CONFLICT(id) DO UPDATE SET
27
+ enabled = excluded.enabled,
28
+ remote_access = excluded.remote_access,
29
+ updated_at = excluded.updated_at
30
+ `)
31
+ .run(value.enabled ? 1 : 0, value.remoteAccess ? 1 : 0, updatedAt);
32
+ return { ...value, updatedAt };
33
+ }
34
+ }
35
+ function fromRow(row) {
36
+ return {
37
+ enabled: Boolean(row.enabled),
38
+ remoteAccess: Boolean(row.remote_access),
39
+ updatedAt: String(row.updated_at),
40
+ };
41
+ }
@@ -0,0 +1,3 @@
1
+ import type { PluginMcpRegistrar } from "../../mcp/server/plugin-mcp-registrar.js";
2
+ import type { ComputerService } from "./computer-service.js";
3
+ export declare function registerComputerTools(mcp: PluginMcpRegistrar, service: ComputerService): void;