ds-harness-remote 0.4.25 → 0.4.27

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 (42) hide show
  1. package/README.md +6 -6
  2. package/dist/client-runtime.d.ts +11 -0
  3. package/dist/client-runtime.d.ts.map +1 -1
  4. package/dist/client-runtime.js +62 -0
  5. package/dist/client-runtime.js.map +1 -1
  6. package/dist/client.github.js +74 -107
  7. package/dist/client.js +74 -107
  8. package/dist/client.js.map +1 -1
  9. package/dist/codex/domain.d.ts.map +1 -1
  10. package/dist/codex/domain.js +22 -0
  11. package/dist/codex/domain.js.map +1 -1
  12. package/dist/config.d.ts +6 -0
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +4 -1
  15. package/dist/config.js.map +1 -1
  16. package/dist/control-runtime.d.ts.map +1 -1
  17. package/dist/control-runtime.js +16 -1
  18. package/dist/control-runtime.js.map +1 -1
  19. package/dist/harness-version.d.ts.map +1 -1
  20. package/dist/harness-version.js +16 -3
  21. package/dist/harness-version.js.map +1 -1
  22. package/dist/index.js +213 -81
  23. package/dist/index.js.map +4 -4
  24. package/dist/loopback-host.d.ts +2 -2
  25. package/dist/loopback-host.d.ts.map +1 -1
  26. package/dist/loopback-host.js +41 -16
  27. package/dist/loopback-host.js.map +1 -1
  28. package/dist/server-api.d.ts +2 -0
  29. package/dist/server-api.d.ts.map +1 -1
  30. package/dist/server-api.js +5 -0
  31. package/dist/server-api.js.map +1 -1
  32. package/dist/server-connection.d.ts.map +1 -1
  33. package/dist/server-connection.js +8 -0
  34. package/dist/server-connection.js.map +1 -1
  35. package/dist/service.d.ts +4 -1
  36. package/dist/service.d.ts.map +1 -1
  37. package/dist/service.js +19 -5
  38. package/dist/service.js.map +1 -1
  39. package/dist/version.d.ts +1 -1
  40. package/dist/version.js +1 -1
  41. package/dsh-plugin.json +1 -1
  42. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { randomBytes, randomUUID } from "node:crypto";
9
9
  import { createServer } from "node:http";
10
10
  import { WebSocketServer } from "ws";
11
11
 
12
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
12
+ // ../../node_modules/zod/v3/external.js
13
13
  var external_exports = {};
