replicas-computer 0.3.29 → 0.3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +120 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/client.ts
4
- import { createConnection as createConnection3 } from "net";
4
+ import { createConnection as createConnection4 } from "net";
5
5
 
6
6
  // src/daemon.ts
7
7
  import { spawnSync as spawnSync5 } from "child_process";
8
8
  import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync6, rmSync as rmSync5 } from "fs";
9
- import { createConnection as createConnection2, createServer as createServer2 } from "net";
9
+ import { createConnection as createConnection3, createServer as createServer2 } from "net";
10
10
  import { dirname as dirname5 } from "path";
11
11
 
12
12
  // src/commands/desktop.ts
@@ -21,6 +21,8 @@ function isRecord(value) {
21
21
 
22
22
  // ../shared/src/engine/environment.ts
23
23
  var DESKTOP_STREAM_PORT = 6080;
24
+ var DESKTOP_COMPUTER_SOCKET = "/tmp/replicas-desktop-computer.sock";
25
+ var DESKTOP_COMPUTER_VIEW_PORT = 6091;
24
26
  var DEVICES_DIR = ".ssh/replicas-devices";
25
27
  var DEVICE_SCREEN_FILE_SUFFIX = ".screen.json";
26
28
  function parseDeviceScreenState(value) {
@@ -1137,9 +1139,9 @@ async function openChromeSession(webSocketDebuggerUrl) {
1137
1139
  const fail2 = (error) => {
1138
1140
  if (closed) return;
1139
1141
  closed = true;
1140
- for (const request of pending.values()) {
1141
- clearTimeout(request.timeout);
1142
- request.reject(error);
1142
+ for (const request2 of pending.values()) {
1143
+ clearTimeout(request2.timeout);
1144
+ request2.reject(error);
1143
1145
  }
1144
1146
  pending.clear();
1145
1147
  socket.close();
@@ -1156,12 +1158,12 @@ async function openChromeSession(webSocketDebuggerUrl) {
1156
1158
  if (!isRecord(message)) return;
1157
1159
  if (typeof message.method === "string" && isRecord(message.params)) listeners.get(message.method)?.(message.params);
1158
1160
  if (typeof message.id !== "number") return;
1159
- const request = pending.get(message.id);
1160
- if (!request) return;
1161
- clearTimeout(request.timeout);
1161
+ const request2 = pending.get(message.id);
1162
+ if (!request2) return;
1163
+ clearTimeout(request2.timeout);
1162
1164
  pending.delete(message.id);
1163
1165
  const detail = isRecord(message.error) && typeof message.error.message === "string" ? message.error.message : void 0;
1164
- request.resolve(message.error ? { error: { message: detail } } : { result: isRecord(message.result) ? message.result : {} });
1166
+ request2.resolve(message.error ? { error: { message: detail } } : { result: isRecord(message.result) ? message.result : {} });
1165
1167
  });
1166
1168
  socket.addEventListener("error", () => fail2(new Error("Chrome DevTools WebSocket failed")));
1167
1169
  socket.addEventListener("close", () => fail2(new Error("Chrome DevTools WebSocket closed unexpectedly")));
@@ -3007,10 +3009,68 @@ async function computerDragCommand(fx, fy, tx, ty) {
3007
3009
  console.log(`dragged (${fromX},${fromY}) -> (${toX},${toY})`);
3008
3010
  }
3009
3011
 
3010
- // src/commands/screen.ts
3012
+ // src/commands/mac.ts
3011
3013
  import { spawn as spawn3 } from "child_process";
3012
- import { closeSync, existsSync as existsSync5, mkdirSync as mkdirSync5, openSync, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync4, symlinkSync, writeFileSync as writeFileSync5 } from "fs";
3013
- import { createConnection, createServer } from "net";
3014
+ import { randomUUID } from "crypto";
3015
+ import { writeFileSync as writeFileSync5 } from "fs";
3016
+ import { createConnection } from "net";
3017
+ var REQUEST_TIMEOUT_MS = 12e4;
3018
+ function request(payload) {
3019
+ return new Promise((resolve5, reject) => {
3020
+ const socket = createConnection(DESKTOP_COMPUTER_SOCKET);
3021
+ let reply = "";
3022
+ const disconnected = () => reject(new Error("No Mac is connected. Open this workspace in the Replicas desktop app on the Mac, with computer use turned on."));
3023
+ socket.once("error", disconnected);
3024
+ socket.once("close", disconnected);
3025
+ socket.setTimeout(REQUEST_TIMEOUT_MS, () => {
3026
+ socket.destroy();
3027
+ reject(new Error(`The Mac's driver didn't answer within ${REQUEST_TIMEOUT_MS / 1e3} seconds.`));
3028
+ });
3029
+ socket.on("data", (chunk) => {
3030
+ reply += chunk.toString("utf8");
3031
+ const end = reply.indexOf("\n");
3032
+ if (end === -1) return;
3033
+ socket.destroy();
3034
+ try {
3035
+ resolve5(JSON.parse(reply.slice(0, end)));
3036
+ } catch (error) {
3037
+ reject(error);
3038
+ }
3039
+ });
3040
+ socket.write(`${JSON.stringify(payload)}
3041
+ `);
3042
+ });
3043
+ }
3044
+ async function showView() {
3045
+ const origin = `http://127.0.0.1:${DESKTOP_COMPUTER_VIEW_PORT}/`;
3046
+ if ((await getChromePages().catch(() => [])).some((page) => page.url?.startsWith(origin))) return;
3047
+ ensureServicesRunning();
3048
+ spawn3(CHROME_WRAPPER, ["--new-window", "--start-maximized", `--app=${origin}`], { env: withDisplay(), detached: true, stdio: "ignore" }).unref();
3049
+ }
3050
+ async function computerMacCommand(tool, json, options) {
3051
+ let args;
3052
+ try {
3053
+ args = JSON.parse(json ?? "{}");
3054
+ } catch {
3055
+ fail(`Arguments must be a JSON object, got: ${json}`);
3056
+ }
3057
+ if (!isRecord(args)) fail(`Arguments must be a JSON object, got: ${json}`);
3058
+ const session = options.session ?? `replicas-${randomUUID()}`;
3059
+ const reply = await request({ method: "call", name: tool, args: { ...args, session }, session_id: session, client_kind: "cli", observation_origin: "direct" }).catch((error) => fail(error instanceof Error ? error.message : String(error)));
3060
+ if (!options.session) await request({ method: "session_end", session_id: session, client_kind: "cli" }).catch(() => void 0);
3061
+ await showView().catch(() => void 0);
3062
+ if (!isRecord(reply) || reply.ok !== true || !isRecord(reply.result)) fail(`The Mac's driver refused: ${JSON.stringify(isRecord(reply) ? reply.error ?? reply : reply)}`);
3063
+ const { content, structuredContent } = reply.result;
3064
+ const blocks = Array.isArray(content) ? content.filter(isRecord) : [];
3065
+ const image = blocks.find((block) => block.type === "image" && typeof block.data === "string");
3066
+ if (image && options.screenshot) writeFileSync5(options.screenshot, Buffer.from(String(image.data), "base64"));
3067
+ console.log(structuredContent === void 0 ? blocks.filter((block) => block.type === "text").map((block) => block.text).join("\n") : JSON.stringify(structuredContent, null, 2));
3068
+ }
3069
+
3070
+ // src/commands/screen.ts
3071
+ import { spawn as spawn4 } from "child_process";
3072
+ import { closeSync, existsSync as existsSync5, mkdirSync as mkdirSync5, openSync, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync4, symlinkSync, writeFileSync as writeFileSync6 } from "fs";
3073
+ import { createConnection as createConnection2, createServer } from "net";
3014
3074
  import { homedir } from "os";
3015
3075
  import { join } from "path";
3016
3076
  import { setTimeout as sleep2 } from "timers/promises";
@@ -3026,7 +3086,7 @@ function ownsProcess(session, pid) {
3026
3086
  }
3027
3087
  function isListening(port2) {
3028
3088
  return new Promise((resolve5) => {
3029
- const socket = createConnection({ host: "127.0.0.1", port: port2 });
3089
+ const socket = createConnection2({ host: "127.0.0.1", port: port2 });
3030
3090
  const done = (listening) => {
3031
3091
  socket.destroy();
3032
3092
  resolve5(listening);
@@ -3050,7 +3110,7 @@ async function freePorts(count) {
3050
3110
  }
3051
3111
  function spawnLogged(bin, args, log) {
3052
3112
  const fd = openSync(log, "a");
3053
- const child = spawn3(bin, args, { detached: true, stdio: ["ignore", fd, fd] });
3113
+ const child = spawn4(bin, args, { detached: true, stdio: ["ignore", fd, fd] });
3054
3114
  closeSync(fd);
3055
3115
  child.unref();
3056
3116
  let exited = false;
@@ -3069,7 +3129,7 @@ async function waitForPort(port2, child) {
3069
3129
  }
3070
3130
  function readBanner(port2) {
3071
3131
  return new Promise((resolve5) => {
3072
- const socket = createConnection({ host: "127.0.0.1", port: port2 });
3132
+ const socket = createConnection2({ host: "127.0.0.1", port: port2 });
3073
3133
  let banner = "";
3074
3134
  const done = () => {
3075
3135
  socket.destroy();
@@ -3138,7 +3198,7 @@ async function openSession(device, dir, previous) {
3138
3198
  pids.push(bridge.pid);
3139
3199
  if (!await waitForPort(webPort, bridge)) abort(`Could not start the screen viewer: ${readFileSync5(bridgeLog, "utf8").trim() || "timed out"}`);
3140
3200
  const session = { webPort, tunnelPort, pids };
3141
- writeFileSync5(join(dir, "session.json"), JSON.stringify(session));
3201
+ writeFileSync6(join(dir, "session.json"), JSON.stringify(session));
3142
3202
  return session;
3143
3203
  }
3144
3204
  async function computerScreenCommand(device, options) {
@@ -3168,7 +3228,7 @@ async function showScreen(device, session) {
3168
3228
  const findPage = async () => (await getChromePages().catch(() => [])).find((page2) => page2.webSocketDebuggerUrl && page2.url?.startsWith(origin));
3169
3229
  let page = await findPage();
3170
3230
  if (!page) {
3171
- spawn3(CHROME_WRAPPER, ["--new-window", `--app=${origin}?device=${device}&requestFps=0`], { env: withDisplay(), detached: true, stdio: "ignore" }).unref();
3231
+ spawn4(CHROME_WRAPPER, ["--new-window", `--app=${origin}?device=${device}&requestFps=0`], { env: withDisplay(), detached: true, stdio: "ignore" }).unref();
3172
3232
  const deadline2 = Date.now() + CONNECT_TIMEOUT_MS;
3173
3233
  while (!page && Date.now() < deadline2) {
3174
3234
  await sleep2(250);
@@ -3263,7 +3323,7 @@ async function computerStatusCommand() {
3263
3323
  }
3264
3324
 
3265
3325
  // src/version.ts
3266
- var COMPUTER_USE_VERSION = "0.3.29";
3326
+ var COMPUTER_USE_VERSION = "0.3.30";
3267
3327
  var COMPUTER_USE_PROTOCOL_VERSION = 1;
3268
3328
 
3269
3329
  // src/program.ts
@@ -3301,6 +3361,7 @@ function createProgram() {
3301
3361
  program.command("scroll <direction>").description("Scroll the desktop").option("--amount <n>", "Wheel ticks").option("--x <x>", "Pointer x").option("--y <y>", "Pointer y").action((direction, options) => computerScrollCommand(direction, options));
3302
3362
  program.command("drag <fromX> <fromY> <toX> <toY>").description("Drag between desktop coordinates").action((fromX, fromY, toX, toY) => computerDragCommand(fromX, fromY, toX, toY));
3303
3363
  program.command("launch <app> [args...]").description("Launch an application on the desktop").action((app, args) => computerLaunchCommand(app, args));
3364
+ program.command("mac <tool> [json]", { hidden: true }).description("Call a Cua Driver tool on the user's Mac, in the background, through the Replicas desktop app").option("--screenshot <path>", "Write the screenshot in the reply to this PNG").option("--session <name>", "Keep element tokens across calls under this session name").action((tool, json, options) => computerMacCommand(tool, json, options));
3304
3365
  program.command("screen <device>", { hidden: true }).description("Show a device's screen in a window on this desktop, where the other commands drive it").option("--close", "Close the window and its connection").action((device, options) => computerScreenCommand(device, options));
3305
3366
  const record = program.command("record").description("Record the workspace display");
3306
3367
  record.command("start <path>").description("Start a recording").option("--fps <n>", "Frame rate. Default 60.").action((path, options) => computerRecordStartCommand(path, options));
@@ -3355,7 +3416,7 @@ function writeResult(socket, result) {
3355
3416
  async function hasSocketListener() {
3356
3417
  if (!existsSync6(COMPUTER_USE_SOCKET_PATH)) return false;
3357
3418
  return await new Promise((resolve5) => {
3358
- const socket = createConnection2(COMPUTER_USE_SOCKET_PATH);
3419
+ const socket = createConnection3(COMPUTER_USE_SOCKET_PATH);
3359
3420
  socket.setTimeout(500, () => socket.destroy());
3360
3421
  socket.once("connect", () => {
3361
3422
  socket.destroy();
@@ -3398,18 +3459,18 @@ async function runComputerDaemon() {
3398
3459
  if (rejected) return;
3399
3460
  socket.setTimeout(0);
3400
3461
  queue = queue.then(async () => {
3401
- let request;
3462
+ let request2;
3402
3463
  try {
3403
- request = JSON.parse(input);
3464
+ request2 = JSON.parse(input);
3404
3465
  } catch {
3405
3466
  writeResult(socket, { exitCode: 2, stdout: "", stderr: "Invalid computer-use request JSON\n" });
3406
3467
  return;
3407
3468
  }
3408
- if (!isDaemonRequest(request)) {
3469
+ if (!isDaemonRequest(request2)) {
3409
3470
  writeResult(socket, { exitCode: 2, stdout: "", stderr: "Invalid or incompatible computer-use request\n" });
3410
3471
  return;
3411
3472
  }
3412
- writeResult(socket, await runDirectCommand(request.argv, request.cwd));
3473
+ writeResult(socket, await runDirectCommand(request2.argv, request2.cwd));
3413
3474
  }).catch((error) => {
3414
3475
  writeResult(socket, { exitCode: 1, stdout: "", stderr: `${error instanceof Error ? error.message : String(error)}
3415
3476
  ` });
@@ -3454,7 +3515,7 @@ var ComputerDaemonUnavailableError = class extends Error {
3454
3515
  };
3455
3516
  function sendComputerRequest(argv) {
3456
3517
  return new Promise((resolve5, reject) => {
3457
- const socket = createConnection3(COMPUTER_USE_SOCKET_PATH);
3518
+ const socket = createConnection4(COMPUTER_USE_SOCKET_PATH);
3458
3519
  let response = "";
3459
3520
  let settled = false;
3460
3521
  const finish = (error, result) => {
@@ -3505,7 +3566,7 @@ async function runComputerClient(argv) {
3505
3566
  }
3506
3567
 
3507
3568
  // src/media-server.ts
3508
- import { spawn as spawn6 } from "child_process";
3569
+ import { spawn as spawn7 } from "child_process";
3509
3570
  import { createHash as createHash3 } from "crypto";
3510
3571
  import { createReadStream, existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
3511
3572
  import { createServer as createServer3 } from "http";
@@ -3515,7 +3576,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
3515
3576
  import WebSocket2, { WebSocketServer } from "ws";
3516
3577
 
3517
3578
  // src/encoder.ts
3518
- import { spawn as spawn4 } from "child_process";
3579
+ import { spawn as spawn5 } from "child_process";
3519
3580
  import { createSocket } from "dgram";
3520
3581
  import { createInterface } from "readline";
3521
3582
 
@@ -3750,7 +3811,7 @@ function superviseEncoder(options) {
3750
3811
  const warmupFrames = active ? options.warmupFrames ?? 0 : 0;
3751
3812
  const command = options.command?.() ?? "ffmpeg";
3752
3813
  const args = options.args(socket.address().port, warmupFrames);
3753
- const child = spawn4(command, args, { env: options.env, stdio: [options.controllable?.(command) ? "pipe" : "ignore", options.onOutput ? "pipe" : "ignore", "pipe"] });
3814
+ const child = spawn5(command, args, { env: options.env, stdio: [options.controllable?.(command) ? "pipe" : "ignore", options.onOutput ? "pipe" : "ignore", "pipe"] });
3754
3815
  child.stdin?.on("error", () => {
3755
3816
  });
3756
3817
  child.stderr?.on("data", (chunk) => process.stderr.write(`[desktop-stream] ${chunk}`));
@@ -3932,7 +3993,11 @@ function readReplicasRuntimeEnv(readEnv, [namespacedKey, legacyKey]) {
3932
3993
  return readEnv(namespacedKey) ?? readEnv(legacyKey);
3933
3994
  }
3934
3995
  function parsePosixEnvFile(content) {
3996
+ return parsePosixEnv(content).values;
3997
+ }
3998
+ function parsePosixEnv(content) {
3935
3999
  const result = {};
4000
+ const unsetKeys = [];
3936
4001
  let pos = 0;
3937
4002
  while (pos < content.length) {
3938
4003
  let lineStart;
@@ -3945,6 +4010,9 @@ function parsePosixEnvFile(content) {
3945
4010
  }
3946
4011
  if (!content.startsWith("export ", lineStart)) {
3947
4012
  const nl2 = content.indexOf("\n", lineStart);
4013
+ if (content.startsWith("unset ", lineStart)) {
4014
+ unsetKeys.push(content.slice(lineStart + "unset ".length, nl2 === -1 ? void 0 : nl2).trim());
4015
+ }
3948
4016
  if (nl2 === -1) break;
3949
4017
  pos = nl2 + 1;
3950
4018
  continue;
@@ -3983,7 +4051,7 @@ function parsePosixEnvFile(content) {
3983
4051
  const nl = content.indexOf("\n", cursor);
3984
4052
  pos = nl === -1 ? content.length : nl + 1;
3985
4053
  }
3986
- return result;
4054
+ return { values: result, unsetKeys };
3987
4055
  }
3988
4056
 
3989
4057
  // src/ice-servers.ts
@@ -4674,7 +4742,7 @@ function superviseVideoEncoder(options) {
4674
4742
  }
4675
4743
 
4676
4744
  // src/input-bridge.ts
4677
- import { spawn as spawn5 } from "child_process";
4745
+ import { spawn as spawn6 } from "child_process";
4678
4746
  var scrollPixelsPerStep = 80;
4679
4747
  var namedKeys = {
4680
4748
  AltLeft: "Alt_L",
@@ -4855,7 +4923,7 @@ var InputBridge = class {
4855
4923
  }
4856
4924
  write(command) {
4857
4925
  if (!this.process || this.process.exitCode !== null || this.process.stdin.destroyed) {
4858
- const child = spawn5("xte", [], {
4926
+ const child = spawn6("xte", [], {
4859
4927
  env: { ...process.env, DISPLAY: this.display },
4860
4928
  stdio: ["pipe", "pipe", "pipe"]
4861
4929
  });
@@ -4956,7 +5024,7 @@ function drainDesktopTheme() {
4956
5024
  if (applied) appliedTheme = theme;
4957
5025
  drainDesktopTheme();
4958
5026
  };
4959
- const child = spawn6("bash", [SERVICES_SCRIPT, "--theme", theme], { detached: true, stdio: "ignore" });
5027
+ const child = spawn7("bash", [SERVICES_SCRIPT, "--theme", theme], { detached: true, stdio: "ignore" });
4960
5028
  child.unref();
4961
5029
  child.once("exit", (code) => finish(code === 0));
4962
5030
  child.once("error", () => finish(false));
@@ -5263,8 +5331,8 @@ async function runMediaServer() {
5263
5331
  for (const viewer of viewers.values()) viewer.rtc?.setBudget(budgetBps());
5264
5332
  syncEncoder();
5265
5333
  };
5266
- const resetLadder = (request) => {
5267
- rung = request.transport === "webrtc" && request.adaptive ? webrtcStartupRung : 0;
5334
+ const resetLadder = (request2) => {
5335
+ rung = request2.transport === "webrtc" && request2.adaptive ? webrtcStartupRung : 0;
5268
5336
  cleanTransportSeconds = 0;
5269
5337
  descents = [];
5270
5338
  failedRung = -1;
@@ -5692,8 +5760,8 @@ async function runMediaServer() {
5692
5760
  audioSampleRate: 48e3,
5693
5761
  audioChannels: 2
5694
5762
  };
5695
- const httpServer = createServer3((request, response) => {
5696
- const url = new URL(request.url || "/", "http://localhost");
5763
+ const httpServer = createServer3((request2, response) => {
5764
+ const url = new URL(request2.url || "/", "http://localhost");
5697
5765
  if (url.pathname === "/health" || url.pathname === "/telemetry") {
5698
5766
  const all = [...viewers.values()];
5699
5767
  const memory = process.memoryUsage();
@@ -5746,7 +5814,7 @@ async function runMediaServer() {
5746
5814
  return;
5747
5815
  }
5748
5816
  if (url.pathname === "/snapshot") {
5749
- const capture = spawn6("ffmpeg", [
5817
+ const capture = spawn7("ffmpeg", [
5750
5818
  "-hide_banner",
5751
5819
  "-loglevel",
5752
5820
  "error",
@@ -5803,20 +5871,20 @@ async function runMediaServer() {
5803
5871
  createReadStream(path).pipe(response);
5804
5872
  });
5805
5873
  const webSocketServer = new WebSocketServer({ noServer: true, maxPayload: 64 * 1024 });
5806
- httpServer.on("upgrade", (request, socket, head) => {
5807
- const url = new URL(request.url || "/", "http://localhost");
5874
+ httpServer.on("upgrade", (request2, socket, head) => {
5875
+ const url = new URL(request2.url || "/", "http://localhost");
5808
5876
  if (url.pathname !== "/stream") {
5809
5877
  socket.destroy();
5810
5878
  return;
5811
5879
  }
5812
5880
  const streamRequest = parseStreamRequest(url.searchParams, defaultRequest);
5813
- void (webrtc && streamRequest.transport === "webrtc" ? currentIceServers() : Promise.resolve(void 0)).then((ice) => webSocketServer.handleUpgrade(request, socket, head, (client) => webSocketServer.emit("connection", client, streamRequest, url.searchParams.get("standby") === "1", ice)));
5881
+ void (webrtc && streamRequest.transport === "webrtc" ? currentIceServers() : Promise.resolve(void 0)).then((ice) => webSocketServer.handleUpgrade(request2, socket, head, (client) => webSocketServer.emit("connection", client, streamRequest, url.searchParams.get("standby") === "1", ice)));
5814
5882
  });
5815
- webSocketServer.on("connection", (socket, request, standby, ice) => {
5883
+ webSocketServer.on("connection", (socket, request2, standby, ice) => {
5816
5884
  const viewer = {
5817
5885
  socket,
5818
5886
  input: new InputBridge(display, width, height),
5819
- request,
5887
+ request: request2,
5820
5888
  standby,
5821
5889
  fallback: false,
5822
5890
  waitingForKeyframe: true,
@@ -5834,23 +5902,23 @@ async function runMediaServer() {
5834
5902
  rttFloorMs: 0,
5835
5903
  rttSamples: []
5836
5904
  };
5837
- if (viewers.size === 0) resetLadder(request);
5838
- if (request.profile !== activeProfile || request.adaptive !== adaptive) {
5839
- record("viewer request", `${request.profile} profile, ${request.adaptive ? "adaptive" : "pinned"} quality`);
5840
- activeProfile = request.profile;
5841
- adaptive = request.adaptive;
5905
+ if (viewers.size === 0) resetLadder(request2);
5906
+ if (request2.profile !== activeProfile || request2.adaptive !== adaptive) {
5907
+ record("viewer request", `${request2.profile} profile, ${request2.adaptive ? "adaptive" : "pinned"} quality`);
5908
+ activeProfile = request2.profile;
5909
+ adaptive = request2.adaptive;
5842
5910
  if (!adaptive) rung = 0;
5843
5911
  }
5844
5912
  viewers.set(socket, viewer);
5845
- record("viewer connected", `${request.transport} requested${standby ? " in standby" : ""}, ${viewers.size} connected`);
5913
+ record("viewer connected", `${request2.transport} requested${standby ? " in standby" : ""}, ${viewers.size} connected`);
5846
5914
  const reply = (message) => {
5847
5915
  if (socket.readyState === WebSocket2.OPEN) socket.send(JSON.stringify(message));
5848
5916
  };
5849
5917
  const fallbackProfile = profile() === "high444" ? "main" : profile();
5850
- const configMessage = { ...config, videoCodec: H264_PROFILES[fallbackProfile].codec, iceServers: ice?.browser, request };
5918
+ const configMessage = { ...config, videoCodec: H264_PROFILES[fallbackProfile].codec, iceServers: ice?.browser, request: request2 };
5851
5919
  reply(configMessage);
5852
5920
  if (ice) openWebRtc(viewer, reply, ice.native);
5853
- if (!viewer.rtc) enterFallback(viewer, request.transport === "webrtc" ? "webrtc unavailable" : "websocket requested");
5921
+ if (!viewer.rtc) enterFallback(viewer, request2.transport === "webrtc" ? "webrtc unavailable" : "websocket requested");
5854
5922
  ensureEncoders();
5855
5923
  socket.on("message", (raw, binary) => {
5856
5924
  if (binary) return;
@@ -5908,7 +5976,7 @@ async function runMediaServer() {
5908
5976
 
5909
5977
  // src/setup.ts
5910
5978
  import { spawnSync as spawnSync6 } from "child_process";
5911
- import { accessSync, chmodSync as chmodSync2, constants, cpSync, existsSync as existsSync9, mkdirSync as mkdirSync7, readdirSync as readdirSync4, writeFileSync as writeFileSync6 } from "fs";
5979
+ import { accessSync, chmodSync as chmodSync2, constants, cpSync, existsSync as existsSync9, mkdirSync as mkdirSync7, readdirSync as readdirSync4, writeFileSync as writeFileSync7 } from "fs";
5912
5980
  import { dirname as dirname8, resolve as resolve4 } from "path";
5913
5981
  import { fileURLToPath as fileURLToPath3 } from "url";
5914
5982
  var dependencies = [
@@ -6053,13 +6121,13 @@ async function setupComputer(options = {}) {
6053
6121
  chmodSync2("/usr/local/bin/replicas-start-desktop-services", 493);
6054
6122
  chmodSync2("/usr/local/bin/replicas-chrome", 493);
6055
6123
  chmodSync2("/usr/local/bin/replicas-terminal", 493);
6056
- writeFileSync6("/etc/systemd/system/replicas-computer.service", serviceUnit, { mode: 420 });
6124
+ writeFileSync7("/etc/systemd/system/replicas-computer.service", serviceUnit, { mode: 420 });
6057
6125
  if (existsSync9("/run/systemd/system")) {
6058
6126
  const reload = spawnSync6("systemctl", ["daemon-reload"], { stdio: "pipe" });
6059
6127
  if (reload.status !== 0) throw new Error(`Failed to reload systemd: ${reload.stderr?.toString().trim() || `exit ${reload.status}`}`);
6060
6128
  }
6061
6129
  mkdirSync7("/usr/local/share/replicas-computer", { recursive: true });
6062
- writeFileSync6("/usr/local/share/replicas-computer/install.json", `${JSON.stringify({
6130
+ writeFileSync7("/usr/local/share/replicas-computer/install.json", `${JSON.stringify({
6063
6131
  version: COMPUTER_USE_VERSION,
6064
6132
  protocolVersion: COMPUTER_USE_PROTOCOL_VERSION,
6065
6133
  dependencies: found
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-computer",
3
- "version": "0.3.29",
3
+ "version": "0.3.30",
4
4
  "description": "Replicas workspace computer-use runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",