@cli-remote/local 0.5.0 → 0.5.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 +342 -155
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -5893,7 +5893,7 @@ var require_has_flag = __commonJS({
5893
5893
  var require_supports_color = __commonJS({
5894
5894
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module2) {
5895
5895
  "use strict";
5896
- var os2 = require("os");
5896
+ var os3 = require("os");
5897
5897
  var tty = require("tty");
5898
5898
  var hasFlag = require_has_flag();
5899
5899
  var { env } = process;
@@ -5941,7 +5941,7 @@ var require_supports_color = __commonJS({
5941
5941
  return min;
5942
5942
  }
5943
5943
  if (process.platform === "win32") {
5944
- const osRelease = os2.release().split(".");
5944
+ const osRelease = os3.release().split(".");
5945
5945
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
5946
5946
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
5947
5947
  }
@@ -12638,13 +12638,13 @@ function __disposeResources(env) {
12638
12638
  }
12639
12639
  return next();
12640
12640
  }
12641
- function __rewriteRelativeImportExtension(path, preserveJsx) {
12642
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
12643
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
12641
+ function __rewriteRelativeImportExtension(path2, preserveJsx) {
12642
+ if (typeof path2 === "string" && /^\.\.?\//.test(path2)) {
12643
+ return path2.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
12644
12644
  return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
12645
12645
  });
12646
12646
  }
12647
- return path;
12647
+ return path2;
12648
12648
  }
12649
12649
  var extendStatics, __assign, __createBinding, __setModuleDefault, ownKeys, _SuppressedError, tslib_es6_default;
12650
12650
  var init_tslib_es6 = __esm({
@@ -24999,14 +24999,14 @@ var require_dependency_container = __commonJS({
24999
24999
  provider = providerOrConstructor;
25000
25000
  }
25001
25001
  if (providers_1.isTokenProvider(provider)) {
25002
- const path = [token];
25002
+ const path2 = [token];
25003
25003
  let tokenProvider = provider;
25004
25004
  while (tokenProvider != null) {
25005
25005
  const currentToken = tokenProvider.useToken;
25006
- if (path.includes(currentToken)) {
25007
- throw new Error(`Token registration cycle detected! ${[...path, currentToken].join(" -> ")}`);
25006
+ if (path2.includes(currentToken)) {
25007
+ throw new Error(`Token registration cycle detected! ${[...path2, currentToken].join(" -> ")}`);
25008
25008
  }
25009
- path.push(currentToken);
25009
+ path2.push(currentToken);
25010
25010
  const registration = this._registry.get(currentToken);
25011
25011
  if (registration && providers_1.isTokenProvider(registration.provider)) {
25012
25012
  tokenProvider = registration.provider;
@@ -36708,7 +36708,7 @@ var require_multicast_dns = __commonJS({
36708
36708
  var dgram = require("dgram");
36709
36709
  var thunky = require_thunky();
36710
36710
  var events = require("events");
36711
- var os2 = require("os");
36711
+ var os3 = require("os");
36712
36712
  var noop = function() {
36713
36713
  };
36714
36714
  module2.exports = function(opts) {
@@ -36838,14 +36838,14 @@ var require_multicast_dns = __commonJS({
36838
36838
  return that;
36839
36839
  };
36840
36840
  function defaultInterface() {
36841
- var networks = os2.networkInterfaces();
36841
+ var networks = os3.networkInterfaces();
36842
36842
  var names = Object.keys(networks);
36843
36843
  for (var i = 0; i < names.length; i++) {
36844
36844
  var net3 = networks[names[i]];
36845
36845
  for (var j = 0; j < net3.length; j++) {
36846
36846
  var iface = net3[j];
36847
36847
  if (isIPv45(iface.family) && !iface.internal) {
36848
- if (os2.platform() === "darwin" && names[i] === "en0") return iface.address;
36848
+ if (os3.platform() === "darwin" && names[i] === "en0") return iface.address;
36849
36849
  return "0.0.0.0";
36850
36850
  }
36851
36851
  }
@@ -36853,7 +36853,7 @@ var require_multicast_dns = __commonJS({
36853
36853
  return "127.0.0.1";
36854
36854
  }
36855
36855
  function allInterfaces() {
36856
- var networks = os2.networkInterfaces();
36856
+ var networks = os3.networkInterfaces();
36857
36857
  var names = Object.keys(networks);
36858
36858
  var res = [];
36859
36859
  for (var i = 0; i < names.length; i++) {
@@ -56942,10 +56942,10 @@ var require_segments = __commonJS({
56942
56942
  const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
56943
56943
  const nodes = buildNodes(segs);
56944
56944
  const graph = buildGraph(nodes, version);
56945
- const path = dijkstra.find_path(graph.map, "start", "end");
56945
+ const path2 = dijkstra.find_path(graph.map, "start", "end");
56946
56946
  const optimizedSegs = [];
56947
- for (let i = 1; i < path.length - 1; i++) {
56948
- optimizedSegs.push(graph.table[path[i]].node);
56947
+ for (let i = 1; i < path2.length - 1; i++) {
56948
+ optimizedSegs.push(graph.table[path2[i]].node);
56949
56949
  }
56950
56950
  return exports2.fromArray(mergeSegments(optimizedSegs));
56951
56951
  };
@@ -59381,7 +59381,7 @@ var require_utils3 = __commonJS({
59381
59381
  // ../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js
59382
59382
  var require_png2 = __commonJS({
59383
59383
  "../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/png.js"(exports2) {
59384
- var fs = require("fs");
59384
+ var fs2 = require("fs");
59385
59385
  var PNG = require_png().PNG;
59386
59386
  var Utils = require_utils3();
59387
59387
  exports2.render = function render(qrData, options) {
@@ -59422,7 +59422,7 @@ var require_png2 = __commonJS({
59422
59422
  });
59423
59423
  png.pack();
59424
59424
  };
59425
- exports2.renderToFile = function renderToFile(path, qrData, options, cb) {
59425
+ exports2.renderToFile = function renderToFile(path2, qrData, options, cb) {
59426
59426
  if (typeof cb === "undefined") {
59427
59427
  cb = options;
59428
59428
  options = void 0;
@@ -59433,7 +59433,7 @@ var require_png2 = __commonJS({
59433
59433
  called = true;
59434
59434
  cb.apply(null, args);
59435
59435
  };
59436
- const stream = fs.createWriteStream(path);
59436
+ const stream = fs2.createWriteStream(path2);
59437
59437
  stream.on("error", done);
59438
59438
  stream.on("close", done);
59439
59439
  exports2.renderToFileStream(stream, qrData, options);
@@ -59495,14 +59495,14 @@ var require_utf83 = __commonJS({
59495
59495
  }
59496
59496
  return output;
59497
59497
  };
59498
- exports2.renderToFile = function renderToFile(path, qrData, options, cb) {
59498
+ exports2.renderToFile = function renderToFile(path2, qrData, options, cb) {
59499
59499
  if (typeof cb === "undefined") {
59500
59500
  cb = options;
59501
59501
  options = void 0;
59502
59502
  }
59503
- const fs = require("fs");
59503
+ const fs2 = require("fs");
59504
59504
  const utf8 = exports2.render(qrData, options);
59505
- fs.writeFile(path, utf8, cb);
59505
+ fs2.writeFile(path2, utf8, cb);
59506
59506
  };
59507
59507
  }
59508
59508
  });
@@ -59623,7 +59623,7 @@ var require_svg_tag = __commonJS({
59623
59623
  return str;
59624
59624
  }
59625
59625
  function qrToPath(data, size, margin) {
59626
- let path = "";
59626
+ let path2 = "";
59627
59627
  let moveBy = 0;
59628
59628
  let newRow = false;
59629
59629
  let lineLength = 0;
@@ -59634,19 +59634,19 @@ var require_svg_tag = __commonJS({
59634
59634
  if (data[i]) {
59635
59635
  lineLength++;
59636
59636
  if (!(i > 0 && col > 0 && data[i - 1])) {
59637
- path += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
59637
+ path2 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
59638
59638
  moveBy = 0;
59639
59639
  newRow = false;
59640
59640
  }
59641
59641
  if (!(col + 1 < size && data[i + 1])) {
59642
- path += svgCmd("h", lineLength);
59642
+ path2 += svgCmd("h", lineLength);
59643
59643
  lineLength = 0;
59644
59644
  }
59645
59645
  } else {
59646
59646
  moveBy++;
59647
59647
  }
59648
59648
  }
59649
- return path;
59649
+ return path2;
59650
59650
  }
59651
59651
  exports2.render = function render(qrData, options, cb) {
59652
59652
  const opts = Utils.getOptions(options);
@@ -59654,10 +59654,10 @@ var require_svg_tag = __commonJS({
59654
59654
  const data = qrData.modules.data;
59655
59655
  const qrcodesize = size + opts.margin * 2;
59656
59656
  const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
59657
- const path = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
59657
+ const path2 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
59658
59658
  const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
59659
59659
  const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
59660
- const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path + "</svg>\n";
59660
+ const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path2 + "</svg>\n";
59661
59661
  if (typeof cb === "function") {
59662
59662
  cb(null, svgTag);
59663
59663
  }
@@ -59671,15 +59671,15 @@ var require_svg = __commonJS({
59671
59671
  "../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg.js"(exports2) {
59672
59672
  var svgTagRenderer = require_svg_tag();
59673
59673
  exports2.render = svgTagRenderer.render;
59674
- exports2.renderToFile = function renderToFile(path, qrData, options, cb) {
59674
+ exports2.renderToFile = function renderToFile(path2, qrData, options, cb) {
59675
59675
  if (typeof cb === "undefined") {
59676
59676
  cb = options;
59677
59677
  options = void 0;
59678
59678
  }
59679
- const fs = require("fs");
59679
+ const fs2 = require("fs");
59680
59680
  const svgTag = exports2.render(qrData, options);
59681
59681
  const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
59682
- fs.writeFile(path, xmlStr, cb);
59682
+ fs2.writeFile(path2, xmlStr, cb);
59683
59683
  };
59684
59684
  }
59685
59685
  });
@@ -59837,8 +59837,8 @@ var require_server = __commonJS({
59837
59837
  cb
59838
59838
  };
59839
59839
  }
59840
- function getTypeFromFilename(path) {
59841
- return path.slice((path.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
59840
+ function getTypeFromFilename(path2) {
59841
+ return path2.slice((path2.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
59842
59842
  }
59843
59843
  function getRendererFromType(type) {
59844
59844
  switch (type) {
@@ -59902,17 +59902,17 @@ var require_server = __commonJS({
59902
59902
  const renderer = getRendererFromType(params.opts.type);
59903
59903
  return render(renderer.renderToBuffer, text, params);
59904
59904
  };
59905
- exports2.toFile = function toFile(path, text, opts, cb) {
59906
- if (typeof path !== "string" || !(typeof text === "string" || typeof text === "object")) {
59905
+ exports2.toFile = function toFile(path2, text, opts, cb) {
59906
+ if (typeof path2 !== "string" || !(typeof text === "string" || typeof text === "object")) {
59907
59907
  throw new Error("Invalid argument");
59908
59908
  }
59909
59909
  if (arguments.length < 3 && !canPromise()) {
59910
59910
  throw new Error("Too few arguments provided");
59911
59911
  }
59912
59912
  const params = checkParams(text, opts, cb);
59913
- const type = params.opts.type || getTypeFromFilename(path);
59913
+ const type = params.opts.type || getTypeFromFilename(path2);
59914
59914
  const renderer = getRendererFromType(type);
59915
- const renderToFile = renderer.renderToFile.bind(null, path);
59915
+ const renderToFile = renderer.renderToFile.bind(null, path2);
59916
59916
  return render(renderToFile, text, params);
59917
59917
  };
59918
59918
  exports2.toFileStream = function toFileStream(stream, text, opts) {
@@ -59935,10 +59935,10 @@ var require_lib = __commonJS({
59935
59935
  });
59936
59936
 
59937
59937
  // src/index.ts
59938
- var import_node_fs5 = require("node:fs");
59939
- var import_node_child_process5 = require("node:child_process");
59940
- var import_node_os8 = require("node:os");
59941
- var import_node_path8 = require("node:path");
59938
+ var import_node_fs6 = require("node:fs");
59939
+ var import_node_child_process6 = require("node:child_process");
59940
+ var import_node_os9 = require("node:os");
59941
+ var import_node_path9 = require("node:path");
59942
59942
  var import_node_url = require("node:url");
59943
59943
 
59944
59944
  // ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs
@@ -59953,11 +59953,11 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
59953
59953
  var wrapper_default = import_websocket.default;
59954
59954
 
59955
59955
  // src/client.ts
59956
- var import_node_child_process4 = require("node:child_process");
59956
+ var import_node_child_process5 = require("node:child_process");
59957
59957
  var import_node_readline = require("node:readline");
59958
- var import_node_fs4 = require("node:fs");
59959
- var import_node_os7 = require("node:os");
59960
- var import_node_path7 = require("node:path");
59958
+ var import_node_fs5 = require("node:fs");
59959
+ var import_node_os8 = require("node:os");
59960
+ var import_node_path8 = require("node:path");
59961
59961
 
59962
59962
  // ../shared/src/codec.ts
59963
59963
  var import_msgpack = __toESM(require_dist(), 1);
@@ -59978,6 +59978,9 @@ var REFRESH_TOKEN_TTL_MS = 30 * 24 * 60 * 6e4;
59978
59978
  var REFRESH_MARGIN_MS = 5 * 6e4;
59979
59979
  var OUTPUT_BUFFER_SIZE = 500;
59980
59980
  var AUDIT_RETENTION_DAYS = 14;
59981
+ var DESKTOP_MEDIA_CHUNK_BYTES = 120 * 1024;
59982
+ var DESKTOP_MEDIA_DEFAULT_FPS = 4;
59983
+ var DESKTOP_MEDIA_MAX_FPS = 10;
59981
59984
  var FILE_CHUNK_SIZE = 64 * 1024;
59982
59985
  var MAX_TRANSFER_BYTES = 500 * 1024 * 1024;
59983
59986
  var UPLOAD_DIR = "uploads";
@@ -60859,7 +60862,7 @@ var DesktopP2P = class {
60859
60862
  const pc = new this.werift.RTCPeerConnection({
60860
60863
  iceServers: this.config.iceServers.map((urls) => ({ urls }))
60861
60864
  });
60862
- const st = { pc, dc: null, active: false, dead: false };
60865
+ const st = { pc, dc: null, mediaDc: null, active: false, dead: false };
60863
60866
  this.sessions.set(sessionId, st);
60864
60867
  pc.onicecandidate = (ev) => {
60865
60868
  const c = ev.candidate;
@@ -60888,6 +60891,12 @@ var DesktopP2P = class {
60888
60891
  this.hooks.log(`desktop ${sessionId}: p2p offer failed \u2014 ${reason}`);
60889
60892
  }
60890
60893
  }
60894
+ /** v0.9.3: the session's media DataChannel when open (web created it in
60895
+ * the offer; label 'media'). Null → media frames ride the relay. */
60896
+ mediaChannel(sessionId) {
60897
+ const dc = this.sessions.get(sessionId)?.mediaDc;
60898
+ return dc && dc.readyState === "open" ? dc : null;
60899
+ }
60891
60900
  /** Trickle ICE from the web side. */
60892
60901
  async addIceCandidate(sessionId, candidate, sdpMid, sdpMLineIndex) {
60893
60902
  const st = this.sessions.get(sessionId);
@@ -60915,6 +60924,13 @@ var DesktopP2P = class {
60915
60924
  // -------------------------------------------------------------------------
60916
60925
  wireChannel(sessionId, st) {
60917
60926
  const dc = st.dc;
60927
+ if (dc.label === "media") {
60928
+ st.mediaDc = dc;
60929
+ dc.onclose = () => {
60930
+ if (st.mediaDc === dc) st.mediaDc = null;
60931
+ };
60932
+ return;
60933
+ }
60918
60934
  dc.onopen = () => {
60919
60935
  if (st.dead || this.sessions.get(sessionId) !== st) return;
60920
60936
  const sink = {
@@ -61000,6 +61016,135 @@ var DesktopP2P = class {
61000
61016
  }
61001
61017
  };
61002
61018
 
61019
+ // src/desktop-media.ts
61020
+ var import_node_child_process2 = require("node:child_process");
61021
+ var import_node_util2 = require("node:util");
61022
+ var import_node_fs3 = require("node:fs");
61023
+ var import_node_os4 = __toESM(require("node:os"), 1);
61024
+ var import_node_path4 = __toESM(require("node:path"), 1);
61025
+ var import_node_crypto = require("node:crypto");
61026
+ var execFileP2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
61027
+ var DESKTOP_MEDIA_MAGIC = 77;
61028
+ function defaultCapture(file, display0) {
61029
+ return execFileP2("screencapture", ["-x", "-D", String(display0 + 1), "-t", "jpg", file]).then(() => void 0);
61030
+ }
61031
+ function frameChunk(seq, idx, count, slice) {
61032
+ const head = 13;
61033
+ const out = new Uint8Array(head + slice.byteLength);
61034
+ const v = new DataView(out.buffer);
61035
+ v.setUint8(0, DESKTOP_MEDIA_MAGIC);
61036
+ v.setUint32(1, seq);
61037
+ v.setUint32(5, idx);
61038
+ v.setUint32(9, count);
61039
+ out.set(slice, head);
61040
+ return out;
61041
+ }
61042
+ var DesktopMediaManager = class {
61043
+ constructor(hooks, platform2 = process.platform, captureImpl) {
61044
+ this.hooks = hooks;
61045
+ this.platform = platform2;
61046
+ this.capture = captureImpl ?? defaultCapture;
61047
+ }
61048
+ sessions = /* @__PURE__ */ new Map();
61049
+ capture;
61050
+ has(sessionId) {
61051
+ return this.sessions.has(sessionId);
61052
+ }
61053
+ /** Start (or restart on another display) the stream. The first capture
61054
+ * doubles as the probe: it validates the display index AND the Screen
61055
+ * Recording permission — failures become actionable reasons. */
61056
+ async start(sessionId, opts) {
61057
+ if (this.platform !== "darwin") {
61058
+ return { ok: false, reason: "\u5A92\u4F53\u6D41\u91C7\u96C6\u76EE\u524D\u4EC5\u652F\u6301 macOS\uFF08\u8BBE\u5907\u7AEF\uFF09" };
61059
+ }
61060
+ if (!Number.isInteger(opts.display) || opts.display < 0 || opts.display > 15) {
61061
+ return { ok: false, reason: `\u65E0\u6548\u7684\u663E\u793A\u5668\u5E8F\u53F7 ${opts.display}` };
61062
+ }
61063
+ const fps = Math.min(DESKTOP_MEDIA_MAX_FPS, Math.max(1, Math.round(opts.fps ?? DESKTOP_MEDIA_DEFAULT_FPS)));
61064
+ this.stop(sessionId);
61065
+ const tmpFile = import_node_path4.default.join(import_node_os4.default.tmpdir(), `cli-remote-media-${(0, import_node_crypto.randomUUID)()}.jpg`);
61066
+ try {
61067
+ await this.capture(tmpFile, opts.display);
61068
+ } catch (e) {
61069
+ const detail = e instanceof Error ? e.message : String(e);
61070
+ return {
61071
+ ok: false,
61072
+ reason: /invalid display/i.test(detail) ? `\u663E\u793A\u5668 ${opts.display + 1} \u4E0D\u5B58\u5728\uFF08\u91CD\u65B0\u6253\u5F00\u684C\u9762\u9875\u4EE5\u5237\u65B0\u5217\u8868\uFF09` : `\u91C7\u96C6\u5931\u8D25\uFF1A${detail}\uFF08\u68C0\u67E5\u300C\u5C4F\u5E55\u5F55\u5236\u300D\u6743\u9650\uFF1A\u7CFB\u7EDF\u8BBE\u7F6E \u2192 \u9690\u79C1\u4E0E\u5B89\u5168\u6027\uFF09`
61073
+ };
61074
+ }
61075
+ const st = {
61076
+ display: opts.display,
61077
+ intervalMs: Math.round(1e3 / fps),
61078
+ seq: 0,
61079
+ timer: null,
61080
+ busy: false,
61081
+ stopped: false,
61082
+ tmpFile,
61083
+ failures: 0
61084
+ };
61085
+ this.sessions.set(sessionId, st);
61086
+ this.hooks.log(`desktop ${sessionId}: media stream started (display ${opts.display + 1}, ${fps}fps)`);
61087
+ await this.emit(sessionId, st);
61088
+ if (st.stopped) return { ok: true, fps };
61089
+ this.schedule(sessionId, st);
61090
+ return { ok: true, fps };
61091
+ }
61092
+ /** Stop the stream (idempotent). The RFB session is untouched. */
61093
+ stop(sessionId) {
61094
+ const st = this.sessions.get(sessionId);
61095
+ if (!st) return;
61096
+ st.stopped = true;
61097
+ if (st.timer) clearTimeout(st.timer);
61098
+ this.sessions.delete(sessionId);
61099
+ void import_node_fs3.promises.unlink(st.tmpFile).catch(() => {
61100
+ });
61101
+ this.hooks.log(`desktop ${sessionId}: media stream stopped`);
61102
+ }
61103
+ /** Session ended (kill/exit/ws death) → drop everything. */
61104
+ stopAll() {
61105
+ for (const id of [...this.sessions.keys()]) this.stop(id);
61106
+ }
61107
+ // --------------------------------------------------------------------------
61108
+ schedule(sessionId, st) {
61109
+ if (st.stopped) return;
61110
+ st.timer = setTimeout(() => {
61111
+ st.timer = null;
61112
+ void this.emit(sessionId, st).then(() => this.schedule(sessionId, st));
61113
+ }, st.intervalMs);
61114
+ }
61115
+ /** capture → read → chunk → send. Congested transport ⇒ skip this cycle
61116
+ * (the NEXT frame carries the freshest pixels — never queue stale ones). */
61117
+ async emit(sessionId, st) {
61118
+ if (st.busy || st.stopped) return;
61119
+ st.busy = true;
61120
+ try {
61121
+ if (this.hooks.congested(sessionId)) return;
61122
+ try {
61123
+ await this.capture(st.tmpFile, st.display);
61124
+ } catch {
61125
+ st.failures++;
61126
+ if (st.failures >= 3) {
61127
+ this.stop(sessionId);
61128
+ this.hooks.ended(sessionId, "\u91C7\u96C6\u8FDE\u7EED\u5931\u8D25\uFF08\u6743\u9650\u88AB\u6536\u56DE\u6216\u663E\u793A\u5DF2\u65AD\u5F00\uFF09\uFF0C\u5DF2\u56DE\u9000 RFB \u753B\u9762");
61129
+ }
61130
+ return;
61131
+ }
61132
+ st.failures = 0;
61133
+ const jpg = await import_node_fs3.promises.readFile(st.tmpFile);
61134
+ if (st.stopped || this.sessions.get(sessionId) !== st) return;
61135
+ const seq = st.seq++;
61136
+ const total = Math.ceil(jpg.byteLength / DESKTOP_MEDIA_CHUNK_BYTES) || 1;
61137
+ for (let i = 0; i < total; i++) {
61138
+ if (st.stopped) return;
61139
+ const slice = jpg.subarray(i * DESKTOP_MEDIA_CHUNK_BYTES, Math.min((i + 1) * DESKTOP_MEDIA_CHUNK_BYTES, jpg.byteLength));
61140
+ this.hooks.send(sessionId, frameChunk(seq, i, total, slice));
61141
+ }
61142
+ } finally {
61143
+ st.busy = false;
61144
+ }
61145
+ }
61146
+ };
61147
+
61003
61148
  // src/config.ts
61004
61149
  function resolveDesktopConfig(cfg) {
61005
61150
  return {
@@ -61018,9 +61163,9 @@ function resolveDesktopP2PConfig(cfg) {
61018
61163
 
61019
61164
  // src/gateway-api.ts
61020
61165
  var import_node_http = require("node:http");
61021
- var import_node_fs3 = require("node:fs");
61022
- var import_node_os4 = require("node:os");
61023
- var import_node_path4 = require("node:path");
61166
+ var import_node_fs4 = require("node:fs");
61167
+ var import_node_os5 = require("node:os");
61168
+ var import_node_path5 = require("node:path");
61024
61169
  var DEFAULT_API_PORT = 18790;
61025
61170
  function apiPortFromEnv() {
61026
61171
  return Number(process.env.CLI_LOCAL_API_PORT) || DEFAULT_API_PORT;
@@ -61029,7 +61174,7 @@ function readConfiguredPort() {
61029
61174
  if (process.env.CLI_LOCAL_API_PORT) return apiPortFromEnv();
61030
61175
  try {
61031
61176
  const cfg = JSON.parse(
61032
- (0, import_node_fs3.readFileSync)((0, import_node_path4.join)((0, import_node_os4.homedir)(), DEFAULT_CONFIG_DIR, "config.json"), "utf-8")
61177
+ (0, import_node_fs4.readFileSync)((0, import_node_path5.join)((0, import_node_os5.homedir)(), DEFAULT_CONFIG_DIR, "config.json"), "utf-8")
61033
61178
  );
61034
61179
  return Number(cfg.gateway?.apiPort) || DEFAULT_API_PORT;
61035
61180
  } catch {
@@ -61072,11 +61217,11 @@ function startControlApi(opts) {
61072
61217
  close: () => server.close()
61073
61218
  };
61074
61219
  }
61075
- async function apiGet(port, path, timeoutMs = 800) {
61220
+ async function apiGet(port, path2, timeoutMs = 800) {
61076
61221
  try {
61077
61222
  const ctrl = new AbortController();
61078
61223
  const timer2 = setTimeout(() => ctrl.abort(), timeoutMs);
61079
- const res = await fetch(`http://127.0.0.1:${port}${path}`, {
61224
+ const res = await fetch(`http://127.0.0.1:${port}${path2}`, {
61080
61225
  signal: ctrl.signal
61081
61226
  });
61082
61227
  clearTimeout(timer2);
@@ -61086,11 +61231,11 @@ async function apiGet(port, path, timeoutMs = 800) {
61086
61231
  return null;
61087
61232
  }
61088
61233
  }
61089
- async function apiPost(port, path, timeoutMs = 800) {
61234
+ async function apiPost(port, path2, timeoutMs = 800) {
61090
61235
  try {
61091
61236
  const ctrl = new AbortController();
61092
61237
  const timer2 = setTimeout(() => ctrl.abort(), timeoutMs);
61093
- const res = await fetch(`http://127.0.0.1:${port}${path}`, {
61238
+ const res = await fetch(`http://127.0.0.1:${port}${path2}`, {
61094
61239
  method: "POST",
61095
61240
  signal: ctrl.signal
61096
61241
  });
@@ -61103,11 +61248,11 @@ async function apiPost(port, path, timeoutMs = 800) {
61103
61248
 
61104
61249
  // src/setup-callback.ts
61105
61250
  var import_node_http2 = require("node:http");
61106
- var import_node_crypto = require("node:crypto");
61251
+ var import_node_crypto2 = require("node:crypto");
61107
61252
  var BODY_LIMIT = 64 * 1024;
61108
61253
  function startSetupCallback(timeoutMs = 3 * 6e4) {
61109
61254
  return new Promise((resolveStart, rejectStart) => {
61110
- const chan = (0, import_node_crypto.randomBytes)(8).toString("hex");
61255
+ const chan = (0, import_node_crypto2.randomBytes)(8).toString("hex");
61111
61256
  let timer2 = null;
61112
61257
  let settled = false;
61113
61258
  let server = null;
@@ -61201,21 +61346,21 @@ function startSetupCallback(timeoutMs = 3 * 6e4) {
61201
61346
  }
61202
61347
 
61203
61348
  // src/auth.ts
61204
- var import_node_child_process3 = require("node:child_process");
61205
- var import_node_crypto3 = require("node:crypto");
61349
+ var import_node_child_process4 = require("node:child_process");
61350
+ var import_node_crypto4 = require("node:crypto");
61206
61351
  var import_promises10 = require("node:fs/promises");
61207
- var import_node_os6 = require("node:os");
61208
- var import_node_path6 = require("node:path");
61352
+ var import_node_os7 = require("node:os");
61353
+ var import_node_path7 = require("node:path");
61209
61354
  var import_qrcode = __toESM(require_lib(), 1);
61210
61355
 
61211
61356
  // src/machine-id.ts
61212
- var import_node_child_process2 = require("node:child_process");
61213
- var import_node_crypto2 = require("node:crypto");
61357
+ var import_node_child_process3 = require("node:child_process");
61358
+ var import_node_crypto3 = require("node:crypto");
61214
61359
  var import_promises9 = require("node:fs/promises");
61215
- var import_node_os5 = require("node:os");
61216
- var import_node_path5 = require("node:path");
61217
- var import_node_util2 = require("node:util");
61218
- var execFileAsync = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
61360
+ var import_node_os6 = require("node:os");
61361
+ var import_node_path6 = require("node:path");
61362
+ var import_node_util3 = require("node:util");
61363
+ var execFileAsync = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
61219
61364
  var MACHINE_ID_DOMAIN = "cli-remote.machineid.v1";
61220
61365
  function normalizeHardwareId(raw) {
61221
61366
  return raw.trim().toLowerCase().replace(/\s+/g, " ");
@@ -61244,7 +61389,7 @@ function isValidHardwareId(raw) {
61244
61389
  return true;
61245
61390
  }
61246
61391
  function deriveMachineId(tag, raw) {
61247
- const h = (0, import_node_crypto2.createHash)("sha256").update(`${MACHINE_ID_DOMAIN}|${tag}|${normalizeHardwareId(raw)}`).digest("hex");
61392
+ const h = (0, import_node_crypto3.createHash)("sha256").update(`${MACHINE_ID_DOMAIN}|${tag}|${normalizeHardwareId(raw)}`).digest("hex");
61248
61393
  return "m_" + h.slice(0, 32);
61249
61394
  }
61250
61395
  async function ioregValue(exec, key) {
@@ -61260,9 +61405,9 @@ async function firstPhysicalMacMac(deps) {
61260
61405
  try {
61261
61406
  const names = (await deps.readDir("/sys/class/net")).sort();
61262
61407
  for (const name of names) {
61263
- const base = (0, import_node_path5.join)("/sys/class/net", name);
61264
- if (!await deps.statOrNull((0, import_node_path5.join)(base, "device"))) continue;
61265
- const mac = await deps.readFile((0, import_node_path5.join)(base, "address"));
61408
+ const base = (0, import_node_path6.join)("/sys/class/net", name);
61409
+ if (!await deps.statOrNull((0, import_node_path6.join)(base, "device"))) continue;
61410
+ const mac = await deps.readFile((0, import_node_path6.join)(base, "address"));
61266
61411
  return normalizeHardwareId(mac);
61267
61412
  }
61268
61413
  } catch {
@@ -61284,7 +61429,7 @@ async function winMachineGuid(exec) {
61284
61429
  }
61285
61430
  }
61286
61431
  async function resolveHardwareMachineId(deps = {}) {
61287
- const plat = deps.platform ?? (0, import_node_os5.platform)();
61432
+ const plat = deps.platform ?? (0, import_node_os6.platform)();
61288
61433
  const readFileDeps = deps.readFile ?? ((p) => (0, import_promises9.readFile)(p, "utf-8"));
61289
61434
  const execDeps = deps.exec ?? (async (cmd, args) => {
61290
61435
  const { stdout } = await execFileAsync(cmd, args, { timeout: 3e3 });
@@ -61338,7 +61483,7 @@ async function resolveHardwareMachineId(deps = {}) {
61338
61483
 
61339
61484
  // src/auth.ts
61340
61485
  function credentialsPath() {
61341
- return (0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
61486
+ return (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
61342
61487
  }
61343
61488
  async function loadCredentials() {
61344
61489
  try {
@@ -61350,11 +61495,11 @@ async function loadCredentials() {
61350
61495
  }
61351
61496
  }
61352
61497
  async function saveCredentials(creds) {
61353
- const path = credentialsPath();
61354
- await (0, import_promises10.mkdir)((0, import_node_path6.join)(path, ".."), { recursive: true });
61355
- await (0, import_promises10.writeFile)(path, JSON.stringify(creds, null, 2) + "\n", { mode: 384 });
61498
+ const path2 = credentialsPath();
61499
+ await (0, import_promises10.mkdir)((0, import_node_path7.join)(path2, ".."), { recursive: true });
61500
+ await (0, import_promises10.writeFile)(path2, JSON.stringify(creds, null, 2) + "\n", { mode: 384 });
61356
61501
  try {
61357
- await (0, import_promises10.chmod)(path, 384);
61502
+ await (0, import_promises10.chmod)(path2, 384);
61358
61503
  } catch {
61359
61504
  }
61360
61505
  }
@@ -61380,7 +61525,7 @@ function openBrowser(url) {
61380
61525
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
61381
61526
  const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
61382
61527
  try {
61383
- const child = (0, import_node_child_process3.spawn)(cmd, args, { stdio: "ignore", detached: true });
61528
+ const child = (0, import_node_child_process4.spawn)(cmd, args, { stdio: "ignore", detached: true });
61384
61529
  child.unref();
61385
61530
  } catch {
61386
61531
  }
@@ -61409,15 +61554,15 @@ async function loginAndFetchRegistrationKey(baseUrl, email, password) {
61409
61554
  return { registrationKey: data.registrationKey, user: data.user?.email ?? email };
61410
61555
  }
61411
61556
  async function mergeLocalConfig(patch) {
61412
- const dir = (0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR);
61413
- const path = (0, import_node_path6.join)(dir, CONFIG_FILE);
61557
+ const dir = (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR);
61558
+ const path2 = (0, import_node_path7.join)(dir, CONFIG_FILE);
61414
61559
  let existing = {};
61415
61560
  try {
61416
- existing = JSON.parse(await (0, import_promises10.readFile)(path, "utf-8"));
61561
+ existing = JSON.parse(await (0, import_promises10.readFile)(path2, "utf-8"));
61417
61562
  } catch {
61418
61563
  }
61419
61564
  await (0, import_promises10.mkdir)(dir, { recursive: true });
61420
- await (0, import_promises10.writeFile)(path, JSON.stringify({ ...existing, ...patch }, null, 2) + "\n");
61565
+ await (0, import_promises10.writeFile)(path2, JSON.stringify({ ...existing, ...patch }, null, 2) + "\n");
61421
61566
  }
61422
61567
  var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
61423
61568
  var AuthError = class extends Error {
@@ -61431,7 +61576,7 @@ async function deviceFlowAuthorize(baseUrl, registrationKey, deviceId) {
61431
61576
  const res = await postJson(`${baseUrl}/oauth/device_authorization`, {
61432
61577
  registrationKey,
61433
61578
  device_id: deviceId,
61434
- device_name: (0, import_node_os6.hostname)(),
61579
+ device_name: (0, import_node_os7.hostname)(),
61435
61580
  platform: process.platform
61436
61581
  });
61437
61582
  if (res.status !== 200) {
@@ -61521,9 +61666,9 @@ async function ensureFreshAccessToken(baseUrl, creds) {
61521
61666
  return refreshInFlight;
61522
61667
  }
61523
61668
  async function ensureMachineId() {
61524
- const path = (0, import_node_path6.join)((0, import_node_os6.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
61669
+ const path2 = (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
61525
61670
  try {
61526
- const cfg = JSON.parse(await (0, import_promises10.readFile)(path, "utf-8"));
61671
+ const cfg = JSON.parse(await (0, import_promises10.readFile)(path2, "utf-8"));
61527
61672
  if (typeof cfg.machineId === "string" && cfg.machineId) return cfg.machineId;
61528
61673
  } catch {
61529
61674
  }
@@ -61532,7 +61677,7 @@ async function ensureMachineId() {
61532
61677
  await mergeLocalConfig({ machineId: hw.id, machineIdSource: hw.source });
61533
61678
  return hw.id;
61534
61679
  }
61535
- const machineId = "m_" + (0, import_node_crypto3.randomBytes)(16).toString("hex");
61680
+ const machineId = "m_" + (0, import_node_crypto4.randomBytes)(16).toString("hex");
61536
61681
  await mergeLocalConfig({ machineId, machineIdSource: "random" });
61537
61682
  return machineId;
61538
61683
  }
@@ -61556,9 +61701,9 @@ function isPermanentAuthFailure(e) {
61556
61701
  return e instanceof AuthError && e.message.includes("invalid_grant");
61557
61702
  }
61558
61703
  async function loadConfig() {
61559
- const path = (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
61704
+ const path2 = (0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, CONFIG_FILE);
61560
61705
  try {
61561
- return JSON.parse((0, import_node_fs4.readFileSync)(path, "utf-8"));
61706
+ return JSON.parse((0, import_node_fs5.readFileSync)(path2, "utf-8"));
61562
61707
  } catch {
61563
61708
  return {};
61564
61709
  }
@@ -61588,10 +61733,10 @@ function detectCommands(desktopEnabled) {
61588
61733
  for (const [cmd, bin] of bins) {
61589
61734
  let ok = false;
61590
61735
  if (process.platform === "win32") {
61591
- ok = (0, import_node_child_process4.spawnSync)("where", [bin], { timeout: 5e3 }).status === 0;
61736
+ ok = (0, import_node_child_process5.spawnSync)("where", [bin], { timeout: 5e3 }).status === 0;
61592
61737
  } else {
61593
61738
  const shell = process.env.SHELL ?? "/bin/bash";
61594
- ok = (0, import_node_child_process4.spawnSync)(shell, ["-l", "-c", `command -v ${bin}`], {
61739
+ ok = (0, import_node_child_process5.spawnSync)(shell, ["-l", "-c", `command -v ${bin}`], {
61595
61740
  timeout: 5e3
61596
61741
  }).status === 0;
61597
61742
  }
@@ -61732,6 +61877,7 @@ async function startLocal(opts = {}) {
61732
61877
  logger2?.logExit(code);
61733
61878
  loggers.delete(sessionId);
61734
61879
  p2p.closeSession(sessionId);
61880
+ media.stop(sessionId);
61735
61881
  safeSend(encodeFrame({ t: "exit", sessionId, code }));
61736
61882
  },
61737
61883
  log: (msg) => console.log(`[local] ${msg}`)
@@ -61748,6 +61894,26 @@ async function startLocal(opts = {}) {
61748
61894
  resolveDesktopP2PConfig(config.desktop?.p2p),
61749
61895
  desktops
61750
61896
  );
61897
+ const media = new DesktopMediaManager({
61898
+ send: (sessionId, framed) => {
61899
+ const dc = p2p.mediaChannel(sessionId);
61900
+ if (dc) {
61901
+ dc.send(Buffer.from(framed.buffer, framed.byteOffset, framed.byteLength));
61902
+ return;
61903
+ }
61904
+ safeSend(encodeFrame({ t: "desktop-media-data", sessionId, data: framed }));
61905
+ },
61906
+ congested: (sessionId) => {
61907
+ const dc = p2p.mediaChannel(sessionId);
61908
+ if (dc) return dc.bufferedAmount > 4 * 1024 * 1024;
61909
+ return ws ? ws.bufferedAmount > 4 * 1024 * 1024 : false;
61910
+ },
61911
+ ended: (sessionId, reason) => {
61912
+ safeSend(encodeFrame({ t: "desktop-media-res", sessionId, ok: false, reason }));
61913
+ console.log(`[local] desktop ${sessionId} media: ${reason}`);
61914
+ },
61915
+ log: (msg) => console.log(`[local] ${msg}`)
61916
+ });
61751
61917
  const other = acquireSingleInstanceLock();
61752
61918
  if (other !== null) {
61753
61919
  console.error(`[local] \u53E6\u4E00\u4E2A cli-local \u6B63\u5728\u8FD0\u884C (pid ${other})\uFF0C\u62D2\u7EDD\u53CC\u5F00\u3002`);
@@ -61830,14 +61996,14 @@ async function startLocal(opts = {}) {
61830
61996
  console.error("[local] \uFF08\u672C\u8FDB\u7A0B\u4FDD\u6301\u8FD0\u884C\uFF0CPTY \u4F1A\u8BDD\u4FDD\u6D3B\uFF1B\u914D\u5BF9\u5B8C\u6210\u540E\u81EA\u52A8\u91CD\u8FDE\uFF09");
61831
61997
  if (pairingTimer) return;
61832
61998
  try {
61833
- pairingCredMtime = (0, import_node_fs4.statSync)(credentialsPathOf()).mtimeMs;
61999
+ pairingCredMtime = (0, import_node_fs5.statSync)(credentialsPathOf()).mtimeMs;
61834
62000
  } catch {
61835
62001
  pairingCredMtime = 0;
61836
62002
  }
61837
62003
  pairingTimer = setInterval(async () => {
61838
62004
  let mtime;
61839
62005
  try {
61840
- mtime = (0, import_node_fs4.statSync)(credentialsPathOf()).mtimeMs;
62006
+ mtime = (0, import_node_fs5.statSync)(credentialsPathOf()).mtimeMs;
61841
62007
  } catch {
61842
62008
  return;
61843
62009
  }
@@ -61924,6 +62090,7 @@ async function startLocal(opts = {}) {
61924
62090
  console.log("[local] disconnected; PTY sessions kept alive, reconnecting\u2026");
61925
62091
  desktops.killAll();
61926
62092
  p2p.closeAll();
62093
+ media.stopAll();
61927
62094
  if (phase !== "needs-pairing") setPhase("reconnecting");
61928
62095
  scheduleReconnect();
61929
62096
  });
@@ -61964,6 +62131,7 @@ async function startLocal(opts = {}) {
61964
62131
  transfers.abortAll();
61965
62132
  desktops.killAll();
61966
62133
  p2p.closeAll();
62134
+ media.stopAll();
61967
62135
  pty.killAll();
61968
62136
  for (const [, logger2] of loggers) logger2.logExit(-1);
61969
62137
  loggers.clear();
@@ -62008,6 +62176,12 @@ async function startLocal(opts = {}) {
62008
62176
  case "desktop-switch":
62009
62177
  void handleDesktopSwitch(frame);
62010
62178
  break;
62179
+ case "desktop-media-req":
62180
+ void handleDesktopMediaReq(frame);
62181
+ break;
62182
+ case "desktop-media-stop":
62183
+ media.stop(frame.sessionId);
62184
+ break;
62011
62185
  case "input":
62012
62186
  handleInput(frame);
62013
62187
  break;
@@ -62171,6 +62345,19 @@ async function startLocal(opts = {}) {
62171
62345
  );
62172
62346
  });
62173
62347
  }
62348
+ function handleDesktopMediaReq(frame) {
62349
+ const sessionId = frame.sessionId;
62350
+ if (!desktops.has(sessionId)) {
62351
+ safeSend(encodeFrame({ t: "desktop-media-res", sessionId, ok: false, reason: "\u6CA1\u6709\u6D3B\u52A8\u7684\u684C\u9762\u4F1A\u8BDD" }));
62352
+ return;
62353
+ }
62354
+ void media.start(sessionId, { display: frame.display, fps: frame.fps }).then((r) => {
62355
+ if (r.ok) safeSend(encodeFrame({ t: "desktop-media-res", sessionId, ok: true, fps: r.fps }));
62356
+ else safeSend(encodeFrame({ t: "desktop-media-res", sessionId, ok: false, reason: r.reason }));
62357
+ }).catch((e) => {
62358
+ safeSend(encodeFrame({ t: "desktop-media-res", sessionId, ok: false, reason: e.message }));
62359
+ });
62360
+ }
62174
62361
  async function handleDesktopSwitch(frame) {
62175
62362
  const logger2 = loggers.get(frame.sessionId);
62176
62363
  const reason = await desktops.switch(frame.sessionId, {
@@ -62311,10 +62498,10 @@ async function startLocal(opts = {}) {
62311
62498
  }
62312
62499
  }
62313
62500
  function credentialsPathOf() {
62314
- return (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, "credentials.json");
62501
+ return (0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "credentials.json");
62315
62502
  }
62316
62503
  function instanceLockPath() {
62317
- return (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, "instance.lock");
62504
+ return (0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "instance.lock");
62318
62505
  }
62319
62506
  function processAlive(pid) {
62320
62507
  try {
@@ -62325,17 +62512,17 @@ function processAlive(pid) {
62325
62512
  }
62326
62513
  }
62327
62514
  function acquireSingleInstanceLock() {
62328
- const path = instanceLockPath();
62515
+ const path2 = instanceLockPath();
62329
62516
  try {
62330
- const pid = Number((0, import_node_fs4.readFileSync)(path, "utf-8").trim());
62517
+ const pid = Number((0, import_node_fs5.readFileSync)(path2, "utf-8").trim());
62331
62518
  if (Number.isFinite(pid) && pid !== process.pid && processAlive(pid)) {
62332
62519
  return pid;
62333
62520
  }
62334
62521
  } catch {
62335
62522
  }
62336
62523
  try {
62337
- (0, import_node_fs4.mkdirSync)((0, import_node_path7.join)(path, ".."), { recursive: true });
62338
- (0, import_node_fs4.writeFileSync)(path, String(process.pid));
62524
+ (0, import_node_fs5.mkdirSync)((0, import_node_path8.join)(path2, ".."), { recursive: true });
62525
+ (0, import_node_fs5.writeFileSync)(path2, String(process.pid));
62339
62526
  } catch {
62340
62527
  }
62341
62528
  return null;
@@ -62364,21 +62551,21 @@ function toUint8(raw) {
62364
62551
  throw new Error("unexpected raw type");
62365
62552
  }
62366
62553
  function gatewayPidFile() {
62367
- return (0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid");
62554
+ return (0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid");
62368
62555
  }
62369
62556
  function writeGatewayPid() {
62370
- (0, import_node_fs4.mkdirSync)((0, import_node_path7.join)((0, import_node_os7.homedir)(), DEFAULT_CONFIG_DIR), { recursive: true });
62371
- (0, import_node_fs4.writeFileSync)(gatewayPidFile(), String(process.pid));
62557
+ (0, import_node_fs5.mkdirSync)((0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR), { recursive: true });
62558
+ (0, import_node_fs5.writeFileSync)(gatewayPidFile(), String(process.pid));
62372
62559
  }
62373
62560
  function removeGatewayPid() {
62374
62561
  try {
62375
- (0, import_node_fs4.rmSync)(gatewayPidFile());
62562
+ (0, import_node_fs5.rmSync)(gatewayPidFile());
62376
62563
  } catch {
62377
62564
  }
62378
62565
  }
62379
62566
  function gatewayPid() {
62380
62567
  try {
62381
- const pid = Number((0, import_node_fs4.readFileSync)(gatewayPidFile(), "utf-8").trim());
62568
+ const pid = Number((0, import_node_fs5.readFileSync)(gatewayPidFile(), "utf-8").trim());
62382
62569
  return Number.isInteger(pid) && pid > 0 ? pid : null;
62383
62570
  } catch {
62384
62571
  return null;
@@ -62412,15 +62599,15 @@ function resolveHere() {
62412
62599
  if (DEBUG) console.error("[debug] cannot resolve script path");
62413
62600
  return;
62414
62601
  }
62415
- const hereDir = (0, import_node_path8.dirname)(here);
62602
+ const hereDir = (0, import_node_path9.dirname)(here);
62416
62603
  const candidates = [
62417
- (0, import_node_path8.join)(hereDir, "..", "node_modules", "node-pty", "prebuilds"),
62418
- (0, import_node_path8.join)(hereDir, "..", "..", "node-pty", "prebuilds"),
62419
- (0, import_node_path8.join)(hereDir, "..", "..", "..", "node_modules", "node-pty", "prebuilds")
62604
+ (0, import_node_path9.join)(hereDir, "..", "node_modules", "node-pty", "prebuilds"),
62605
+ (0, import_node_path9.join)(hereDir, "..", "..", "node-pty", "prebuilds"),
62606
+ (0, import_node_path9.join)(hereDir, "..", "..", "..", "node_modules", "node-pty", "prebuilds")
62420
62607
  ];
62421
62608
  let prebuildsDir = null;
62422
62609
  for (const c of candidates) {
62423
- if ((0, import_node_fs5.existsSync)(c)) {
62610
+ if ((0, import_node_fs6.existsSync)(c)) {
62424
62611
  prebuildsDir = c;
62425
62612
  break;
62426
62613
  }
@@ -62430,11 +62617,11 @@ function resolveHere() {
62430
62617
  return;
62431
62618
  }
62432
62619
  let n = 0;
62433
- for (const sub of (0, import_node_fs5.readdirSync)(prebuildsDir)) {
62434
- const helper = (0, import_node_path8.join)(prebuildsDir, sub, "spawn-helper");
62435
- if ((0, import_node_fs5.existsSync)(helper)) {
62620
+ for (const sub of (0, import_node_fs6.readdirSync)(prebuildsDir)) {
62621
+ const helper = (0, import_node_path9.join)(prebuildsDir, sub, "spawn-helper");
62622
+ if ((0, import_node_fs6.existsSync)(helper)) {
62436
62623
  try {
62437
- (0, import_node_fs5.chmodSync)(helper, 493);
62624
+ (0, import_node_fs6.chmodSync)(helper, 493);
62438
62625
  n++;
62439
62626
  } catch {
62440
62627
  }
@@ -62445,10 +62632,10 @@ function resolveHere() {
62445
62632
  var argUrl = process.argv[2];
62446
62633
  var argMatch = argUrl && (argUrl.startsWith("ws://") || argUrl.startsWith("wss://"));
62447
62634
  function readVersion() {
62448
- if (true) return "0.5.0";
62635
+ if (true) return "0.5.1";
62449
62636
  try {
62450
62637
  const pkg = JSON.parse(
62451
- (0, import_node_fs5.readFileSync)(new URL("../package.json", import_meta.url), "utf-8")
62638
+ (0, import_node_fs6.readFileSync)(new URL("../package.json", import_meta.url), "utf-8")
62452
62639
  );
62453
62640
  return pkg.version ?? "unknown";
62454
62641
  } catch {
@@ -62505,20 +62692,20 @@ example:
62505
62692
  }
62506
62693
  var LAUNCHD_LABEL = "net.cli-remote.local";
62507
62694
  function launchdPlistPath() {
62508
- return (0, import_node_path8.join)((0, import_node_os8.homedir)(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
62695
+ return (0, import_node_path9.join)((0, import_node_os9.homedir)(), "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
62509
62696
  }
62510
62697
  function entryScript() {
62511
62698
  const a1 = process.argv[1];
62512
62699
  if (!a1 || a1.endsWith(".ts")) return null;
62513
62700
  try {
62514
- return (0, import_node_fs5.realpathSync)(a1);
62701
+ return (0, import_node_fs6.realpathSync)(a1);
62515
62702
  } catch {
62516
62703
  return a1;
62517
62704
  }
62518
62705
  }
62519
62706
  function run(cmd, args, okToFail = false) {
62520
62707
  try {
62521
- return (0, import_node_child_process5.execFileSync)(cmd, args, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
62708
+ return (0, import_node_child_process6.execFileSync)(cmd, args, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
62522
62709
  } catch (e) {
62523
62710
  if (okToFail) return null;
62524
62711
  throw e;
@@ -62529,7 +62716,7 @@ function launchdInstall(urlArg) {
62529
62716
  console.error(`[local] launchd \u5E38\u9A7B\u4EC5\u652F\u6301 macOS\uFF08\u5F53\u524D ${process.platform}\uFF09\uFF1BLinux \u8BF7\u7528 systemd --user \u81EA\u884C\u6258\u7BA1`);
62530
62717
  process.exit(1);
62531
62718
  }
62532
- const home = (0, import_node_os8.homedir)();
62719
+ const home = (0, import_node_os9.homedir)();
62533
62720
  const entry = entryScript();
62534
62721
  if (!entry) {
62535
62722
  console.error("[local] \u5F53\u524D\u4EE5\u6E90\u7801\uFF08tsx\uFF09\u6A21\u5F0F\u8FD0\u884C\uFF0C\u65E0\u6CD5\u5B89\u88C5\u5E38\u9A7B\u670D\u52A1\u3002");
@@ -62537,28 +62724,28 @@ function launchdInstall(urlArg) {
62537
62724
  process.exit(1);
62538
62725
  }
62539
62726
  if (urlArg) {
62540
- const cfgDir = (0, import_node_path8.join)(home, DEFAULT_CONFIG_DIR);
62541
- (0, import_node_fs5.mkdirSync)(cfgDir, { recursive: true });
62542
- const cfgPath = (0, import_node_path8.join)(cfgDir, "config.json");
62727
+ const cfgDir = (0, import_node_path9.join)(home, DEFAULT_CONFIG_DIR);
62728
+ (0, import_node_fs6.mkdirSync)(cfgDir, { recursive: true });
62729
+ const cfgPath = (0, import_node_path9.join)(cfgDir, "config.json");
62543
62730
  let cfg = {};
62544
62731
  try {
62545
- cfg = JSON.parse((0, import_node_fs5.readFileSync)(cfgPath, "utf-8"));
62732
+ cfg = JSON.parse((0, import_node_fs6.readFileSync)(cfgPath, "utf-8"));
62546
62733
  } catch {
62547
62734
  }
62548
62735
  cfg.relayUrl = urlArg;
62549
- (0, import_node_fs5.writeFileSync)(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
62736
+ (0, import_node_fs6.writeFileSync)(cfgPath, JSON.stringify(cfg, null, 2) + "\n");
62550
62737
  console.log(`[local] relayUrl \u5DF2\u5199\u5165 ${cfgPath}`);
62551
62738
  }
62552
- const credPath = (0, import_node_path8.join)(home, DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
62553
- if (!(0, import_node_fs5.existsSync)(credPath)) {
62739
+ const credPath = (0, import_node_path9.join)(home, DEFAULT_CONFIG_DIR, CREDENTIALS_FILE);
62740
+ if (!(0, import_node_fs6.existsSync)(credPath)) {
62554
62741
  console.error("[local] \u5C1A\u672A\u6388\u6743\uFF08\u627E\u4E0D\u5230 credentials.json\uFF09\u3002");
62555
62742
  console.error("[local] \u8BF7\u5148\u4EA4\u4E92\u5F0F\u8FD0\u884C\u4E00\u6B21 cli-local \u5B8C\u6210\u914D\u7F6E\u4E0E\u6388\u6743\uFF0C\u518D\u5B89\u88C5\u5E38\u9A7B\u670D\u52A1\u3002");
62556
62743
  process.exit(1);
62557
62744
  }
62558
62745
  const plist = launchdPlistPath();
62559
- const logDir = (0, import_node_path8.join)(home, DEFAULT_CONFIG_DIR, "logs");
62560
- (0, import_node_fs5.mkdirSync)((0, import_node_path8.dirname)(plist), { recursive: true });
62561
- (0, import_node_fs5.mkdirSync)(logDir, { recursive: true });
62746
+ const logDir = (0, import_node_path9.join)(home, DEFAULT_CONFIG_DIR, "logs");
62747
+ (0, import_node_fs6.mkdirSync)((0, import_node_path9.dirname)(plist), { recursive: true });
62748
+ (0, import_node_fs6.mkdirSync)(logDir, { recursive: true });
62562
62749
  const xml = `<?xml version="1.0" encoding="UTF-8"?>
62563
62750
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
62564
62751
  <plist version="1.0">
@@ -62572,12 +62759,12 @@ function launchdInstall(urlArg) {
62572
62759
  <key>RunAtLoad</key><true/>
62573
62760
  <key>KeepAlive</key><true/>
62574
62761
  <key>ThrottleInterval</key><integer>30</integer>
62575
- <key>StandardOutPath</key><string>${(0, import_node_path8.join)(logDir, "daemon.out.log")}</string>
62576
- <key>StandardErrorPath</key><string>${(0, import_node_path8.join)(logDir, "daemon.err.log")}</string>
62762
+ <key>StandardOutPath</key><string>${(0, import_node_path9.join)(logDir, "daemon.out.log")}</string>
62763
+ <key>StandardErrorPath</key><string>${(0, import_node_path9.join)(logDir, "daemon.err.log")}</string>
62577
62764
  </dict>
62578
62765
  </plist>
62579
62766
  `;
62580
- (0, import_node_fs5.writeFileSync)(plist, xml);
62767
+ (0, import_node_fs6.writeFileSync)(plist, xml);
62581
62768
  const uid = process.getuid?.();
62582
62769
  if (uid === void 0) {
62583
62770
  console.error("[local] \u65E0\u6CD5\u786E\u5B9A uid\uFF0Claunchd \u5B89\u88C5\u5931\u8D25");
@@ -62595,7 +62782,7 @@ function launchdInstall(urlArg) {
62595
62782
  }
62596
62783
  function launchdUninstall() {
62597
62784
  const plist = launchdPlistPath();
62598
- if (!(0, import_node_fs5.existsSync)(plist)) {
62785
+ if (!(0, import_node_fs6.existsSync)(plist)) {
62599
62786
  console.log("[local] \u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684\u5E38\u9A7B\u670D\u52A1\uFF08nothing to uninstall\uFF09");
62600
62787
  process.exit(0);
62601
62788
  }
@@ -62603,7 +62790,7 @@ function launchdUninstall() {
62603
62790
  const guiDomain = `gui/${uid ?? 0}`;
62604
62791
  run("launchctl", ["bootout", guiDomain, plist], true);
62605
62792
  run("launchctl", ["unload", "-w", plist], true);
62606
- (0, import_node_fs5.rmSync)(plist);
62793
+ (0, import_node_fs6.rmSync)(plist);
62607
62794
  console.log(`[local] launchd \u670D\u52A1\u5DF2\u505C\u6B62\u5E76\u5378\u8F7D\uFF1A${LAUNCHD_LABEL}`);
62608
62795
  }
62609
62796
  if (argUrl && !argMatch && argUrl === "install") {
@@ -62616,11 +62803,11 @@ if (argUrl && !argMatch && argUrl === "uninstall") {
62616
62803
  }
62617
62804
  if (argUrl === "pair") {
62618
62805
  void (async () => {
62619
- const home = (0, import_node_os8.homedir)();
62620
- const cfgPath = (0, import_node_path8.join)(home, DEFAULT_CONFIG_DIR, "config.json");
62806
+ const home = (0, import_node_os9.homedir)();
62807
+ const cfgPath = (0, import_node_path9.join)(home, DEFAULT_CONFIG_DIR, "config.json");
62621
62808
  let cfg = {};
62622
62809
  try {
62623
- cfg = JSON.parse((0, import_node_fs5.readFileSync)(cfgPath, "utf-8"));
62810
+ cfg = JSON.parse((0, import_node_fs6.readFileSync)(cfgPath, "utf-8"));
62624
62811
  } catch {
62625
62812
  }
62626
62813
  const url = process.argv[4] ?? process.env.RELAY_URL ?? cfg.relayUrl;
@@ -62655,29 +62842,29 @@ if (argUrl === "pair") {
62655
62842
  }
62656
62843
  if (argUrl === "gateway") {
62657
62844
  let gatewayLogFile = function() {
62658
- return (0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "logs", "gateway.log");
62845
+ return (0, import_node_path9.join)((0, import_node_os9.homedir)(), DEFAULT_CONFIG_DIR, "logs", "gateway.log");
62659
62846
  }, gatewayLogs = function() {
62660
62847
  const follow = rest.includes("-f") || rest.includes("--follow");
62661
62848
  const li = rest.findIndex((a) => a === "-n" || a === "--lines");
62662
62849
  const lines = li >= 0 ? Number(rest[li + 1]) || 50 : 50;
62663
62850
  const file = gatewayLogFile();
62664
- if (!(0, import_node_fs5.existsSync)(file)) {
62851
+ if (!(0, import_node_fs6.existsSync)(file)) {
62665
62852
  console.log(`[gateway] \u6682\u65E0\u65E5\u5FD7\uFF08${file} \u4E0D\u5B58\u5728\uFF09`);
62666
62853
  process.exit(0);
62667
62854
  }
62668
- const tail = (0, import_node_fs5.readFileSync)(file, "utf-8").trimEnd().split("\n").slice(-lines);
62855
+ const tail = (0, import_node_fs6.readFileSync)(file, "utf-8").trimEnd().split("\n").slice(-lines);
62669
62856
  console.log(tail.join("\n"));
62670
62857
  if (!follow) process.exit(0);
62671
- let size = (0, import_node_fs5.statSync)(file).size;
62858
+ let size = (0, import_node_fs6.statSync)(file).size;
62672
62859
  console.log("--- following (Ctrl+C \u9000\u51FA) ---");
62673
62860
  setInterval(() => {
62674
62861
  try {
62675
- const st = (0, import_node_fs5.statSync)(file);
62862
+ const st = (0, import_node_fs6.statSync)(file);
62676
62863
  if (st.size > size) {
62677
- const fd = (0, import_node_fs5.openSync)(file, "r");
62864
+ const fd = (0, import_node_fs6.openSync)(file, "r");
62678
62865
  const buf = Buffer.alloc(st.size - size);
62679
- (0, import_node_fs5.readSync)(fd, buf, 0, buf.length, size);
62680
- (0, import_node_fs5.closeSync)(fd);
62866
+ (0, import_node_fs6.readSync)(fd, buf, 0, buf.length, size);
62867
+ (0, import_node_fs6.closeSync)(fd);
62681
62868
  size = st.size;
62682
62869
  process.stdout.write(buf.toString("utf-8"));
62683
62870
  } else if (st.size < size) {
@@ -62699,11 +62886,11 @@ if (argUrl === "gateway") {
62699
62886
  console.log(`[gateway] already running (pid ${gatewayPid()})`);
62700
62887
  process.exit(0);
62701
62888
  }
62702
- const home = (0, import_node_os8.homedir)();
62889
+ const home = (0, import_node_os9.homedir)();
62703
62890
  const entry = entryScript();
62704
- const cfgDir = (0, import_node_path8.join)(home, DEFAULT_CONFIG_DIR);
62705
- const cfgPath = (0, import_node_path8.join)(cfgDir, "config.json");
62706
- const hasCfg = (0, import_node_fs5.existsSync)(cfgPath);
62891
+ const cfgDir = (0, import_node_path9.join)(home, DEFAULT_CONFIG_DIR);
62892
+ const cfgPath = (0, import_node_path9.join)(cfgDir, "config.json");
62893
+ const hasCfg = (0, import_node_fs6.existsSync)(cfgPath);
62707
62894
  if (!entry) {
62708
62895
  console.error("[gateway] \u6E90\u7801\uFF08tsx\uFF09\u6A21\u5F0F\u4E0D\u652F\u6301\u540E\u53F0\u8FD0\u884C\uFF1B\u8BF7\u7528 npm \u5B89\u88C5\u7248\uFF1Anpm i -g @cli-remote/local");
62709
62896
  process.exit(1);
@@ -62713,13 +62900,13 @@ if (argUrl === "gateway") {
62713
62900
  console.error("[gateway] \uFF08\u65E0\u51ED\u8BC1\u4E5F\u53EF\u4EE5\u542F\u52A8\uFF1Agateway \u4F1A\u8FDB\u5165 needs-pairing\uFF0C\u7B49 cli-local pair\uFF09");
62714
62901
  process.exit(1);
62715
62902
  }
62716
- (0, import_node_fs5.mkdirSync)((0, import_node_path8.dirname)(gatewayLogFile()), { recursive: true });
62717
- const out = (0, import_node_fs5.openSync)(gatewayLogFile(), "a");
62903
+ (0, import_node_fs6.mkdirSync)((0, import_node_path9.dirname)(gatewayLogFile()), { recursive: true });
62904
+ const out = (0, import_node_fs6.openSync)(gatewayLogFile(), "a");
62718
62905
  const env = {};
62719
62906
  for (const [k, v] of Object.entries(process.env)) if (v !== void 0) env[k] = v;
62720
62907
  const args = [entry, "gateway", "run"];
62721
62908
  if (hubArg) args.push("--hub", hubArg);
62722
- const child = (0, import_node_child_process5.spawn)(process.execPath, args, {
62909
+ const child = (0, import_node_child_process6.spawn)(process.execPath, args, {
62723
62910
  detached: true,
62724
62911
  stdio: ["ignore", out, out],
62725
62912
  env
@@ -62745,12 +62932,12 @@ if (argUrl === "gateway") {
62745
62932
  while (Date.now() - t02 < 5e3 && gatewayAlive()) {
62746
62933
  await new Promise((res) => setTimeout(res, 150));
62747
62934
  }
62748
- (0, import_node_fs5.rmSync)((0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62935
+ (0, import_node_fs6.rmSync)((0, import_node_path9.join)((0, import_node_os9.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62749
62936
  return;
62750
62937
  }
62751
62938
  const pid = gatewayPid();
62752
62939
  if (pid === null || !gatewayAlive()) {
62753
- (0, import_node_fs5.rmSync)((0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62940
+ (0, import_node_fs6.rmSync)((0, import_node_path9.join)((0, import_node_os9.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62754
62941
  return;
62755
62942
  }
62756
62943
  try {
@@ -62761,7 +62948,7 @@ if (argUrl === "gateway") {
62761
62948
  while (Date.now() - t0 < 5e3 && gatewayAlive()) {
62762
62949
  await new Promise((res) => setTimeout(res, 150));
62763
62950
  }
62764
- (0, import_node_fs5.rmSync)((0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62951
+ (0, import_node_fs6.rmSync)((0, import_node_path9.join)((0, import_node_os9.homedir)(), DEFAULT_CONFIG_DIR, "gateway.pid"), { force: true });
62765
62952
  }
62766
62953
  async function gatewayStop() {
62767
62954
  const pid = gatewayPid();
@@ -62802,7 +62989,7 @@ if (argUrl === "gateway") {
62802
62989
  const pid = gatewayPid();
62803
62990
  let hub = "(\u672A\u914D\u7F6E)";
62804
62991
  try {
62805
- const cfg = JSON.parse((0, import_node_fs5.readFileSync)((0, import_node_path8.join)((0, import_node_os8.homedir)(), DEFAULT_CONFIG_DIR, "config.json"), "utf-8"));
62992
+ const cfg = JSON.parse((0, import_node_fs6.readFileSync)((0, import_node_path9.join)((0, import_node_os9.homedir)(), DEFAULT_CONFIG_DIR, "config.json"), "utf-8"));
62806
62993
  hub = cfg.relayUrl ?? hub;
62807
62994
  } catch {
62808
62995
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cli-remote/local",
3
- "version": "0.5.0",
3
+ "version": "0.5.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": {