14
14
  __export(external_exports, {
15
15
  BRAND: () => BRAND,
@@ -121,7 +121,7 @@ __export(external_exports, {
121
121
  void: () => voidType
122
122
  });
123
123
 
124
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
124
+ // ../../node_modules/zod/v3/helpers/util.js
125
125
  var util;
126
126
  (function(util2) {
127
127
  util2.assertEqual = (_) => {
@@ -255,7 +255,7 @@ var getParsedType = (data2) => {
255
255
  }
256
256
  };
257
257
 
258
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
258
+ // ../../node_modules/zod/v3/ZodError.js
259
259
  var ZodIssueCode = util.arrayToEnum([
260
260
  "invalid_type",
261
261
  "invalid_literal",
@@ -373,7 +373,7 @@ ZodError.create = (issues) => {
373
373
  return error;
374
374
  };
375
375
 
376
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
376
+ // ../../node_modules/zod/v3/locales/en.js
377
377
  var errorMap = (issue, _ctx) => {
378
378
  let message;
379
379
  switch (issue.code) {
@@ -476,7 +476,7 @@ var errorMap = (issue, _ctx) => {
476
476
  };
477
477
  var en_default = errorMap;
478
478
 
479
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
479
+ // ../../node_modules/zod/v3/errors.js
480
480
  var overrideErrorMap = en_default;
481
481
  function setErrorMap(map) {
482
482
  overrideErrorMap = map;
@@ -485,7 +485,7 @@ function getErrorMap() {
485
485
  return overrideErrorMap;
486
486
  }
487
487
 
488
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
488
+ // ../../node_modules/zod/v3/helpers/parseUtil.js
489
489
  var makeIssue = (params) => {
490
490
  const { data: data2, path, errorMaps, issueData } = params;
491
491
  const fullPath = [...path, ...issueData.path || []];
@@ -595,14 +595,14 @@ var isDirty = (x) => x.status === "dirty";
595
595
  var isValid = (x) => x.status === "valid";
596
596
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
597
597
 
598
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
598
+ // ../../node_modules/zod/v3/helpers/errorUtil.js
599
599
  var errorUtil;
600
600
  (function(errorUtil2) {
601
601
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
602
602
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
603
603
  })(errorUtil || (errorUtil = {}));
604
604
 
605
- // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
605
+ // ../../node_modules/zod/v3/types.js
606
606
  var ParseInputLazyPath = class {
607
607
  constructor(parent, value, path, key) {
608
608
  this._cachedPath = [];
@@ -4646,22 +4646,22 @@ function headerPairs(headers) {
4646
4646
  return Object.entries(headers).flatMap(([name2, value]) => value === void 0 ? [] : (Array.isArray(value) ? value : [value]).map((item) => [name2, item]));
4647
4647
  }
4648
4648
  var LoopbackHost = class {
4649
- handles = /* @__PURE__ */ new Map();
4650
- ports;
4651
- closed = false;
4652
- timer;
4653
- constructor(ports) {
4654
- this.ports = [...ports];
4649
+ constructor(getPorts, onClose) {
4650
+ this.onClose = onClose;
4651
+ this.ports = [...getPorts()];
4655
4652
  this.timer = setInterval(() => {
4656
4653
  for (const [id4, handle] of this.handles) if (Date.now() - handle.touched > 6e4) this.close(id4);
4657
4654
  }, 1e4);
4658
4655
  this.timer.unref();
4659
4656
  }
4657
+ handles = /* @__PURE__ */ new Map();
4658
+ ports;
4659
+ closed = false;
4660
+ timer;
4660
4661
  setPorts(ports) {
4661
4662
  this.ports = [...ports];
4662
- }
4663
- hasPorts() {
4664
- return this.ports.length > 0;
4663
+ const allowed = new Set(ports);
4664
+ for (const [id4, handle] of this.handles) if (!allowed.has(handle.port)) this.close(id4);
4665
4665
  }
4666
4666
  async call(input2) {
4667
4667
  if (this.closed) throw new RpcError("TRANSPORT_CLOSED", "Preview connection closed.");
@@ -4678,10 +4678,13 @@ var LoopbackHost = class {
4678
4678
  );
4679
4679
  if (this.handles.has(value.id)) throw new RpcError("REQUEST_CONFLICT", "Preview handle is already in use.");
4680
4680
  if (this.handles.size >= LOOPBACK_MAX_CONNECTIONS) throw new RpcError("RATE_LIMITED", "Too many active preview requests.");
4681
+ let openedHandle;
4681
4682
  try {
4682
- return value.op === "http.open" ? await this.openHttp(value) : await this.openWs(value);
4683
+ const opening = value.op === "http.open" ? this.openHttp(value) : this.openWs(value);
4684
+ openedHandle = this.handles.get(value.id);
4685
+ return await opening;
4683
4686
  } catch {
4684
- this.close(value.id);
4687
+ this.close(value.id, openedHandle);
4685
4688
  throw new RpcError("LOOPBACK_UNAVAILABLE", "The allowed loopback service did not respond. Check that it is running on the Host.");
4686
4689
  }
4687
4690
  }
@@ -4712,6 +4715,7 @@ var LoopbackHost = class {
4712
4715
  response.once("close", ready);
4713
4716
  response.once("error", fail4);
4714
4717
  });
4718
+ if (this.handles.get(value.id) !== handle) throw new Error("closed");
4715
4719
  chunk = response.read(Math.min(response.readableLength || LOOPBACK_CHUNK_BYTES, LOOPBACK_CHUNK_BYTES));
4716
4720
  if (chunk === null && response.readableLength > 0) chunk = response.read(Math.min(response.readableLength, LOOPBACK_CHUNK_BYTES));
4717
4721
  }
@@ -4719,10 +4723,10 @@ var LoopbackHost = class {
4719
4723
  if (done && !response.complete) throw new Error("truncated");
4720
4724
  handle.total += chunk?.length ?? 0;
4721
4725
  if (handle.total > 64 * 1024 * 1024) throw new Error("size");
4722
- if (done) this.close(value.id);
4726
+ if (done) this.close(value.id, handle);
4723
4727
  return { data: chunk?.toString("base64") ?? "", done };
4724
4728
  } catch {
4725
- this.close(value.id);
4729
+ this.close(value.id, handle);
4726
4730
  throw new RpcError("LOOPBACK_READ_FAILED", "Preview response ended or exceeded its limit; reload to retry.");
4727
4731
  } finally {
4728
4732
  handle.reading = false;
@@ -4762,7 +4766,7 @@ var LoopbackHost = class {
4762
4766
  }
4763
4767
  handle.bytes -= bytes;
4764
4768
  const closed = handle.closed && handle.messages.length === 0;
4765
- if (closed) this.close(value.id);
4769
+ if (closed) this.close(value.id, handle);
4766
4770
  return { messages, closed };
4767
4771
  } finally {
4768
4772
  handle.reading = false;
@@ -4772,12 +4776,15 @@ var LoopbackHost = class {
4772
4776
  throw new RpcError("INVALID_MESSAGE", "Preview handle kind does not match the operation.");
4773
4777
  }
4774
4778
  closeAll() {
4779
+ if (this.closed) return;
4775
4780
  this.closed = true;
4776
4781
  clearInterval(this.timer);
4777
4782
  for (const id4 of this.handles.keys()) this.close(id4);
4783
+ this.onClose?.();
4778
4784
  }
4779
- close(id4) {
4785
+ close(id4, expected) {
4780
4786
  const handle = this.handles.get(id4);
4787
+ if (expected !== void 0 && handle !== expected) return;
4781
4788
  this.handles.delete(id4);
4782
4789
  if (handle?.kind === "http") {
4783
4790
  handle.response?.destroy();
@@ -4785,6 +4792,8 @@ var LoopbackHost = class {
4785
4792
  }
4786
4793
  if (handle?.kind === "ws") {
4787
4794
  handle.closed = true;
4795
+ handle.messages = [];
4796
+ handle.bytes = 0;
4788
4797
  handle.wake?.();
4789
4798
  handle.socket.terminate();
4790
4799
  }
@@ -4794,6 +4803,7 @@ var LoopbackHost = class {
4794
4803
  if ((body?.length ?? 0) > LOOPBACK_MAX_BODY_BYTES) throw new Error("body limit");
4795
4804
  return new Promise((resolve4, reject) => {
4796
4805
  const headers = Object.fromEntries(cleanHeaders(value.headers));
4806
+ let handle;
4797
4807
  const request = httpRequest({
4798
4808
  hostname: "127.0.0.1",
4799
4809
  port: value.port,
@@ -4803,8 +4813,7 @@ var LoopbackHost = class {
4803
4813
  agent: false,
4804
4814
  maxHeaderSize: 32 * 1024
4805
4815
  }, (response) => {
4806
- const handle = this.handles.get(value.id);
4807
- if (handle?.kind !== "http") {
4816
+ if (this.handles.get(value.id) !== handle) {
4808
4817
  response.destroy();
4809
4818
  return;
4810
4819
  }
@@ -4821,7 +4830,8 @@ var LoopbackHost = class {
4821
4830
  clearTimeout(timer);
4822
4831
  reject(new Error("upstream"));
4823
4832
  });
4824
- this.handles.set(value.id, { kind: "http", request, reading: false, total: 0, touched: Date.now() });
4833
+ handle = { kind: "http", port: value.port, request, reading: false, total: 0, touched: Date.now() };
4834
+ this.handles.set(value.id, handle);
4825
4835
  request.end(body);
4826
4836
  });
4827
4837
  }
@@ -4834,13 +4844,14 @@ var LoopbackHost = class {
4834
4844
  maxPayload: LOOPBACK_MAX_WS_BYTES,
4835
4845
  perMessageDeflate: false
4836
4846
  });
4837
- const handle = { kind: "ws", socket, messages: [], bytes: 0, reading: false, closed: false, touched: Date.now() };
4847
+ const handle = { kind: "ws", port: value.port, socket, messages: [], bytes: 0, reading: false, closed: false, touched: Date.now() };
4838
4848
  this.handles.set(value.id, handle);
4839
4849
  socket.once("open", () => resolve4({ protocol: socket.protocol }));
4840
4850
  socket.on("message", (data2, binary) => {
4851
+ if (handle.closed) return;
4841
4852
  const message = { data: Buffer.from(data2).toString("base64"), binary };
4842
4853
  if (handle.bytes + message.data.length > 1024 * 1024 || handle.messages.length >= 256) {
4843
- this.close(value.id);
4854
+ this.close(value.id, handle);
4844
4855
  return;
4845
4856
  }
4846
4857
  handle.messages.push(message);
@@ -6950,6 +6961,9 @@ var AdaptiveTransport = class extends BaseTransport {
6950
6961
  negotiatedCapabilities = ["transport.relay"];
6951
6962
  controlFrameLimits = {};
6952
6963
  connectedAt;
6964
+ heartbeatIntervalMs;
6965
+ lastControlReceivedAt;
6966
+ lastControlSentAt;
6953
6967
  lastRtcDiagnostics;
6954
6968
  constructor(url, options) {
6955
6969
  super();
@@ -7026,6 +7040,9 @@ var AdaptiveTransport = class extends BaseTransport {
7026
7040
  return {
7027
7041
  ...this.connectionId === void 0 ? {} : { connectionId: this.connectionId },
7028
7042
  ...this.connectedAt === void 0 ? {} : { connectedAt: this.connectedAt },
7043
+ ...this.heartbeatIntervalMs === void 0 ? {} : { heartbeatIntervalMs: this.heartbeatIntervalMs },
7044
+ ...this.lastControlReceivedAt === void 0 ? {} : { lastControlReceivedAt: this.lastControlReceivedAt },
7045
+ ...this.lastControlSentAt === void 0 ? {} : { lastControlSentAt: this.lastControlSentAt },
7029
7046
  controlChannelUrl: this.url,
7030
7047
  controlChannelState: socketState(this.socket?.readyState),
7031
7048
  preferredTransports: this.options.forceRelay === true ? ["relay"] : [...this.options.preferredTransports ?? DEFAULT_PREFERRED_TRANSPORTS],
@@ -7074,10 +7091,12 @@ var AdaptiveTransport = class extends BaseTransport {
7074
7091
  if (typeof raw !== "string")
7075
7092
  throw new Error("Adaptive control frames must be text JSON");
7076
7093
  const frame = decodeControlFrame(raw, this.controlFrameLimits);
7094
+ this.lastControlReceivedAt = Date.now();
7077
7095
  if (frame.type === "hello.ack") {
7078
7096
  const payload = frame.payload;
7079
7097
  if (payload.protocol !== PROTOCOL_VERSION)
7080
7098
  throw new Error("Server selected an unsupported protocol version");
7099
+ this.heartbeatIntervalMs = payload.heartbeatIntervalMs;
7081
7100
  const offered = this.options.capabilities ?? DEFAULT_CAPABILITIES;
7082
7101
  this.negotiatedCapabilities = acceptNegotiatedCapabilities(offered, payload.capabilities);
7083
7102
  this.controlFrameLimits = {
@@ -7297,6 +7316,7 @@ var AdaptiveTransport = class extends BaseTransport {
7297
7316
  if (this.socket?.readyState !== WebSocket.OPEN)
7298
7317
  throw new Error("adaptive control socket is not open");
7299
7318
  this.socket.send(encodeControlFrame(createControlFrame(type, payload), this.controlFrameLimits));
7319
+ this.lastControlSentAt = Date.now();
7300
7320
  }
7301
7321
  finishConnection() {
7302
7322
  this.clearHandshake();
@@ -7466,11 +7486,11 @@ var ApiProxySwitch = class {
7466
7486
  }
7467
7487
  };
7468
7488
 
7469
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/cryptoNode.js
7489
+ // ../crypto/node_modules/@noble/ciphers/esm/cryptoNode.js
7470
7490
  import * as nc from "node:crypto";
7471
7491
  var crypto = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
7472
7492
 
7473
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/webcrypto.js
7493
+ // ../crypto/node_modules/@noble/ciphers/esm/webcrypto.js
7474
7494
  function randomBytes2(bytesLength = 32) {
7475
7495
  if (crypto && typeof crypto.getRandomValues === "function") {
7476
7496
  return crypto.getRandomValues(new Uint8Array(bytesLength));
@@ -7481,11 +7501,11 @@ function randomBytes2(bytesLength = 32) {
7481
7501
  throw new Error("crypto.getRandomValues must be defined");
7482
7502
  }
7483
7503
 
7484
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/cryptoNode.js
7504
+ // ../../node_modules/@noble/hashes/esm/cryptoNode.js
7485
7505
  import * as nc2 from "node:crypto";
7486
7506
  var crypto2 = nc2 && typeof nc2 === "object" && "webcrypto" in nc2 ? nc2.webcrypto : nc2 && typeof nc2 === "object" && "randomBytes" in nc2 ? nc2 : void 0;
7487
7507
 
7488
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js
7508
+ // ../../node_modules/@noble/hashes/esm/utils.js
7489
7509
  function isBytes(a) {
7490
7510
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
7491
7511
  }
@@ -7612,7 +7632,7 @@ function randomBytes3(bytesLength = 32) {
7612
7632
  throw new Error("crypto.getRandomValues must be defined");
7613
7633
  }
7614
7634
 
7615
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js
7635
+ // ../../node_modules/@noble/hashes/esm/_md.js
7616
7636
  function setBigUint64(view, byteOffset, value, isLE3) {
7617
7637
  if (typeof view.setBigUint64 === "function")
7618
7638
  return view.setBigUint64(byteOffset, value, isLE3);
@@ -7734,7 +7754,7 @@ var SHA512_IV = /* @__PURE__ */ Uint32Array.from([
7734
7754
  327033209
7735
7755
  ]);
7736
7756
 
7737
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_u64.js
7757
+ // ../../node_modules/@noble/hashes/esm/_u64.js
7738
7758
  var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
7739
7759
  var _32n = /* @__PURE__ */ BigInt(32);
7740
7760
  function fromBig(n, le = false) {
@@ -7769,7 +7789,7 @@ var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0
7769
7789
  var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
7770
7790
  var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
7771
7791
 
7772
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js
7792
+ // ../../node_modules/@noble/hashes/esm/sha2.js
7773
7793
  var K512 = /* @__PURE__ */ (() => split([
7774
7794
  "0x428a2f98d728ae22",
7775
7795
  "0x7137449123ef65cd",
@@ -7969,7 +7989,7 @@ var SHA512 = class extends HashMD {
7969
7989
  };
7970
7990
  var sha512 = /* @__PURE__ */ createHasher(() => new SHA512());
7971
7991
 
7972
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/utils.js
7992
+ // ../../node_modules/@noble/curves/esm/utils.js
7973
7993
  var _0n = /* @__PURE__ */ BigInt(0);
7974
7994
  var _1n = /* @__PURE__ */ BigInt(1);
7975
7995
  function _abool2(value, title = "") {
@@ -8082,7 +8102,7 @@ function memoized(fn) {
8082
8102
  };
8083
8103
  }
8084
8104
 
8085
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/modular.js
8105
+ // ../../node_modules/@noble/curves/esm/abstract/modular.js
8086
8106
  var _0n2 = BigInt(0);
8087
8107
  var _1n2 = BigInt(1);
8088
8108
  var _2n = /* @__PURE__ */ BigInt(2);
@@ -8408,7 +8428,7 @@ function Field(ORDER, bitLenOrOpts, isLE3 = false, opts = {}) {
8408
8428
  return Object.freeze(f);
8409
8429
  }
8410
8430
 
8411
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/curve.js
8431
+ // ../../node_modules/@noble/curves/esm/abstract/curve.js
8412
8432
  var _0n3 = BigInt(0);
8413
8433
  var _1n3 = BigInt(1);
8414
8434
  function negateCt(condition, item) {
@@ -8671,7 +8691,7 @@ function _createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
8671
8691
  return { CURVE, Fp: Fp2, Fn: Fn2 };
8672
8692
  }
8673
8693
 
8674
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/edwards.js
8694
+ // ../../node_modules/@noble/curves/esm/abstract/edwards.js
8675
8695
  var _0n4 = BigInt(0);
8676
8696
  var _1n4 = BigInt(1);
8677
8697
  var _2n2 = BigInt(2);
@@ -9222,7 +9242,7 @@ function twistedEdwards(c) {
9222
9242
  return _eddsa_new_output_to_legacy(c, EDDSA);
9223
9243
  }
9224
9244
 
9225
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/montgomery.js
9245
+ // ../../node_modules/@noble/curves/esm/abstract/montgomery.js
9226
9246
  var _0n5 = BigInt(0);
9227
9247
  var _1n5 = BigInt(1);
9228
9248
  var _2n3 = BigInt(2);
@@ -9342,7 +9362,7 @@ function montgomery(curveDef) {
9342
9362
  };
9343
9363
  }
9344
9364
 
9345
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/ed25519.js
9365
+ // ../../node_modules/@noble/curves/esm/ed25519.js
9346
9366
  var _0n6 = /* @__PURE__ */ BigInt(0);
9347
9367
  var _1n6 = BigInt(1);
9348
9368
  var _2n4 = BigInt(2);
@@ -9577,7 +9597,7 @@ _RistrettoPoint.ZERO = /* @__PURE__ */ (() => new _RistrettoPoint(ed25519.Point.
9577
9597
  _RistrettoPoint.Fp = /* @__PURE__ */ (() => Fp)();
9578
9598
  _RistrettoPoint.Fn = /* @__PURE__ */ (() => Fn)();
9579
9599
 
9580
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/constants.js
9600
+ // ../../node_modules/@lukeburns/clatterjs/dist/constants.js
9581
9601
  var MAX_KEY_LEN = 32;
9582
9602
  var MAX_TAG_LEN = 16;
9583
9603
  var MAX_MESSAGE_LEN = 65535;
@@ -9587,7 +9607,7 @@ var MAX_TOKENS_PER_HS_MESSAGE = 8;
9587
9607
  var MAX_HS_MESSAGES_PER_ROLE = 8;
9588
9608
  var HYBRID_DUAL_LAYER = new TextEncoder().encode("clatter.hybrid_dual_layer.outer");
9589
9609
 
9590
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/errors.js
9610
+ // ../../node_modules/@lukeburns/clatterjs/dist/errors.js
9591
9611
  var CipherError = class extends Error {
9592
9612
  code;
9593
9613
  constructor(code, message) {
@@ -9623,7 +9643,7 @@ var TransportError = class extends Error {
9623
9643
  }
9624
9644
  };
9625
9645
 
9626
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/handshakePattern.js
9646
+ // ../../node_modules/@lukeburns/clatterjs/dist/handshakePattern.js
9627
9647
  function checkMsgLens(initiator, responder) {
9628
9648
  for (const g of initiator) {
9629
9649
  if (g.length > MAX_TOKENS_PER_HS_MESSAGE) {
@@ -9792,7 +9812,7 @@ var HandshakePattern = class _HandshakePattern {
9792
9812
  }
9793
9813
  };
9794
9814
 
9795
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/cipherState.js
9815
+ // ../../node_modules/@lukeburns/clatterjs/dist/cipherState.js
9796
9816
  var U64_MAX = 0xfffffffffffffffn;
9797
9817
  var CipherState = class {
9798
9818
  C;
@@ -9864,7 +9884,7 @@ var CipherStates = class {
9864
9884
  }
9865
9885
  };
9866
9886
 
9867
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/symmetricState.js
9887
+ // ../../node_modules/@lukeburns/clatterjs/dist/symmetricState.js
9868
9888
  function deriveCipherKey(temp, C) {
9869
9889
  return temp.slice(0, C.keyLen);
9870
9890
  }
@@ -9951,7 +9971,7 @@ function concat(a, b) {
9951
9971
  return o;
9952
9972
  }
9953
9973
 
9954
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/transportState.js
9974
+ // ../../node_modules/@lukeburns/clatterjs/dist/transportState.js
9955
9975
  function mapCipher(e) {
9956
9976
  if (e instanceof TransportError)
9957
9977
  return e;
@@ -10113,7 +10133,7 @@ var TransportState = class {
10113
10133
  }
10114
10134
  };
10115
10135
 
10116
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/_u64.js
10136
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/_u64.js
10117
10137
  var U32_MASK642 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))();
10118
10138
  var _32n2 = /* @__PURE__ */ BigInt(32);
10119
10139
  function fromBig2(n, le = false) {
@@ -10158,7 +10178,7 @@ var add4H2 = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) |
10158
10178
  var add5L2 = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
10159
10179
  var add5H2 = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
10160
10180
 
10161
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/utils.js
10181
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/utils.js
10162
10182
  function isBytes2(a) {
10163
10183
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
10164
10184
  }
@@ -10333,7 +10353,7 @@ var oidNist = (suffix) => ({
10333
10353
  oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
10334
10354
  });
10335
10355
 
10336
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/_md.js
10356
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/_md.js
10337
10357
  function Chi2(a, b, c) {
10338
10358
  return a & b ^ ~a & c;
10339
10359
  }
@@ -10464,7 +10484,7 @@ var SHA512_IV2 = /* @__PURE__ */ Uint32Array.from([
10464
10484
  327033209
10465
10485
  ]);
10466
10486
 
10467
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/sha2.js
10487
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/sha2.js
10468
10488
  var SHA256_K = /* @__PURE__ */ Uint32Array.from([
10469
10489
  1116352408,
10470
10490
  1899447441,
@@ -10861,7 +10881,7 @@ var sha5122 = /* @__PURE__ */ createHasher2(
10861
10881
  /* @__PURE__ */ oidNist(3)
10862
10882
  );
10863
10883
 
10864
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/utils.js
10884
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/utils.js
10865
10885
  function aarray(item, title, inner = () => {
10866
10886
  }) {
10867
10887
  if (!Array.isArray(item))
@@ -10980,7 +11000,7 @@ function validateObject2(object, fields = {}, optFields = {}, title = "object")
10980
11000
  iter(optFields, true);
10981
11001
  }
10982
11002
 
10983
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/abstract/modular.js
11003
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/abstract/modular.js
10984
11004
  var _0n8 = /* @__PURE__ */ BigInt(0);
10985
11005
  var _1n8 = /* @__PURE__ */ BigInt(1);
10986
11006
  var _2n5 = /* @__PURE__ */ BigInt(2);
@@ -11409,7 +11429,7 @@ function Field2(ORDER, opts = {}) {
11409
11429
  return new _Field(ORDER, opts);
11410
11430
  }
11411
11431
 
11412
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/abstract/curve.js
11432
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/abstract/curve.js
11413
11433
  var _0n9 = /* @__PURE__ */ BigInt(0);
11414
11434
  var _1n9 = /* @__PURE__ */ BigInt(1);
11415
11435
  var _4n3 = /* @__PURE__ */ BigInt(4);
@@ -11796,7 +11816,7 @@ function createKeygen(randomSecretKey, getPublicKey) {
11796
11816
  };
11797
11817
  }
11798
11818
 
11799
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/abstract/edwards.js
11819
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/abstract/edwards.js
11800
11820
  var _0n10 = /* @__PURE__ */ BigInt(0);
11801
11821
  var _1n10 = /* @__PURE__ */ BigInt(1);
11802
11822
  var _2n6 = /* @__PURE__ */ BigInt(2);
@@ -12090,7 +12110,7 @@ function edwards2(params, extraOpts = {}) {
12090
12110
  return Point;
12091
12111
  }
12092
12112
 
12093
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/abstract/montgomery.js
12113
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/abstract/montgomery.js
12094
12114
  var _0n11 = /* @__PURE__ */ BigInt(0);
12095
12115
  var _1n11 = /* @__PURE__ */ BigInt(1);
12096
12116
  var _2n7 = /* @__PURE__ */ BigInt(2);
@@ -12237,7 +12257,7 @@ function montgomery2(curveDef) {
12237
12257
  });
12238
12258
  }
12239
12259
 
12240
- // ../../node_modules/.pnpm/@noble+curves@2.3.0/node_modules/@noble/curves/ed25519.js
12260
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/curves/ed25519.js
12241
12261
  var _0n12 = /* @__PURE__ */ BigInt(0);
12242
12262
  var _1n12 = /* @__PURE__ */ BigInt(1);
12243
12263
  var _2n8 = /* @__PURE__ */ BigInt(2);
@@ -12323,7 +12343,7 @@ var x255192 = /* @__PURE__ */ (() => {
12323
12343
  });
12324
12344
  })();
12325
12345
 
12326
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/dhX25519.js
12346
+ // ../../node_modules/@lukeburns/clatterjs/dist/dhX25519.js
12327
12347
  var PK = 32;
12328
12348
  var X25519_NAME = "25519";
12329
12349
  function x25519Keygen(rng) {
@@ -12337,12 +12357,12 @@ function dhPubKeyLen() {
12337
12357
  return PK;
12338
12358
  }
12339
12359
 
12340
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/protocolNames.js
12360
+ // ../../node_modules/@lukeburns/clatterjs/dist/protocolNames.js
12341
12361
  function nqProtocolName(patternName, cipher, hash) {
12342
12362
  return `Noise_${patternName}_${X25519_NAME}_${cipher.name}_${hash.name}`;
12343
12363
  }
12344
12364
 
12345
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/nqHandshake.js
12365
+ // ../../node_modules/@lukeburns/clatterjs/dist/nqHandshake.js
12346
12366
  var PK2 = () => dhPubKeyLen();
12347
12367
  var NqHandshake = class {
12348
12368
  pattern;
@@ -12715,7 +12735,7 @@ function raiseInv() {
12715
12735
  throw new HandshakeError("InvalidState");
12716
12736
  }
12717
12737
 
12718
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/_blake.js
12738
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/_blake.js
12719
12739
  var BSIGMA = /* @__PURE__ */ Uint8Array.from([
12720
12740
  0,
12721
12741
  1,
@@ -12990,7 +13010,7 @@ function G2s(a, b, c, d, x) {
12990
13010
  return { a, b, c, d };
12991
13011
  }
12992
13012
 
12993
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/blake2.js
13013
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/blake2.js
12994
13014
  var B2B_IV = /* @__PURE__ */ Uint32Array.from([
12995
13015
  4089235720,
12996
13016
  1779033703,
@@ -13423,7 +13443,7 @@ var _BLAKE2s = class extends _BLAKE2 {
13423
13443
  };
13424
13444
  var blake2s = /* @__PURE__ */ createHasher2((opts) => new _BLAKE2s(opts));
13425
13445
 
13426
- // ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/hmac.js
13446
+ // ../../node_modules/@lukeburns/clatterjs/node_modules/@noble/hashes/hmac.js
13427
13447
  var _HMAC = class {
13428
13448
  oHash;
13429
13449
  iHash;
@@ -13500,7 +13520,7 @@ var hmac = /* @__PURE__ */ (() => {
13500
13520
  return hmac_;
13501
13521
  })();
13502
13522
 
13503
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/crypto/hash.js
13523
+ // ../../node_modules/@lukeburns/clatterjs/dist/crypto/hash.js
13504
13524
  function makeHash(name2, hash, hashLen, blockLen) {
13505
13525
  const doHash = (data2) => hash.create().update(data2).digest();
13506
13526
  const hmac1 = (key, data2) => hmac(hash, key, data2);
@@ -13535,7 +13555,7 @@ var sha512H = makeHash("SHA512", sha5122, 64, 128);
13535
13555
  var blake2bH = makeHash("BLAKE2b", blake2b, 64, 128);
13536
13556
  var blake2sH = makeHash("BLAKE2s", blake2s, 32, 64);
13537
13557
 
13538
- // ../../node_modules/.pnpm/@noble+ciphers@2.3.0/node_modules/@noble/ciphers/utils.js
13558
+ // ../../node_modules/@noble/ciphers/utils.js
13539
13559
  function isBytes4(a) {
13540
13560
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
13541
13561
  }
@@ -13702,7 +13722,7 @@ function copyBytes4(bytes) {
13702
13722
  return Uint8Array.from(abytes4(bytes));
13703
13723
  }
13704
13724
 
13705
- // ../../node_modules/.pnpm/@noble+ciphers@2.3.0/node_modules/@noble/ciphers/_arx.js
13725
+ // ../../node_modules/@noble/ciphers/_arx.js
13706
13726
  var encodeStr = (str) => Uint8Array.from(str.split(""), (c) => c.charCodeAt(0));
13707
13727
  var sigma16_32 = /* @__PURE__ */ (() => swap32IfBE2(u322(encodeStr("expand 16-byte k"))))();
13708
13728
  var sigma32_32 = /* @__PURE__ */ (() => swap32IfBE2(u322(encodeStr("expand 32-byte k"))))();
@@ -13829,7 +13849,7 @@ function createCipher(core, opts) {
13829
13849
  };
13830
13850
  }
13831
13851
 
13832
- // ../../node_modules/.pnpm/@noble+ciphers@2.3.0/node_modules/@noble/ciphers/_poly1305.js
13852
+ // ../../node_modules/@noble/ciphers/_poly1305.js
13833
13853
  function u8to16(a, i) {
13834
13854
  return a[i++] & 255 | (a[i++] & 255) << 8;
13835
13855
  }
@@ -14080,7 +14100,7 @@ var Poly1305 = class {
14080
14100
  };
14081
14101
  var poly1305 = /* @__PURE__ */ wrapMacConstructor(32, (key) => new Poly1305(key));
14082
14102
 
14083
- // ../../node_modules/.pnpm/@noble+ciphers@2.3.0/node_modules/@noble/ciphers/chacha.js
14103
+ // ../../node_modules/@noble/ciphers/chacha.js
14084
14104
  function chachaCore(s2, k, n, out, cnt, rounds = 20) {
14085
14105
  let y00 = s2[0], y01 = s2[1], y02 = s2[2], y03 = s2[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2];
14086
14106
  let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
@@ -14230,7 +14250,7 @@ var chacha20poly1305 = /* @__PURE__ */ wrapCipher(
14230
14250
  /* @__PURE__ */ _poly1305_aead(chacha20)
14231
14251
  );
14232
14252
 
14233
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/crypto/cipher.js
14253
+ // ../../node_modules/@lukeburns/clatterjs/dist/crypto/cipher.js
14234
14254
  var U64_MAX2 = 0xfffffffffffffffn;
14235
14255
  function chachaNonce(n) {
14236
14256
  const b = new Uint8Array(12);
@@ -14292,7 +14312,7 @@ var chachaPoly = /* @__PURE__ */ (() => {
14292
14312
  };
14293
14313
  })();
14294
14314
 
14295
- // ../../node_modules/.pnpm/@lukeburns+clatterjs@1.0.0/node_modules/@lukeburns/clatterjs/dist/noiseNq.js
14315
+ // ../../node_modules/@lukeburns/clatterjs/dist/noiseNq.js
14296
14316
  function noiseIk() {
14297
14317
  return new HandshakePattern("IK", [], [
14298
14318
  1
@@ -14736,7 +14756,7 @@ function uuidV7(now = Date.now()) {
14736
14756
  }
14737
14757
 
14738
14758
  // src/harness-version.ts
14739
- import { readFile } from "node:fs/promises";
14759
+ import { readFile, realpath as realpathEntrypoint } from "node:fs/promises";
14740
14760
  import { createRequire } from "node:module";
14741
14761
  import { dirname, isAbsolute, join } from "node:path";
14742
14762
  var LEGACY_PLACEHOLDER_VERSION = "0.0.1";
@@ -14771,7 +14791,13 @@ async function readHarnessManifestVersion(manifestPath) {
14771
14791
  }
14772
14792
  async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
14773
14793
  if (entrypoint === void 0 || !isAbsolute(entrypoint)) return void 0;
14774
- let directory = dirname(entrypoint);
14794
+ let resolvedEntrypoint = entrypoint;
14795
+ try {
14796
+ resolvedEntrypoint = await realpathEntrypoint(entrypoint);
14797
+ } catch {
14798
+ }
14799
+ if (!isAbsolute(resolvedEntrypoint)) return void 0;
14800
+ let directory = dirname(resolvedEntrypoint);
14775
14801
  for (let depth = 0; depth < 8; depth += 1) {
14776
14802
  const version = await readHarnessManifestVersion(join(directory, "package.json"));
14777
14803
  if (version !== void 0) return version;
@@ -14780,7 +14806,7 @@ async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
14780
14806
  directory = parent;
14781
14807
  }
14782
14808
  try {
14783
- return await readHarnessManifestVersion(createRequire(entrypoint).resolve(`${HARNESS_PACKAGE_NAME}/package.json`));
14809
+ return await readHarnessManifestVersion(createRequire(resolvedEntrypoint).resolve(`${HARNESS_PACKAGE_NAME}/package.json`));
14784
14810
  } catch {
14785
14811
  return void 0;
14786
14812
  }
@@ -18277,6 +18303,7 @@ var entryConfigSchema = s.object({
18277
18303
  serverUrl: s.string(),
18278
18304
  deviceName: s.string(),
18279
18305
  terminal: s.object({ enabled: s.boolean() }),
18306
+ hostControl: s.object({ enabled: s.boolean() }),
18280
18307
  loopback: s.object({ ports: s.array(s.number()) }),
18281
18308
  forceRelay: s.boolean(),
18282
18309
  logLevel: s.union(["debug", "info", "warn", "error"]),
@@ -18313,6 +18340,7 @@ var configSchema = external_exports.object({
18313
18340
  serverUrl: external_exports.string().url().optional(),
18314
18341
  deviceName: external_exports.string().trim().min(1).max(80).optional(),
18315
18342
  terminal: external_exports.object({ enabled: external_exports.boolean().optional() }).strict().optional(),
18343
+ hostControl: external_exports.object({ enabled: external_exports.boolean().optional() }).strict().optional(),
18316
18344
  loopback: external_exports.object({ ports: external_exports.array(external_exports.number().int().min(1024).max(65535)).max(16).optional() }).strict().optional(),
18317
18345
  forceRelay: external_exports.boolean().optional(),
18318
18346
  logLevel: external_exports.enum(["debug", "info", "warn", "error"]).optional(),
@@ -18338,7 +18366,8 @@ function resolveConfig(input2 = {}, env = process.env) {
18338
18366
  role: parsed.role ?? "host",
18339
18367
  ...serverUrl === void 0 ? {} : { serverUrl },
18340
18368
  deviceName: parsed.deviceName ?? hostname(),
18341
- terminal: { enabled: parsed.terminal?.enabled ?? env.DSH_REMOTE_TERMINAL_ENABLED === "true" },
18369
+ hostControl: { enabled: parsed.hostControl?.enabled ?? true },
18370
+ terminal: { enabled: parsed.terminal?.enabled ?? (env.DSH_REMOTE_TERMINAL_ENABLED === void 0 || env.DSH_REMOTE_TERMINAL_ENABLED === "true") },
18342
18371
  loopback: { ports: [...new Set(parsed.loopback?.ports ?? [])] },
18343
18372
  forceRelay: parsed.forceRelay ?? false,
18344
18373
  logLevel: parsed.logLevel ?? "info",
@@ -18378,7 +18407,7 @@ function normalizeServerUrl(value) {
18378
18407
  }
18379
18408
 
18380
18409
  // src/version.ts
18381
- var PLUGIN_VERSION = "0.4.25";
18410
+ var PLUGIN_VERSION = "0.4.27";
18382
18411
 
18383
18412
  // src/server-api.ts
18384
18413
  var TERMINAL_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
@@ -18407,6 +18436,11 @@ var HostServerApi = class {
18407
18436
  ...this.credentials.account === void 0 ? {} : { account: this.credentials.account }
18408
18437
  };
18409
18438
  }
18439
+ /** Check the persisted device credential without issuing or refreshing one. */
18440
+ async hasStoredAuthorization() {
18441
+ const identity = this.requireIdentity();
18442
+ return await this.store.load(this.baseUrl, identity.deviceId) !== void 0;
18443
+ }
18410
18444
  async clearAuthorization() {
18411
18445
  this.credentials = void 0;
18412
18446
  this.credentialsPromise = void 0;
@@ -20052,6 +20086,13 @@ var REMOTE_COMMAND_LIST_MIN_VERSION = [0, 3, 16];
20052
20086
  var REMOTE_FILE_VIEWER_MIN_VERSION = [0, 3, 17];
20053
20087
  var DIRECT_WEBRTC_NEGOTIATE_TIMEOUT_MS = 12e3;
20054
20088
  var DIRECT_LAN_PROGRESS_DISPLAY_MS = 1400;
20089
+ var HOST_AUTHORIZATION_ERRORS = /* @__PURE__ */ new Set([
20090
+ "ACCOUNT_AUTH_REQUIRED",
20091
+ "AUTH_INVALID",
20092
+ "DEVICE_OWNERSHIP_REQUIRED",
20093
+ "DEVICE_REVOKED",
20094
+ "TOKEN_EXPIRED"
20095
+ ]);
20055
20096
  var ClientModeRuntime = class {
20056
20097
  constructor(config, identities, server, apiProxy, typertGateway, logger, host, rtcFactoryProvider = loadNodeRtcFactory) {
20057
20098
  this.config = config;
@@ -20084,6 +20125,27 @@ var ClientModeRuntime = class {
20084
20125
  deviceId: shortId(this.identity.deviceId),
20085
20126
  fingerprint: this.identity.fingerprint
20086
20127
  });
20128
+ if (this.config.hostControl?.enabled !== false && this.host !== void 0 && this.server.hasStoredAuthorization !== void 0) {
20129
+ try {
20130
+ if (await this.server.hasStoredAuthorization() && (this.host.hasStoredAuthorization === void 0 || !await this.host.hasStoredAuthorization())) {
20131
+ await this.authorizeHostByDefault();
20132
+ }
20133
+ } catch (error) {
20134
+ this.logger.warn("automatic Host authorization failed", { code: safeErrorCode(error) });
20135
+ }
20136
+ }
20137
+ }
20138
+ async authorizeHostByDefault() {
20139
+ try {
20140
+ if (this.host === void 0) return;
20141
+ if (this.config.hostControl?.enabled === false) return;
20142
+ if (this.host.hostStatus().authorized) return;
20143
+ if (this.host.hasStoredAuthorization !== void 0 && await this.host.hasStoredAuthorization()) return;
20144
+ const credentials = await this.server.authenticate(this.requireIdentity());
20145
+ await this.host.authorizeHostAsOwned(credentials.accessToken, credentials.account);
20146
+ } catch (error) {
20147
+ this.logger.warn("automatic Host authorization failed", { code: safeErrorCode(error) });
20148
+ }
20087
20149
  }
20088
20150
  registerControl(connection, webServer) {
20089
20151
  return registerControlRoute(connection, (endpoint, payload, signal) => this.handleControl(endpoint, payload, signal), webServer);
@@ -20143,6 +20205,7 @@ var ClientModeRuntime = class {
20143
20205
  };
20144
20206
  }
20145
20207
  async devices() {
20208
+ this.assertHostAuthorizationForDeviceDiscovery();
20146
20209
  this.requireIdentity();
20147
20210
  const serverDevices = await this.server.listDevices();
20148
20211
  const remoteDevices = serverDevices.filter((device) => device.deviceId !== this.host?.hostStatus().deviceId);
@@ -20152,6 +20215,20 @@ var ClientModeRuntime = class {
20152
20215
  return { ...device, ...presence };
20153
20216
  }));
20154
20217
  }
20218
+ /**
20219
+ * Device discovery is exposed through the local app control route. When this
20220
+ * installation also runs a Host, keep that route closed after the Host's
20221
+ * Server credential has become terminally invalid. The Client credential can
20222
+ * remain usable for a short time after a revoke, so checking only
20223
+ * `ClientServerApi.listDevices()` would otherwise leak the device directory
20224
+ * from a Host that the user has already been told to re-authorize.
20225
+ */
20226
+ assertHostAuthorizationForDeviceDiscovery() {
20227
+ const status2 = this.host?.hostStatus();
20228
+ if (status2 === void 0 || status2.error === void 0 || !HOST_AUTHORIZATION_ERRORS.has(status2.error)) return;
20229
+ const message = status2.error === "DEVICE_REVOKED" ? "The local Host was revoked on the Server. Sign out and authorize this Host again." : "The local Host authorization is no longer valid. Sign out and authorize this Host again.";
20230
+ throw new ClientModeError(status2.error, message);
20231
+ }
20155
20232
  async authorizeClientWithAccount(email, password) {
20156
20233
  let authorization;
20157
20234
  try {
@@ -20162,6 +20239,7 @@ var ClientModeRuntime = class {
20162
20239
  this.server.bindIdentity(this.identity);
20163
20240
  authorization = await this.server.authorizeWithAccount(this.identity, email, password);
20164
20241
  }
20242
+ await this.authorizeHostByDefault();
20165
20243
  this.logger.info("Client account authorized");
20166
20244
  return authorization;
20167
20245
  }
@@ -20176,6 +20254,7 @@ var ClientModeRuntime = class {
20176
20254
  return this.identity;
20177
20255
  });
20178
20256
  if (result.status === "complete") this.logger.info("Client account authorized with QR login");
20257
+ if (result.status === "complete") await this.authorizeHostByDefault();
20179
20258
  return result;
20180
20259
  }
20181
20260
  async clearClientAuthorization() {
@@ -21509,6 +21588,16 @@ var PluginControlRuntime = class {
21509
21588
  if (endpoint === "settings.acp.add") return ok3(await this.addAcp(payload));
21510
21589
  if (endpoint === "settings.acp.remove") return ok3(await this.removeAcp(payload));
21511
21590
  if (endpoint === "settings.logout") return ok3(await this.logout());
21591
+ if (endpoint === "host.authorization.set" && this.client !== void 0) {
21592
+ const value = record5(payload);
21593
+ if (typeof value.enabled !== "boolean") throw new ClientModeError("INVALID_MESSAGE", "Host authorization state is required.");
21594
+ const status2 = await this.client.setHostAuthorization(value.enabled);
21595
+ if (this.settings !== void 0) {
21596
+ const current = resolveConfig(this.settings.get());
21597
+ await this.settings.replace(editableConfig({ ...current, hostControl: { enabled: value.enabled } }));
21598
+ }
21599
+ return ok3(status2);
21600
+ }
21512
21601
  if (endpoint === "host.reconnect") {
21513
21602
  if (this.host === void 0) throw new ClientModeError("METHOD_NOT_ALLOWED", "This plugin is not running as a Host.");
21514
21603
  this.host.reconnectHost();
@@ -21566,6 +21655,9 @@ var PluginControlRuntime = class {
21566
21655
  }
21567
21656
  authorization = await api.authorizeWithAccount(identity, value.email, value.password);
21568
21657
  }
21658
+ if (value.role === "client" && resolveConfig(this.settings.get()).hostControl?.enabled !== false) {
21659
+ await this.client?.authorizeHostByDefault();
21660
+ }
21569
21661
  await this.settings.replace(editableConfig(next));
21570
21662
  return {
21571
21663
  status: "authorized",
@@ -21612,7 +21704,7 @@ var PluginControlRuntime = class {
21612
21704
  const current = editableConfig(resolveConfig(this.settings.get()));
21613
21705
  const next = resolveConfig({
21614
21706
  ...current,
21615
- terminal: { enabled: value.terminalEnabled === void 0 ? current.terminal?.enabled ?? false : value.terminalEnabled },
21707
+ terminal: { enabled: value.terminalEnabled === void 0 ? current.terminal?.enabled ?? true : value.terminalEnabled },
21616
21708
  loopback: { ports: value.ports === void 0 ? current.loopback?.ports ?? [] : value.ports }
21617
21709
  });
21618
21710
  await this.settings.replace(editableConfig(next));
@@ -21760,6 +21852,7 @@ function editableConfig(config) {
21760
21852
  role: config.role,
21761
21853
  ...config.serverUrl === void 0 ? {} : { serverUrl: config.serverUrl },
21762
21854
  terminal: config.terminal,
21855
+ hostControl: config.hostControl ?? { enabled: true },
21763
21856
  loopback: config.loopback,
21764
21857
  forceRelay: config.forceRelay,
21765
21858
  logLevel: config.logLevel,
@@ -22540,6 +22633,13 @@ var HostServerConnection = class {
22540
22633
  if (TERMINAL_AUTH_ERRORS.has(code)) {
22541
22634
  this.logger.warn(code === "CONNECTION_REPLACED" ? "Another instance is using this Host identity. Stop it or use a separate DSH_HOME; automatic reconnect is paused." : code === "SERVER_CREDENTIALS_BUSY" ? "Credential refresh is locked. Stop other instances; after a crash, stop all instances before removing server-credentials.json.refresh-lock and authorizing again." : "Host authorization failed. Run /remote login or authorize this Host again in Remote settings.");
22542
22635
  }
22636
+ if (code === "DEVICE_REVOKED") {
22637
+ try {
22638
+ await this.api.clearAuthorization();
22639
+ } catch (clearError) {
22640
+ this.logger.error("failed to clear revoked Host authorization", { code: errorCode2(clearError) });
22641
+ }
22642
+ }
22543
22643
  if (TERMINAL_AUTH_ERRORS.has(code) || !this.config.reconnect.enabled) return;
22544
22644
  }
22545
22645
  if (this.stopped) return;
@@ -24657,6 +24757,7 @@ function isRecord10(value) {
24657
24757
 
24658
24758
  // src/codex/domain.ts
24659
24759
  import { randomUUID as randomUUID2 } from "node:crypto";
24760
+ import { accessSync, constants, existsSync as existsSync2, readFileSync } from "node:fs";
24660
24761
  import { readdir as readdir2, realpath, stat as stat4 } from "node:fs/promises";
24661
24762
  import { homedir as homedir3 } from "node:os";
24662
24763
  import { basename as basename3, isAbsolute as isAbsolute3, join as join5, relative, resolve as resolve2 } from "node:path";
@@ -26105,7 +26206,26 @@ var CodexRemoteDomain = class {
26105
26206
  };
26106
26207
  function codexBinaryCandidates(configured, hostPlatform = process.platform, userHome = homedir3()) {
26107
26208
  if (configured !== "codex" || hostPlatform !== "darwin") return [configured];
26209
+ const bundledCandidates = [
26210
+ "/Applications/ChatGPT.app",
26211
+ join5(userHome, "Applications", "ChatGPT.app")
26212
+ ].flatMap((chatGptApp) => {
26213
+ const codexCli = join5(chatGptApp, "Contents", "Resources", "codex-cli");
26214
+ try {
26215
+ const manifest = JSON.parse(readFileSync(join5(codexCli, "codex-package.json"), "utf8"));
26216
+ if (!isRecord13(manifest) || typeof manifest.entrypoint !== "string" || manifest.entrypoint.length === 0) {
26217
+ return [];
26218
+ }
26219
+ const candidate = join5(codexCli, manifest.entrypoint);
26220
+ if (!existsSync2(candidate)) return [];
26221
+ accessSync(candidate, constants.X_OK);
26222
+ return [candidate];
26223
+ } catch {
26224
+ return [];
26225
+ }
26226
+ });
26108
26227
  return [.../* @__PURE__ */ new Set([
26228
+ ...bundledCandidates,
26109
26229
  "/Applications/ChatGPT.app/Contents/Resources/codex",
26110
26230
  join5(userHome, "Applications", "ChatGPT.app", "Contents", "Resources", "codex"),
26111
26231
  configured
@@ -26926,7 +27046,7 @@ var HostPluginRuntime = class {
26926
27046
  this.fileViewerHost = fileViewerHost;
26927
27047
  this.terminalSpawner = terminalSpawner;
26928
27048
  this.terminalEnabled = config.terminal.enabled;
26929
- this.loopback = new LoopbackHost(config.loopback.ports);
27049
+ this.loopbackPorts = [...config.loopback.ports];
26930
27050
  this.codex = new CodexRemoteDomain(config.codex, logger);
26931
27051
  this.connections = new ConnectionController(this.identities, (context, send) => {
26932
27052
  const harnessApi = this.apiProxy === void 0 ? void 0 : new HarnessApiBridge(
@@ -26969,7 +27089,8 @@ var HostPluginRuntime = class {
26969
27089
  () => this.hostCapabilities(),
26970
27090
  codex,
26971
27091
  acp,
26972
- this.loopback
27092
+ // Handles and their lifetime belong to this connection; only policy is shared.
27093
+ this.createLoopbackHost()
26973
27094
  );
26974
27095
  }, this.logger);
26975
27096
  if (config.serverUrl !== void 0) {
@@ -26978,8 +27099,9 @@ var HostPluginRuntime = class {
26978
27099
  }
26979
27100
  connections;
26980
27101
  terminalOwners = /* @__PURE__ */ new Map();
27102
+ loopbackHosts = /* @__PURE__ */ new Set();
26981
27103
  terminalEnabled;
26982
- loopback;
27104
+ loopbackPorts;
26983
27105
  identity;
26984
27106
  serverApi;
26985
27107
  serverConnection;
@@ -26993,7 +27115,14 @@ var HostPluginRuntime = class {
26993
27115
  this.terminalEnabled = enabled;
26994
27116
  }
26995
27117
  setLoopbackPorts(ports) {
26996
- this.loopback.setPorts(ports);
27118
+ this.loopbackPorts = [...ports];
27119
+ for (const loopback of this.loopbackHosts) loopback.setPorts(this.loopbackPorts);
27120
+ }
27121
+ createLoopbackHost() {
27122
+ let loopback;
27123
+ loopback = new LoopbackHost(() => this.loopbackPorts, () => this.loopbackHosts.delete(loopback));
27124
+ this.loopbackHosts.add(loopback);
27125
+ return loopback;
26997
27126
  }
26998
27127
  async start() {
26999
27128
  if (this.closed) throw new Error("remote runtime is closed");
@@ -27036,6 +27165,9 @@ var HostPluginRuntime = class {
27036
27165
  connectedClients: this.listConnectedClients()
27037
27166
  };
27038
27167
  }
27168
+ async hasStoredAuthorization() {
27169
+ return this.serverApi?.hasStoredAuthorization() ?? false;
27170
+ }
27039
27171
  listConnectedClients() {
27040
27172
  return this.connections.connectedPeers().map((peer) => {
27041
27173
  const trusted = this.identities.trustedPeer(peer.deviceId);
@@ -27219,7 +27351,7 @@ var HostPluginRuntime = class {
27219
27351
  }
27220
27352
  hostCapabilities() {
27221
27353
  const capabilities = [];
27222
- if (this.loopback.hasPorts()) capabilities.push("loopback.http-ws.v1");
27354
+ if (this.loopbackPorts.length > 0) capabilities.push("loopback.http-ws.v1");
27223
27355
  if (this.localGateway?.supportsCarrier === true) {
27224
27356
  capabilities.push(
27225
27357
  harnessSessionGeneration(this.harnessVersion) === "v3" ? "harness.remote.v3" : "harness.remote.v1",