@chatroomcp/chatroom 0.2.0 → 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.
- package/dist/native/linux/chatroom-computer-helper +0 -0
- package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
- package/dist/native/windows/chatroom-computer-helper.exe +0 -0
- package/dist/plugins/computer/computer-native-host.d.ts +2 -1
- package/dist/plugins/computer/computer-native-host.js +107 -17
- package/dist/plugins/computer/computer-schemas.d.ts +1 -0
- package/dist/plugins/computer/computer-schemas.js +1 -1
- package/dist/plugins/computer/types.d.ts +1 -1
- package/dist/web/assets/{index-BXlxEk8f.css → index-B4vO7wVS.css} +1 -1
- package/dist/web/assets/{index-DUM6zVHS.js → index-BU7LCgKB.js} +2 -2
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
|
Binary file
|
package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -15,9 +15,10 @@ export declare class ComputerNativeHost {
|
|
|
15
15
|
restart(reason?: string): void;
|
|
16
16
|
dispose(): Promise<void>;
|
|
17
17
|
private ensureStarted;
|
|
18
|
+
private startHelper;
|
|
18
19
|
private startMacHelper;
|
|
19
20
|
private attachSocket;
|
|
20
|
-
private
|
|
21
|
+
private startPipeHelper;
|
|
21
22
|
private failTransport;
|
|
22
23
|
private reset;
|
|
23
24
|
private rejectPending;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
2
|
+
import { spawn, spawnSync, } from "node:child_process";
|
|
3
3
|
import { chmodSync, existsSync, rmSync } from "node:fs";
|
|
4
4
|
import { createServer } from "node:net";
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
@@ -21,6 +21,8 @@ export class ComputerNativeHost {
|
|
|
21
21
|
return "macos";
|
|
22
22
|
if (process.platform === "win32")
|
|
23
23
|
return "windows";
|
|
24
|
+
if (process.platform === "linux")
|
|
25
|
+
return "linux";
|
|
24
26
|
return "unsupported";
|
|
25
27
|
}
|
|
26
28
|
get idle() {
|
|
@@ -59,18 +61,16 @@ export class ComputerNativeHost {
|
|
|
59
61
|
this.reset(new Error("Computer helper stopped"));
|
|
60
62
|
}
|
|
61
63
|
async ensureStarted() {
|
|
62
|
-
|
|
64
|
+
const platform = this.platform;
|
|
65
|
+
if (platform === "macos" && this.socket && !this.socket.destroyed)
|
|
63
66
|
return;
|
|
64
|
-
if (
|
|
67
|
+
if ((platform === "windows" || platform === "linux") &&
|
|
68
|
+
this.child &&
|
|
69
|
+
!this.child.killed)
|
|
65
70
|
return;
|
|
66
71
|
if (this.starting)
|
|
67
72
|
return this.starting;
|
|
68
|
-
this.starting =
|
|
69
|
-
this.platform === "macos"
|
|
70
|
-
? this.startMacHelper()
|
|
71
|
-
: this.platform === "windows"
|
|
72
|
-
? this.startWindowsHelper()
|
|
73
|
-
: Promise.reject(new ChatRoomError("UNSUPPORTED", "Computer Use is supported only on macOS and Windows"));
|
|
73
|
+
this.starting = this.startHelper(platform);
|
|
74
74
|
try {
|
|
75
75
|
await this.starting;
|
|
76
76
|
}
|
|
@@ -78,6 +78,18 @@ export class ComputerNativeHost {
|
|
|
78
78
|
this.starting = null;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
startHelper(platform) {
|
|
82
|
+
switch (platform) {
|
|
83
|
+
case "macos":
|
|
84
|
+
return this.startMacHelper();
|
|
85
|
+
case "windows":
|
|
86
|
+
return this.startPipeHelper(windowsHelperPath(), "Windows");
|
|
87
|
+
case "linux":
|
|
88
|
+
return this.startPipeHelper(linuxHelperPath(), "Linux X11", linuxDesktopEnvironment());
|
|
89
|
+
case "unsupported":
|
|
90
|
+
return Promise.reject(new ChatRoomError("UNSUPPORTED", "Computer Use is supported only on macOS, Windows, and Linux X11"));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
81
93
|
async startMacHelper() {
|
|
82
94
|
const app = macHelperAppPath();
|
|
83
95
|
if (!app)
|
|
@@ -131,13 +143,13 @@ export class ComputerNativeHost {
|
|
|
131
143
|
socket.once("error", (error) => this.failTransport(socket, error));
|
|
132
144
|
socket.once("close", () => this.failTransport(socket, new Error("Computer helper exited")));
|
|
133
145
|
}
|
|
134
|
-
async
|
|
135
|
-
const executable = windowsHelperPath();
|
|
146
|
+
async startPipeHelper(executable, platformName, env = process.env) {
|
|
136
147
|
if (!executable)
|
|
137
|
-
throw new ChatRoomError("UNSUPPORTED",
|
|
148
|
+
throw new ChatRoomError("UNSUPPORTED", `${platformName} Computer helper is missing`);
|
|
138
149
|
const child = spawn(executable, [], {
|
|
139
150
|
stdio: ["pipe", "pipe", "pipe"],
|
|
140
|
-
windowsHide:
|
|
151
|
+
windowsHide: process.platform === "win32",
|
|
152
|
+
env,
|
|
141
153
|
});
|
|
142
154
|
this.child = child;
|
|
143
155
|
this.lines = createInterface({ input: child.stdout });
|
|
@@ -236,10 +248,88 @@ function projectRoot() {
|
|
|
236
248
|
return path.resolve(path.dirname(current), "../../..");
|
|
237
249
|
}
|
|
238
250
|
function macHelperAppPath() {
|
|
239
|
-
|
|
240
|
-
return existsSync(app) ? app : null;
|
|
251
|
+
return nativeHelperPath("macos", "ChatRoomComputerHelper.app");
|
|
241
252
|
}
|
|
242
253
|
function windowsHelperPath() {
|
|
243
|
-
|
|
244
|
-
|
|
254
|
+
return nativeHelperPath("windows", "chatroom-computer-helper.exe");
|
|
255
|
+
}
|
|
256
|
+
function linuxHelperPath() {
|
|
257
|
+
return nativeHelperPath("linux", "chatroom-computer-helper");
|
|
258
|
+
}
|
|
259
|
+
function nativeHelperPath(...parts) {
|
|
260
|
+
const target = path.join(projectRoot(), "dist", "native", ...parts);
|
|
261
|
+
return existsSync(target) ? target : null;
|
|
262
|
+
}
|
|
263
|
+
function linuxDesktopEnvironment() {
|
|
264
|
+
const env = { ...process.env };
|
|
265
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : null;
|
|
266
|
+
if (!env.XDG_RUNTIME_DIR && uid !== null) {
|
|
267
|
+
const runtimeDir = `/run/user/${uid}`;
|
|
268
|
+
if (existsSync(runtimeDir))
|
|
269
|
+
env.XDG_RUNTIME_DIR = runtimeDir;
|
|
270
|
+
}
|
|
271
|
+
if (!env.DISPLAY) {
|
|
272
|
+
const display = activeX11Display(uid);
|
|
273
|
+
if (display) {
|
|
274
|
+
env.DISPLAY = display;
|
|
275
|
+
env.XDG_SESSION_TYPE = "x11";
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (!env.XAUTHORITY) {
|
|
279
|
+
const candidates = [
|
|
280
|
+
env.HOME ? path.join(env.HOME, ".Xauthority") : null,
|
|
281
|
+
env.XDG_RUNTIME_DIR
|
|
282
|
+
? path.join(env.XDG_RUNTIME_DIR, "gdm", "Xauthority")
|
|
283
|
+
: null,
|
|
284
|
+
];
|
|
285
|
+
const authority = candidates.find((candidate) => !!candidate && existsSync(candidate));
|
|
286
|
+
if (authority)
|
|
287
|
+
env.XAUTHORITY = authority;
|
|
288
|
+
}
|
|
289
|
+
if (!env.DBUS_SESSION_BUS_ADDRESS && env.XDG_RUNTIME_DIR) {
|
|
290
|
+
const bus = path.join(env.XDG_RUNTIME_DIR, "bus");
|
|
291
|
+
if (existsSync(bus))
|
|
292
|
+
env.DBUS_SESSION_BUS_ADDRESS = `unix:path=${bus}`;
|
|
293
|
+
}
|
|
294
|
+
return env;
|
|
295
|
+
}
|
|
296
|
+
function activeX11Display(uid) {
|
|
297
|
+
if (process.platform !== "linux" || uid === null)
|
|
298
|
+
return null;
|
|
299
|
+
const loginctl = existsSync("/usr/bin/loginctl")
|
|
300
|
+
? "/usr/bin/loginctl"
|
|
301
|
+
: "loginctl";
|
|
302
|
+
const sessions = spawnSync(loginctl, ["list-sessions", "--no-legend", "--no-pager"], {
|
|
303
|
+
encoding: "utf8",
|
|
304
|
+
timeout: 2_000,
|
|
305
|
+
});
|
|
306
|
+
if (sessions.status !== 0 || !sessions.stdout)
|
|
307
|
+
return null;
|
|
308
|
+
const userId = String(uid);
|
|
309
|
+
for (const line of sessions.stdout.split("\n")) {
|
|
310
|
+
const [sessionId, sessionUid] = line.trim().split(/\s+/, 3);
|
|
311
|
+
if (!sessionId || sessionUid !== userId)
|
|
312
|
+
continue;
|
|
313
|
+
const details = spawnSync(loginctl, [
|
|
314
|
+
"show-session",
|
|
315
|
+
sessionId,
|
|
316
|
+
"--no-pager",
|
|
317
|
+
"-p",
|
|
318
|
+
"Type",
|
|
319
|
+
"-p",
|
|
320
|
+
"Active",
|
|
321
|
+
"-p",
|
|
322
|
+
"Display",
|
|
323
|
+
], { encoding: "utf8", timeout: 2_000 });
|
|
324
|
+
if (details.status !== 0 || !details.stdout)
|
|
325
|
+
continue;
|
|
326
|
+
const values = Object.fromEntries(details.stdout
|
|
327
|
+
.split("\n")
|
|
328
|
+
.map((item) => item.split("=", 2))
|
|
329
|
+
.filter((item) => item.length === 2));
|
|
330
|
+
if (values.Type === "x11" && values.Active === "yes" && values.Display) {
|
|
331
|
+
return values.Display;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
245
335
|
}
|
|
@@ -30,7 +30,7 @@ export const computerScreenshotSchema = z.object({
|
|
|
30
30
|
data: z.string(),
|
|
31
31
|
});
|
|
32
32
|
export const computerNativeStatusSchema = z.object({
|
|
33
|
-
platform: z.enum(["macos", "windows", "unsupported"]),
|
|
33
|
+
platform: z.enum(["macos", "windows", "linux", "unsupported"]),
|
|
34
34
|
helper: z.enum(["running", "stopped", "unavailable"]),
|
|
35
35
|
permissions: z.object({
|
|
36
36
|
accessibility: computerPermissionStateSchema,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type ComputerAccessScope = "local" | "remote";
|
|
2
|
-
export type ComputerPlatform = "macos" | "windows" | "unsupported";
|
|
2
|
+
export type ComputerPlatform = "macos" | "windows" | "linux" | "unsupported";
|
|
3
3
|
export type ComputerHelperState = "running" | "stopped" | "unavailable";
|
|
4
4
|
export type ComputerPermissionState = "granted" | "denied" | "unknown" | "not-required";
|
|
5
5
|
export type ComputerPermission = "accessibility" | "screenRecording";
|