@cli-remote/local 0.4.0 → 0.4.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 (2) hide show
  1. package/dist/index.cjs +65 -15
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -10468,16 +10468,65 @@ var DesktopManager = class {
10468
10468
  /** Probes displays/workspaces. Degrades gracefully — missing tools yield
10469
10469
  * empty/unknown values, never throws (web always gets an answer). */
10470
10470
  async queryInfo() {
10471
- if (this.platform !== "linux") {
10472
- return { displays: [], workspaces: null, currentWorkspace: null, canPickDisplay: false };
10471
+ if (this.platform === "darwin") {
10472
+ const displays = await this.listScreensMac().catch(() => []);
10473
+ return {
10474
+ displays,
10475
+ workspaces: null,
10476
+ currentWorkspace: null,
10477
+ canPickDisplay: displays.length > 1,
10478
+ cropMode: "client"
10479
+ };
10473
10480
  }
10474
- const [heads, ws] = await Promise.all([this.listHeads().catch(() => []), this.workspaceState().catch(() => null)]);
10475
- return {
10476
- displays: heads.map((h) => ({ name: h.name, width: h.w, height: h.h })),
10477
- workspaces: ws?.count ?? null,
10478
- currentWorkspace: ws?.current ?? null,
10479
- canPickDisplay: heads.length > 0
10480
- };
10481
+ if (this.platform === "linux") {
10482
+ const [heads, ws] = await Promise.all([
10483
+ this.listHeads().catch(() => []),
10484
+ this.workspaceState().catch(() => null)
10485
+ ]);
10486
+ return {
10487
+ displays: heads.map((h) => ({ name: h.name, width: h.w, height: h.h, x: h.x, y: h.y })),
10488
+ workspaces: ws?.count ?? null,
10489
+ currentWorkspace: ws?.current ?? null,
10490
+ canPickDisplay: heads.length > 0,
10491
+ cropMode: "server"
10492
+ };
10493
+ }
10494
+ return { displays: [], workspaces: null, currentWorkspace: null, canPickDisplay: false, cropMode: "client" };
10495
+ }
10496
+ /** macOS: NSScreen frames via JXA (osascript -l JavaScript + AppKit).
10497
+ * AppKit origins are bottom-left → converted to CG top-left coords to
10498
+ * match the RFB framebuffer. Warm run ~1.5s; any failure → empty list. */
10499
+ async listScreensMac() {
10500
+ const script = [
10501
+ 'ObjC.import("AppKit")',
10502
+ "const screens = $.NSScreen.screens",
10503
+ "let gb = 0",
10504
+ "for (let i = 0; i < screens.count; i++) {",
10505
+ " const f = screens.objectAtIndex(i).frame",
10506
+ " gb = Math.max(gb, f.origin.y + f.size.height)",
10507
+ "}",
10508
+ "const out = []",
10509
+ "for (let i = 0; i < screens.count; i++) {",
10510
+ " const s = screens.objectAtIndex(i)",
10511
+ " const f = s.frame",
10512
+ ' out.push([Math.round(f.origin.x), Math.round(gb - f.origin.y - f.size.height), Math.round(f.size.width), Math.round(f.size.height), s.localizedName.js].join("|"))',
10513
+ "}",
10514
+ 'out.join("\n")'
10515
+ ].join("\n");
10516
+ const out = await this.exec("osascript", ["-l", "JavaScript", "-e", script], 8e3);
10517
+ const displays = [];
10518
+ for (const line of out.split("\n").filter((l) => l.trim())) {
10519
+ const [x, y, w, h, ...rest] = line.split("|");
10520
+ if (x === void 0 || w === void 0 || rest.length === 0) continue;
10521
+ displays.push({
10522
+ name: rest.join("|"),
10523
+ x: Number(x),
10524
+ y: Number(y),
10525
+ width: Number(w),
10526
+ height: Number(h)
10527
+ });
10528
+ }
10529
+ return displays;
10481
10530
  }
10482
10531
  /** `xrandr --query` connected heads (name + geometry). */
10483
10532
  async listHeads() {
@@ -10508,9 +10557,6 @@ var DesktopManager = class {
10508
10557
  if (opts.workspace !== void 0 && this.platform !== "linux") {
10509
10558
  throw new Error("workspace selection is not supported on this platform (session-internal prev/next still works on macOS)");
10510
10559
  }
10511
- if (opts.display !== void 0 && this.platform !== "linux") {
10512
- throw new Error("display selection is not supported on this platform");
10513
- }
10514
10560
  if (opts.workspace !== void 0) {
10515
10561
  await this.switchWorkspaceAbsolute(opts.workspace);
10516
10562
  this.hooks.log(`desktop ${sessionId}: workspace \u2192 ${opts.workspace}`);
@@ -10518,7 +10564,7 @@ var DesktopManager = class {
10518
10564
  let tcp = await probeConnect(host, port, 750);
10519
10565
  let ownChild = null;
10520
10566
  let clip;
10521
- if (opts.display !== void 0) {
10567
+ if (opts.display !== void 0 && this.platform === "linux") {
10522
10568
  const heads = await this.listHeads().catch(() => []);
10523
10569
  clip = heads[opts.display];
10524
10570
  if (!clip) {
@@ -10673,6 +10719,9 @@ var DesktopManager = class {
10673
10719
  /** Linux: respawn OUR x11vnc with a new -clip and swap the TCP socket.
10674
10720
  * The RFB handshake restarts on the web side (viewer re-attaches). */
10675
10721
  async switchDisplay(s, display) {
10722
+ if (this.platform === "darwin") {
10723
+ return "display switching is client-side on this platform (web viewport crop)";
10724
+ }
10676
10725
  if (this.platform !== "linux") return "display switching is not supported on this platform";
10677
10726
  if (s.externalServer || !s.x11vnc) {
10678
10727
  return "cannot switch displays on an external VNC server (only locally started x11vnc)";
@@ -11895,7 +11944,8 @@ async function startLocal(opts = {}) {
11895
11944
  displays: [],
11896
11945
  workspaces: null,
11897
11946
  currentWorkspace: null,
11898
- canPickDisplay: false
11947
+ canPickDisplay: false,
11948
+ cropMode: "client"
11899
11949
  })
11900
11950
  );
11901
11951
  });
@@ -12174,7 +12224,7 @@ function resolveHere() {
12174
12224
  var argUrl = process.argv[2];
12175
12225
  var argMatch = argUrl && (argUrl.startsWith("ws://") || argUrl.startsWith("wss://"));
12176
12226
  function readVersion() {
12177
- if (true) return "0.4.0";
12227
+ if (true) return "0.4.1";
12178
12228
  try {
12179
12229
  const pkg = JSON.parse(
12180
12230
  (0, import_node_fs5.readFileSync)(new URL("../package.json", import_meta.url), "utf-8")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cli-remote/local",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Local PTY agent for cli-remote — exposes your local CLI tools (claude/codex/kimi-cli/shell) to the mobile web client via a self-hosted hub.",
5
5
  "license": "MIT",
6
6
  "repository": {