tesseract-agent 0.9.31 → 0.9.33

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-bundle/cli.js +2046 -367
  2. package/package.json +1 -1
@@ -1885,7 +1885,7 @@ var require_sender = __commonJS({
1885
1885
  * @param {Function} [cb] Callback
1886
1886
  * @private
1887
1887
  */
1888
- getBlobData(blob, compress, options, cb) {
1888
+ getBlobData(blob, compress2, options, cb) {
1889
1889
  this._bufferedBytes += options[kByteLength];
1890
1890
  this._state = GET_BLOB_DATA;
1891
1891
  blob.arrayBuffer().then((arrayBuffer) => {
@@ -1898,12 +1898,12 @@ var require_sender = __commonJS({
1898
1898
  }
1899
1899
  this._bufferedBytes -= options[kByteLength];
1900
1900
  const data = toBuffer(arrayBuffer);
1901
- if (!compress) {
1901
+ if (!compress2) {
1902
1902
  this._state = DEFAULT;
1903
1903
  this.sendFrame(_Sender.frame(data, options), cb);
1904
1904
  this.dequeue();
1905
1905
  } else {
1906
- this.dispatch(data, compress, options, cb);
1906
+ this.dispatch(data, compress2, options, cb);
1907
1907
  }
1908
1908
  }).catch((err2) => {
1909
1909
  process.nextTick(onError, this, err2, cb);
@@ -1932,8 +1932,8 @@ var require_sender = __commonJS({
1932
1932
  * @param {Function} [cb] Callback
1933
1933
  * @private
1934
1934
  */
1935
- dispatch(data, compress, options, cb) {
1936
- if (!compress) {
1935
+ dispatch(data, compress2, options, cb) {
1936
+ if (!compress2) {
1937
1937
  this.sendFrame(_Sender.frame(data, options), cb);
1938
1938
  return;
1939
1939
  }
@@ -2249,7 +2249,7 @@ var require_extension = __commonJS({
2249
2249
  if (dest[name] === void 0) dest[name] = [elem];
2250
2250
  else dest[name].push(elem);
2251
2251
  }
2252
- function parse3(header2) {
2252
+ function parse4(header2) {
2253
2253
  const offers = /* @__PURE__ */ Object.create(null);
2254
2254
  let params = /* @__PURE__ */ Object.create(null);
2255
2255
  let mustUnescape = false;
@@ -2389,7 +2389,7 @@ var require_extension = __commonJS({
2389
2389
  }).join(", ");
2390
2390
  }).join(", ");
2391
2391
  }
2392
- module.exports = { format, parse: parse3 };
2392
+ module.exports = { format, parse: parse4 };
2393
2393
  }
2394
2394
  });
2395
2395
 
@@ -2423,7 +2423,7 @@ var require_websocket = __commonJS({
2423
2423
  var {
2424
2424
  EventTarget: { addEventListener, removeEventListener }
2425
2425
  } = require_event_target();
2426
- var { format, parse: parse3 } = require_extension();
2426
+ var { format, parse: parse4 } = require_extension();
2427
2427
  var { toBuffer } = require_buffer_util();
2428
2428
  var kAborted = Symbol("kAborted");
2429
2429
  var protocolVersions = [8, 13];
@@ -2941,7 +2941,7 @@ var require_websocket = __commonJS({
2941
2941
  }
2942
2942
  const defaultPort = isSecure ? 443 : 80;
2943
2943
  const key2 = randomBytes12(16).toString("base64");
2944
- const request = isSecure ? https.request : http.request;
2944
+ const request2 = isSecure ? https.request : http.request;
2945
2945
  const protocolSet = /* @__PURE__ */ new Set();
2946
2946
  let perMessageDeflate;
2947
2947
  opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
@@ -3018,12 +3018,12 @@ var require_websocket = __commonJS({
3018
3018
  if (opts.auth && !options.headers.authorization) {
3019
3019
  options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
3020
3020
  }
3021
- req = websocket._req = request(opts);
3021
+ req = websocket._req = request2(opts);
3022
3022
  if (websocket._redirects) {
3023
3023
  websocket.emit("redirect", websocket.url, req);
3024
3024
  }
3025
3025
  } else {
3026
- req = websocket._req = request(opts);
3026
+ req = websocket._req = request2(opts);
3027
3027
  }
3028
3028
  if (opts.timeout) {
3029
3029
  req.on("timeout", () => {
@@ -3100,7 +3100,7 @@ var require_websocket = __commonJS({
3100
3100
  }
3101
3101
  let extensions;
3102
3102
  try {
3103
- extensions = parse3(secWebSocketExtensions);
3103
+ extensions = parse4(secWebSocketExtensions);
3104
3104
  } catch (err2) {
3105
3105
  const message = "Invalid Sec-WebSocket-Extensions header";
3106
3106
  abortHandshake(websocket, socket2, message);
@@ -3392,7 +3392,7 @@ var require_subprotocol = __commonJS({
3392
3392
  "../../node_modules/ws/lib/subprotocol.js"(exports, module) {
3393
3393
  "use strict";
3394
3394
  var { tokenChars } = require_validation();
3395
- function parse3(header2) {
3395
+ function parse4(header2) {
3396
3396
  const protocols = /* @__PURE__ */ new Set();
3397
3397
  let start3 = -1;
3398
3398
  let end2 = -1;
@@ -3428,7 +3428,7 @@ var require_subprotocol = __commonJS({
3428
3428
  protocols.add(protocol);
3429
3429
  return protocols;
3430
3430
  }
3431
- module.exports = { parse: parse3 };
3431
+ module.exports = { parse: parse4 };
3432
3432
  }
3433
3433
  });
3434
3434
 
@@ -5580,11 +5580,11 @@ function parseEnginePathStore(raw) {
5580
5580
  function engineEnvKeySuffix(engineId) {
5581
5581
  return engineId.toUpperCase().replace(/[^A-Z0-9]/g, "_");
5582
5582
  }
5583
- function pathSep(platform7) {
5584
- return platform7 === "win32" ? "\\" : "/";
5583
+ function pathSep(platform8) {
5584
+ return platform8 === "win32" ? "\\" : "/";
5585
5585
  }
5586
- function joinPath2(platform7, ...parts) {
5587
- const sep10 = pathSep(platform7);
5586
+ function joinPath2(platform8, ...parts) {
5587
+ const sep10 = pathSep(platform8);
5588
5588
  return parts.filter((p) => p !== "").map((p, i) => i === 0 ? p.replace(/[\\/]+$/, "") : p.replace(/^[\\/]+|[\\/]+$/g, "")).join(sep10);
5589
5589
  }
5590
5590
  function dedupe(dirs) {
@@ -5600,10 +5600,10 @@ function dedupe(dirs) {
5600
5600
  return out;
5601
5601
  }
5602
5602
  function engineSearchDirs(opts) {
5603
- const { home, platform: platform7 } = opts;
5603
+ const { home, platform: platform8 } = opts;
5604
5604
  const env = opts.env ?? {};
5605
- const j = (...parts) => joinPath2(platform7, ...parts);
5606
- if (platform7 === "win32") {
5605
+ const j = (...parts) => joinPath2(platform8, ...parts);
5606
+ if (platform8 === "win32") {
5607
5607
  const appData = env.APPDATA ?? j(home, "AppData", "Roaming");
5608
5608
  const localAppData = env.LOCALAPPDATA ?? j(home, "AppData", "Local");
5609
5609
  const programFiles = env.ProgramFiles ?? "C:\\Program Files";
@@ -5620,7 +5620,7 @@ function engineSearchDirs(opts) {
5620
5620
  j(programFiles, "nodejs")
5621
5621
  ]);
5622
5622
  }
5623
- const pnpmHome = env.PNPM_HOME ?? (platform7 === "darwin" ? j(home, "Library", "pnpm") : j(home, ".local", "share", "pnpm"));
5623
+ const pnpmHome = env.PNPM_HOME ?? (platform8 === "darwin" ? j(home, "Library", "pnpm") : j(home, ".local", "share", "pnpm"));
5624
5624
  return dedupe([
5625
5625
  "/opt/homebrew/bin",
5626
5626
  "/usr/local/bin",
@@ -9225,8 +9225,8 @@ function base64urlToUint8Array(base64url3) {
9225
9225
  function uint8ArrayToBase64url(bytes2) {
9226
9226
  return uint8ArrayToBase64(bytes2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
9227
9227
  }
9228
- function hexToUint8Array(hex5) {
9229
- const cleanHex = hex5.replace(/^0x/, "");
9228
+ function hexToUint8Array(hex6) {
9229
+ const cleanHex = hex6.replace(/^0x/, "");
9230
9230
  if (cleanHex.length % 2 !== 0) {
9231
9231
  throw new Error("Invalid hex string length");
9232
9232
  }
@@ -32377,8 +32377,8 @@ ${full.slice(-8e3)}`;
32377
32377
  return;
32378
32378
  }
32379
32379
  const todos = live.todos?.map((t) => ({ content: t.content, status: String(t.status) }));
32380
- const call2 = gate === "review" ? reviewGrade(rv.task, finalText) : completenessGrade(rv.task, finalText, todos);
32381
- const raw = await llm({ model: live.model, system: call2.system, prompt: call2.prompt, maxTokens: 16e3, schema: call2.schema });
32380
+ const call3 = gate === "review" ? reviewGrade(rv.task, finalText) : completenessGrade(rv.task, finalText, todos);
32381
+ const raw = await llm({ model: live.model, system: call3.system, prompt: call3.prompt, maxTokens: 16e3, schema: call3.schema });
32382
32382
  if (live.rv !== rv || live.reaped) {
32383
32383
  if (live.reaped || live.rv === void 0) {
32384
32384
  emitVerification({ action: "done", gate, cycle: rv.cycles, maxCycles: RV_MAX_CYCLES, unavailable: "This run ended before it could be verified." });
@@ -32632,19 +32632,19 @@ ${qText}`;
32632
32632
  * reply (→ respondToUserDialog). Mirrors onElicitation: the CLI parks the flow until
32633
32633
  * we answer; an unanswered/aborted dialog resolves 'cancelled' so the CLI applies the
32634
32634
  * dialog's default behavior (e.g. the classic refusal message) rather than hanging. */
32635
- raiseUserDialog(live, request, signal) {
32635
+ raiseUserDialog(live, request2, signal) {
32636
32636
  return new Promise((resolve16) => {
32637
32637
  const requestId = randomUUID6();
32638
- log("user_dialog raised:", request.dialogKind, "requestId=" + requestId, "payloadKeys=" + Object.keys(request.payload ?? {}).join(","));
32638
+ log("user_dialog raised:", request2.dialogKind, "requestId=" + requestId, "payloadKeys=" + Object.keys(request2.payload ?? {}).join(","));
32639
32639
  const onAbort = () => {
32640
32640
  if (this.pendingUserDialogs.delete(requestId)) {
32641
- log("user_dialog aborted (cancelled):", request.dialogKind, requestId);
32641
+ log("user_dialog aborted (cancelled):", request2.dialogKind, requestId);
32642
32642
  resolve16({ behavior: "cancelled" });
32643
32643
  }
32644
32644
  };
32645
32645
  const cleanup2 = () => signal.removeEventListener("abort", onAbort);
32646
32646
  if (signal.aborted) {
32647
- log("user_dialog pre-aborted (cancelled):", request.dialogKind);
32647
+ log("user_dialog pre-aborted (cancelled):", request2.dialogKind);
32648
32648
  resolve16({ behavior: "cancelled" });
32649
32649
  return;
32650
32650
  }
@@ -32654,15 +32654,15 @@ ${qText}`;
32654
32654
  type: "agent:user_dialog_request",
32655
32655
  sessionId: live.sessionId,
32656
32656
  requestId,
32657
- dialogKind: request.dialogKind,
32658
- payload: request.payload ?? {},
32659
- ...request.toolUseID ? { toolUseId: request.toolUseID } : {}
32657
+ dialogKind: request2.dialogKind,
32658
+ payload: request2.payload ?? {},
32659
+ ...request2.toolUseID ? { toolUseId: request2.toolUseID } : {}
32660
32660
  };
32661
32661
  if (live.clientRequestId)
32662
32662
  this.send({ ...evt, clientRequestId: live.clientRequestId }, live.origin);
32663
32663
  else
32664
32664
  this.send(evt, live.origin);
32665
- this.autoAnswerPrompt(live, requestId, { kind: "dialog", dialogKind: request.dialogKind }, (a) => {
32665
+ this.autoAnswerPrompt(live, requestId, { kind: "dialog", dialogKind: request2.dialogKind }, (a) => {
32666
32666
  if (!this.pendingUserDialogs.has(requestId))
32667
32667
  return false;
32668
32668
  this.respondToUserDialog(requestId, a.dialogResult ? { behavior: "completed", result: a.dialogResult } : { behavior: "cancelled" });
@@ -34042,7 +34042,7 @@ CRITICAL RULES:
34042
34042
  // M5 H6 — an MCP server requesting user input (a form, or url-based OAuth).
34043
34043
  // Default is auto-cancel; we park a Promise and raise an inline card, then
34044
34044
  // resolve it from chat:elicitation (respondToElicitation). Mirrors canUseTool.
34045
- onElicitation: (request, opts) => new Promise((resolve16) => {
34045
+ onElicitation: (request2, opts) => new Promise((resolve16) => {
34046
34046
  const requestId = randomUUID6();
34047
34047
  const onAbort = () => {
34048
34048
  if (this.pendingElicitations.delete(requestId))
@@ -34059,19 +34059,19 @@ CRITICAL RULES:
34059
34059
  type: "agent:elicitation_request",
34060
34060
  sessionId: live.sessionId,
34061
34061
  requestId,
34062
- serverName: request.serverName,
34063
- message: request.message,
34064
- ...request.mode ? { mode: request.mode } : {},
34065
- ...request.url ? { url: request.url } : {},
34066
- ...request.elicitationId ? { elicitationId: request.elicitationId } : {},
34067
- ...request.requestedSchema ? { requestedSchema: request.requestedSchema } : {},
34068
- ...request.title ? { title: request.title } : {}
34062
+ serverName: request2.serverName,
34063
+ message: request2.message,
34064
+ ...request2.mode ? { mode: request2.mode } : {},
34065
+ ...request2.url ? { url: request2.url } : {},
34066
+ ...request2.elicitationId ? { elicitationId: request2.elicitationId } : {},
34067
+ ...request2.requestedSchema ? { requestedSchema: request2.requestedSchema } : {},
34068
+ ...request2.title ? { title: request2.title } : {}
34069
34069
  };
34070
34070
  if (live.clientRequestId)
34071
34071
  this.send({ ...evt, clientRequestId: live.clientRequestId }, live.origin);
34072
34072
  else
34073
34073
  this.send(evt, live.origin);
34074
- this.autoAnswerPrompt(live, requestId, { kind: "elicitation", serverName: request.serverName }, () => {
34074
+ this.autoAnswerPrompt(live, requestId, { kind: "elicitation", serverName: request2.serverName }, () => {
34075
34075
  if (!this.pendingElicitations.has(requestId))
34076
34076
  return false;
34077
34077
  this.respondToElicitation(requestId, { action: "decline" });
@@ -34082,7 +34082,7 @@ CRITICAL RULES:
34082
34082
  // asks the host to render. Without this the flow degrades to no-dialog (a model
34083
34083
  // refusal ends the turn with the classic error). We declare the kinds we render
34084
34084
  // (supportedDialogKinds); the CLI fails closed and never emits an undeclared kind.
34085
- onUserDialog: (request, opts) => this.raiseUserDialog(live, request, opts.signal),
34085
+ onUserDialog: (request2, opts) => this.raiseUserDialog(live, request2, opts.signal),
34086
34086
  supportedDialogKinds: KNOWN_DIALOG_KINDS,
34087
34087
  // Capture file edits for the client's "Review changes" (see pendingEdits
34088
34088
  // above). Bash-driven writes aren't visible here — only the editing tools.
@@ -35859,7 +35859,7 @@ async function startTesseractMcpEndpoint() {
35859
35859
  }
35860
35860
  const id = msg.id ?? null;
35861
35861
  const reply3 = (result) => send2(res, 200, { jsonrpc: "2.0", id, result });
35862
- const fail3 = (code, message) => send2(res, 200, { jsonrpc: "2.0", id, error: { code, message } });
35862
+ const fail4 = (code, message) => send2(res, 200, { jsonrpc: "2.0", id, error: { code, message } });
35863
35863
  switch (msg.method) {
35864
35864
  case "initialize":
35865
35865
  reply3({
@@ -35879,7 +35879,7 @@ async function startTesseractMcpEndpoint() {
35879
35879
  const name = String(msg.params?.name ?? "");
35880
35880
  const tool19 = byName.get(name);
35881
35881
  if (!tool19) {
35882
- fail3(-32602, `Unknown tool "${name}"`);
35882
+ fail4(-32602, `Unknown tool "${name}"`);
35883
35883
  return;
35884
35884
  }
35885
35885
  try {
@@ -35891,7 +35891,7 @@ async function startTesseractMcpEndpoint() {
35891
35891
  return;
35892
35892
  }
35893
35893
  default:
35894
- fail3(-32601, `Method not found: ${String(msg.method)}`);
35894
+ fail4(-32601, `Method not found: ${String(msg.method)}`);
35895
35895
  }
35896
35896
  } catch (e) {
35897
35897
  try {
@@ -44102,7 +44102,7 @@ var require_decoder = __commonJS({
44102
44102
  }).bind(this);
44103
44103
  xhr.send(null);
44104
44104
  },
44105
- parse: function parse3(data) {
44105
+ parse: function parse4(data) {
44106
44106
  var maxResolutionInPixels = this.opts.maxResolutionInMP * 1e3 * 1e3;
44107
44107
  var offset = 0, length = data.length;
44108
44108
  function readUint16() {
@@ -46147,7 +46147,7 @@ function __addDisposableResource(env, value, async) {
46147
46147
  return value;
46148
46148
  }
46149
46149
  function __disposeResources(env) {
46150
- function fail3(e) {
46150
+ function fail4(e) {
46151
46151
  env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
46152
46152
  env.hasError = true;
46153
46153
  }
@@ -46159,12 +46159,12 @@ function __disposeResources(env) {
46159
46159
  if (r.dispose) {
46160
46160
  var result = r.dispose.call(r.value);
46161
46161
  if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
46162
- fail3(e);
46162
+ fail4(e);
46163
46163
  return next();
46164
46164
  });
46165
46165
  } else s |= 1;
46166
46166
  } catch (e) {
46167
- fail3(e);
46167
+ fail4(e);
46168
46168
  }
46169
46169
  }
46170
46170
  if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
@@ -48583,8 +48583,8 @@ ${values.join("\n")}` : `${blockName} :`;
48583
48583
  assertBigInt();
48584
48584
  const bigIntValue = BigInt(value);
48585
48585
  const writer = new ViewWriter();
48586
- const hex5 = bigIntValue.toString(16).replace(/^-/, "");
48587
- const view = new Uint8Array(pvtsutils__namespace.Convert.FromHex(hex5));
48586
+ const hex6 = bigIntValue.toString(16).replace(/^-/, "");
48587
+ const view = new Uint8Array(pvtsutils__namespace.Convert.FromHex(hex6));
48588
48588
  if (bigIntValue < 0) {
48589
48589
  const first = new Uint8Array(view.length + (view[0] & 128 ? 1 : 0));
48590
48590
  first[0] |= 128;
@@ -51735,11 +51735,11 @@ var require_hex = __commonJS({
51735
51735
  "use strict";
51736
51736
  Object.defineProperty(exports, "__esModule", { value: true });
51737
51737
  exports.hex = exports.formats = void 0;
51738
- exports.normalize = normalize2;
51738
+ exports.normalize = normalize3;
51739
51739
  exports.is = is;
51740
51740
  exports.encode = encode3;
51741
51741
  exports.decode = decode3;
51742
- exports.parse = parse3;
51742
+ exports.parse = parse4;
51743
51743
  exports.format = format;
51744
51744
  var index_js_1 = require_bytes();
51745
51745
  var HEX_CHARACTER_REGEX = /^[0-9a-f]$/i;
@@ -51893,7 +51893,7 @@ var require_hex = __commonJS({
51893
51893
  }
51894
51894
  return chunks.join(group.separator);
51895
51895
  }
51896
- function normalize2(text9, options = {}) {
51896
+ function normalize3(text9, options = {}) {
51897
51897
  return normalizeText(text9, options);
51898
51898
  }
51899
51899
  function is(text9, options = {}) {
@@ -51901,7 +51901,7 @@ var require_hex = __commonJS({
51901
51901
  return false;
51902
51902
  }
51903
51903
  try {
51904
- normalize2(text9, options);
51904
+ normalize3(text9, options);
51905
51905
  return true;
51906
51906
  } catch {
51907
51907
  return false;
@@ -51932,15 +51932,15 @@ var require_hex = __commonJS({
51932
51932
  return `${options.prefix ?? ""}${body}`;
51933
51933
  }
51934
51934
  function decode3(text9, options = {}) {
51935
- const normalized = normalize2(text9, options);
51935
+ const normalized = normalize3(text9, options);
51936
51936
  const result = new Uint8Array(normalized.length / 2);
51937
51937
  for (let i = 0; i < normalized.length; i += 2) {
51938
51938
  result[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
51939
51939
  }
51940
51940
  return result;
51941
51941
  }
51942
- function parse3(text9, options = {}) {
51943
- const normalized = normalize2(text9, options);
51942
+ function parse4(text9, options = {}) {
51943
+ const normalized = normalize3(text9, options);
51944
51944
  return {
51945
51945
  bytes: decode3(normalized),
51946
51946
  format: detectFormat(text9),
@@ -51958,7 +51958,7 @@ var require_hex = __commonJS({
51958
51958
  groupsOf4: Object.freeze({ group: { size: 4, separator: " " } }),
51959
51959
  prefixed: Object.freeze({ prefix: "0x" })
51960
51960
  };
51961
- exports.hex = { encode: encode3, decode: decode3, format, formats: exports.formats, is, normalize: normalize2, parse: parse3 };
51961
+ exports.hex = { encode: encode3, decode: decode3, format, formats: exports.formats, is, normalize: normalize3, parse: parse4 };
51962
51962
  }
51963
51963
  });
51964
51964
 
@@ -52017,7 +52017,7 @@ var require_base64 = __commonJS({
52017
52017
  "use strict";
52018
52018
  Object.defineProperty(exports, "__esModule", { value: true });
52019
52019
  exports.base64 = void 0;
52020
- exports.normalize = normalize2;
52020
+ exports.normalize = normalize3;
52021
52021
  exports.pad = pad2;
52022
52022
  exports.is = is;
52023
52023
  exports.encode = encode3;
@@ -52028,7 +52028,7 @@ var require_base64 = __commonJS({
52028
52028
  function nodeBuffer() {
52029
52029
  return globalThis.Buffer;
52030
52030
  }
52031
- function normalize2(text9) {
52031
+ function normalize3(text9) {
52032
52032
  return text9.replace(/[\n\r\t ]/g, "");
52033
52033
  }
52034
52034
  function pad2(text9) {
@@ -52039,7 +52039,7 @@ var require_base64 = __commonJS({
52039
52039
  if (typeof text9 !== "string") {
52040
52040
  return false;
52041
52041
  }
52042
- const normalized = normalize2(text9);
52042
+ const normalized = normalize3(text9);
52043
52043
  return normalized === "" || BASE64_REGEX.test(normalized);
52044
52044
  }
52045
52045
  function encode3(data, _options) {
@@ -52051,7 +52051,7 @@ var require_base64 = __commonJS({
52051
52051
  return btoa((0, binary_js_1.encode)(bytes2));
52052
52052
  }
52053
52053
  function decode3(text9, _options) {
52054
- const normalized = normalize2(text9);
52054
+ const normalized = normalize3(text9);
52055
52055
  if (!is(normalized)) {
52056
52056
  throw new TypeError("Input is not valid Base64 text");
52057
52057
  }
@@ -52061,7 +52061,7 @@ var require_base64 = __commonJS({
52061
52061
  }
52062
52062
  return (0, binary_js_1.decode)(atob(normalized));
52063
52063
  }
52064
- exports.base64 = { encode: encode3, decode: decode3, is, normalize: normalize2, pad: pad2 };
52064
+ exports.base64 = { encode: encode3, decode: decode3, is, normalize: normalize3, pad: pad2 };
52065
52065
  }
52066
52066
  });
52067
52067
 
@@ -52071,29 +52071,29 @@ var require_base64url = __commonJS({
52071
52071
  "use strict";
52072
52072
  Object.defineProperty(exports, "__esModule", { value: true });
52073
52073
  exports.base64url = void 0;
52074
- exports.normalize = normalize2;
52074
+ exports.normalize = normalize3;
52075
52075
  exports.is = is;
52076
52076
  exports.encode = encode3;
52077
52077
  exports.decode = decode3;
52078
52078
  var base64_js_1 = require_base64();
52079
52079
  var BASE64URL_REGEX = /^[A-Za-z0-9_-]*$/;
52080
- function normalize2(text9) {
52080
+ function normalize3(text9) {
52081
52081
  return text9.replace(/[\n\r\t ]/g, "");
52082
52082
  }
52083
52083
  function is(text9) {
52084
- return typeof text9 === "string" && BASE64URL_REGEX.test(normalize2(text9));
52084
+ return typeof text9 === "string" && BASE64URL_REGEX.test(normalize3(text9));
52085
52085
  }
52086
52086
  function encode3(data, _options) {
52087
52087
  return base64_js_1.base64.encode(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
52088
52088
  }
52089
52089
  function decode3(text9, _options) {
52090
- const normalized = normalize2(text9);
52090
+ const normalized = normalize3(text9);
52091
52091
  if (!is(normalized)) {
52092
52092
  throw new TypeError("Input is not valid Base64Url text");
52093
52093
  }
52094
52094
  return base64_js_1.base64.decode(base64_js_1.base64.pad(normalized.replace(/-/g, "+").replace(/_/g, "/")));
52095
52095
  }
52096
- exports.base64url = { encode: encode3, decode: decode3, is, normalize: normalize2 };
52096
+ exports.base64url = { encode: encode3, decode: decode3, is, normalize: normalize3 };
52097
52097
  }
52098
52098
  });
52099
52099
 
@@ -59756,8 +59756,8 @@ var require_x509_cjs = __commonJS({
59756
59756
  if (j === 8) {
59757
59757
  row.push("");
59758
59758
  }
59759
- const hex5 = view[i++].toString(16).padStart(2, "0");
59760
- row.push(hex5);
59759
+ const hex6 = view[i++].toString(16).padStart(2, "0");
59760
+ row.push(hex6);
59761
59761
  }
59762
59762
  res.push(`${pad2}${row.join(" ")}`);
59763
59763
  }
@@ -60181,7 +60181,7 @@ var require_x509_cjs = __commonJS({
60181
60181
  if (!matches) {
60182
60182
  throw new Error("Cannot parse GUID value. Value doesn't match to regular expression");
60183
60183
  }
60184
- const hex5 = matches.slice(1).map((o, i) => {
60184
+ const hex6 = matches.slice(1).map((o, i) => {
60185
60185
  if (i < 3) {
60186
60186
  return pvtsutils.Convert.ToHex(new Uint8Array(pvtsutils.Convert.FromHex(o)).reverse());
60187
60187
  }
@@ -60190,7 +60190,7 @@ var require_x509_cjs = __commonJS({
60190
60190
  name = new asn1X509__namespace.GeneralName({
60191
60191
  otherName: new asn1X509__namespace.OtherName({
60192
60192
  typeId: id_GUID,
60193
- value: asn1Schema.AsnConvert.serialize(new asn1Schema.OctetString(pvtsutils.Convert.FromHex(hex5)))
60193
+ value: asn1Schema.AsnConvert.serialize(new asn1Schema.OctetString(pvtsutils.Convert.FromHex(hex6)))
60194
60194
  })
60195
60195
  });
60196
60196
  break;
@@ -63139,9 +63139,9 @@ function socketPeerLink(socket2, peerHostId, path6, opts) {
63139
63139
  });
63140
63140
  const hsTimer = setTimeout(() => {
63141
63141
  if (!authed)
63142
- fail3(new Error("peer-link: token handshake timeout"));
63142
+ fail4(new Error("peer-link: token handshake timeout"));
63143
63143
  }, TOKEN_HANDSHAKE_MS);
63144
- function fail3(err2) {
63144
+ function fail4(err2) {
63145
63145
  if (closed)
63146
63146
  return;
63147
63147
  closed = true;
@@ -63167,7 +63167,7 @@ function socketPeerLink(socket2, peerHostId, path6, opts) {
63167
63167
  try {
63168
63168
  frames = dec.push(new Uint8Array(d.buffer, d.byteOffset, d.byteLength));
63169
63169
  } catch (e) {
63170
- fail3(e);
63170
+ fail4(e);
63171
63171
  return;
63172
63172
  }
63173
63173
  for (const f of frames) {
@@ -63177,7 +63177,7 @@ function socketPeerLink(socket2, peerHostId, path6, opts) {
63177
63177
  clearTimeout(hsTimer);
63178
63178
  resolveReady();
63179
63179
  } else {
63180
- fail3(new Error("peer-link: bad/absent token (fail-closed)"));
63180
+ fail4(new Error("peer-link: bad/absent token (fail-closed)"));
63181
63181
  return;
63182
63182
  }
63183
63183
  continue;
@@ -63186,7 +63186,7 @@ function socketPeerLink(socket2, peerHostId, path6, opts) {
63186
63186
  cb(f);
63187
63187
  }
63188
63188
  });
63189
- socket2.once("error", (e) => fail3(e instanceof Error ? e : new Error(String(e))));
63189
+ socket2.once("error", (e) => fail4(e instanceof Error ? e : new Error(String(e))));
63190
63190
  socket2.once("close", () => closeOk());
63191
63191
  if (opts.sendToken) {
63192
63192
  try {
@@ -63194,7 +63194,7 @@ function socketPeerLink(socket2, peerHostId, path6, opts) {
63194
63194
  clearTimeout(hsTimer);
63195
63195
  resolveReady();
63196
63196
  } catch (e) {
63197
- fail3(e);
63197
+ fail4(e);
63198
63198
  }
63199
63199
  }
63200
63200
  const link = {
@@ -63560,12 +63560,13 @@ function wrapConstructorWithOpts(hashCons) {
63560
63560
  hashC.create = (opts) => hashCons(opts);
63561
63561
  return hashC;
63562
63562
  }
63563
- var u8, u32, isLE, byteSwap, byteSwapIfBE, Hash, toStr;
63563
+ var u8, u32, rotr, isLE, byteSwap, byteSwapIfBE, Hash, toStr;
63564
63564
  var init_utils = __esm({
63565
63565
  "../../node_modules/@noble/hashes/esm/utils.js"() {
63566
63566
  init_assert();
63567
63567
  u8 = (arr) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
63568
63568
  u32 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
63569
+ rotr = (word, shift) => word << 32 - shift | word >>> shift;
63569
63570
  isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68;
63570
63571
  byteSwap = (word) => word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
63571
63572
  byteSwapIfBE = isLE ? (n) => n : (n) => byteSwap(n);
@@ -64820,7 +64821,7 @@ var require_cjs12 = __commonJS({
64820
64821
  out.publicSuffix = (_a4 = hostnameParts[hostnameParts.length - 1]) !== null && _a4 !== void 0 ? _a4 : null;
64821
64822
  }
64822
64823
  var RESULT = getEmptyResult();
64823
- function parse3(url2, options = {}) {
64824
+ function parse4(url2, options = {}) {
64824
64825
  return parseImpl(url2, 5, suffixLookup, options, getEmptyResult());
64825
64826
  }
64826
64827
  function getHostname(url2, options = {}) {
@@ -64848,7 +64849,7 @@ var require_cjs12 = __commonJS({
64848
64849
  exports.getHostname = getHostname;
64849
64850
  exports.getPublicSuffix = getPublicSuffix;
64850
64851
  exports.getSubdomain = getSubdomain;
64851
- exports.parse = parse3;
64852
+ exports.parse = parse4;
64852
64853
  }
64853
64854
  });
64854
64855
 
@@ -64863,6 +64864,9 @@ function compareUtf8(a, b) {
64863
64864
  }
64864
64865
  return ea.length === eb.length ? 0 : ea.length < eb.length ? -1 : 1;
64865
64866
  }
64867
+ function canonicalStrs(items) {
64868
+ return [...new Set(items)].sort(compareUtf8);
64869
+ }
64866
64870
  var MeshCodecError, fail, LIMITS, Writer, Reader;
64867
64871
  var init_codec = __esm({
64868
64872
  "../../packages/mesh-pki/dist/codec.js"() {
@@ -65104,6 +65108,20 @@ function isMasked(addr, len) {
65104
65108
  }
65105
65109
  return true;
65106
65110
  }
65111
+ function mask(addr, len) {
65112
+ const out = new Uint8Array(addr);
65113
+ for (let i = 0; i < out.length; i++) {
65114
+ const bitsBefore = i * 8;
65115
+ if (bitsBefore >= len) {
65116
+ out[i] = 0;
65117
+ continue;
65118
+ }
65119
+ const keep = Math.min(8, len - bitsBefore);
65120
+ if (keep < 8)
65121
+ out[i] &= 255 << 8 - keep;
65122
+ }
65123
+ return out;
65124
+ }
65107
65125
  function makePrefix(afi, addr, len) {
65108
65126
  if (afi !== AFI_V4 && afi !== AFI_V6)
65109
65127
  throw new MeshCodecError("bad-value", `afi ${afi}`);
@@ -65140,6 +65158,10 @@ function comparePrefix(a, b) {
65140
65158
  }
65141
65159
  return a.len === b.len ? 0 : a.len < b.len ? -1 : 1;
65142
65160
  }
65161
+ function canonicalPrefixes(items) {
65162
+ const sorted = [...items].sort(comparePrefix);
65163
+ return sorted.filter((p, i) => i === 0 || comparePrefix(sorted[i - 1], p) !== 0);
65164
+ }
65143
65165
  function writePrefixes(w, items) {
65144
65166
  if (items.length > LIMITS.VEC)
65145
65167
  throw new MeshCodecError("too-long", `routes ${items.length}`);
@@ -65187,6 +65209,26 @@ function isValidMeshRange(p) {
65187
65209
  return (p.addr[0] & 254) === 252;
65188
65210
  return false;
65189
65211
  }
65212
+ function prefixContainsAddr(p, addr) {
65213
+ if (addr.length !== widthOf(p.afi))
65214
+ return false;
65215
+ let bits = p.len;
65216
+ for (let i = 0; i < addr.length && bits > 0; i++) {
65217
+ const keep = Math.min(8, bits);
65218
+ const m = keep === 8 ? 255 : 255 << 8 - keep & 255;
65219
+ if ((addr[i] & m) !== (p.addr[i] & m))
65220
+ return false;
65221
+ bits -= keep;
65222
+ }
65223
+ return true;
65224
+ }
65225
+ function prefixContains(outer, inner) {
65226
+ if (outer.afi !== inner.afi)
65227
+ return false;
65228
+ if (inner.len < outer.len)
65229
+ return false;
65230
+ return prefixContainsAddr(outer, inner.addr);
65231
+ }
65190
65232
  function formatPrefix(p) {
65191
65233
  return `${formatAddr(p.afi, p.addr)}/${p.len}`;
65192
65234
  }
@@ -65233,7 +65275,71 @@ function formatAddr(afi, addr) {
65233
65275
  s = s + ":";
65234
65276
  return s;
65235
65277
  }
65236
- var AFI_V4, AFI_V6, widthOf, maxLenOf, MIN_MESH_PREFIX_LEN;
65278
+ function parsePrefix(text9) {
65279
+ const slash = text9.lastIndexOf("/");
65280
+ if (slash < 0)
65281
+ throw new MeshCodecError("bad-value", `missing / in ${text9}`);
65282
+ const host = text9.slice(0, slash);
65283
+ const lenStr = text9.slice(slash + 1);
65284
+ if (!/^\d{1,3}$/.test(lenStr))
65285
+ throw new MeshCodecError("bad-value", `prefix len ${lenStr}`);
65286
+ const len = Number(lenStr);
65287
+ const { afi, addr } = parseAddr(host);
65288
+ if (len > maxLenOf(afi))
65289
+ throw new MeshCodecError("bad-value", `len ${len} for v${afi}`);
65290
+ return makePrefix(afi, mask(addr, len), len);
65291
+ }
65292
+ function parseAddr(text9) {
65293
+ if (text9.includes(":"))
65294
+ return { afi: AFI_V6, addr: parseV6(text9) };
65295
+ return { afi: AFI_V4, addr: parseV4(text9) };
65296
+ }
65297
+ function parseV4(text9) {
65298
+ const parts = text9.split(".");
65299
+ if (parts.length !== 4)
65300
+ throw new MeshCodecError("bad-value", `bad IPv4 ${text9}`);
65301
+ const out = new Uint8Array(4);
65302
+ for (let i = 0; i < 4; i++) {
65303
+ if (!/^(0|[1-9]\d{0,2})$/.test(parts[i]))
65304
+ throw new MeshCodecError("bad-value", `bad IPv4 octet ${parts[i]}`);
65305
+ const v = Number(parts[i]);
65306
+ if (v > 255)
65307
+ throw new MeshCodecError("bad-value", `bad IPv4 octet ${parts[i]}`);
65308
+ out[i] = v;
65309
+ }
65310
+ return out;
65311
+ }
65312
+ function parseV6(text9) {
65313
+ if (text9.includes("::")) {
65314
+ const halves = text9.split("::");
65315
+ if (halves.length !== 2)
65316
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text9}`);
65317
+ const head = halves[0] ? halves[0].split(":") : [];
65318
+ const tail3 = halves[1] ? halves[1].split(":") : [];
65319
+ if (head.length + tail3.length > 7)
65320
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text9}`);
65321
+ const zeros = new Array(8 - head.length - tail3.length).fill("0");
65322
+ return groupsToBytes([...head, ...zeros, ...tail3], text9);
65323
+ }
65324
+ const g = text9.split(":");
65325
+ if (g.length !== 8)
65326
+ throw new MeshCodecError("bad-value", `bad IPv6 ${text9}`);
65327
+ return groupsToBytes(g, text9);
65328
+ }
65329
+ function groupsToBytes(groups, orig) {
65330
+ if (groups.length !== 8)
65331
+ throw new MeshCodecError("bad-value", `bad IPv6 ${orig}`);
65332
+ const out = new Uint8Array(16);
65333
+ for (let i = 0; i < 8; i++) {
65334
+ if (!/^[0-9a-fA-F]{1,4}$/.test(groups[i]))
65335
+ throw new MeshCodecError("bad-value", `bad IPv6 group ${groups[i]}`);
65336
+ const v = parseInt(groups[i], 16);
65337
+ out[i * 2] = v >>> 8 & 255;
65338
+ out[i * 2 + 1] = v & 255;
65339
+ }
65340
+ return out;
65341
+ }
65342
+ var AFI_V4, AFI_V6, widthOf, maxLenOf, prefixEqual, MIN_MESH_PREFIX_LEN;
65237
65343
  var init_prefix = __esm({
65238
65344
  "../../packages/mesh-pki/dist/prefix.js"() {
65239
65345
  "use strict";
@@ -65242,19 +65348,144 @@ var init_prefix = __esm({
65242
65348
  AFI_V6 = 6;
65243
65349
  widthOf = (afi) => afi === AFI_V4 ? 4 : 16;
65244
65350
  maxLenOf = (afi) => afi === AFI_V4 ? 32 : 128;
65351
+ prefixEqual = (a, b) => comparePrefix(a, b) === 0;
65245
65352
  MIN_MESH_PREFIX_LEN = 8;
65246
65353
  }
65247
65354
  });
65248
65355
 
65356
+ // ../../node_modules/@noble/hashes/esm/blake2s.js
65357
+ function G1s(a, b, c, d, x) {
65358
+ a = a + b + x | 0;
65359
+ d = rotr(d ^ a, 16);
65360
+ c = c + d | 0;
65361
+ b = rotr(b ^ c, 12);
65362
+ return { a, b, c, d };
65363
+ }
65364
+ function G2s(a, b, c, d, x) {
65365
+ a = a + b + x | 0;
65366
+ d = rotr(d ^ a, 8);
65367
+ c = c + d | 0;
65368
+ b = rotr(b ^ c, 7);
65369
+ return { a, b, c, d };
65370
+ }
65371
+ function compress(s, offset, msg, rounds, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) {
65372
+ let j = 0;
65373
+ for (let i = 0; i < rounds; i++) {
65374
+ ({ a: v0, b: v4, c: v8, d: v12 } = G1s(v0, v4, v8, v12, msg[offset + s[j++]]));
65375
+ ({ a: v0, b: v4, c: v8, d: v12 } = G2s(v0, v4, v8, v12, msg[offset + s[j++]]));
65376
+ ({ a: v1, b: v5, c: v9, d: v13 } = G1s(v1, v5, v9, v13, msg[offset + s[j++]]));
65377
+ ({ a: v1, b: v5, c: v9, d: v13 } = G2s(v1, v5, v9, v13, msg[offset + s[j++]]));
65378
+ ({ a: v2, b: v6, c: v10, d: v14 } = G1s(v2, v6, v10, v14, msg[offset + s[j++]]));
65379
+ ({ a: v2, b: v6, c: v10, d: v14 } = G2s(v2, v6, v10, v14, msg[offset + s[j++]]));
65380
+ ({ a: v3, b: v7, c: v11, d: v15 } = G1s(v3, v7, v11, v15, msg[offset + s[j++]]));
65381
+ ({ a: v3, b: v7, c: v11, d: v15 } = G2s(v3, v7, v11, v15, msg[offset + s[j++]]));
65382
+ ({ a: v0, b: v5, c: v10, d: v15 } = G1s(v0, v5, v10, v15, msg[offset + s[j++]]));
65383
+ ({ a: v0, b: v5, c: v10, d: v15 } = G2s(v0, v5, v10, v15, msg[offset + s[j++]]));
65384
+ ({ a: v1, b: v6, c: v11, d: v12 } = G1s(v1, v6, v11, v12, msg[offset + s[j++]]));
65385
+ ({ a: v1, b: v6, c: v11, d: v12 } = G2s(v1, v6, v11, v12, msg[offset + s[j++]]));
65386
+ ({ a: v2, b: v7, c: v8, d: v13 } = G1s(v2, v7, v8, v13, msg[offset + s[j++]]));
65387
+ ({ a: v2, b: v7, c: v8, d: v13 } = G2s(v2, v7, v8, v13, msg[offset + s[j++]]));
65388
+ ({ a: v3, b: v4, c: v9, d: v14 } = G1s(v3, v4, v9, v14, msg[offset + s[j++]]));
65389
+ ({ a: v3, b: v4, c: v9, d: v14 } = G2s(v3, v4, v9, v14, msg[offset + s[j++]]));
65390
+ }
65391
+ return { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 };
65392
+ }
65393
+ var B2S_IV, BLAKE2s, blake2s;
65394
+ var init_blake2s = __esm({
65395
+ "../../node_modules/@noble/hashes/esm/blake2s.js"() {
65396
+ init_blake();
65397
+ init_u64();
65398
+ init_utils();
65399
+ B2S_IV = /* @__PURE__ */ new Uint32Array([
65400
+ 1779033703,
65401
+ 3144134277,
65402
+ 1013904242,
65403
+ 2773480762,
65404
+ 1359893119,
65405
+ 2600822924,
65406
+ 528734635,
65407
+ 1541459225
65408
+ ]);
65409
+ BLAKE2s = class extends BLAKE {
65410
+ constructor(opts = {}) {
65411
+ super(64, opts.dkLen === void 0 ? 32 : opts.dkLen, opts, 32, 8, 8);
65412
+ this.v0 = B2S_IV[0] | 0;
65413
+ this.v1 = B2S_IV[1] | 0;
65414
+ this.v2 = B2S_IV[2] | 0;
65415
+ this.v3 = B2S_IV[3] | 0;
65416
+ this.v4 = B2S_IV[4] | 0;
65417
+ this.v5 = B2S_IV[5] | 0;
65418
+ this.v6 = B2S_IV[6] | 0;
65419
+ this.v7 = B2S_IV[7] | 0;
65420
+ const keyLength = opts.key ? opts.key.length : 0;
65421
+ this.v0 ^= this.outputLen | keyLength << 8 | 1 << 16 | 1 << 24;
65422
+ if (opts.salt) {
65423
+ const salt = u32(toBytes(opts.salt));
65424
+ this.v4 ^= byteSwapIfBE(salt[0]);
65425
+ this.v5 ^= byteSwapIfBE(salt[1]);
65426
+ }
65427
+ if (opts.personalization) {
65428
+ const pers = u32(toBytes(opts.personalization));
65429
+ this.v6 ^= byteSwapIfBE(pers[0]);
65430
+ this.v7 ^= byteSwapIfBE(pers[1]);
65431
+ }
65432
+ if (opts.key) {
65433
+ const tmp = new Uint8Array(this.blockLen);
65434
+ tmp.set(toBytes(opts.key));
65435
+ this.update(tmp);
65436
+ }
65437
+ }
65438
+ get() {
65439
+ const { v0, v1, v2, v3, v4, v5, v6, v7 } = this;
65440
+ return [v0, v1, v2, v3, v4, v5, v6, v7];
65441
+ }
65442
+ // prettier-ignore
65443
+ set(v0, v1, v2, v3, v4, v5, v6, v7) {
65444
+ this.v0 = v0 | 0;
65445
+ this.v1 = v1 | 0;
65446
+ this.v2 = v2 | 0;
65447
+ this.v3 = v3 | 0;
65448
+ this.v4 = v4 | 0;
65449
+ this.v5 = v5 | 0;
65450
+ this.v6 = v6 | 0;
65451
+ this.v7 = v7 | 0;
65452
+ }
65453
+ compress(msg, offset, isLast) {
65454
+ const { h, l } = fromBig(BigInt(this.length));
65455
+ const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(SIGMA, offset, msg, 10, this.v0, this.v1, this.v2, this.v3, this.v4, this.v5, this.v6, this.v7, B2S_IV[0], B2S_IV[1], B2S_IV[2], B2S_IV[3], l ^ B2S_IV[4], h ^ B2S_IV[5], isLast ? ~B2S_IV[6] : B2S_IV[6], B2S_IV[7]);
65456
+ this.v0 ^= v0 ^ v8;
65457
+ this.v1 ^= v1 ^ v9;
65458
+ this.v2 ^= v2 ^ v10;
65459
+ this.v3 ^= v3 ^ v11;
65460
+ this.v4 ^= v4 ^ v12;
65461
+ this.v5 ^= v5 ^ v13;
65462
+ this.v6 ^= v6 ^ v14;
65463
+ this.v7 ^= v7 ^ v15;
65464
+ }
65465
+ destroy() {
65466
+ this.destroyed = true;
65467
+ this.buffer32.fill(0);
65468
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
65469
+ }
65470
+ };
65471
+ blake2s = /* @__PURE__ */ wrapConstructorWithOpts((opts) => new BLAKE2s(opts));
65472
+ }
65473
+ });
65474
+
65249
65475
  // ../../packages/mesh-pki/dist/crypto.js
65250
- function randomBytes9(n) {
65476
+ function randomBytes7(n) {
65251
65477
  return globalThis.crypto.getRandomValues(new Uint8Array(n));
65252
65478
  }
65253
65479
  async function generateSigningKey(extractable = true) {
65254
- const kp = await subtle4.generateKey(ED25519, extractable, ["sign", "verify"]);
65255
- const publicRaw = new Uint8Array(await subtle4.exportKey("raw", kp.publicKey));
65480
+ const kp = await subtle3.generateKey(ED25519, extractable, ["sign", "verify"]);
65481
+ const publicRaw = new Uint8Array(await subtle3.exportKey("raw", kp.publicKey));
65256
65482
  return { privateKey: kp.privateKey, publicRaw };
65257
65483
  }
65484
+ async function importSigningPublic(raw) {
65485
+ if (raw.length !== 32)
65486
+ throw new Error(`Ed25519 public key must be 32 bytes, got ${raw.length}`);
65487
+ return subtle3.importKey("raw", bs3(raw), ED25519, true, ["verify"]);
65488
+ }
65258
65489
  async function signingKeyFromSeed(seed) {
65259
65490
  if (seed.length !== 32)
65260
65491
  throw new Error(`Ed25519 seed must be 32 bytes, got ${seed.length}`);
@@ -65277,14 +65508,14 @@ async function signingKeyFromSeed(seed) {
65277
65508
  32
65278
65509
  ]);
65279
65510
  const pkcs8 = concat2(prefix, seed);
65280
- const privateKey = await subtle4.importKey("pkcs8", bs4(pkcs8), ED25519, true, ["sign"]);
65281
- const jwk = await subtle4.exportKey("jwk", privateKey);
65511
+ const privateKey = await subtle3.importKey("pkcs8", bs3(pkcs8), ED25519, true, ["sign"]);
65512
+ const jwk = await subtle3.exportKey("jwk", privateKey);
65282
65513
  if (typeof jwk.x !== "string")
65283
65514
  throw new Error("Ed25519 JWK missing x");
65284
65515
  return { privateKey, publicRaw: unb64u2(jwk.x) };
65285
65516
  }
65286
65517
  async function exportStaticPrivate(kp) {
65287
- const jwk = await subtle4.exportKey("jwk", kp.privateKey);
65518
+ const jwk = await subtle3.exportKey("jwk", kp.privateKey);
65288
65519
  if (typeof jwk.d !== "string")
65289
65520
  throw new Error("X25519 JWK missing d");
65290
65521
  const raw = unb64u2(jwk.d);
@@ -65292,16 +65523,44 @@ async function exportStaticPrivate(kp) {
65292
65523
  throw new Error(`X25519 private key must be 32 bytes, got ${raw.length}`);
65293
65524
  return raw;
65294
65525
  }
65526
+ async function exportSigningPrivate(kp) {
65527
+ return subtle3.exportKey("jwk", kp.privateKey);
65528
+ }
65529
+ async function importSigningPrivate(jwk) {
65530
+ const privateKey = await subtle3.importKey("jwk", jwk, ED25519, true, ["sign"]);
65531
+ if (typeof jwk.x !== "string")
65532
+ throw new Error("Ed25519 JWK missing x");
65533
+ return { privateKey, publicRaw: unb64u2(jwk.x) };
65534
+ }
65295
65535
  async function sign2(privateKey, message) {
65296
- return new Uint8Array(await subtle4.sign(ED25519, privateKey, bs4(message)));
65536
+ return new Uint8Array(await subtle3.sign(ED25519, privateKey, bs3(message)));
65537
+ }
65538
+ async function verify2(publicRaw, message, sig) {
65539
+ if (sig.length !== 64 || publicRaw.length !== 32)
65540
+ return false;
65541
+ try {
65542
+ const key2 = await importSigningPublic(publicRaw);
65543
+ return await subtle3.verify(ED25519, key2, bs3(sig), bs3(message));
65544
+ } catch {
65545
+ return false;
65546
+ }
65297
65547
  }
65298
65548
  async function generateStaticKey(extractable = true) {
65299
- const kp = await subtle4.generateKey(X25519, extractable, ["deriveBits"]);
65300
- const publicRaw = new Uint8Array(await subtle4.exportKey("raw", kp.publicKey));
65549
+ const kp = await subtle3.generateKey(X25519, extractable, ["deriveBits"]);
65550
+ const publicRaw = new Uint8Array(await subtle3.exportKey("raw", kp.publicKey));
65301
65551
  return { privateKey: kp.privateKey, publicRaw };
65302
65552
  }
65303
65553
  async function sha2562(bytes2) {
65304
- return new Uint8Array(await subtle4.digest("SHA-256", bs4(bytes2)));
65554
+ return new Uint8Array(await subtle3.digest("SHA-256", bs3(bytes2)));
65555
+ }
65556
+ function blake2s256(bytes2) {
65557
+ return blake2s(bytes2, { dkLen: 32 });
65558
+ }
65559
+ function b64u2(bytes2) {
65560
+ let s = "";
65561
+ for (const b of bytes2)
65562
+ s += String.fromCharCode(b);
65563
+ return btoa(s).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
65305
65564
  }
65306
65565
  function unb64u2(s) {
65307
65566
  const pad2 = s.length % 4 === 0 ? "" : "=".repeat(4 - s.length % 4);
@@ -65314,7 +65573,7 @@ function unb64u2(s) {
65314
65573
  function hex3(bytes2) {
65315
65574
  return Array.from(bytes2, (b) => b.toString(16).padStart(2, "0")).join("");
65316
65575
  }
65317
- function utf83(s) {
65576
+ function utf82(s) {
65318
65577
  return new TextEncoder().encode(s);
65319
65578
  }
65320
65579
  function concat2(...parts) {
@@ -65327,12 +65586,21 @@ function concat2(...parts) {
65327
65586
  }
65328
65587
  return out;
65329
65588
  }
65330
- var subtle4, bs4, ED25519, X25519;
65589
+ function bytesEqual(a, b) {
65590
+ if (a.length !== b.length)
65591
+ return false;
65592
+ let diff = 0;
65593
+ for (let i = 0; i < a.length; i++)
65594
+ diff |= a[i] ^ b[i];
65595
+ return diff === 0;
65596
+ }
65597
+ var subtle3, bs3, ED25519, X25519;
65331
65598
  var init_crypto = __esm({
65332
65599
  "../../packages/mesh-pki/dist/crypto.js"() {
65333
65600
  "use strict";
65334
- subtle4 = globalThis.crypto.subtle;
65335
- bs4 = (b) => b;
65601
+ init_blake2s();
65602
+ subtle3 = globalThis.crypto.subtle;
65603
+ bs3 = (b) => b;
65336
65604
  ED25519 = "Ed25519";
65337
65605
  X25519 = "X25519";
65338
65606
  }
@@ -65417,9 +65685,55 @@ function readGenesisBody(r) {
65417
65685
  validateGenesis(g);
65418
65686
  return g;
65419
65687
  }
65688
+ function encodeSignedGenesis(sg) {
65689
+ const body = encodeGenesis(sg.block);
65690
+ const w = new Writer();
65691
+ w.bytes(body, LIMITS.GENESIS);
65692
+ w.vec(sg.sigs, (ww, s) => {
65693
+ ww.u8(s.keyIndex).fixed(s.sig, 64);
65694
+ });
65695
+ return w.finish();
65696
+ }
65697
+ function decodeSignedGenesis(bytes2) {
65698
+ const r = new Reader(bytes2);
65699
+ const body = r.bytes(LIMITS.GENESIS);
65700
+ const sigs = r.vec((rr) => ({ keyIndex: rr.u8(), sig: rr.fixed(64) }));
65701
+ r.finish();
65702
+ return { block: decodeGenesis(body), sigs };
65703
+ }
65420
65704
  async function genesisFingerprint(g) {
65421
65705
  return sha2562(encodeGenesis(g));
65422
65706
  }
65707
+ function fingerprintShort(fp, groups = 12) {
65708
+ const h = hex3(fp.subarray(0, Math.min(fp.length, groups * 2)));
65709
+ return (h.match(/.{1,4}/g) ?? []).join(" ");
65710
+ }
65711
+ async function signGenesis(block2, signers) {
65712
+ const body = encodeGenesis(block2);
65713
+ const sigs = [];
65714
+ for (const s of [...signers].sort((a, b) => a.keyIndex - b.keyIndex)) {
65715
+ if (s.keyIndex < 0 || s.keyIndex >= block2.caKeys.length) {
65716
+ throw new MeshCodecError("bad-value", `signer index ${s.keyIndex}`);
65717
+ }
65718
+ sigs.push({ keyIndex: s.keyIndex, sig: await sign2(s.privateKey, body) });
65719
+ }
65720
+ return { block: block2, sigs };
65721
+ }
65722
+ async function verifyGenesis(sg) {
65723
+ const { block: block2, sigs } = sg;
65724
+ const body = encodeGenesis(block2);
65725
+ const seen = /* @__PURE__ */ new Set();
65726
+ for (const s of sigs) {
65727
+ if (s.keyIndex >= block2.caKeys.length)
65728
+ return false;
65729
+ if (seen.has(s.keyIndex))
65730
+ return false;
65731
+ if (!await verify2(block2.caKeys[s.keyIndex], body, s.sig))
65732
+ return false;
65733
+ seen.add(s.keyIndex);
65734
+ }
65735
+ return seen.size >= block2.kCa;
65736
+ }
65423
65737
  async function deriveMeshPrefix6(orgId) {
65424
65738
  const h = await sha2562(new TextEncoder().encode(orgId));
65425
65739
  const out = new Uint8Array(6);
@@ -65562,6 +65876,9 @@ function decodeCert(bytes2) {
65562
65876
  r.finish();
65563
65877
  return { details: decodeDetails(body), sigs };
65564
65878
  }
65879
+ async function certFingerprint(d) {
65880
+ return sha2562(encodeDetails(d));
65881
+ }
65565
65882
  async function issueCert(details, signers) {
65566
65883
  const body = encodeDetails(details);
65567
65884
  const sigs = [];
@@ -65570,7 +65887,115 @@ async function issueCert(details, signers) {
65570
65887
  }
65571
65888
  return { details, sigs };
65572
65889
  }
65573
- var TNC_VERSION, FLAG_IS_CA, FLAG_IS_EXIT_NODE, FLAG_IS_RELAY, FLAG_IS_EPHEMERAL, KNOWN_FLAGS, NAME_RE, ZERO16;
65890
+ async function verifyCert(leaf, genesis, opts) {
65891
+ const genFp = await genesisFingerprint(genesis);
65892
+ const byFp = /* @__PURE__ */ new Map();
65893
+ for (const c of opts.intermediates ?? []) {
65894
+ byFp.set(hexKey(await certFingerprint(c.details)), c);
65895
+ }
65896
+ let cur = leaf;
65897
+ let depth = 0;
65898
+ const seen = /* @__PURE__ */ new Set();
65899
+ for (; ; ) {
65900
+ const d = cur.details;
65901
+ if (d.version !== TNC_VERSION)
65902
+ return no("bad-version");
65903
+ if (!bytesEqual(d.genesisFp, genFp))
65904
+ return no("wrong-mesh");
65905
+ if (!opts.ignoreTime) {
65906
+ if (opts.now + CLOCK_SKEW_MS < d.notBefore)
65907
+ return no("not-yet-valid");
65908
+ if (opts.now - CLOCK_SKEW_MS > d.notAfter)
65909
+ return no("expired");
65910
+ }
65911
+ if (opts.revokedSerials?.some((s) => bytesEqual(s, d.serial)))
65912
+ return no("revoked", "serial");
65913
+ if (opts.revokedStatics?.some((s) => bytesEqual(s, d.staticPub)))
65914
+ return no("revoked", "staticPub");
65915
+ const selfFp = await certFingerprint(d);
65916
+ const selfKey = hexKey(selfFp);
65917
+ if (seen.has(selfKey))
65918
+ return no("chain-cycle");
65919
+ seen.add(selfKey);
65920
+ const body = encodeDetails(d);
65921
+ if (bytesEqual(d.issuerFp, genFp)) {
65922
+ const q2 = await checkQuorum(body, cur.sigs, genesis.caKeys, genesis.kCa);
65923
+ if (q2 !== "ok")
65924
+ return no(q2);
65925
+ return { ok: true, details: leaf.details, chainDepth: depth };
65926
+ }
65927
+ const parent = byFp.get(hexKey(d.issuerFp));
65928
+ if (!parent)
65929
+ return no("unknown-issuer");
65930
+ if (!isCa(parent.details))
65931
+ return no("issuer-not-ca");
65932
+ const q = await checkQuorum(body, cur.sigs, [parent.details.sigPub], 1);
65933
+ if (q !== "ok")
65934
+ return no(q);
65935
+ const narrow = checkNarrowing(parent.details, d);
65936
+ if (narrow)
65937
+ return no(narrow);
65938
+ depth++;
65939
+ if (depth >= MAX_CHAIN_DEPTH)
65940
+ return no("chain-too-deep");
65941
+ cur = parent;
65942
+ }
65943
+ }
65944
+ function no(reason, detail) {
65945
+ return { ok: false, reason, detail };
65946
+ }
65947
+ async function checkQuorum(body, sigs, keys, threshold) {
65948
+ const seen = /* @__PURE__ */ new Set();
65949
+ for (const s of sigs) {
65950
+ if (s.keyIndex >= keys.length)
65951
+ return "bad-signature";
65952
+ if (seen.has(s.keyIndex))
65953
+ return "bad-signature";
65954
+ if (!await verify2(keys[s.keyIndex], body, s.sig))
65955
+ return "bad-signature";
65956
+ seen.add(s.keyIndex);
65957
+ }
65958
+ return seen.size >= threshold ? "ok" : "quorum-not-met";
65959
+ }
65960
+ function checkNarrowing(parent, child) {
65961
+ const parentGroups = new Set(parent.groups);
65962
+ for (const g of child.groups) {
65963
+ if (!parentGroups.has(g))
65964
+ return "narrowing-groups";
65965
+ }
65966
+ for (const r of child.routes) {
65967
+ if (!parent.routes.some((p) => prefixContains(p, r)))
65968
+ return "narrowing-routes";
65969
+ }
65970
+ if (child.notAfter > parent.notAfter)
65971
+ return "narrowing-expiry";
65972
+ if (parent.overlayIp4 !== 0 && child.overlayIp4 !== parent.overlayIp4)
65973
+ return "narrowing-address";
65974
+ if (hasV6(parent) && !bytesEqual(child.overlayIp6, parent.overlayIp6))
65975
+ return "narrowing-address";
65976
+ const widened = child.flags & ~parent.flags & (FLAG_IS_EXIT_NODE | FLAG_IS_RELAY);
65977
+ if (widened !== 0)
65978
+ return "narrowing-address";
65979
+ return null;
65980
+ }
65981
+ function maySourceAddr(d, afi, src) {
65982
+ if (afi === AFI_V4) {
65983
+ if (src.length !== 4)
65984
+ return false;
65985
+ const asU32 = (src[0] << 24 >>> 0) + (src[1] << 16) + (src[2] << 8) + src[3];
65986
+ if (d.overlayIp4 !== 0 && asU32 === d.overlayIp4)
65987
+ return true;
65988
+ } else if (afi === AFI_V6) {
65989
+ if (src.length !== 16)
65990
+ return false;
65991
+ if (hasV6(d) && bytesEqual(src, d.overlayIp6))
65992
+ return true;
65993
+ } else {
65994
+ return false;
65995
+ }
65996
+ return d.routes.some((p) => p.afi === afi && prefixContainsAddr(p, src));
65997
+ }
65998
+ var TNC_VERSION, FLAG_IS_CA, FLAG_IS_EXIT_NODE, FLAG_IS_RELAY, FLAG_IS_EPHEMERAL, KNOWN_FLAGS, CLOCK_SKEW_MS, MAX_CHAIN_DEPTH, NAME_RE, isCa, isExitNode, isRelay, ZERO16, hasV6, hexKey;
65574
65999
  var init_cert = __esm({
65575
66000
  "../../packages/mesh-pki/dist/cert.js"() {
65576
66001
  "use strict";
@@ -65584,12 +66009,56 @@ var init_cert = __esm({
65584
66009
  FLAG_IS_RELAY = 1 << 2;
65585
66010
  FLAG_IS_EPHEMERAL = 1 << 3;
65586
66011
  KNOWN_FLAGS = FLAG_IS_CA | FLAG_IS_EXIT_NODE | FLAG_IS_RELAY | FLAG_IS_EPHEMERAL;
66012
+ CLOCK_SKEW_MS = 12e4;
66013
+ MAX_CHAIN_DEPTH = 4;
65587
66014
  NAME_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
66015
+ isCa = (d) => (d.flags & FLAG_IS_CA) !== 0;
66016
+ isExitNode = (d) => (d.flags & FLAG_IS_EXIT_NODE) !== 0;
66017
+ isRelay = (d) => (d.flags & FLAG_IS_RELAY) !== 0;
65588
66018
  ZERO16 = new Uint8Array(16);
66019
+ hasV6 = (d) => !bytesEqual(d.overlayIp6, ZERO16);
66020
+ hexKey = (b) => Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
65589
66021
  }
65590
66022
  });
65591
66023
 
65592
66024
  // ../../packages/mesh-pki/dist/addr.js
66025
+ function deriveOverlayV6(meshPrefix6, genesisFp, staticPub) {
66026
+ if (meshPrefix6.length !== 6)
66027
+ throw new MeshCodecError("bad-value", "meshPrefix6 must be 6 bytes");
66028
+ if (genesisFp.length !== 32)
66029
+ throw new MeshCodecError("bad-value", "genesisFp must be 32 bytes");
66030
+ if (staticPub.length !== 32)
66031
+ throw new MeshCodecError("bad-value", "staticPub must be 32 bytes");
66032
+ const iid = blake2s256(concat2(CTX_V6, genesisFp, staticPub));
66033
+ const out = new Uint8Array(16);
66034
+ out.set(meshPrefix6, 0);
66035
+ out.set(iid.subarray(0, 10), 6);
66036
+ return out;
66037
+ }
66038
+ function deriveOverlayV4Hint(cidr, genesisFp, staticPub) {
66039
+ if (cidr.afi !== AFI_V4)
66040
+ throw new MeshCodecError("bad-value", "cidr must be IPv4");
66041
+ const hostBits = maxLenOf(AFI_V4) - cidr.len;
66042
+ if (hostBits < 2)
66043
+ throw new MeshCodecError("bad-value", `mesh cidr /${cidr.len} too small`);
66044
+ const h = blake2s256(concat2(CTX_V4, genesisFp, staticPub));
66045
+ const raw = (h[0] << 24 >>> 0) + (h[1] << 16) + (h[2] << 8) + h[3];
66046
+ const span = hostBits >= 32 ? 4294967296 : 2 ** hostBits;
66047
+ const host = raw % (span - 2) + 1;
66048
+ const base = (cidr.addr[0] << 24 >>> 0) + (cidr.addr[1] << 16) + (cidr.addr[2] << 8) + cidr.addr[3];
66049
+ return base + host >>> 0;
66050
+ }
66051
+ function u32ToAddr(v) {
66052
+ return new Uint8Array([v >>> 24 & 255, v >>> 16 & 255, v >>> 8 & 255, v & 255]);
66053
+ }
66054
+ function addrToU32(a) {
66055
+ if (a.length !== 4)
66056
+ throw new MeshCodecError("bad-value", "IPv4 must be 4 bytes");
66057
+ return (a[0] << 24 >>> 0) + (a[1] << 16) + (a[2] << 8) + a[3] >>> 0;
66058
+ }
66059
+ function meshFqdn(name, orgSlug) {
66060
+ return `${name}.${orgSlug}.tsr.internal`;
66061
+ }
65593
66062
  var CTX_V6, CTX_V4;
65594
66063
  var init_addr = __esm({
65595
66064
  "../../packages/mesh-pki/dist/addr.js"() {
@@ -65597,12 +66066,41 @@ var init_addr = __esm({
65597
66066
  init_crypto();
65598
66067
  init_prefix();
65599
66068
  init_codec();
65600
- CTX_V6 = utf83("tsr-addr6-v1");
65601
- CTX_V4 = utf83("tsr-addr4-v1");
66069
+ CTX_V6 = utf82("tsr-addr6-v1");
66070
+ CTX_V4 = utf82("tsr-addr4-v1");
65602
66071
  }
65603
66072
  });
65604
66073
 
65605
66074
  // ../../packages/mesh-pki/dist/policy.js
66075
+ function canonicalGroups(indices) {
66076
+ return [...new Set(indices)].sort((a, b) => a - b);
66077
+ }
66078
+ function canonicalPorts(ranges) {
66079
+ const sorted = [...ranges].sort((a, b) => a.lo - b.lo || a.hi - b.hi);
66080
+ for (let i = 0; i < sorted.length; i++) {
66081
+ const r = sorted[i];
66082
+ if (!Number.isInteger(r.lo) || !Number.isInteger(r.hi) || r.lo < 0 || r.hi > 65535 || r.lo > r.hi) {
66083
+ throw new MeshCodecError("bad-value", `port range ${r.lo}-${r.hi}`);
66084
+ }
66085
+ if (i > 0 && r.lo <= sorted[i - 1].hi) {
66086
+ throw new MeshCodecError("bad-value", `overlapping port ranges ${sorted[i - 1].lo}-${sorted[i - 1].hi} / ${r.lo}-${r.hi}`);
66087
+ }
66088
+ }
66089
+ return sorted;
66090
+ }
66091
+ function makeRule(r = {}) {
66092
+ const rule = {
66093
+ action: r.action ?? ACTION_ACCEPT,
66094
+ proto: r.proto ?? PROTO_ANY,
66095
+ srcGroups: canonicalGroups(r.srcGroups ?? []),
66096
+ srcCidrs: canonicalPrefixes(r.srcCidrs ?? []),
66097
+ dstCidrs: canonicalPrefixes(r.dstCidrs ?? []),
66098
+ ports: canonicalPorts(r.ports ?? []),
66099
+ caps: r.caps ?? 0
66100
+ };
66101
+ validateRule(rule);
66102
+ return rule;
66103
+ }
65606
66104
  function validateRule(r) {
65607
66105
  if (r.action !== ACTION_ACCEPT && r.action !== ACTION_DROP) {
65608
66106
  throw new MeshCodecError("bad-value", `action ${r.action}`);
@@ -65638,6 +66136,107 @@ function writeRule(w, r) {
65638
66136
  w.u16(p.lo).u16(p.hi);
65639
66137
  w.u32(r.caps);
65640
66138
  }
66139
+ function readRule(r) {
66140
+ const action = r.u8();
66141
+ const proto = r.u8();
66142
+ const nG = r.u16();
66143
+ if (nG > LIMITS.VEC)
66144
+ throw new MeshCodecError("too-long", "srcGroups");
66145
+ const srcGroups = [];
66146
+ for (let i = 0; i < nG; i++) {
66147
+ const g = r.u16();
66148
+ if (i > 0) {
66149
+ if (g === srcGroups[i - 1])
66150
+ throw new MeshCodecError("duplicate", "srcGroups");
66151
+ if (g < srcGroups[i - 1])
66152
+ throw new MeshCodecError("not-sorted", "srcGroups");
66153
+ }
66154
+ srcGroups.push(g);
66155
+ }
66156
+ const srcCidrs = readPrefixes(r);
66157
+ const dstCidrs = readPrefixes(r);
66158
+ const nP = r.u16();
66159
+ if (nP > LIMITS.VEC)
66160
+ throw new MeshCodecError("too-long", "ports");
66161
+ const ports = [];
66162
+ for (let i = 0; i < nP; i++) {
66163
+ const lo = r.u16();
66164
+ const hi = r.u16();
66165
+ if (lo > hi)
66166
+ throw new MeshCodecError("bad-value", `port range ${lo}-${hi}`);
66167
+ if (i > 0 && lo <= ports[i - 1].hi)
66168
+ throw new MeshCodecError("not-sorted", "ports");
66169
+ ports.push({ lo, hi });
66170
+ }
66171
+ const caps = r.u32();
66172
+ const rule = { action, proto, srcGroups, srcCidrs, dstCidrs, ports, caps };
66173
+ validateRule(rule);
66174
+ return rule;
66175
+ }
66176
+ function ruleMatches(r, peerGroups, q) {
66177
+ if (r.proto !== PROTO_ANY && r.proto !== q.proto)
66178
+ return false;
66179
+ if (r.srcGroups.length > 0 && !r.srcGroups.some((g) => peerGroups.has(g)))
66180
+ return false;
66181
+ if (r.srcCidrs.length > 0 && !r.srcCidrs.some((p) => p.afi === q.afi && prefixContainsAddr(p, q.src)))
66182
+ return false;
66183
+ if (r.dstCidrs.length > 0 && !r.dstCidrs.some((p) => p.afi === q.afi && prefixContainsAddr(p, q.dst)))
66184
+ return false;
66185
+ if (r.ports.length > 0) {
66186
+ if (!PORTED.has(q.proto))
66187
+ return false;
66188
+ const dp = q.dport;
66189
+ if (dp === void 0)
66190
+ return false;
66191
+ if (!r.ports.some((p) => dp >= p.lo && dp <= p.hi))
66192
+ return false;
66193
+ }
66194
+ return true;
66195
+ }
66196
+ function evaluate(rules, peerGroups, q) {
66197
+ for (let i = 0; i < rules.length; i++) {
66198
+ if (ruleMatches(rules[i], peerGroups, q)) {
66199
+ return {
66200
+ allowed: rules[i].action === ACTION_ACCEPT,
66201
+ caps: rules[i].action === ACTION_ACCEPT ? rules[i].caps : 0,
66202
+ ruleIndex: i
66203
+ };
66204
+ }
66205
+ }
66206
+ return { allowed: false, caps: 0, ruleIndex: -1 };
66207
+ }
66208
+ function compilePeerFilter(rules, peerGroups) {
66209
+ const live = rules.filter((r) => r.srcGroups.length === 0 || r.srcGroups.some((g) => peerGroups.has(g)));
66210
+ if (live.length === 0)
66211
+ return { kind: "deny-all" };
66212
+ const first = live[0];
66213
+ const unconditional = first.action === ACTION_ACCEPT && first.proto === PROTO_ANY && first.srcCidrs.length === 0 && first.dstCidrs.length === 0 && first.ports.length === 0;
66214
+ if (unconditional)
66215
+ return { kind: "allow-all", caps: first.caps };
66216
+ return { kind: "rules", rules: live };
66217
+ }
66218
+ function applyPeerFilter(f, peerGroups, q) {
66219
+ switch (f.kind) {
66220
+ case "deny-all":
66221
+ return { allowed: false, caps: 0 };
66222
+ case "allow-all":
66223
+ return { allowed: true, caps: f.caps };
66224
+ case "rules": {
66225
+ const r = evaluate(f.rules, peerGroups, q);
66226
+ return { allowed: r.allowed, caps: r.caps };
66227
+ }
66228
+ }
66229
+ }
66230
+ function resolveGroups(groupTable, certGroups) {
66231
+ const idx = new Map(groupTable.map((g, i) => [g, i]));
66232
+ const out = /* @__PURE__ */ new Set();
66233
+ for (const g of certGroups) {
66234
+ const i = idx.get(g);
66235
+ if (i !== void 0)
66236
+ out.add(i);
66237
+ }
66238
+ return out;
66239
+ }
65641
66240
  var ACTION_ACCEPT, ACTION_DROP, PROTO_ANY, PROTO_ICMP, PROTO_TCP, PROTO_UDP, PROTO_ICMPV6, KNOWN_PROTOS, PORTED, CAP_EXIT_NODE, CAP_USE_ROUTE, KNOWN_CAPS;
65642
66241
  var init_policy = __esm({
65643
66242
  "../../packages/mesh-pki/dist/policy.js"() {
@@ -65660,6 +66259,14 @@ var init_policy = __esm({
65660
66259
  });
65661
66260
 
65662
66261
  // ../../packages/mesh-pki/dist/bundle.js
66262
+ function sortedUniqueBytes(items, what) {
66263
+ const sorted = [...items].sort(cmpBytes);
66264
+ for (let i = 1; i < sorted.length; i++) {
66265
+ if (cmpBytes(sorted[i - 1], sorted[i]) === 0)
66266
+ throw new MeshCodecError("duplicate", what);
66267
+ }
66268
+ return sorted;
66269
+ }
65663
66270
  function validateBundle(b) {
65664
66271
  if (b.version !== TPB_VERSION)
65665
66272
  throw new MeshCodecError("bad-value", `bundle version ${b.version}`);
@@ -65735,6 +66342,101 @@ function writeRevocations(w, items, width) {
65735
66342
  for (const it of items)
65736
66343
  w.fixed(it, width);
65737
66344
  }
66345
+ function readRevocations(r, width) {
66346
+ const n = r.u16();
66347
+ if (n > LIMITS.REVOKED)
66348
+ throw new MeshCodecError("too-long", "revocations");
66349
+ const out = [];
66350
+ for (let i = 0; i < n; i++) {
66351
+ const v = r.fixed(width);
66352
+ if (i > 0) {
66353
+ const c = cmpBytes(out[i - 1], v);
66354
+ if (c === 0)
66355
+ throw new MeshCodecError("duplicate", "revocations");
66356
+ if (c > 0)
66357
+ throw new MeshCodecError("not-sorted", "revocations");
66358
+ }
66359
+ out.push(v);
66360
+ }
66361
+ return out;
66362
+ }
66363
+ function decodeBundle(bytes2) {
66364
+ if (bytes2.length > LIMITS.BUNDLE)
66365
+ throw new MeshCodecError("too-long", "bundle");
66366
+ const r = new Reader(bytes2);
66367
+ const version2 = r.u8();
66368
+ const genesisFp = r.fixed(32);
66369
+ const epoch2 = r.u64();
66370
+ const issuedAt = r.u64();
66371
+ const maxStaleness = r.u32();
66372
+ const nG = r.u16();
66373
+ if (nG > LIMITS.GROUPS)
66374
+ throw new MeshCodecError("too-long", "groupTable");
66375
+ const groupTable = [];
66376
+ for (let i = 0; i < nG; i++)
66377
+ groupTable.push(r.str());
66378
+ const nR = r.u16();
66379
+ if (nR > LIMITS.RULES)
66380
+ throw new MeshCodecError("too-long", "rules");
66381
+ const rules = [];
66382
+ for (let i = 0; i < nR; i++)
66383
+ rules.push(readRule(r));
66384
+ const nRo = r.u16();
66385
+ if (nRo > LIMITS.ROSTER)
66386
+ throw new MeshCodecError("too-long", "roster");
66387
+ const roster = [];
66388
+ for (let i = 0; i < nRo; i++) {
66389
+ const e = {
66390
+ nodeId: r.str(),
66391
+ name: r.str(),
66392
+ staticPub: r.fixed(32),
66393
+ certFp: r.fixed(32),
66394
+ ip4: r.u32(),
66395
+ ip6: r.fixed(16)
66396
+ };
66397
+ if (i > 0) {
66398
+ const c = cmpBytes(roster[i - 1].staticPub, e.staticPub);
66399
+ if (c === 0)
66400
+ throw new MeshCodecError("duplicate", "roster");
66401
+ if (c > 0)
66402
+ throw new MeshCodecError("not-sorted", "roster");
66403
+ }
66404
+ roster.push(e);
66405
+ }
66406
+ const revokedSerials = readRevocations(r, 16);
66407
+ const revokedStatics = readRevocations(r, 32);
66408
+ const nE = r.u16();
66409
+ if (nE > LIMITS.ROSTER)
66410
+ throw new MeshCodecError("too-long", "ip4Exceptions");
66411
+ const ip4Exceptions = [];
66412
+ for (let i = 0; i < nE; i++) {
66413
+ const e = { staticPub: r.fixed(32), ip4: r.u32() };
66414
+ if (i > 0) {
66415
+ const c = cmpBytes(ip4Exceptions[i - 1].staticPub, e.staticPub);
66416
+ if (c === 0)
66417
+ throw new MeshCodecError("duplicate", "ip4Exceptions");
66418
+ if (c > 0)
66419
+ throw new MeshCodecError("not-sorted", "ip4Exceptions");
66420
+ }
66421
+ ip4Exceptions.push(e);
66422
+ }
66423
+ r.finish();
66424
+ const b = {
66425
+ version: version2,
66426
+ genesisFp,
66427
+ epoch: epoch2,
66428
+ issuedAt,
66429
+ maxStaleness,
66430
+ groupTable,
66431
+ rules,
66432
+ roster,
66433
+ revokedSerials,
66434
+ revokedStatics,
66435
+ ip4Exceptions
66436
+ };
66437
+ validateBundle(b);
66438
+ return b;
66439
+ }
65738
66440
  function encodeSignedBundle(sb) {
65739
66441
  const body = encodeBundle(sb.bundle);
65740
66442
  const w = new Writer();
@@ -65744,6 +66446,13 @@ function encodeSignedBundle(sb) {
65744
66446
  });
65745
66447
  return w.finish();
65746
66448
  }
66449
+ function decodeSignedBundle(bytes2) {
66450
+ const r = new Reader(bytes2);
66451
+ const body = r.bytes(LIMITS.BUNDLE);
66452
+ const sigs = r.vec((rr) => ({ keyIndex: rr.u8(), sig: rr.fixed(64) }));
66453
+ r.finish();
66454
+ return { bundle: decodeBundle(body), sigs };
66455
+ }
65747
66456
  async function signBundle(bundle, signers) {
65748
66457
  const body = encodeBundle(bundle);
65749
66458
  const sigs = [];
@@ -65752,7 +66461,38 @@ async function signBundle(bundle, signers) {
65752
66461
  }
65753
66462
  return { bundle, sigs };
65754
66463
  }
65755
- var TPB_VERSION, DEFAULT_MAX_STALENESS_MS, cmpBytes;
66464
+ async function verifyBundle(sb, genesis, genesisFp, opts) {
66465
+ const b = sb.bundle;
66466
+ if (b.version !== TPB_VERSION)
66467
+ return { ok: false, reason: "bad-version" };
66468
+ if (!bytesEqual(b.genesisFp, genesisFp))
66469
+ return { ok: false, reason: "wrong-mesh" };
66470
+ if (opts.knownEpoch !== void 0 && b.epoch <= opts.knownEpoch) {
66471
+ return { ok: false, reason: "rollback" };
66472
+ }
66473
+ if (!opts.ignoreStaleness && opts.now - b.issuedAt > b.maxStaleness) {
66474
+ return { ok: false, reason: "stale" };
66475
+ }
66476
+ const body = encodeBundle(b);
66477
+ const seen = /* @__PURE__ */ new Set();
66478
+ for (const s of sb.sigs) {
66479
+ if (s.keyIndex >= genesis.polKeys.length)
66480
+ return { ok: false, reason: "bad-signature" };
66481
+ if (seen.has(s.keyIndex))
66482
+ return { ok: false, reason: "bad-signature" };
66483
+ if (!await verify2(genesis.polKeys[s.keyIndex], body, s.sig)) {
66484
+ return { ok: false, reason: "bad-signature" };
66485
+ }
66486
+ seen.add(s.keyIndex);
66487
+ }
66488
+ if (seen.size < genesis.kPol)
66489
+ return { ok: false, reason: "quorum-not-met" };
66490
+ return { ok: true };
66491
+ }
66492
+ async function bundleHash(b) {
66493
+ return sha2562(encodeBundle(b));
66494
+ }
66495
+ var TPB_VERSION, DEFAULT_MAX_STALENESS_MS, cmpBytes, canonicalRoster, canonicalExceptions, canonicalRevocations, isFresh, revokes;
65756
66496
  var init_bundle = __esm({
65757
66497
  "../../packages/mesh-pki/dist/bundle.js"() {
65758
66498
  "use strict";
@@ -65768,6 +66508,11 @@ var init_bundle = __esm({
65768
66508
  return a[i] < b[i] ? -1 : 1;
65769
66509
  return a.length === b.length ? 0 : a.length < b.length ? -1 : 1;
65770
66510
  };
66511
+ canonicalRoster = (r) => [...r].sort((a, b) => cmpBytes(a.staticPub, b.staticPub));
66512
+ canonicalExceptions = (e) => [...e].sort((a, b) => cmpBytes(a.staticPub, b.staticPub));
66513
+ canonicalRevocations = (r) => sortedUniqueBytes(r, "revocation");
66514
+ isFresh = (b, now2) => now2 - b.issuedAt <= b.maxStaleness;
66515
+ revokes = (b, serial, staticPub) => b.revokedSerials.some((s) => bytesEqual(s, serial)) || b.revokedStatics.some((s) => bytesEqual(s, staticPub));
65771
66516
  }
65772
66517
  });
65773
66518
 
@@ -67827,7 +68572,66 @@ zoo`.split("\n");
67827
68572
  });
67828
68573
 
67829
68574
  // ../../packages/mesh-pki/dist/sas.js
67830
- var WORD_BITS, WORD_MASK, CTX_ENROLL;
68575
+ function wordsFromDigest(digest, count = SAS_WORDS) {
68576
+ const bits = count * WORD_BITS;
68577
+ if (bits < SAS_MIN_BITS) {
68578
+ throw new MeshCodecError("bad-value", `${count} words = ${bits} bits, below the ${SAS_MIN_BITS}-bit floor`);
68579
+ }
68580
+ const needBytes = Math.ceil((bits + 7) / 8) + 1;
68581
+ if (digest.length < needBytes) {
68582
+ throw new MeshCodecError("bad-value", `digest too short: need ${needBytes}, got ${digest.length}`);
68583
+ }
68584
+ const out = [];
68585
+ for (let i = 0; i < count; i++) {
68586
+ const bitOffset = i * WORD_BITS;
68587
+ const byteIdx = bitOffset >>> 3;
68588
+ const bitInByte = bitOffset & 7;
68589
+ const chunk = (digest[byteIdx] << 16 | digest[byteIdx + 1] << 8 | digest[byteIdx + 2]) >>> 0;
68590
+ const idx = chunk >>> 24 - bitInByte - WORD_BITS & WORD_MASK;
68591
+ out.push(wordlist[idx]);
68592
+ }
68593
+ return out;
68594
+ }
68595
+ function enrolmentSas(genesisFp, staticPub, count = SAS_WORDS) {
68596
+ if (genesisFp.length !== 32)
68597
+ throw new MeshCodecError("bad-value", "genesisFp must be 32 bytes");
68598
+ if (staticPub.length !== 32)
68599
+ throw new MeshCodecError("bad-value", "staticPub must be 32 bytes");
68600
+ return wordsFromDigest(blake2s256(concat2(CTX_ENROLL, genesisFp, staticPub)), count);
68601
+ }
68602
+ function fingerprintWords(genesisFp, count = SAS_WORDS) {
68603
+ if (genesisFp.length !== 32)
68604
+ throw new MeshCodecError("bad-value", "genesisFp must be 32 bytes");
68605
+ return wordsFromDigest(genesisFp, count);
68606
+ }
68607
+ function nameWords(entropy, count = 2) {
68608
+ if (count < 1 || count > 8)
68609
+ throw new MeshCodecError("bad-value", `nameWords count ${count}`);
68610
+ if (entropy.length < count * 2) {
68611
+ throw new MeshCodecError("bad-value", "not enough entropy for that many words");
68612
+ }
68613
+ const out = [];
68614
+ for (let i = 0; i < count; i++) {
68615
+ const idx = (entropy[i * 2] << 8 | entropy[i * 2 + 1]) & 2047;
68616
+ out.push(wordlist[idx]);
68617
+ }
68618
+ return out;
68619
+ }
68620
+ function sasEqual(a, b) {
68621
+ if (a.length !== b.length)
68622
+ return false;
68623
+ let diff = 0;
68624
+ for (let i = 0; i < a.length; i++) {
68625
+ const x = a[i];
68626
+ const y = b[i];
68627
+ diff |= x.length ^ y.length;
68628
+ for (let j = 0; j < Math.max(x.length, y.length); j++) {
68629
+ diff |= (x.charCodeAt(j) | 0) ^ (y.charCodeAt(j) | 0);
68630
+ }
68631
+ }
68632
+ return diff === 0;
68633
+ }
68634
+ var WORD_BITS, WORD_MASK, SAS_WORDS, SAS_MIN_BITS, CTX_ENROLL, formatWords;
67831
68635
  var init_sas = __esm({
67832
68636
  "../../packages/mesh-pki/dist/sas.js"() {
67833
68637
  "use strict";
@@ -67836,10 +68640,13 @@ var init_sas = __esm({
67836
68640
  init_crypto();
67837
68641
  WORD_BITS = 11;
67838
68642
  WORD_MASK = (1 << WORD_BITS) - 1;
67839
- CTX_ENROLL = utf83("tsr-enroll-sas-v1");
68643
+ SAS_WORDS = 6;
68644
+ SAS_MIN_BITS = 64;
68645
+ CTX_ENROLL = utf82("tsr-enroll-sas-v1");
67840
68646
  if (wordlist.length !== 1 << WORD_BITS) {
67841
68647
  throw new Error(`BIP-39 wordlist must have ${1 << WORD_BITS} entries, got ${wordlist.length}`);
67842
68648
  }
68649
+ formatWords = (words) => words.join("-");
67843
68650
  }
67844
68651
  });
67845
68652
 
@@ -67874,7 +68681,7 @@ function clean(...arrays) {
67874
68681
  function createView(arr) {
67875
68682
  return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
67876
68683
  }
67877
- function rotr(word, shift) {
68684
+ function rotr2(word, shift) {
67878
68685
  return word << 32 - shift | word >>> shift;
67879
68686
  }
67880
68687
  function utf8ToBytes2(str3) {
@@ -68136,15 +68943,15 @@ var init_sha2 = __esm({
68136
68943
  for (let i = 16; i < 64; i++) {
68137
68944
  const W15 = SHA256_W[i - 15];
68138
68945
  const W2 = SHA256_W[i - 2];
68139
- const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
68140
- const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
68946
+ const s0 = rotr2(W15, 7) ^ rotr2(W15, 18) ^ W15 >>> 3;
68947
+ const s1 = rotr2(W2, 17) ^ rotr2(W2, 19) ^ W2 >>> 10;
68141
68948
  SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
68142
68949
  }
68143
68950
  let { A, B, C, D, E, F, G: G2, H } = this;
68144
68951
  for (let i = 0; i < 64; i++) {
68145
- const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
68952
+ const sigma1 = rotr2(E, 6) ^ rotr2(E, 11) ^ rotr2(E, 25);
68146
68953
  const T1 = H + sigma1 + Chi(E, F, G2) + SHA256_K[i] + SHA256_W[i] | 0;
68147
- const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
68954
+ const sigma0 = rotr2(A, 2) ^ rotr2(A, 13) ^ rotr2(A, 22);
68148
68955
  const T2 = sigma0 + Maj(A, B, C) | 0;
68149
68956
  H = G2;
68150
68957
  G2 = F;
@@ -68254,7 +69061,7 @@ function alphabet(letters) {
68254
69061
  };
68255
69062
  }
68256
69063
  // @__NO_SIDE_EFFECTS__
68257
- function join70(separator = "") {
69064
+ function join61(separator = "") {
68258
69065
  astr("join", separator);
68259
69066
  return {
68260
69067
  encode: (from) => {
@@ -68459,13 +69266,25 @@ var init_esm = __esm({
68459
69266
  convertRadix2,
68460
69267
  radix,
68461
69268
  radix2,
68462
- join: join70,
69269
+ join: join61,
68463
69270
  padding
68464
69271
  };
68465
69272
  }
68466
69273
  });
68467
69274
 
68468
69275
  // ../../node_modules/@scure/bip39/esm/index.js
69276
+ function nfkd(str3) {
69277
+ if (typeof str3 !== "string")
69278
+ throw new TypeError("invalid mnemonic type: " + typeof str3);
69279
+ return str3.normalize("NFKD");
69280
+ }
69281
+ function normalize2(str3) {
69282
+ const norm = nfkd(str3);
69283
+ const words = norm.split(" ");
69284
+ if (![12, 15, 18, 21, 24].includes(words.length))
69285
+ throw new Error("Invalid mnemonic");
69286
+ return { nfkd: norm, words };
69287
+ }
68469
69288
  function aentropy(ent) {
68470
69289
  abytes(ent, 16, 20, 24, 28, 32);
68471
69290
  }
@@ -68478,11 +69297,25 @@ function getCoder(wordlist2) {
68478
69297
  });
68479
69298
  return utils.chain(utils.checksum(1, calcChecksum), utils.radix2(11, true), utils.alphabet(wordlist2));
68480
69299
  }
69300
+ function mnemonicToEntropy(mnemonic, wordlist2) {
69301
+ const { words } = normalize2(mnemonic);
69302
+ const entropy = getCoder(wordlist2).decode(words);
69303
+ aentropy(entropy);
69304
+ return entropy;
69305
+ }
68481
69306
  function entropyToMnemonic(entropy, wordlist2) {
68482
69307
  aentropy(entropy);
68483
69308
  const words = getCoder(wordlist2).encode(entropy);
68484
69309
  return words.join(isJapanese(wordlist2) ? "\u3000" : " ");
68485
69310
  }
69311
+ function validateMnemonic(mnemonic, wordlist2) {
69312
+ try {
69313
+ mnemonicToEntropy(mnemonic, wordlist2);
69314
+ } catch (e) {
69315
+ return false;
69316
+ }
69317
+ return true;
69318
+ }
68486
69319
  var isJapanese, calcChecksum;
68487
69320
  var init_esm2 = __esm({
68488
69321
  "../../node_modules/@scure/bip39/esm/index.js"() {
@@ -68504,7 +69337,7 @@ function validateKdf2(k) {
68504
69337
  throw new MeshCodecError("bad-value", `unsupported KDF cost (m=${k.m} t=${k.t} p=${k.p})`);
68505
69338
  }
68506
69339
  function kdf(passphrase, salt, cost) {
68507
- return argon2id(utf83(passphrase.normalize("NFKC")), salt, { ...cost, dkLen: KEY_LEN });
69340
+ return argon2id(utf82(passphrase.normalize("NFKC")), salt, { ...cost, dkLen: KEY_LEN });
68508
69341
  }
68509
69342
  function header(version2, label, kdfCost, salt, nonce2) {
68510
69343
  const w = new Writer();
@@ -68522,8 +69355,8 @@ async function sealCaKey(seed, passphrase, label = "mesh CA", cost = DEFAULT_KDF
68522
69355
  if (label.length > MAX_LABEL)
68523
69356
  throw new MeshCodecError("too-long", "label too long");
68524
69357
  validateKdf2(cost);
68525
- const salt = randomBytes9(SALT_LEN);
68526
- const nonce2 = randomBytes9(NONCE_LEN);
69358
+ const salt = randomBytes7(SALT_LEN);
69359
+ const nonce2 = randomBytes7(NONCE_LEN);
68527
69360
  const aad = header(RECOVERY_VERSION, label, cost, salt, nonce2);
68528
69361
  const key2 = await aesKey(kdf(passphrase, salt, cost));
68529
69362
  const ct = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce2, additionalData: aad }, key2, seed));
@@ -68568,11 +69401,26 @@ function caKeyToMnemonic(seed) {
68568
69401
  throw new MeshCodecError("bad-value", `CA seed must be ${SECRET_LEN} bytes`);
68569
69402
  return entropyToMnemonic(seed, wordlist);
68570
69403
  }
69404
+ function caKeyFromMnemonic(mnemonic) {
69405
+ const norm = mnemonic.normalize("NFKD").trim().replace(/\s+/g, " ").toLowerCase();
69406
+ if (norm.split(" ").length !== MNEMONIC_WORDS) {
69407
+ throw new MeshCodecError("bad-value", `recovery mnemonic must be ${MNEMONIC_WORDS} words`);
69408
+ }
69409
+ if (!validateMnemonic(norm, wordlist)) {
69410
+ throw new MeshCodecError("bad-value", "recovery mnemonic failed its checksum \u2014 check for a mistyped word");
69411
+ }
69412
+ return mnemonicToEntropy(norm, wordlist);
69413
+ }
68571
69414
  async function newDisablement() {
68572
- const secret = randomBytes9(SECRET_LEN);
69415
+ const secret = randomBytes7(SECRET_LEN);
68573
69416
  return { secret, hash: await sha2562(secret) };
68574
69417
  }
68575
- var RECOVERY_VERSION, SECRET_LEN, KDF_MEMORY_KIB, KDF_PASSES, KDF_LANES, DEFAULT_KDF, KDF_MIN, KDF_MAX, SALT_LEN, NONCE_LEN, KEY_LEN, MAX_LABEL, DOMAIN;
69418
+ async function verifyDisablement(secret, committedHash) {
69419
+ if (secret.length !== SECRET_LEN || committedHash.length !== 32)
69420
+ return false;
69421
+ return bytesEqual(await sha2562(secret), committedHash);
69422
+ }
69423
+ var RECOVERY_VERSION, SECRET_LEN, MNEMONIC_WORDS, KDF_MEMORY_KIB, KDF_PASSES, KDF_LANES, DEFAULT_KDF, KDF_MIN, KDF_MAX, SALT_LEN, NONCE_LEN, KEY_LEN, MAX_LABEL, DOMAIN;
68576
69424
  var init_recovery = __esm({
68577
69425
  "../../packages/mesh-pki/dist/recovery.js"() {
68578
69426
  "use strict";
@@ -68583,6 +69431,7 @@ var init_recovery = __esm({
68583
69431
  init_crypto();
68584
69432
  RECOVERY_VERSION = 1;
68585
69433
  SECRET_LEN = 32;
69434
+ MNEMONIC_WORDS = 24;
68586
69435
  KDF_MEMORY_KIB = 64 * 1024;
68587
69436
  KDF_PASSES = 3;
68588
69437
  KDF_LANES = 4;
@@ -68593,12 +69442,114 @@ var init_recovery = __esm({
68593
69442
  NONCE_LEN = 12;
68594
69443
  KEY_LEN = 32;
68595
69444
  MAX_LABEL = 128;
68596
- DOMAIN = utf83("tesseract-mesh-recovery-v1");
69445
+ DOMAIN = utf82("tesseract-mesh-recovery-v1");
68597
69446
  }
68598
69447
  });
68599
69448
 
68600
69449
  // ../../packages/mesh-pki/dist/enroll.js
68601
- var DEFAULT_TICKET_TTL_MS;
69450
+ async function mintJoinTicket(opts) {
69451
+ const genesisFp = await genesisFingerprint(opts.genesis);
69452
+ const ttl = opts.ttlMs ?? DEFAULT_TICKET_TTL_MS;
69453
+ const details = {
69454
+ version: 1,
69455
+ serial: randomBytes7(16),
69456
+ genesisFp,
69457
+ nodeId: opts.nodeId,
69458
+ name: opts.name,
69459
+ // The intermediate is a signing identity, not a data-plane peer. It carries no
69460
+ // usable X25519 static key — the redeeming node supplies its own.
69461
+ staticPub: new Uint8Array(32),
69462
+ sigPub: opts.intermediate.publicRaw,
69463
+ overlayIp4: opts.overlayIp4,
69464
+ overlayIp6: opts.overlayIp6,
69465
+ routes: canonicalPrefixes(opts.routes ?? []),
69466
+ flags: FLAG_IS_CA,
69467
+ groups: canonicalStrs(opts.groups),
69468
+ notBefore: opts.now - 6e4,
69469
+ // small backdate absorbs clock skew at redemption
69470
+ notAfter: opts.now + ttl,
69471
+ issuerFp: genesisFp
69472
+ };
69473
+ return {
69474
+ genesis: opts.genesis,
69475
+ caCert: await issueCert(details, opts.signers),
69476
+ caPrivate: opts.intermediate.privateScalar
69477
+ };
69478
+ }
69479
+ function encodeJoinTicket(t) {
69480
+ const w = new Writer();
69481
+ w.u8(TICKET_VERSION);
69482
+ w.bytes(encodeGenesis(t.genesis), LIMITS.GENESIS);
69483
+ w.bytes(encodeCert(t.caCert), LIMITS.CERT);
69484
+ w.fixed(t.caPrivate, 32);
69485
+ return w.finish();
69486
+ }
69487
+ function decodeJoinTicket(bytes2) {
69488
+ const r = new Reader(bytes2);
69489
+ const version2 = r.u8();
69490
+ if (version2 !== TICKET_VERSION)
69491
+ throw new MeshCodecError("bad-value", `ticket version ${version2}`);
69492
+ const genesis = decodeGenesis(r.bytes(LIMITS.GENESIS));
69493
+ const caCert = decodeCert(r.bytes(LIMITS.CERT));
69494
+ const caPrivate = r.fixed(32);
69495
+ r.finish();
69496
+ return { genesis, caCert, caPrivate };
69497
+ }
69498
+ async function redeemJoinTicket(opts) {
69499
+ const { ticket } = opts;
69500
+ const ca = ticket.caCert.details;
69501
+ if (!(ca.flags & FLAG_IS_CA))
69502
+ return { ok: false, reason: "ticket-not-ca" };
69503
+ if (opts.now > ca.notAfter)
69504
+ return { ok: false, reason: "ticket-expired" };
69505
+ const groups = canonicalStrs(opts.groups ?? ca.groups);
69506
+ const parentGroups = new Set(ca.groups);
69507
+ if (groups.some((g) => !parentGroups.has(g)))
69508
+ return { ok: false, reason: "widens-groups" };
69509
+ const routes = canonicalPrefixes(opts.routes ?? ca.routes);
69510
+ const parentKeys = new Set(ca.routes.map((p) => `${p.afi}/${p.len}/${p.addr.join(".")}`));
69511
+ if (routes.some((p) => !parentKeys.has(`${p.afi}/${p.len}/${p.addr.join(".")}`))) {
69512
+ return { ok: false, reason: "widens-routes" };
69513
+ }
69514
+ const wanted2 = opts.now + (opts.leafTtlMs ?? DEFAULT_TICKET_TTL_MS);
69515
+ const notAfter = Math.min(wanted2, ca.notAfter);
69516
+ const genesisFp = await genesisFingerprint(ticket.genesis);
69517
+ const details = {
69518
+ version: 1,
69519
+ serial: randomBytes7(16),
69520
+ genesisFp,
69521
+ nodeId: opts.nodeId ?? ca.nodeId,
69522
+ name: opts.name ?? ca.name,
69523
+ staticPub: opts.staticPub,
69524
+ sigPub: opts.sigPub,
69525
+ // Pinned by the ticket — narrowing forbids changing these.
69526
+ overlayIp4: ca.overlayIp4,
69527
+ overlayIp6: ca.overlayIp6,
69528
+ routes,
69529
+ flags: 0,
69530
+ groups,
69531
+ notBefore: opts.now - 6e4,
69532
+ notAfter,
69533
+ issuerFp: await certFingerprint(ca)
69534
+ };
69535
+ const key2 = await importSigningPrivate({
69536
+ kty: "OKP",
69537
+ crv: "Ed25519",
69538
+ d: b64u2(ticket.caPrivate),
69539
+ x: b64u2(ca.sigPub),
69540
+ key_ops: ["sign"],
69541
+ ext: true
69542
+ });
69543
+ const leaf = await issueCert(details, [{ keyIndex: 0, privateKey: key2.privateKey }]);
69544
+ return {
69545
+ ok: true,
69546
+ result: { leaf, genesis: ticket.genesis, intermediates: [ticket.caCert] }
69547
+ };
69548
+ }
69549
+ async function predictOverlayV6(genesis, staticPub) {
69550
+ return deriveOverlayV6(genesis.meshPrefix6, await genesisFingerprint(genesis), staticPub);
69551
+ }
69552
+ var TICKET_VERSION, DEFAULT_TICKET_TTL_MS, joinTicketToString, joinTicketFromString;
68602
69553
  var init_enroll = __esm({
68603
69554
  "../../packages/mesh-pki/dist/enroll.js"() {
68604
69555
  "use strict";
@@ -68609,11 +69560,167 @@ var init_enroll = __esm({
68609
69560
  init_crypto();
68610
69561
  init_codec();
68611
69562
  init_addr();
69563
+ TICKET_VERSION = 1;
68612
69564
  DEFAULT_TICKET_TTL_MS = 15 * 60 * 1e3;
69565
+ joinTicketToString = (t) => b64u2(encodeJoinTicket(t));
69566
+ joinTicketFromString = (s) => decodeJoinTicket(unb64u2(s));
68613
69567
  }
68614
69568
  });
68615
69569
 
68616
69570
  // ../../packages/mesh-pki/dist/index.js
69571
+ var dist_exports3 = {};
69572
+ __export(dist_exports3, {
69573
+ ACTION_ACCEPT: () => ACTION_ACCEPT,
69574
+ ACTION_DROP: () => ACTION_DROP,
69575
+ AFI_V4: () => AFI_V4,
69576
+ AFI_V6: () => AFI_V6,
69577
+ CAP_EXIT_NODE: () => CAP_EXIT_NODE,
69578
+ CAP_USE_ROUTE: () => CAP_USE_ROUTE,
69579
+ CLOCK_SKEW_MS: () => CLOCK_SKEW_MS,
69580
+ DEFAULT_MAX_STALENESS_MS: () => DEFAULT_MAX_STALENESS_MS,
69581
+ DEFAULT_MESH_CIDR4: () => DEFAULT_MESH_CIDR4,
69582
+ DEFAULT_TICKET_TTL_MS: () => DEFAULT_TICKET_TTL_MS,
69583
+ ED25519: () => ED25519,
69584
+ FLAG_IS_CA: () => FLAG_IS_CA,
69585
+ FLAG_IS_EPHEMERAL: () => FLAG_IS_EPHEMERAL,
69586
+ FLAG_IS_EXIT_NODE: () => FLAG_IS_EXIT_NODE,
69587
+ FLAG_IS_RELAY: () => FLAG_IS_RELAY,
69588
+ GENESIS_VERSION: () => GENESIS_VERSION,
69589
+ KDF_LANES: () => KDF_LANES,
69590
+ KDF_MEMORY_KIB: () => KDF_MEMORY_KIB,
69591
+ KDF_PASSES: () => KDF_PASSES,
69592
+ LIMITS: () => LIMITS,
69593
+ MAX_CHAIN_DEPTH: () => MAX_CHAIN_DEPTH,
69594
+ MIN_MESH_PREFIX_LEN: () => MIN_MESH_PREFIX_LEN,
69595
+ MNEMONIC_WORDS: () => MNEMONIC_WORDS,
69596
+ MeshCodecError: () => MeshCodecError,
69597
+ PROTO_ANY: () => PROTO_ANY,
69598
+ PROTO_ICMP: () => PROTO_ICMP,
69599
+ PROTO_ICMPV6: () => PROTO_ICMPV6,
69600
+ PROTO_TCP: () => PROTO_TCP,
69601
+ PROTO_UDP: () => PROTO_UDP,
69602
+ RECOVERY_VERSION: () => RECOVERY_VERSION,
69603
+ Reader: () => Reader,
69604
+ SAS_MIN_BITS: () => SAS_MIN_BITS,
69605
+ SAS_WORDS: () => SAS_WORDS,
69606
+ SECRET_LEN: () => SECRET_LEN,
69607
+ TICKET_VERSION: () => TICKET_VERSION,
69608
+ TNC_VERSION: () => TNC_VERSION,
69609
+ TPB_VERSION: () => TPB_VERSION,
69610
+ Writer: () => Writer,
69611
+ X25519: () => X25519,
69612
+ addrToU32: () => addrToU32,
69613
+ applyPeerFilter: () => applyPeerFilter,
69614
+ b64u: () => b64u2,
69615
+ blake2s256: () => blake2s256,
69616
+ bundleHash: () => bundleHash,
69617
+ bytesEqual: () => bytesEqual,
69618
+ caKeyFromMnemonic: () => caKeyFromMnemonic,
69619
+ caKeyToMnemonic: () => caKeyToMnemonic,
69620
+ canonicalExceptions: () => canonicalExceptions,
69621
+ canonicalGroups: () => canonicalGroups,
69622
+ canonicalPorts: () => canonicalPorts,
69623
+ canonicalPrefixes: () => canonicalPrefixes,
69624
+ canonicalRevocations: () => canonicalRevocations,
69625
+ canonicalRoster: () => canonicalRoster,
69626
+ canonicalStrs: () => canonicalStrs,
69627
+ certFingerprint: () => certFingerprint,
69628
+ checkNarrowing: () => checkNarrowing,
69629
+ comparePrefix: () => comparePrefix,
69630
+ compareUtf8: () => compareUtf8,
69631
+ compilePeerFilter: () => compilePeerFilter,
69632
+ concat: () => concat2,
69633
+ decodeBundle: () => decodeBundle,
69634
+ decodeCert: () => decodeCert,
69635
+ decodeDetails: () => decodeDetails,
69636
+ decodeGenesis: () => decodeGenesis,
69637
+ decodeJoinTicket: () => decodeJoinTicket,
69638
+ decodeRecoveryBundle: () => decodeRecoveryBundle,
69639
+ decodeSignedBundle: () => decodeSignedBundle,
69640
+ decodeSignedGenesis: () => decodeSignedGenesis,
69641
+ deriveMeshPrefix6: () => deriveMeshPrefix6,
69642
+ deriveOverlayV4Hint: () => deriveOverlayV4Hint,
69643
+ deriveOverlayV6: () => deriveOverlayV6,
69644
+ encodeBundle: () => encodeBundle,
69645
+ encodeCert: () => encodeCert,
69646
+ encodeDetails: () => encodeDetails,
69647
+ encodeGenesis: () => encodeGenesis,
69648
+ encodeJoinTicket: () => encodeJoinTicket,
69649
+ encodeRecoveryBundle: () => encodeRecoveryBundle,
69650
+ encodeSignedBundle: () => encodeSignedBundle,
69651
+ encodeSignedGenesis: () => encodeSignedGenesis,
69652
+ enrolmentSas: () => enrolmentSas,
69653
+ evaluate: () => evaluate,
69654
+ exportSigningPrivate: () => exportSigningPrivate,
69655
+ exportStaticPrivate: () => exportStaticPrivate,
69656
+ fingerprintShort: () => fingerprintShort,
69657
+ fingerprintWords: () => fingerprintWords,
69658
+ formatAddr: () => formatAddr,
69659
+ formatPrefix: () => formatPrefix,
69660
+ formatWords: () => formatWords,
69661
+ generateSigningKey: () => generateSigningKey,
69662
+ generateStaticKey: () => generateStaticKey,
69663
+ genesisFingerprint: () => genesisFingerprint,
69664
+ hex: () => hex3,
69665
+ importSigningPrivate: () => importSigningPrivate,
69666
+ importSigningPublic: () => importSigningPublic,
69667
+ isCa: () => isCa,
69668
+ isExitNode: () => isExitNode,
69669
+ isFresh: () => isFresh,
69670
+ isMasked: () => isMasked,
69671
+ isRelay: () => isRelay,
69672
+ isValidMeshRange: () => isValidMeshRange,
69673
+ issueCert: () => issueCert,
69674
+ joinTicketFromString: () => joinTicketFromString,
69675
+ joinTicketToString: () => joinTicketToString,
69676
+ makeGenesis: () => makeGenesis,
69677
+ makePrefix: () => makePrefix,
69678
+ makeRule: () => makeRule,
69679
+ mask: () => mask,
69680
+ maxLenOf: () => maxLenOf,
69681
+ maySourceAddr: () => maySourceAddr,
69682
+ meshFqdn: () => meshFqdn,
69683
+ mintJoinTicket: () => mintJoinTicket,
69684
+ nameWords: () => nameWords,
69685
+ newDisablement: () => newDisablement,
69686
+ openCaKey: () => openCaKey,
69687
+ parseAddr: () => parseAddr,
69688
+ parsePrefix: () => parsePrefix,
69689
+ predictOverlayV6: () => predictOverlayV6,
69690
+ prefixContains: () => prefixContains,
69691
+ prefixContainsAddr: () => prefixContainsAddr,
69692
+ prefixEqual: () => prefixEqual,
69693
+ randomBytes: () => randomBytes7,
69694
+ readPrefix: () => readPrefix,
69695
+ readPrefixes: () => readPrefixes,
69696
+ readRule: () => readRule,
69697
+ redeemJoinTicket: () => redeemJoinTicket,
69698
+ resolveGroups: () => resolveGroups,
69699
+ revokes: () => revokes,
69700
+ sasEqual: () => sasEqual,
69701
+ sealCaKey: () => sealCaKey,
69702
+ sha256: () => sha2562,
69703
+ sign: () => sign2,
69704
+ signBundle: () => signBundle,
69705
+ signGenesis: () => signGenesis,
69706
+ signingKeyFromSeed: () => signingKeyFromSeed,
69707
+ u32ToAddr: () => u32ToAddr,
69708
+ unb64u: () => unb64u2,
69709
+ utf8: () => utf82,
69710
+ validateBundle: () => validateBundle,
69711
+ validateDetails: () => validateDetails,
69712
+ validateGenesis: () => validateGenesis,
69713
+ verify: () => verify2,
69714
+ verifyBundle: () => verifyBundle,
69715
+ verifyCert: () => verifyCert,
69716
+ verifyDisablement: () => verifyDisablement,
69717
+ verifyGenesis: () => verifyGenesis,
69718
+ widthOf: () => widthOf,
69719
+ wordsFromDigest: () => wordsFromDigest,
69720
+ writePrefix: () => writePrefix,
69721
+ writePrefixes: () => writePrefixes,
69722
+ writeRule: () => writeRule
69723
+ });
68617
69724
  var init_dist6 = __esm({
68618
69725
  "../../packages/mesh-pki/dist/index.js"() {
68619
69726
  "use strict";
@@ -69782,7 +70889,7 @@ async function netCaCommand(rest, flags) {
69782
70889
  if (pass.length < 12) die("Use a passphrase of at least 12 characters \u2014 this key issues every identity on the mesh.");
69783
70890
  const confirm2 = await readPassphrase("Confirm: ");
69784
70891
  if (pass !== confirm2) die("Passphrases did not match.");
69785
- const seed = randomBytes9(SEED_LEN);
70892
+ const seed = randomBytes7(SEED_LEN);
69786
70893
  const ca = await signingKeyFromSeed(seed);
69787
70894
  const pol = ca;
69788
70895
  const disable = await newDisablement();
@@ -69847,7 +70954,7 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
69847
70954
  const cert = await issueCert(
69848
70955
  {
69849
70956
  version: 1,
69850
- serial: randomBytes9(16),
70957
+ serial: randomBytes7(16),
69851
70958
  genesisFp: fp,
69852
70959
  nodeId: name,
69853
70960
  name,
@@ -72086,10 +73193,10 @@ function createHostedVerification() {
72086
73193
  let reviewText = "";
72087
73194
  for (let i = 0; i < rv.RV_MAX_CYCLES * 2 + 2; i++) {
72088
73195
  const gate = state3.phase === "review" ? "review" : "completeness";
72089
- const call2 = gate === "review" ? rv.reviewGrade(task, reviewText || text9) : rv.completenessGrade(task, text9, todos);
73196
+ const call3 = gate === "review" ? rv.reviewGrade(task, reviewText || text9) : rv.completenessGrade(task, text9, todos);
72090
73197
  let verdict = null;
72091
73198
  try {
72092
- verdict = rv.parseVerdict(await grade({ model, system: call2.system, prompt: call2.prompt, maxTokens: 16e3, schema: call2.schema }));
73199
+ verdict = rv.parseVerdict(await grade({ model, system: call3.system, prompt: call3.prompt, maxTokens: 16e3, schema: call3.schema }));
72093
73200
  } catch {
72094
73201
  verdict = null;
72095
73202
  }
@@ -73373,7 +74480,7 @@ async function pickPort() {
73373
74480
  var CALL_TIMEOUT_MS = 8e3;
73374
74481
  function createEngineHttpApi(port, host = "127.0.0.1") {
73375
74482
  const baseUrl = `http://${host}:${port}`;
73376
- async function call2(method, path6, body, timeoutMs = CALL_TIMEOUT_MS) {
74483
+ async function call3(method, path6, body, timeoutMs = CALL_TIMEOUT_MS) {
73377
74484
  const ac = new AbortController();
73378
74485
  const timer2 = setTimeout(() => ac.abort(), timeoutMs);
73379
74486
  try {
@@ -73401,12 +74508,12 @@ function createEngineHttpApi(port, host = "127.0.0.1") {
73401
74508
  }
73402
74509
  return {
73403
74510
  baseUrl,
73404
- get: (path6, timeoutMs) => call2("GET", path6, void 0, timeoutMs),
73405
- post: (path6, body, timeoutMs, method) => call2(method ?? "POST", path6, body, timeoutMs),
74511
+ get: (path6, timeoutMs) => call3("GET", path6, void 0, timeoutMs),
74512
+ post: (path6, body, timeoutMs, method) => call3(method ?? "POST", path6, body, timeoutMs),
73406
74513
  async ready(timeoutMs = 5e3) {
73407
74514
  const deadline = Date.now() + timeoutMs;
73408
74515
  while (Date.now() < deadline) {
73409
- const h = await call2("GET", "/global/health", void 0, 1500);
74516
+ const h = await call3("GET", "/global/health", void 0, 1500);
73410
74517
  if (h && h !== true && h.healthy !== false)
73411
74518
  return true;
73412
74519
  if (h === true)
@@ -74784,20 +75891,20 @@ ${text9}`);
74784
75891
  }
74785
75892
  async function sendMessage(params) {
74786
75893
  const origin = params.origin;
74787
- const fail3 = (sessionId, error51, transient = false) => send4({ type: "chat:error", sessionId, clientRequestId: params.clientRequestId, error: error51, ...transient ? { transient: true } : {} }, origin);
75894
+ const fail4 = (sessionId, error51, transient = false) => send4({ type: "chat:error", sessionId, clientRequestId: params.clientRequestId, error: error51, ...transient ? { transient: true } : {} }, origin);
74788
75895
  const spawnCfg = resolve16(engine.id);
74789
75896
  if (!spawnCfg) {
74790
- fail3(params.sessionId ?? "", `${engine.label} isn't installed or configured. Open Settings \u2192 Models & accounts.`);
75897
+ fail4(params.sessionId ?? "", `${engine.label} isn't installed or configured. Open Settings \u2192 Models & accounts.`);
74791
75898
  return;
74792
75899
  }
74793
75900
  const configError = spawnConfigError(spawnCfg);
74794
75901
  if (configError) {
74795
- fail3(params.sessionId ?? "", configError);
75902
+ fail4(params.sessionId ?? "", configError);
74796
75903
  send4({ type: "agent:status", sessionId: params.sessionId ?? "", clientRequestId: params.clientRequestId, status: "error" }, origin);
74797
75904
  return;
74798
75905
  }
74799
75906
  if (!params.projectDir) {
74800
- fail3(params.sessionId ?? "", "No project folder is open. Open a folder to start working with the agent.");
75907
+ fail4(params.sessionId ?? "", "No project folder is open. Open a folder to start working with the agent.");
74801
75908
  return;
74802
75909
  }
74803
75910
  let t;
@@ -74819,13 +75926,13 @@ ${text9}`);
74819
75926
  try {
74820
75927
  t = await ensureProcess(spawnCfg.command, spawnCfg.env, params.projectDir, mcpSpecsFor(params), !!wantSandbox, JSON.stringify(engine.askEnv?.(params.permissionMode) ?? null));
74821
75928
  } catch (e) {
74822
- fail3(params.sessionId ?? "", `OpenCode failed to start: ${String(e?.message ?? e)}`, true);
75929
+ fail4(params.sessionId ?? "", `OpenCode failed to start: ${String(e?.message ?? e)}`, true);
74823
75930
  return;
74824
75931
  }
74825
75932
  if (params.message.trim() === "/compact" && !engine.compactCommand && params.sessionId) {
74826
75933
  const from = params.sessionId;
74827
75934
  if (turns.has(from)) {
74828
- fail3(from, `${engine.label} is still working on this conversation \u2014 compaction will run once it finishes.`, false);
75935
+ fail4(from, `${engine.label} is still working on this conversation \u2014 compaction will run once it finishes.`, false);
74829
75936
  send4({ type: "agent:status", sessionId: from, clientRequestId: params.clientRequestId, status: "idle" }, origin);
74830
75937
  return;
74831
75938
  }
@@ -74853,7 +75960,7 @@ ${text9}`);
74853
75960
  turns.delete(from);
74854
75961
  }
74855
75962
  if (!snapshot3) {
74856
- fail3(from, `${engine.label} could not summarise this conversation to compact it.`, false);
75963
+ fail4(from, `${engine.label} could not summarise this conversation to compact it.`, false);
74857
75964
  send4({ type: "agent:status", sessionId: from, clientRequestId: params.clientRequestId, status: "idle" }, origin);
74858
75965
  return;
74859
75966
  }
@@ -74861,7 +75968,7 @@ ${text9}`);
74861
75968
  const fresh = await t.request("session/new", { cwd: params.projectDir, mcpServers: mcpServersFor(params, compactHold) }).catch(() => null);
74862
75969
  const next = fresh?.sessionId;
74863
75970
  if (!next) {
74864
- fail3(from, `${engine.label} could not open a fresh session to compact into.`, true);
75971
+ fail4(from, `${engine.label} could not open a fresh session to compact into.`, true);
74865
75972
  send4({ type: "agent:status", sessionId: from, clientRequestId: params.clientRequestId, status: "error" }, origin);
74866
75973
  return;
74867
75974
  }
@@ -74932,7 +76039,7 @@ ${text9}`);
74932
76039
  await applyRunMode(t, sid, params.permissionMode, params.model);
74933
76040
  await applyThinking(t, sid, params.thinking);
74934
76041
  } catch (e) {
74935
- fail3(params.sessionId ?? "", `Couldn't start a ${engineLabel} session: ${String(e?.message ?? e)}`, true);
76042
+ fail4(params.sessionId ?? "", `Couldn't start a ${engineLabel} session: ${String(e?.message ?? e)}`, true);
74936
76043
  return;
74937
76044
  }
74938
76045
  const userSeq = userTurnSeq.get(sid) ?? 0;
@@ -75067,7 +76174,7 @@ ${text9}`);
75067
76174
  send4({ type: "agent:status", sessionId: sid, clientRequestId: params.clientRequestId, status: "idle" }, origin);
75068
76175
  return;
75069
76176
  }
75070
- fail3(sid, overflow ? `${CONTEXT_OVERFLOW_HINT}
76177
+ fail4(sid, overflow ? `${CONTEXT_OVERFLOW_HINT}
75071
76178
 
75072
76179
  ${detail}` : detail, !overflow);
75073
76180
  send4({ type: "agent:status", sessionId: sid, clientRequestId: params.clientRequestId, status: "error" }, origin);
@@ -76090,7 +77197,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76090
77197
  }
76091
77198
  const pendingApprovals = /* @__PURE__ */ new Map();
76092
77199
  const pendingDialogs = /* @__PURE__ */ new Map();
76093
- const fail3 = (sessionId, clientRequestId, error51, origin, transient = false) => {
77200
+ const fail4 = (sessionId, clientRequestId, error51, origin, transient = false) => {
76094
77201
  send4({ type: "chat:error", sessionId, clientRequestId, error: error51, ...transient ? { transient: true } : {} }, origin);
76095
77202
  };
76096
77203
  function parkApproval(raw, toolName, allow, allowPersist, deny, detail) {
@@ -76292,7 +77399,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76292
77399
  const t = p.turn ?? {};
76293
77400
  if (t.status === "failed" && !turn.reported) {
76294
77401
  turn.reported = true;
76295
- fail3(threadId, turn.clientRequestId, codexErrorText(t.error), turn.origin, true);
77402
+ fail4(threadId, turn.clientRequestId, codexErrorText(t.error), turn.origin, true);
76296
77403
  }
76297
77404
  turn.finish(t.status ?? null);
76298
77405
  return;
@@ -76303,7 +77410,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76303
77410
  return;
76304
77411
  if (!turn.reported) {
76305
77412
  turn.reported = true;
76306
- fail3(threadId, turn.clientRequestId, codexErrorText(p.error), turn.origin, true);
77413
+ fail4(threadId, turn.clientRequestId, codexErrorText(p.error), turn.origin, true);
76307
77414
  }
76308
77415
  turn.finish(null);
76309
77416
  return;
@@ -76377,7 +77484,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76377
77484
  spawnedCwd = null;
76378
77485
  for (const [tid, turn] of turns) {
76379
77486
  turn.finish(null);
76380
- fail3(tid, turn.clientRequestId, `${label} restarted.`, turn.origin, true);
77487
+ fail4(tid, turn.clientRequestId, `${label} restarted.`, turn.origin, true);
76381
77488
  }
76382
77489
  turns.clear();
76383
77490
  for (const w of compactWaiters.values())
@@ -76496,17 +77603,17 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76496
77603
  const origin = params.origin;
76497
77604
  const cfg2 = resolve16(ENGINE_ID2);
76498
77605
  if (!cfg2) {
76499
- fail3(params.sessionId ?? "", params.clientRequestId, `${label} isn't installed or configured. Open Settings \u2192 Models & accounts.`, origin);
77606
+ fail4(params.sessionId ?? "", params.clientRequestId, `${label} isn't installed or configured. Open Settings \u2192 Models & accounts.`, origin);
76500
77607
  return;
76501
77608
  }
76502
77609
  const cfgErr = spawnConfigError(cfg2);
76503
77610
  if (cfgErr) {
76504
- fail3(params.sessionId ?? "", params.clientRequestId, cfgErr, origin);
77611
+ fail4(params.sessionId ?? "", params.clientRequestId, cfgErr, origin);
76505
77612
  send4({ type: "agent:status", sessionId: params.sessionId ?? "", clientRequestId: params.clientRequestId, status: "error" }, origin);
76506
77613
  return;
76507
77614
  }
76508
77615
  if (!params.projectDir) {
76509
- fail3(params.sessionId ?? "", params.clientRequestId, "No project folder is open. Open a folder to start working with the agent.", origin);
77616
+ fail4(params.sessionId ?? "", params.clientRequestId, "No project folder is open. Open a folder to start working with the agent.", origin);
76510
77617
  return;
76511
77618
  }
76512
77619
  await ensureHostedToolset();
@@ -76514,7 +77621,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76514
77621
  try {
76515
77622
  t = await ensureProcess(cfg2.command, cfg2.env, params.projectDir);
76516
77623
  } catch (e) {
76517
- fail3(params.sessionId ?? "", params.clientRequestId, `${label} failed to start: ${String(e?.message ?? e)}`, origin, true);
77624
+ fail4(params.sessionId ?? "", params.clientRequestId, `${label} failed to start: ${String(e?.message ?? e)}`, origin, true);
76518
77625
  return;
76519
77626
  }
76520
77627
  await installTools(t, { ...injectedServers, ...params.mcpServers ?? {} });
@@ -76546,18 +77653,18 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76546
77653
  if (model)
76547
77654
  sessionModel.set(threadId, model);
76548
77655
  } catch (e) {
76549
- fail3(params.sessionId ?? "", params.clientRequestId, `Couldn't start a ${label} thread: ${String(e?.message ?? e)}`, origin, true);
77656
+ fail4(params.sessionId ?? "", params.clientRequestId, `Couldn't start a ${label} thread: ${String(e?.message ?? e)}`, origin, true);
76550
77657
  return;
76551
77658
  }
76552
77659
  if (params.message.trim() === "/compact") {
76553
77660
  const ok = await t.request("thread/compact/start", { threadId }).then(() => true).catch(() => false);
76554
77661
  if (!ok) {
76555
- fail3(threadId, params.clientRequestId, `${label} could not compact this conversation.`, origin);
77662
+ fail4(threadId, params.clientRequestId, `${label} could not compact this conversation.`, origin);
76556
77663
  send4({ type: "agent:status", sessionId: threadId, clientRequestId: params.clientRequestId, status: "error" }, origin);
76557
77664
  return;
76558
77665
  }
76559
77666
  if (compactWaiters.has(threadId)) {
76560
- fail3(threadId, params.clientRequestId, `${label} is already compacting this conversation.`, origin);
77667
+ fail4(threadId, params.clientRequestId, `${label} is already compacting this conversation.`, origin);
76561
77668
  send4({ type: "agent:status", sessionId: threadId, clientRequestId: params.clientRequestId, status: "idle" }, origin);
76562
77669
  return;
76563
77670
  }
@@ -76578,7 +77685,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76578
77685
  compactWaiters.set(threadId, { settle: finish, keepAlive: arm });
76579
77686
  });
76580
77687
  if (!compacted) {
76581
- fail3(threadId, params.clientRequestId, `${label} did not finish compacting this conversation in time.`, origin);
77688
+ fail4(threadId, params.clientRequestId, `${label} did not finish compacting this conversation in time.`, origin);
76582
77689
  send4({ type: "agent:status", sessionId: threadId, clientRequestId: params.clientRequestId, status: "error" }, origin);
76583
77690
  return;
76584
77691
  }
@@ -76691,7 +77798,7 @@ function createCodexAppServerBackend(send4, resolve16, onBrowserRequest, loadPlu
76691
77798
  send4({ type: "agent:status", sessionId: threadId, clientRequestId: params.clientRequestId, status: "idle" }, origin);
76692
77799
  return;
76693
77800
  }
76694
- fail3(threadId, params.clientRequestId, detail, origin, true);
77801
+ fail4(threadId, params.clientRequestId, detail, origin, true);
76695
77802
  send4({ type: "agent:status", sessionId: threadId, clientRequestId: params.clientRequestId, status: "error" }, origin);
76696
77803
  }
76697
77804
  }
@@ -90468,13 +91575,13 @@ var ActiveLinkEngine = class {
90468
91575
  localByHash.set(h, j);
90469
91576
  });
90470
91577
  const reuse = /* @__PURE__ */ new Map();
90471
- const request = [];
91578
+ const request2 = [];
90472
91579
  blocks.forEach((h, i) => {
90473
91580
  const j = localByHash.get(h);
90474
91581
  if (j !== void 0)
90475
91582
  reuse.set(i, j);
90476
91583
  else
90477
- request.push(i);
91584
+ request2.push(i);
90478
91585
  });
90479
91586
  const existing = this.pendingPulls.get(rel);
90480
91587
  if (existing)
@@ -90482,14 +91589,14 @@ var ActiveLinkEngine = class {
90482
91589
  });
90483
91590
  const assembler = new BlockAssembler(this.stagingPath(rel, "blk"));
90484
91591
  await assembler.open();
90485
- const pending2 = { mtimeMs, mode, size, wholeHash, blocks, reuse, localSize: localRec?.size ?? 0, remaining: new Set(request), assembler };
91592
+ const pending2 = { mtimeMs, mode, size, wholeHash, blocks, reuse, localSize: localRec?.size ?? 0, remaining: new Set(request2), assembler };
90486
91593
  this.pendingPulls.set(rel, pending2);
90487
91594
  this.touchInbound();
90488
- if (request.length === 0) {
91595
+ if (request2.length === 0) {
90489
91596
  await this.finalizeBlockPull(rel);
90490
91597
  return;
90491
91598
  }
90492
- this.send({ type: "link:requestBlocks", linkId: this.opts.linkId, fromHost: this.opts.ownHostId, rel, mtimeMs, indexes: request });
91599
+ this.send({ type: "link:requestBlocks", linkId: this.opts.linkId, fromHost: this.opts.ownHostId, rel, mtimeMs, indexes: request2 });
90493
91600
  }
90494
91601
  async onBlockData(frame) {
90495
91602
  const pending2 = this.pendingPulls.get(frame.rel);
@@ -91521,6 +92628,15 @@ function ownHostId() {
91521
92628
  const mine = serverHosts.find((h) => h.hostId.endsWith(`:${deviceId}`));
91522
92629
  return mine?.hostId ?? "local";
91523
92630
  }
92631
+ var lastOwnHostLog = null;
92632
+ function logOwnHostVerdict() {
92633
+ const own2 = ownHostId();
92634
+ const verdict = own2 === "local" ? `NOT REGISTERED \u2014 the account lists ${serverHosts.length} host(s), none matching this deviceId=${deviceId.slice(0, 8)}; this machine is invisible to every client` : `registered as ${own2}`;
92635
+ if (verdict === lastOwnHostLog)
92636
+ return;
92637
+ lastOwnHostLog = verdict;
92638
+ console.log(`[control-link] own host: ${verdict}`);
92639
+ }
91524
92640
  function presentedHosts() {
91525
92641
  const out = serverHosts.slice();
91526
92642
  if (!out.some((h) => h.hostId.endsWith(`:${deviceId}`))) {
@@ -92321,6 +93437,8 @@ function handleHostChannel(payload) {
92321
93437
  entitlementDenied = true;
92322
93438
  stopHeartbeat();
92323
93439
  const message = typeof payload.message === "string" ? payload.message : "Running agents on your own machines requires a paid plan.";
93440
+ const d = payload;
93441
+ console.log(`[control-link] host:register DENIED reason=${String(d.reason ?? "?")} feature=${String(d.feature ?? "?")} limit=${String(d.limit ?? "?")} \u2014 ${message}`);
92324
93442
  hooks?.notify({ type: "notify", level: "warning", message });
92325
93443
  scheduleEntitlementRetry();
92326
93444
  return;
@@ -92344,6 +93462,7 @@ function handleHostChannel(payload) {
92344
93462
  setActiveLinkPeerOnline(l.linkId, true);
92345
93463
  }
92346
93464
  assertServerSelection();
93465
+ logOwnHostVerdict();
92347
93466
  hooks?.ownHostResolved(ownHostId());
92348
93467
  hooks?.pushHosts(presentedHosts());
92349
93468
  resumeActiveLinks();
@@ -92365,6 +93484,7 @@ function registerAsHost() {
92365
93484
  const upAdvert = upscaleAdvert();
92366
93485
  if (upAdvert.gpu)
92367
93486
  caps.push("gpu");
93487
+ console.log(`[control-link] host:register \u2192 deviceId=${deviceId.slice(0, 8)} machineId=${getMachinePublicId() ?? "none"} kind=${kind ?? "electron"} caps=${caps.join(",")}`);
92368
93488
  send3("host", { type: "host:register", name, platform: process.platform, deviceId, publicMachineId: getMachinePublicId(), caps, ...kind ? { kind } : {}, ...staticMetrics(hostVersion), gpu: upAdvert.gpu, upscaleModels: upAdvert.upscaleModels, ...p2pAdvert ?? {} });
92369
93489
  if (!heartbeat)
92370
93490
  heartbeat = setInterval(() => send3("host", { type: "host:heartbeat", ...dynamicMetrics() }), 2e4);
@@ -92686,7 +93806,7 @@ function connect() {
92686
93806
  } else if (rdSession && typeof p?.type === "string" && p.type.startsWith("rdesk:")) {
92687
93807
  if (inbound) {
92688
93808
  if (driving)
92689
- hooks?.onRdesk?.(env.payload, clientId, rdSession);
93809
+ hooks?.onRdesk?.(env.payload, clientId, rdSession, env.viewerOwner === true);
92690
93810
  } else
92691
93811
  hooks?.deliverRdesk?.(env.payload, typeof env.hostId === "string" ? env.hostId : void 0, rdSession);
92692
93812
  }
@@ -92699,7 +93819,7 @@ function connect() {
92699
93819
  return;
92700
93820
  if (inbound) {
92701
93821
  if (driving)
92702
- hooks?.onRdesk?.(p, clientId, sessionId);
93822
+ hooks?.onRdesk?.(p, clientId, sessionId, env.viewerOwner === true);
92703
93823
  return;
92704
93824
  }
92705
93825
  hooks?.deliverRdesk?.(p, typeof env.hostId === "string" ? env.hostId : void 0, sessionId);
@@ -92931,6 +94051,32 @@ var RdeskSessionManager = class {
92931
94051
  return 0;
92932
94052
  return Math.min(PW_BACKOFF_BASE_MS * 2 ** (over - 1), PW_BACKOFF_MAX_MS);
92933
94053
  }
94054
+ /** Tell the viewer that this host is (or is again) producing a picture.
94055
+ *
94056
+ * Sent by the HOST because only the host can know why: the OS reports a muted or ended
94057
+ * capture track as a fact, whereas a viewer sees an absence of frames and cannot tell a
94058
+ * slept display from a slow link from a genuinely black screen. Audited too, so "it just
94059
+ * showed black" is answerable after the fact. */
94060
+ reportCapture(sessionId, clientId, ok, message) {
94061
+ this.log(`capture ${ok ? "restored" : `lost \u2014 ${message}`} sessionId=${sessionId}`);
94062
+ this.audit({ event: "capture", sessionId, detail: ok ? "ok" : message });
94063
+ this.deps.sendControl(sessionId, clientId, { type: "rdesk:capture", ok, ...message ? { message } : {} });
94064
+ }
94065
+ /** Record which path a session's media actually took, once ICE has settled.
94066
+ *
94067
+ * Media is direct-first (no relay pinning); TURN exists only as a last resort for NATs
94068
+ * that never punch through. That makes relay usage a COST we pay, so it is written to
94069
+ * the audit trail rather than only logged — `path` events in rdesk-audit.jsonl answer
94070
+ * "what fraction of sessions actually relayed?" without grepping daemon logs. Candidate
94071
+ * types only: an audit file is not the place for peer addresses. */
94072
+ recordPath(sessionId, viewerUserId, path6, d) {
94073
+ this.audit({
94074
+ event: "path",
94075
+ sessionId,
94076
+ viewerUserId,
94077
+ detail: `${path6} local=${d.localType ?? "?"} remote=${d.remoteType ?? "?"}`
94078
+ });
94079
+ }
92934
94080
  audit(e) {
92935
94081
  this.deps.audit?.({ at: this.now(), ...e });
92936
94082
  }
@@ -92955,10 +94101,10 @@ var RdeskSessionManager = class {
92955
94101
  const viewer = viewerIn.name || !declared ? viewerIn : { ...viewerIn, name: declared };
92956
94102
  const grant0 = grantOf(msg);
92957
94103
  this.audit({ event: "connect", sessionId, viewerUserId: viewer.userId, viewerName: viewer.name, grant: grant0 });
92958
- const deny = (reason) => {
92959
- this.log(`connect denied sessionId=${sessionId} reason=${reason}`);
92960
- this.audit({ event: "deny", sessionId, viewerUserId: viewer.userId, grant: grant0, detail: reason });
92961
- this.deps.sendControl(sessionId, viewer.clientId, { type: "rdesk:denied", reason });
94104
+ const deny = (reason, message) => {
94105
+ this.log(`connect denied sessionId=${sessionId} reason=${reason}${message ? ` \u2014 ${message}` : ""}`);
94106
+ this.audit({ event: "deny", sessionId, viewerUserId: viewer.userId, grant: grant0, detail: message ? `${reason}: ${message}` : reason });
94107
+ this.deps.sendControl(sessionId, viewer.clientId, { type: "rdesk:denied", reason, ...message ? { message } : {} });
92962
94108
  };
92963
94109
  if (!this.deps.canServe())
92964
94110
  return deny("entitlement");
@@ -92976,6 +94122,10 @@ var RdeskSessionManager = class {
92976
94122
  return deny("busy");
92977
94123
  }
92978
94124
  const grant = grantOf(msg);
94125
+ if (grant === "registry" && viewer.sameAccount !== true) {
94126
+ this.log(`connect denied sessionId=${sessionId} \u2014 'registry' claimed by a viewer the relay does not consider the owner`);
94127
+ return deny("consent");
94128
+ }
92979
94129
  if (grant === "password") {
92980
94130
  if (this.now() < this.pwLockedUntil) {
92981
94131
  this.log(`password attempt refused \u2014 locked for ${Math.ceil((this.pwLockedUntil - this.now()) / 1e3)}s`);
@@ -93016,7 +94166,9 @@ var RdeskSessionManager = class {
93016
94166
  sendControl: (m) => this.deps.sendControl(sessionId, viewer.clientId, m),
93017
94167
  sendData: (_m) => {
93018
94168
  },
93019
- log: (m) => this.log(`${sessionId}: ${m}`)
94169
+ log: (m) => this.log(`${sessionId}: ${m}`),
94170
+ onPath: (path6, d) => this.recordPath(sessionId, viewer.userId, path6, d),
94171
+ onCapture: (ok, message) => this.reportCapture(sessionId, viewer.clientId, ok, message)
93020
94172
  };
93021
94173
  let engine;
93022
94174
  try {
@@ -93027,7 +94179,7 @@ var RdeskSessionManager = class {
93027
94179
  const err2 = e instanceof Error ? e.message : String(e);
93028
94180
  this.log(`engine start failed sessionId=${sessionId}: ${err2}`);
93029
94181
  this.deps.onCaptureBlocked?.({ sessionId, viewerName: viewer.name, error: err2 });
93030
- return deny("offline");
94182
+ return deny("offline", err2);
93031
94183
  }
93032
94184
  const monitors = await engine.listMonitors().catch(() => []);
93033
94185
  const sources = await engine.listSources?.().catch(() => []) ?? [];
@@ -93096,7 +94248,9 @@ var RdeskSessionManager = class {
93096
94248
  sendControl: (m) => this.deps.sendControl(s.sessionId, s.viewer.clientId, m),
93097
94249
  sendData: () => {
93098
94250
  },
93099
- log: (m) => this.log(`${s.sessionId}: ${m}`)
94251
+ log: (m) => this.log(`${s.sessionId}: ${m}`),
94252
+ onPath: (path6, d) => this.recordPath(s.sessionId, s.viewer.userId, path6, d),
94253
+ onCapture: (ok, message) => this.reportCapture(s.sessionId, s.viewer.clientId, ok, message)
93100
94254
  };
93101
94255
  try {
93102
94256
  s.engine = await this.deps.createEngine("tesseract", ctx2);
@@ -93271,6 +94425,93 @@ var RdeskSessionManager = class {
93271
94425
  }
93272
94426
  };
93273
94427
 
94428
+ // ../../packages/host-core/dist/daemon-identity-reload.js
94429
+ var reload = null;
94430
+ function setDaemonIdentityReload(fn) {
94431
+ reload = fn;
94432
+ }
94433
+ function nextDaemonIdentity(fresh, current) {
94434
+ if (!fresh?.accessToken)
94435
+ return { kind: "machine" };
94436
+ if (fresh.accessToken === current.accessToken && (fresh.userId ?? "") === current.userId)
94437
+ return { kind: "unchanged" };
94438
+ return { kind: "account" };
94439
+ }
94440
+
94441
+ // ../../packages/host-core/dist/rdesk/screen-permission.js
94442
+ function screenRecordingStatus() {
94443
+ if (process.platform !== "darwin")
94444
+ return "unsupported";
94445
+ try {
94446
+ const sp = electronModule()?.systemPreferences;
94447
+ const s = sp?.getMediaAccessStatus("screen");
94448
+ if (s === "granted" || s === "denied" || s === "restricted" || s === "not-determined")
94449
+ return s;
94450
+ return "not-determined";
94451
+ } catch {
94452
+ return "not-determined";
94453
+ }
94454
+ }
94455
+ function canCaptureScreen() {
94456
+ const s = screenRecordingStatus();
94457
+ return s === "granted" || s === "unsupported";
94458
+ }
94459
+ async function registerForScreenRecording() {
94460
+ try {
94461
+ const dc = electronModule()?.desktopCapturer;
94462
+ await dc?.getSources({ types: ["screen"], thumbnailSize: { width: 1, height: 1 } });
94463
+ } catch {
94464
+ }
94465
+ }
94466
+ async function openScreenRecordingSettings() {
94467
+ if (process.platform !== "darwin")
94468
+ return;
94469
+ await registerForScreenRecording();
94470
+ try {
94471
+ const shell = electronModule()?.shell;
94472
+ await shell?.openExternal("x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture");
94473
+ } catch {
94474
+ }
94475
+ }
94476
+ var PROMPT_COOLDOWN_MS = 6e4;
94477
+ var lastPromptAt = 0;
94478
+ async function promptForScreenRecording(opts = {}) {
94479
+ if (process.platform !== "darwin")
94480
+ return false;
94481
+ if (screenRecordingStatus() === "granted") {
94482
+ opts.log?.("capture failed although Screen Recording IS granted \u2014 the capture stack is wedged (seen after a GPU-process crash); restarting Tesseract clears it");
94483
+ return false;
94484
+ }
94485
+ const now2 = Date.now();
94486
+ if (now2 - lastPromptAt < PROMPT_COOLDOWN_MS)
94487
+ return false;
94488
+ lastPromptAt = now2;
94489
+ const el2 = electronModule();
94490
+ const who = opts.viewerName ? `${opts.viewerName} is` : "Someone is";
94491
+ opts.log?.(`screen recording not granted \u2014 prompting (${who} waiting)`);
94492
+ if (!el2?.dialog) {
94493
+ opts.log?.("no GUI to prompt with \u2014 grant Screen Recording in System Settings \u2192 Privacy & Security");
94494
+ return false;
94495
+ }
94496
+ try {
94497
+ const { response } = await el2.dialog.showMessageBox({
94498
+ type: "warning",
94499
+ buttons: ["Open System Settings", "Not Now"],
94500
+ defaultId: 0,
94501
+ cancelId: 1,
94502
+ message: "Allow screen sharing on this Mac?",
94503
+ detail: `${who} trying to connect to this computer, but macOS is blocking screen capture.
94504
+
94505
+ Open System Settings \u2192 Privacy & Security \u2192 Screen Recording and switch on Tesseract Remote Desktop, then ask them to connect again.`
94506
+ });
94507
+ if (response === 0)
94508
+ await openScreenRecordingSettings();
94509
+ return true;
94510
+ } catch {
94511
+ return false;
94512
+ }
94513
+ }
94514
+
93274
94515
  // ../../packages/host-core/dist/rdesk/publisher-window.js
93275
94516
  import { join as join54 } from "node:path";
93276
94517
  var windows = /* @__PURE__ */ new Map();
@@ -93308,6 +94549,7 @@ function ensureIpc() {
93308
94549
  el2.ipcMain.on("rdesk:pub:ready", (_e, p) => route2(p, (w) => w.handlers.onReady()));
93309
94550
  el2.ipcMain.on("rdesk:pub:error", (_e, p) => route2(p, (w, x) => w.handlers.onError(String(x.error ?? "publisher error"))));
93310
94551
  el2.ipcMain.on("rdesk:pub:path", (_e, p) => route2(p, (w, x) => w.handlers.onPath?.(String(x.path ?? "unknown"), { localType: x.localType ?? null, remoteType: x.remoteType ?? null })));
94552
+ el2.ipcMain.on("rdesk:pub:capture", (_e, p) => route2(p, (w, x) => w.handlers.onCapture?.(x.ok !== false, String(x.message ?? ""))));
93311
94553
  el2.ipcMain.on("rdesk:pub:stopped", (_e, p) => route2(p, (w) => w.onStoppedAck()));
93312
94554
  }
93313
94555
  async function listPublisherMonitors() {
@@ -93354,21 +94596,41 @@ function displayBoundsById(monitorId) {
93354
94596
  const d = el2.screen.getAllDisplays().find((x) => String(x.id) === monitorId) ?? el2.screen.getPrimaryDisplay();
93355
94597
  return d ? { x: d.bounds.x, y: d.bounds.y, width: d.bounds.width, height: d.bounds.height } : null;
93356
94598
  }
93357
- async function sourceIdForMonitor(monitorId) {
94599
+ async function wakeDisplay(log9) {
94600
+ if (process.platform !== "darwin")
94601
+ return;
94602
+ try {
94603
+ const { spawn: spawn17 } = await import("node:child_process");
94604
+ spawn17("caffeinate", ["-u", "-t", "5"], { detached: true, stdio: "ignore" }).unref();
94605
+ log9?.("display was asleep \u2014 declared user activity to wake it");
94606
+ await new Promise((r) => setTimeout(r, 1200));
94607
+ } catch {
94608
+ }
94609
+ }
94610
+ async function sourceIdForMonitor(monitorId, log9) {
93358
94611
  const el2 = electronModule();
93359
94612
  if (!el2?.desktopCapturer || !el2.screen)
93360
94613
  throw new Error("Screen capture unavailable (Electron desktopCapturer/screen missing).");
93361
94614
  const display = el2.screen.getAllDisplays().find((d) => String(d.id) === monitorId) ?? el2.screen.getPrimaryDisplay();
93362
- const sources = await el2.desktopCapturer.getSources({ types: ["screen"], thumbnailSize: { width: 1, height: 1 } });
94615
+ const list = async () => el2.desktopCapturer.getSources({ types: ["screen"], thumbnailSize: { width: 1, height: 1 } });
94616
+ let sources = await list();
94617
+ if (sources.length === 0) {
94618
+ await wakeDisplay(log9);
94619
+ sources = await list();
94620
+ }
93363
94621
  const match = sources.find((s) => s.display_id === String(display.id)) ?? sources[0];
93364
- if (!match)
93365
- throw new Error("Screen capture failed: no screen source (grant Screen Recording permission).");
94622
+ if (!match) {
94623
+ const denied = !canCaptureScreen();
94624
+ throw new Error(denied ? "Screen capture failed: Screen Recording permission is not granted to this app." : "Screen capture failed: no screen source. Screen Recording IS granted, so this is usually a display that stayed asleep, or a Mac with no active display attached.");
94625
+ }
93366
94626
  return match.id;
93367
94627
  }
93368
94628
  var PublisherWindow = class {
93369
94629
  sessionId;
93370
94630
  handlers;
93371
94631
  win = null;
94632
+ /** powerSaveBlocker id held for the life of the session — see startDisplayHold(). */
94633
+ displayHold = null;
93372
94634
  stopAck = null;
93373
94635
  constructor(sessionId, handlers) {
93374
94636
  this.sessionId = sessionId;
@@ -93386,6 +94648,7 @@ var PublisherWindow = class {
93386
94648
  if (!el2?.BrowserWindow)
93387
94649
  throw new Error("Publisher requires the daemon GUI shell (no BrowserWindow).");
93388
94650
  ensureIpc();
94651
+ this.startDisplayHold();
93389
94652
  const sourceId = opts.sourceId ?? await sourceIdForMonitor(opts.monitorId ?? await this.primaryMonitorId());
93390
94653
  const win3 = new el2.BrowserWindow({
93391
94654
  width: 320,
@@ -93499,7 +94762,36 @@ var PublisherWindow = class {
93499
94762
  maxFps: opts.maxFps
93500
94763
  });
93501
94764
  }
94765
+ /** Hold the display awake for as long as this session lives.
94766
+ *
94767
+ * Waking it once at start is not enough: the idle timer keeps running, so an unattended
94768
+ * host would go dark again a few minutes into a session and capture would die with the
94769
+ * same empty source list it started with. Released in stop() — never leaked, or the host
94770
+ * can never sleep again. */
94771
+ startDisplayHold() {
94772
+ if (this.displayHold !== null)
94773
+ return;
94774
+ try {
94775
+ const psb = electronModule()?.powerSaveBlocker;
94776
+ if (psb)
94777
+ this.displayHold = psb.start("prevent-display-sleep");
94778
+ } catch {
94779
+ }
94780
+ }
94781
+ releaseDisplayHold() {
94782
+ const id = this.displayHold;
94783
+ this.displayHold = null;
94784
+ if (id === null)
94785
+ return;
94786
+ try {
94787
+ const psb = electronModule()?.powerSaveBlocker;
94788
+ if (psb?.isStarted(id))
94789
+ psb.stop(id);
94790
+ } catch {
94791
+ }
94792
+ }
93502
94793
  async stop() {
94794
+ this.releaseDisplayHold();
93503
94795
  const w = this.win;
93504
94796
  this.win = null;
93505
94797
  if (!w || w.isDestroyed()) {
@@ -93861,10 +95153,20 @@ var TesseractEngine = class {
93861
95153
  }
93862
95154
  },
93863
95155
  onReady: () => this.ctx.log("publisher connected"),
93864
- onError: (err2) => this.ctx.log(`publisher error: ${err2}`),
95156
+ onError: (err2) => {
95157
+ this.ctx.log(`publisher error: ${err2}`);
95158
+ this.ctx.sendControl({ type: "rdesk:closed", reason: "network" });
95159
+ },
93865
95160
  // Media is direct-first; log which path actually won so a regression to relay
93866
95161
  // (which costs real bandwidth) is visible instead of silent. Types only, no IPs.
93867
- onPath: (path6, d) => this.ctx.log(`media path=${path6} (local=${d.localType ?? "?"} remote=${d.remoteType ?? "?"})`)
95162
+ onCapture: (ok, message) => {
95163
+ this.ctx.log(`capture ${ok ? "ok" : `LOST \u2014 ${message}`}`);
95164
+ this.ctx.onCapture?.(ok, message);
95165
+ },
95166
+ onPath: (path6, d) => {
95167
+ this.ctx.log(`media path=${path6} (local=${d.localType ?? "?"} remote=${d.remoteType ?? "?"})`);
95168
+ this.ctx.onPath?.(path6, d);
95169
+ }
93868
95170
  });
93869
95171
  this.pub = pub;
93870
95172
  await pub.start({
@@ -96333,7 +97635,7 @@ async function startLocalServer(opts) {
96333
97635
  const rd = opts.getRdesk?.();
96334
97636
  if (rd && env.sessionId) {
96335
97637
  rdeskSessions.add(env.sessionId);
96336
- void rd.onClientMessage(env.sessionId, { clientId: loopbackOrigin, name: "This device" }, env.payload);
97638
+ void rd.onClientMessage(env.sessionId, { clientId: loopbackOrigin, name: "This device", sameAccount: true }, env.payload);
96337
97639
  }
96338
97640
  }
96339
97641
  } else if (env.channel === "signal") {
@@ -96918,8 +98220,8 @@ async function startLocalServer(opts) {
96918
98220
  init_base_paths();
96919
98221
  import { readFileSync as readFileSync45, writeFileSync as writeFileSync38, existsSync as existsSync35, mkdirSync as mkdirSync37, unlinkSync as unlinkSync6, chmodSync as chmodSync7, statSync as statSync9 } from "node:fs";
96920
98222
  import { execFileSync as execFileSync5 } from "node:child_process";
96921
- import { join as join69 } from "node:path";
96922
- import { randomBytes as randomBytes8 } from "node:crypto";
98223
+ import { join as join70 } from "node:path";
98224
+ import { randomBytes as randomBytes10 } from "node:crypto";
96923
98225
  import { hostname as hostname5 } from "node:os";
96924
98226
 
96925
98227
  // ../../packages/shared/dist/daemon-registry.js
@@ -97372,10 +98674,13 @@ function readLocal(meshId) {
97372
98674
  function writeLocal(meshId, state3) {
97373
98675
  try {
97374
98676
  mkdirSync32(oneMeshDir(meshId), { recursive: true, mode: 448 });
97375
- writeFileSync33(join60(oneMeshDir(meshId), FILES.local), JSON.stringify(state3, null, 2));
98677
+ writeFileSync33(join60(oneMeshDir(meshId), FILES.local), JSON.stringify(state3, null, 2), { mode: 384 });
97376
98678
  } catch {
97377
98679
  }
97378
98680
  }
98681
+ function updateLocal(meshId, patch) {
98682
+ writeLocal(meshId, { ...readLocal(meshId), ...patch });
98683
+ }
97379
98684
  function loadMesh(meshId) {
97380
98685
  if (!isMeshId(meshId))
97381
98686
  return null;
@@ -97633,6 +98938,9 @@ function loadMeshCore() {
97633
98938
  }
97634
98939
  }
97635
98940
  var meshCore = loadMeshCore();
98941
+ function meshEngineStatus() {
98942
+ return { available: meshCore.available === true, reason: meshCore.loadError ?? null };
98943
+ }
97636
98944
  var TICK_MS2 = 1e3;
97637
98945
  var BIND_PORT = 0;
97638
98946
  var shortKey = (k) => k.subarray(0, 4).toString("hex");
@@ -97742,9 +99050,54 @@ var MeshNode = class {
97742
99050
  #relayed = /* @__PURE__ */ new Set();
97743
99051
  /** staticPub hex → the Buffer, so events can be matched back to a peer. */
97744
99052
  #peers = /* @__PURE__ */ new Map();
99053
+ /**
99054
+ * Peers whose CERTIFICATE says they are this network's way out, by display name.
99055
+ *
99056
+ * A hint for the UI, never an authorisation: the engine checks the same signed bit per
99057
+ * packet, alongside our own selection and a bundle capability. This exists so a person
99058
+ * can be offered a choice that has somewhere to go.
99059
+ */
99060
+ #exitNodes = /* @__PURE__ */ new Map();
97745
99061
  #lan = null;
97746
99062
  #offRejoin = null;
97747
99063
  #statusTimer = null;
99064
+ /**
99065
+ * Route this machine's non-mesh traffic through the network's exit node, or stop.
99066
+ *
99067
+ * GATE 1 OF THREE, and the only one that lives on this machine. `Engine::exit_allowed`
99068
+ * additionally requires that the CA marked the peer's certificate and that the signed
99069
+ * bundle grants CAP_EXIT_NODE, both checked per packet — so selecting a peer widens
99070
+ * nothing by itself, and selecting one that turns out not to qualify simply drops the
99071
+ * traffic rather than misrouting it.
99072
+ *
99073
+ * Without this call netd installs the routes and the engine refuses every packet that
99074
+ * arrives on them: a machine with its default route captured and nothing carrying it,
99075
+ * which is the worst of both states.
99076
+ *
99077
+ * Returns the name selected, or null when there is nobody to select.
99078
+ */
99079
+ useExitNode(on) {
99080
+ const engine = this.#engine;
99081
+ if (!engine)
99082
+ return null;
99083
+ if (!on) {
99084
+ try {
99085
+ engine.setExitNode?.(null);
99086
+ } catch {
99087
+ }
99088
+ return null;
99089
+ }
99090
+ const first = [...this.#exitNodes.entries()][0];
99091
+ if (first === void 0)
99092
+ return null;
99093
+ const [hex6, name] = first;
99094
+ try {
99095
+ engine.setExitNode?.(Buffer.from(hex6, "hex"));
99096
+ } catch {
99097
+ return null;
99098
+ }
99099
+ return name;
99100
+ }
97748
99101
  status() {
97749
99102
  return {
97750
99103
  available: meshCore.available,
@@ -97756,6 +99109,14 @@ var MeshNode = class {
97756
99109
  peers: this.#engine?.peerCount() ?? 0,
97757
99110
  established: [...this.#established],
97758
99111
  relayed: [...this.#relayed],
99112
+ exitNodes: [...this.#exitNodes.values()],
99113
+ // Derived from the SAME sets the peer list is: an exit node with no established
99114
+ // session is one that cannot carry traffic yet, and saying "waiting" is different
99115
+ // from saying "none". Keyed by name so a caller never has to hold a key to read it.
99116
+ exitPaths: Object.fromEntries([...this.#exitNodes.entries()].map(([hex6, name]) => [
99117
+ name,
99118
+ this.#established.has(hex6) ? this.#relayed.has(hex6) ? "relay" : "direct" : "none"
99119
+ ])),
97759
99120
  meter: this.#engine?.meter() ?? null,
97760
99121
  lastError: this.#lastError,
97761
99122
  // Surfaced so `net status` can say "removed" rather than "not running". Those look
@@ -97927,11 +99288,11 @@ var MeshNode = class {
97927
99288
  const engine = this.#engine;
97928
99289
  if (!engine)
97929
99290
  return;
97930
- const hex5 = staticPub.toString("hex");
99291
+ const hex6 = staticPub.toString("hex");
97931
99292
  try {
97932
- if (!this.#peers.has(hex5)) {
99293
+ if (!this.#peers.has(hex6)) {
97933
99294
  engine.addPeer(staticPub, 0, Buffer.alloc(16));
97934
- this.#peers.set(hex5, staticPub);
99295
+ this.#peers.set(hex6, staticPub);
97935
99296
  }
97936
99297
  engine.addPath(staticPub, `${address}:${port}`, false);
97937
99298
  engine.startHandshake(staticPub, Date.now());
@@ -98008,10 +99369,10 @@ var MeshNode = class {
98008
99369
  const pk = Buffer.from(m.fromStaticPub, "base64");
98009
99370
  if (pk.length !== 32)
98010
99371
  break;
98011
- const hex5 = pk.toString("hex");
98012
- if (!this.#peers.has(hex5)) {
99372
+ const hex6 = pk.toString("hex");
99373
+ if (!this.#peers.has(hex6)) {
98013
99374
  engine.addPeer(pk, 0, Buffer.alloc(16));
98014
- this.#peers.set(hex5, pk);
99375
+ this.#peers.set(hex6, pk);
98015
99376
  }
98016
99377
  for (const ep of m.endpoints ?? []) {
98017
99378
  try {
@@ -98024,9 +99385,11 @@ var MeshNode = class {
98024
99385
  }
98025
99386
  case "mesh:gone": {
98026
99387
  const pk = Buffer.from(m.staticPub, "base64");
99388
+ if (pk.length === 32)
99389
+ this.#exitNodes.delete(pk.toString("hex"));
98027
99390
  if (pk.length === 32) {
98028
- const hex5 = pk.toString("hex");
98029
- this.#peers.delete(hex5);
99391
+ const hex6 = pk.toString("hex");
99392
+ this.#peers.delete(hex6);
98030
99393
  this.#established.delete(shortKey(pk));
98031
99394
  this.#relayed.delete(shortKey(pk));
98032
99395
  }
@@ -98052,10 +99415,22 @@ var MeshNode = class {
98052
99415
  const pk = Buffer.from(p.staticPub, "base64");
98053
99416
  if (pk.length !== 32)
98054
99417
  return;
98055
- const hex5 = pk.toString("hex");
98056
- if (!this.#peers.has(hex5)) {
99418
+ const hex6 = pk.toString("hex");
99419
+ if (p.cert) {
99420
+ try {
99421
+ const bytes2 = Buffer.from(p.cert, "base64");
99422
+ const pki = (init_dist6(), __toCommonJS(dist_exports3));
99423
+ const details = pki.decodeCert(new Uint8Array(bytes2)).details;
99424
+ if (pki.isExitNode(details))
99425
+ this.#exitNodes.set(hex6, details.name);
99426
+ else
99427
+ this.#exitNodes.delete(hex6);
99428
+ } catch {
99429
+ }
99430
+ }
99431
+ if (!this.#peers.has(hex6)) {
98057
99432
  engine.addPeer(pk, 0, Buffer.alloc(16));
98058
- this.#peers.set(hex5, pk);
99433
+ this.#peers.set(hex6, pk);
98059
99434
  }
98060
99435
  for (const e of p.endpoints)
98061
99436
  engine.addPath(pk, `${e.ip}:${e.port}`, false);
@@ -98190,16 +99565,26 @@ var MeshManager = class {
98190
99565
  */
98191
99566
  disable(meshId) {
98192
99567
  this.stop(meshId);
98193
- writeLocal(meshId, { ...readLocal(meshId), enabled: false });
99568
+ updateLocal(meshId, { enabled: false });
98194
99569
  }
98195
99570
  /** Undo `disable`, and start it. */
98196
99571
  enable(meshId) {
98197
- writeLocal(meshId, { ...readLocal(meshId), enabled: true });
99572
+ updateLocal(meshId, { enabled: true });
98198
99573
  return this.start(meshId);
98199
99574
  }
98200
99575
  node(meshId) {
98201
99576
  return this.#nodes.get(meshId) ?? null;
98202
99577
  }
99578
+ /**
99579
+ * The meshes with a LIVE node, which is what routes may be installed for.
99580
+ *
99581
+ * Deliberately not `ids()`: a certificate on disk is not a reason to steer traffic, and a
99582
+ * disabled mesh has one. `syncRoutes` takes this rather than the on-disk list precisely so
99583
+ * that confusion has to be made on purpose.
99584
+ */
99585
+ running() {
99586
+ return [...this.#nodes.keys()];
99587
+ }
98203
99588
  /** The first-joined running mesh — for callers that predate multi-mesh. */
98204
99589
  primary() {
98205
99590
  for (const meshId of this.ids()) {
@@ -98225,17 +99610,238 @@ function meshManager() {
98225
99610
  return singleton3;
98226
99611
  }
98227
99612
 
99613
+ // ../../packages/host-core/dist/mesh/netd-client.js
99614
+ import { connect as connect2 } from "node:net";
99615
+ import { platform as platform3 } from "node:process";
99616
+ var NETD_WIRE_VERSION = 1;
99617
+ var MAX_LINE = 1024 * 1024;
99618
+ var TIMEOUT_MS2 = 15e3;
99619
+ function netdEndpoint() {
99620
+ if (platform3 === "win32")
99621
+ return "\\\\.\\pipe\\tesseract-netd";
99622
+ if (platform3 === "darwin")
99623
+ return "/var/run/tesseract-netd.sock";
99624
+ return "/run/tesseract-netd.sock";
99625
+ }
99626
+ function endpointOverride() {
99627
+ return process.env.CCB_NETD_SOCKET ?? null;
99628
+ }
99629
+ function fail2(code, detail) {
99630
+ return { ok: false, code, detail };
99631
+ }
99632
+ async function call(line) {
99633
+ const endpoint2 = endpointOverride() ?? netdEndpoint();
99634
+ return new Promise((resolve16) => {
99635
+ let settled = false;
99636
+ const done = (r) => {
99637
+ if (settled)
99638
+ return;
99639
+ settled = true;
99640
+ try {
99641
+ sock.destroy();
99642
+ } catch {
99643
+ }
99644
+ resolve16(r);
99645
+ };
99646
+ let sock;
99647
+ try {
99648
+ sock = connect2(endpoint2);
99649
+ } catch (e) {
99650
+ return resolve16(fail2("not-installed", e instanceof Error ? e.message : String(e)));
99651
+ }
99652
+ const timer2 = setTimeout(() => {
99653
+ done(fail2("timeout", `no answer from the network helper in ${TIMEOUT_MS2}ms`));
99654
+ }, TIMEOUT_MS2);
99655
+ timer2.unref?.();
99656
+ sock.setTimeout(TIMEOUT_MS2);
99657
+ sock.on("timeout", () => {
99658
+ clearTimeout(timer2);
99659
+ done(fail2("timeout", "socket idle"));
99660
+ });
99661
+ sock.on("error", (e) => {
99662
+ clearTimeout(timer2);
99663
+ const absent = e.code === "ENOENT" || e.code === "ECONNREFUSED";
99664
+ done(fail2(absent ? "not-installed" : "io", e.message));
99665
+ });
99666
+ let buf = "";
99667
+ sock.on("data", (chunk) => {
99668
+ buf += chunk.toString("utf8");
99669
+ if (buf.length > MAX_LINE) {
99670
+ clearTimeout(timer2);
99671
+ done(fail2("protocol", "the helper sent an oversized line"));
99672
+ return;
99673
+ }
99674
+ const nl = buf.indexOf("\n");
99675
+ if (nl === -1)
99676
+ return;
99677
+ clearTimeout(timer2);
99678
+ done({ ok: true, line: buf.slice(0, nl) });
99679
+ });
99680
+ sock.on("close", () => {
99681
+ clearTimeout(timer2);
99682
+ done(fail2("protocol", "the helper closed the connection without answering"));
99683
+ });
99684
+ sock.on("connect", () => {
99685
+ sock.write(`${line}
99686
+ `);
99687
+ });
99688
+ });
99689
+ }
99690
+ function parse3(line) {
99691
+ let body;
99692
+ try {
99693
+ body = JSON.parse(line);
99694
+ } catch {
99695
+ return fail2("protocol", "the helper sent something that is not JSON");
99696
+ }
99697
+ if (typeof body !== "object" || body === null) {
99698
+ return fail2("protocol", "the helper sent something that is not an object");
99699
+ }
99700
+ const o = body;
99701
+ if (o.ok === false) {
99702
+ const code = typeof o.code === "string" ? o.code : "refused";
99703
+ const detail = typeof o.detail === "string" ? o.detail : "the helper refused";
99704
+ return fail2(code, detail);
99705
+ }
99706
+ if (o.ok !== true)
99707
+ return fail2("protocol", "the helper did not say whether it succeeded");
99708
+ return { ok: true, body: o };
99709
+ }
99710
+ async function request(line) {
99711
+ const r = await call(line);
99712
+ return r.ok ? parse3(r.line) : r;
99713
+ }
99714
+ function hex4(b) {
99715
+ return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
99716
+ }
99717
+ async function netdHello() {
99718
+ const r = await request(JSON.stringify({ op: "hello", wireVersion: NETD_WIRE_VERSION }));
99719
+ if (!r.ok)
99720
+ return r;
99721
+ const v = r.body.wireVersion;
99722
+ if (typeof v !== "number")
99723
+ return fail2("protocol", "the helper did not report a wire version");
99724
+ if (v !== NETD_WIRE_VERSION) {
99725
+ return fail2("wire-version", `the helper speaks ${v}, this build speaks ${NETD_WIRE_VERSION}`);
99726
+ }
99727
+ return { ok: true, wireVersion: v };
99728
+ }
99729
+ async function netdStatus() {
99730
+ const r = await request(JSON.stringify({ op: "status" }));
99731
+ if (!r.ok)
99732
+ return r;
99733
+ const meshes = Array.isArray(r.body.meshes) ? r.body.meshes.filter((m) => typeof m === "string") : [];
99734
+ const iface = typeof r.body.interface === "string" ? r.body.interface : null;
99735
+ return { ok: true, meshes, interface: iface };
99736
+ }
99737
+ async function netdUp(args) {
99738
+ const r = await request(JSON.stringify({
99739
+ op: "up",
99740
+ meshId: args.meshId,
99741
+ genesis: hex4(args.genesis),
99742
+ cert: hex4(args.cert),
99743
+ fullTunnel: args.fullTunnel === true
99744
+ }));
99745
+ return r.ok ? { ok: true } : r;
99746
+ }
99747
+ async function netdDown(meshId) {
99748
+ const r = await request(JSON.stringify({ op: "down", meshId }));
99749
+ return r.ok ? { ok: true } : r;
99750
+ }
99751
+ async function netdAvailable() {
99752
+ return (await netdHello()).ok;
99753
+ }
99754
+
99755
+ // ../../packages/host-core/dist/mesh/route-sync.js
99756
+ async function syncRoutes(running2, log9 = () => {
99757
+ }) {
99758
+ const out = { up: [], down: [], failed: [], helperAbsent: false };
99759
+ if (!await netdAvailable()) {
99760
+ out.helperAbsent = true;
99761
+ return out;
99762
+ }
99763
+ const status2 = await netdStatus();
99764
+ if (!status2.ok) {
99765
+ out.failed.push({ meshId: "*", reason: status2.detail });
99766
+ return out;
99767
+ }
99768
+ const installed = new Set(status2.meshes);
99769
+ const want = new Set(running2);
99770
+ for (const meshId of want) {
99771
+ const identity = loadMesh(meshId);
99772
+ if (identity === null) {
99773
+ out.failed.push({ meshId, reason: "no enrolment on disk" });
99774
+ continue;
99775
+ }
99776
+ const r = await netdUp({
99777
+ meshId,
99778
+ genesis: identity.genesis,
99779
+ cert: identity.cert,
99780
+ // The per-machine choice, and `=== true` rather than a truthiness check: an absent or
99781
+ // malformed field must read as NO. netd unions this across meshes itself — any mesh
99782
+ // asking for a full tunnel makes it one for the machine — so this stays per mesh here.
99783
+ fullTunnel: readLocal(meshId)?.fullTunnel === true
99784
+ });
99785
+ if (r.ok) {
99786
+ out.up.push(meshId);
99787
+ log9(`routes installed for ${meshId}`);
99788
+ } else {
99789
+ out.failed.push({ meshId, reason: r.detail });
99790
+ log9(`routes NOT installed for ${meshId}: ${r.detail}`);
99791
+ }
99792
+ }
99793
+ for (const meshId of installed) {
99794
+ if (want.has(meshId))
99795
+ continue;
99796
+ const r = await netdDown(meshId);
99797
+ if (r.ok) {
99798
+ out.down.push(meshId);
99799
+ log9(`routes removed for ${meshId}`);
99800
+ } else {
99801
+ out.failed.push({ meshId, reason: r.detail });
99802
+ log9(`routes could NOT be removed for ${meshId}: ${r.detail}`);
99803
+ }
99804
+ }
99805
+ return out;
99806
+ }
99807
+
98228
99808
  // ../../packages/host-core/dist/mesh/start-meshes.js
98229
99809
  function startMeshes(log9) {
99810
+ const running2 = startNodes(log9);
99811
+ void syncRoutes(running2, log9).then((r) => {
99812
+ if (r.helperAbsent) {
99813
+ log9("routes: the network helper is not installed \u2014 the overlay carries no traffic yet");
99814
+ return;
99815
+ }
99816
+ if (r.up.length)
99817
+ log9(`routes: installed for ${r.up.join(", ")}`);
99818
+ if (r.down.length)
99819
+ log9(`routes: removed for ${r.down.join(", ")}`);
99820
+ for (const f of r.failed)
99821
+ log9(`routes: ${f.meshId} refused \u2014 ${f.reason}`);
99822
+ }).catch((e) => {
99823
+ log9(`routes: sync threw \u2014 ${e instanceof Error ? e.message : String(e)}`);
99824
+ });
99825
+ }
99826
+ function startNodes(log9) {
98230
99827
  const ids = listMeshIds();
98231
99828
  if (ids.length <= 1) {
99829
+ const only = ids[0];
99830
+ if (only !== void 0 && readLocal(only)?.enabled === false) {
99831
+ log9("mesh: the only network is switched off");
99832
+ return [];
99833
+ }
98232
99834
  const started2 = meshNode().start();
98233
99835
  log9(started2.ok ? "mesh: node up" : `mesh: not started \u2014 ${started2.reason}`);
98234
- return;
99836
+ return started2.ok && only !== void 0 ? [only] : [];
98235
99837
  }
99838
+ const running2 = [];
98236
99839
  for (const r of meshManager().startAll()) {
98237
99840
  log9(r.ok ? `mesh ${r.meshId}: up` : `mesh ${r.meshId}: not started \u2014 ${r.reason}`);
99841
+ if (r.ok)
99842
+ running2.push(r.meshId);
98238
99843
  }
99844
+ return running2;
98239
99845
  }
98240
99846
 
98241
99847
  // ../../packages/host-core/dist/drops/receive-ui.js
@@ -98333,7 +99939,7 @@ import { basename as basename13 } from "node:path";
98333
99939
  // ../../packages/host-core/dist/drops/paths.js
98334
99940
  init_base_paths();
98335
99941
  import { mkdir as mkdir12 } from "node:fs/promises";
98336
- import { join as join61 } from "node:path";
99942
+ import { join as join62 } from "node:path";
98337
99943
 
98338
99944
  // ../../packages/host-core/dist/drops/names.js
98339
99945
  var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
@@ -98342,8 +99948,8 @@ var BIDI = /[\u200e\u200f\u202a-\u202e\u2066-\u2069]/g;
98342
99948
  var MAX_NAME_BYTES = 200;
98343
99949
  var MAX_EXT_BYTES = 32;
98344
99950
  var MAX_DEPTH2 = 32;
98345
- var utf82 = new TextEncoder();
98346
- var byteLen = (s) => utf82.encode(s).length;
99951
+ var utf83 = new TextEncoder();
99952
+ var byteLen = (s) => utf83.encode(s).length;
98347
99953
  function capBytes(stem, ext, max) {
98348
99954
  if (byteLen(stem + ext) <= max)
98349
99955
  return stem + ext;
@@ -98422,7 +100028,7 @@ function basenameOf(p) {
98422
100028
  function resolveDropsRoot() {
98423
100029
  const root = resolveHostRoot();
98424
100030
  const preferred = dropsDir();
98425
- return isInsideRoot(preferred, root) ? preferred : join61(root, "Drops");
100031
+ return isInsideRoot(preferred, root) ? preferred : join62(root, "Drops");
98426
100032
  }
98427
100033
  async function ensureDropsRoot() {
98428
100034
  const dir2 = resolveDropsRoot();
@@ -98438,7 +100044,7 @@ async function ensureDropDir(opts) {
98438
100044
  parts.push(sanitizeDropName(opts.sender, "Unknown sender"));
98439
100045
  if (!opts.singleItem && opts.label)
98440
100046
  parts.push(sanitizeDropName(opts.label, "Files"));
98441
- const dir2 = join61(...parts);
100047
+ const dir2 = join62(...parts);
98442
100048
  await mkdir12(dir2, { recursive: true });
98443
100049
  return dir2;
98444
100050
  }
@@ -98581,7 +100187,7 @@ function createDropHandler(deps) {
98581
100187
  // ../../packages/host-core/dist/drops/blob-fetch.js
98582
100188
  import { createWriteStream as createWriteStream2 } from "node:fs";
98583
100189
  import { mkdir as mkdir13, rm as rm5, chmod as chmod3 } from "node:fs/promises";
98584
- import { dirname as dirname26, join as join62 } from "node:path";
100190
+ import { dirname as dirname26, join as join63 } from "node:path";
98585
100191
  import { Readable as Readable2 } from "node:stream";
98586
100192
  import { pipeline } from "node:stream/promises";
98587
100193
 
@@ -98593,10 +100199,10 @@ var HEADER_BYTES = MAGIC2.length + NONCE_BYTES;
98593
100199
  var FRAME_BYTES = 1024 * 1024;
98594
100200
  var TAG_BYTES = 16;
98595
100201
  var MAX_FRAME_CIPHERTEXT = FRAME_BYTES + TAG_BYTES + 1024;
98596
- var subtle3 = () => globalThis.crypto.subtle;
98597
- var bs3 = (b) => b;
100202
+ var subtle4 = () => globalThis.crypto.subtle;
100203
+ var bs4 = (b) => b;
98598
100204
  async function importKey(raw) {
98599
- return subtle3().importKey("raw", bs3(raw), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
100205
+ return subtle4().importKey("raw", bs4(raw), { name: "AES-GCM" }, false, ["encrypt", "decrypt"]);
98600
100206
  }
98601
100207
  function nonceFor(base, index) {
98602
100208
  const n = Buffer.from(base);
@@ -98691,7 +100297,7 @@ function decryptStream(source, keyRaw) {
98691
100297
  const frame = q.peek(4 + len);
98692
100298
  if (!frame)
98693
100299
  break;
98694
- const plain = Buffer.from(await subtle3().decrypt({ name: "AES-GCM", iv: bs3(nonceFor(base, index)), additionalData: bs3(aadFor(index)) }, key2, bs3(frame.subarray(4))));
100300
+ const plain = Buffer.from(await subtle4().decrypt({ name: "AES-GCM", iv: bs4(nonceFor(base, index)), additionalData: bs4(aadFor(index)) }, key2, bs4(frame.subarray(4))));
98695
100301
  this.push(plain);
98696
100302
  index += 1;
98697
100303
  q.consume(4 + len);
@@ -98753,7 +100359,7 @@ async function fetchBlobDrop(opts) {
98753
100359
  log7(`drop ${opts.dropId}: refusing directory "${item.rel}"`);
98754
100360
  continue;
98755
100361
  }
98756
- const abs = join62(opts.destDir, rel);
100362
+ const abs = join63(opts.destDir, rel);
98757
100363
  if (!isInsideRoot(abs, opts.destDir)) {
98758
100364
  log7(`drop ${opts.dropId}: refusing directory outside the destination`);
98759
100365
  continue;
@@ -98774,7 +100380,7 @@ async function fetchBlobDrop(opts) {
98774
100380
  log7(`drop ${opts.dropId}: refusing "${item.rel}"`);
98775
100381
  continue;
98776
100382
  }
98777
- let abs = join62(opts.destDir, rel);
100383
+ let abs = join63(opts.destDir, rel);
98778
100384
  if (!isInsideRoot(abs, opts.destDir)) {
98779
100385
  log7(`drop ${opts.dropId}: refusing a path outside the destination`);
98780
100386
  continue;
@@ -99052,12 +100658,12 @@ var RdeskServerChannel = class {
99052
100658
 
99053
100659
  // ../../packages/host-core/dist/rdesk/channel-client.js
99054
100660
  import { readFileSync as readFileSync44 } from "node:fs";
99055
- import { join as join63 } from "node:path";
100661
+ import { join as join64 } from "node:path";
99056
100662
  var RECONNECT_MS = 2e3;
99057
100663
  var CLAIM_RETRY_MS = 5e3;
99058
100664
  function readEndpoint(dir2, selfPid) {
99059
100665
  try {
99060
- const s = JSON.parse(readFileSync44(join63(dir2, "status.json"), "utf8"));
100666
+ const s = JSON.parse(readFileSync44(join64(dir2, "status.json"), "utf8"));
99061
100667
  if (selfPid && s.pid === selfPid)
99062
100668
  return null;
99063
100669
  return s.localPort && s.localToken ? `ws://127.0.0.1:${s.localPort}/?token=${s.localToken}` : null;
@@ -99091,11 +100697,11 @@ function startRdeskChannelClient(deps) {
99091
100697
  return;
99092
100698
  retry = setTimeout(() => {
99093
100699
  retry = null;
99094
- connect2();
100700
+ connect3();
99095
100701
  }, RECONNECT_MS);
99096
100702
  retry.unref?.();
99097
100703
  };
99098
- function connect2() {
100704
+ function connect3() {
99099
100705
  if (stopped2 || sock)
99100
100706
  return;
99101
100707
  const url2 = readEndpoint(deps.daemonDir(), deps.selfPid);
@@ -99161,7 +100767,7 @@ function startRdeskChannelClient(deps) {
99161
100767
  ws.on("error", () => {
99162
100768
  });
99163
100769
  }
99164
- connect2();
100770
+ connect3();
99165
100771
  const claimPoll = setInterval(() => {
99166
100772
  if (stopped2 || holding)
99167
100773
  return;
@@ -99198,19 +100804,6 @@ function setRdeskServerAdmin(a) {
99198
100804
  admin = a;
99199
100805
  }
99200
100806
 
99201
- // ../../packages/host-core/dist/daemon-identity-reload.js
99202
- var reload = null;
99203
- function setDaemonIdentityReload(fn) {
99204
- reload = fn;
99205
- }
99206
- function nextDaemonIdentity(fresh, current) {
99207
- if (!fresh?.accessToken)
99208
- return { kind: "machine" };
99209
- if (fresh.accessToken === current.accessToken && (fresh.userId ?? "") === current.userId)
99210
- return { kind: "unchanged" };
99211
- return { kind: "account" };
99212
- }
99213
-
99214
100807
  // ../../packages/host-core/dist/daemon-online-watch.js
99215
100808
  var FIRST_DELAY_MS = 5e3;
99216
100809
  var MAX_DELAY_MS = 3e4;
@@ -99503,10 +101096,10 @@ function registerRdpEngine() {
99503
101096
  // ../../packages/host-core/dist/rdesk/audit.js
99504
101097
  init_credentials();
99505
101098
  import { appendFile, stat as stat8, rename as rename3 } from "node:fs/promises";
99506
- import { join as join64 } from "node:path";
101099
+ import { join as join65 } from "node:path";
99507
101100
  var MAX_BYTES = 2 * 1024 * 1024;
99508
101101
  function rdeskAuditPath() {
99509
- return join64(daemonDir2(), "rdesk-audit.jsonl");
101102
+ return join65(daemonDir2(), "rdesk-audit.jsonl");
99510
101103
  }
99511
101104
  var queue = [];
99512
101105
  var draining = false;
@@ -99546,81 +101139,13 @@ function appendRdeskAudit(e) {
99546
101139
  }
99547
101140
  }
99548
101141
 
99549
- // ../../packages/host-core/dist/rdesk/screen-permission.js
99550
- function screenRecordingStatus() {
99551
- if (process.platform !== "darwin")
99552
- return "unsupported";
99553
- try {
99554
- const sp = electronModule()?.systemPreferences;
99555
- const s = sp?.getMediaAccessStatus("screen");
99556
- if (s === "granted" || s === "denied" || s === "restricted" || s === "not-determined")
99557
- return s;
99558
- return "not-determined";
99559
- } catch {
99560
- return "not-determined";
99561
- }
99562
- }
99563
- async function registerForScreenRecording() {
99564
- try {
99565
- const dc = electronModule()?.desktopCapturer;
99566
- await dc?.getSources({ types: ["screen"], thumbnailSize: { width: 1, height: 1 } });
99567
- } catch {
99568
- }
99569
- }
99570
- async function openScreenRecordingSettings() {
99571
- if (process.platform !== "darwin")
99572
- return;
99573
- await registerForScreenRecording();
99574
- try {
99575
- const shell = electronModule()?.shell;
99576
- await shell?.openExternal("x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture");
99577
- } catch {
99578
- }
99579
- }
99580
- var PROMPT_COOLDOWN_MS = 6e4;
99581
- var lastPromptAt = 0;
99582
- async function promptForScreenRecording(opts = {}) {
99583
- if (process.platform !== "darwin")
99584
- return false;
99585
- if (screenRecordingStatus() === "granted")
99586
- return false;
99587
- const now2 = Date.now();
99588
- if (now2 - lastPromptAt < PROMPT_COOLDOWN_MS)
99589
- return false;
99590
- lastPromptAt = now2;
99591
- const el2 = electronModule();
99592
- const who = opts.viewerName ? `${opts.viewerName} is` : "Someone is";
99593
- opts.log?.(`screen recording not granted \u2014 prompting (${who} waiting)`);
99594
- if (!el2?.dialog) {
99595
- opts.log?.("no GUI to prompt with \u2014 grant Screen Recording in System Settings \u2192 Privacy & Security");
99596
- return false;
99597
- }
99598
- try {
99599
- const { response } = await el2.dialog.showMessageBox({
99600
- type: "warning",
99601
- buttons: ["Open System Settings", "Not Now"],
99602
- defaultId: 0,
99603
- cancelId: 1,
99604
- message: "Allow screen sharing on this Mac?",
99605
- detail: `${who} trying to connect to this computer, but macOS is blocking screen capture.
99606
-
99607
- Open System Settings \u2192 Privacy & Security \u2192 Screen Recording and switch on Tesseract Remote Desktop, then ask them to connect again.`
99608
- });
99609
- if (response === 0)
99610
- await openScreenRecordingSettings();
99611
- return true;
99612
- } catch {
99613
- return false;
99614
- }
99615
- }
99616
-
99617
101142
  // ../../packages/host-core/dist/fileprovider-bridge.js
99618
101143
  import { writeFileSync as writeFileSync34, mkdirSync as mkdirSync33, rmSync as rmSync8, existsSync as existsSync31 } from "node:fs";
99619
101144
  import { homedir as homedir9 } from "node:os";
99620
- import { join as join65 } from "node:path";
101145
+ import { join as join66 } from "node:path";
99621
101146
  var APPEX_BUNDLE_ID = "dev.tesseract.FileProvider";
99622
101147
  function appexBridgeInfoPath() {
99623
- return join65(homedir9(), "Library", "Containers", APPEX_BUNDLE_ID, "Data", "Library", "Application Support", "tesseract-bridge.json");
101148
+ return join66(homedir9(), "Library", "Containers", APPEX_BUNDLE_ID, "Data", "Library", "Application Support", "tesseract-bridge.json");
99624
101149
  }
99625
101150
  function clearBridgeInfo() {
99626
101151
  if (process.platform !== "darwin")
@@ -99787,10 +101312,10 @@ function stopFileProviderBridge() {
99787
101312
  }
99788
101313
 
99789
101314
  // ../../packages/host-core/dist/vault/autofill-bridge.js
99790
- import { randomBytes as randomBytes7 } from "node:crypto";
101315
+ import { randomBytes as randomBytes9 } from "node:crypto";
99791
101316
  import { existsSync as existsSync32, mkdirSync as mkdirSync34, writeFileSync as writeFileSync35, rmSync as rmSync9 } from "node:fs";
99792
101317
  import { homedir as homedir10 } from "node:os";
99793
- import { join as join66 } from "node:path";
101318
+ import { join as join67 } from "node:path";
99794
101319
 
99795
101320
  // ../../packages/host-core/dist/vault/peer-verify.js
99796
101321
  import { execFile as execFile9 } from "node:child_process";
@@ -99852,10 +101377,10 @@ async function isTrustedAutofillPeer(remotePort) {
99852
101377
  var APPEX_BUNDLE_ID2 = "dev.tesseract.AutoFill";
99853
101378
  var BRIDGE_PORTS2 = [17872, 17873, 17874, 17875];
99854
101379
  function appexContainerData() {
99855
- return join66(homedir10(), "Library", "Containers", APPEX_BUNDLE_ID2, "Data");
101380
+ return join67(homedir10(), "Library", "Containers", APPEX_BUNDLE_ID2, "Data");
99856
101381
  }
99857
101382
  function bridgeInfoPath() {
99858
- return join66(appexContainerData(), "Library", "Application Support", "tesseract-autofill-bridge.json");
101383
+ return join67(appexContainerData(), "Library", "Application Support", "tesseract-autofill-bridge.json");
99859
101384
  }
99860
101385
  var infoLoggedOnce = false;
99861
101386
  function writeBridgeInfo(port, token3, log9) {
@@ -99870,7 +101395,7 @@ function writeBridgeInfo(port, token3, log9) {
99870
101395
  }
99871
101396
  return;
99872
101397
  }
99873
- const dir2 = join66(containerData, "Library", "Application Support");
101398
+ const dir2 = join67(containerData, "Library", "Application Support");
99874
101399
  mkdirSync34(dir2, { recursive: true });
99875
101400
  writeFileSync35(bridgeInfoPath(), JSON.stringify({ port, token: token3, pid: process.pid, ts: Date.now() }), { mode: 384 });
99876
101401
  if (!infoLoggedOnce) {
@@ -100031,7 +101556,7 @@ function startAutofillBridge(log9 = () => {
100031
101556
  if (process.platform !== "darwin" || wss2)
100032
101557
  return;
100033
101558
  stopping2 = false;
100034
- token2 = randomBytes7(24).toString("base64url");
101559
+ token2 = randomBytes9(24).toString("base64url");
100035
101560
  bind(0, log9);
100036
101561
  }
100037
101562
  function stopAutofillBridge() {
@@ -100057,15 +101582,15 @@ function stopAutofillBridge() {
100057
101582
 
100058
101583
  // ../../packages/host-core/dist/power-node.js
100059
101584
  import { spawn as spawn13 } from "node:child_process";
100060
- import { platform as platform3 } from "node:os";
101585
+ import { platform as platform4 } from "node:os";
100061
101586
  function createNodePowerController() {
100062
101587
  const active = /* @__PURE__ */ new Set();
100063
101588
  let proc = null;
100064
101589
  function spawnInhibitor() {
100065
101590
  try {
100066
- if (platform3() === "darwin")
101591
+ if (platform4() === "darwin")
100067
101592
  return spawn13("caffeinate", ["-i"], { stdio: "ignore" });
100068
- if (platform3() === "linux") {
101593
+ if (platform4() === "linux") {
100069
101594
  return spawn13("systemd-inhibit", ["--what=sleep", "--why=tesseract agent running", "--mode=block", "sleep", "infinity"], { stdio: "ignore" });
100070
101595
  }
100071
101596
  } catch {
@@ -100115,28 +101640,28 @@ function createNodePowerController() {
100115
101640
  // ../../packages/host-core/dist/native-host.js
100116
101641
  import { execFileSync as execFileSync4 } from "node:child_process";
100117
101642
  import { chmodSync as chmodSync6, existsSync as existsSync33, mkdirSync as mkdirSync35, writeFileSync as writeFileSync36 } from "node:fs";
100118
- import { homedir as homedir11, platform as platform4 } from "node:os";
100119
- import { dirname as dirname27, join as join67, resolve as resolve12 } from "node:path";
101643
+ import { homedir as homedir11, platform as platform5 } from "node:os";
101644
+ import { dirname as dirname27, join as join68, resolve as resolve12 } from "node:path";
100120
101645
  import { fileURLToPath as fileURLToPath5 } from "node:url";
100121
101646
  var HOST_NAME = "com.tesseract.companion";
100122
101647
  var EXTENSION_IDS = ["icpnghhpcmaonjckkpilpajblfehpplo", "giolfpookdhjfafcchaflhmigghaeffn"];
100123
101648
  var BRIDGE_BASENAME = "host.cjs";
100124
101649
  function browserProfileDirs() {
100125
101650
  const home = homedir11();
100126
- const p = platform4();
101651
+ const p = platform5();
100127
101652
  if (p === "darwin") {
100128
- const base = join67(home, "Library/Application Support");
100129
- return ["Google/Chrome", "Google/Chrome Beta", "Google/Chrome Dev", "Google/Chrome Canary", "Chromium", "Microsoft Edge", "BraveSoftware/Brave-Browser", "Vivaldi", "Arc"].map((b) => join67(base, b));
101653
+ const base = join68(home, "Library/Application Support");
101654
+ return ["Google/Chrome", "Google/Chrome Beta", "Google/Chrome Dev", "Google/Chrome Canary", "Chromium", "Microsoft Edge", "BraveSoftware/Brave-Browser", "Vivaldi", "Arc"].map((b) => join68(base, b));
100130
101655
  }
100131
101656
  if (p === "win32")
100132
101657
  return [];
100133
- const cfg2 = join67(home, ".config");
100134
- return ["google-chrome", "google-chrome-beta", "chromium", "microsoft-edge", "BraveSoftware/Brave-Browser", "vivaldi"].map((b) => join67(cfg2, b));
101658
+ const cfg2 = join68(home, ".config");
101659
+ return ["google-chrome", "google-chrome-beta", "chromium", "microsoft-edge", "BraveSoftware/Brave-Browser", "vivaldi"].map((b) => join68(cfg2, b));
100135
101660
  }
100136
101661
  function resolveBridge(log9) {
100137
101662
  const candidates = [
100138
101663
  process.env.CCB_COMPANION_HOST_JS,
100139
- process.resourcesPath ? join67(process.resourcesPath, "companion-host", BRIDGE_BASENAME) : void 0
101664
+ process.resourcesPath ? join68(process.resourcesPath, "companion-host", BRIDGE_BASENAME) : void 0
100140
101665
  ];
100141
101666
  try {
100142
101667
  const here = dirname27(fileURLToPath5(import.meta.url));
@@ -100151,8 +101676,8 @@ function resolveBridge(log9) {
100151
101676
  return null;
100152
101677
  }
100153
101678
  function writeLauncher(daemonDir3, bridge, runtime) {
100154
- const isWin = platform4() === "win32";
100155
- const launcher = join67(daemonDir3, isWin ? "companion-host.cmd" : "companion-host.sh");
101679
+ const isWin = platform5() === "win32";
101680
+ const launcher = join68(daemonDir3, isWin ? "companion-host.cmd" : "companion-host.sh");
100156
101681
  if (isWin) {
100157
101682
  writeFileSync36(launcher, `@echo off\r
100158
101683
  set ELECTRON_RUN_AS_NODE=1\r
@@ -100183,16 +101708,16 @@ function registerNativeHost(opts) {
100183
101708
  type: "stdio",
100184
101709
  allowed_origins: EXTENSION_IDS.map((id) => `chrome-extension://${id}/`)
100185
101710
  }, null, 2);
100186
- if (platform4() === "win32")
101711
+ if (platform5() === "win32")
100187
101712
  return registerWindows(opts.daemonDir, manifestJson, log9);
100188
101713
  let wrote = 0;
100189
101714
  for (const profile of browserProfileDirs()) {
100190
101715
  if (!existsSync33(profile))
100191
101716
  continue;
100192
101717
  try {
100193
- const dir2 = join67(profile, "NativeMessagingHosts");
101718
+ const dir2 = join68(profile, "NativeMessagingHosts");
100194
101719
  mkdirSync35(dir2, { recursive: true });
100195
- writeFileSync36(join67(dir2, `${HOST_NAME}.json`), manifestJson);
101720
+ writeFileSync36(join68(dir2, `${HOST_NAME}.json`), manifestJson);
100196
101721
  wrote++;
100197
101722
  } catch {
100198
101723
  }
@@ -100204,7 +101729,7 @@ function registerNativeHost(opts) {
100204
101729
  }
100205
101730
  function registerWindows(daemonDir3, manifestJson, log9) {
100206
101731
  try {
100207
- const manifestPath = join67(daemonDir3, `${HOST_NAME}.json`);
101732
+ const manifestPath = join68(daemonDir3, `${HOST_NAME}.json`);
100208
101733
  writeFileSync36(manifestPath, manifestJson);
100209
101734
  for (const root of ["Software\\Google\\Chrome", "Software\\Microsoft\\Edge", "Software\\BraveSoftware\\Brave-Browser"]) {
100210
101735
  try {
@@ -100224,9 +101749,9 @@ init_daemon_settings();
100224
101749
  // ../../packages/host-core/dist/activity/activity-tracker.js
100225
101750
  init_credentials();
100226
101751
  import { promises as fsp, writeFileSync as writeFileSync37, mkdirSync as mkdirSync36, existsSync as existsSync34 } from "node:fs";
100227
- import { join as join68 } from "node:path";
101752
+ import { join as join69 } from "node:path";
100228
101753
  function activityProfilePath() {
100229
- return join68(daemonDir2(), "activity-profile.json");
101754
+ return join69(daemonDir2(), "activity-profile.json");
100230
101755
  }
100231
101756
  var MAX_APPS = 300;
100232
101757
  var MAX_AGE_DAYS = 120;
@@ -100535,8 +102060,8 @@ async function runDaemon(opts = {}) {
100535
102060
  log9("paths", JSON.stringify(sealBasePaths()));
100536
102061
  const OUR_STARTED_AT = procStartedAt(process.pid);
100537
102062
  let ownsMachine = false;
100538
- const pidfile = () => join69(daemonDir2(), "daemon.lock");
100539
- const statusFile = () => join69(daemonDir2(), "status.json");
102063
+ const pidfile = () => join70(daemonDir2(), "daemon.lock");
102064
+ const statusFile = () => join70(daemonDir2(), "status.json");
100540
102065
  const isAlive2 = (pid) => {
100541
102066
  try {
100542
102067
  process.kill(pid, 0);
@@ -100976,12 +102501,43 @@ async function runDaemon(opts = {}) {
100976
102501
  } catch {
100977
102502
  }
100978
102503
  });
100979
- eapp.on("render-process-gone", (_e, d) => {
102504
+ const renderRecoveries = [];
102505
+ const RECOVER_WINDOW_MS = 6e4, RECOVER_MAX = 4, RECOVER_DELAY_MS = 300;
102506
+ const recoverRenderer = (wc, reason) => {
102507
+ if (!mergedProcess || deliberateMergedQuit())
102508
+ return;
102509
+ if (reason && !["killed", "crashed", "abnormal-exit", "oom", "launch-failed", "integrity-failure"].includes(reason))
102510
+ return;
102511
+ const now2 = Date.now();
102512
+ while (renderRecoveries.length && now2 - renderRecoveries[0] > RECOVER_WINDOW_MS)
102513
+ renderRecoveries.shift();
102514
+ if (renderRecoveries.length >= RECOVER_MAX) {
102515
+ try {
102516
+ log9(`render-recover: ${RECOVER_MAX} reloads in <60s \u2014 backing off (page may be genuinely crashing)`);
102517
+ } catch {
102518
+ }
102519
+ return;
102520
+ }
102521
+ renderRecoveries.push(now2);
102522
+ const contents = wc;
102523
+ setTimeout(() => {
102524
+ try {
102525
+ if (!contents || contents.isDestroyed?.())
102526
+ return;
102527
+ log9(`render-recover: reloading window after '${reason ?? "unknown"}' (recovery #${renderRecoveries.length})`);
102528
+ contents.reload?.();
102529
+ } catch {
102530
+ }
102531
+ }, RECOVER_DELAY_MS).unref?.();
102532
+ };
102533
+ eapp.on("render-process-gone", (_e, wc, details) => {
102534
+ const reason = details?.reason;
100980
102535
  try {
100981
- log9(`render-process-gone (kept alive) uptime=${Date.now() - daemonStartedAt}ms: ${JSON.stringify(d)}`);
102536
+ log9(`render-process-gone (kept alive) uptime=${Date.now() - daemonStartedAt}ms: ${JSON.stringify(details ?? {})}`);
100982
102537
  snapshotProcs("render-gone");
100983
102538
  } catch {
100984
102539
  }
102540
+ recoverRenderer(wc, reason);
100985
102541
  });
100986
102542
  eapp.on("child-process-gone", (_e, d) => {
100987
102543
  try {
@@ -101000,7 +102556,7 @@ async function runDaemon(opts = {}) {
101000
102556
  }
101001
102557
  if (ownsMachine)
101002
102558
  setHostDaemonRole(true);
101003
- const localToken = randomBytes8(24).toString("hex");
102559
+ const localToken = randomBytes10(24).toString("hex");
101004
102560
  const sendToViewer = (kind, sessionId, clientId, msg) => {
101005
102561
  const lb = loopbackRdeskSend.get(clientId);
101006
102562
  if (lb) {
@@ -101159,7 +102715,7 @@ async function runDaemon(opts = {}) {
101159
102715
  if (r.status === 401) {
101160
102716
  log9("device token no longer valid \u2014 dropping to local-only on restart");
101161
102717
  try {
101162
- unlinkSync6(join69(daemonDir2(), "credentials.json"));
102718
+ unlinkSync6(join70(daemonDir2(), "credentials.json"));
101163
102719
  } catch {
101164
102720
  }
101165
102721
  shutdown(0, "token-revoked-401");
@@ -101557,14 +103113,14 @@ async function runDaemon(opts = {}) {
101557
103113
  // is on; with it off it is the standalone Remote Desktop app, and we forward rather than
101558
103114
  // handle. `provider()` re-reads the setting every time, so switching it back on takes the
101559
103115
  // channel away from the claimant mid-flight — there is never a moment with two servers.
101560
- onRdesk: (payload, clientId, sessionId) => {
103116
+ onRdesk: (payload, clientId, sessionId, viewerOwner) => {
101561
103117
  const p = rdeskChannel.provider();
101562
103118
  if (p && clientId) {
101563
103119
  p.control(sessionId, clientId, payload);
101564
103120
  return;
101565
103121
  }
101566
103122
  if (rdesk && clientId)
101567
- void rdesk.onClientMessage(sessionId, { clientId }, payload);
103123
+ void rdesk.onClientMessage(sessionId, { clientId, sameAccount: viewerOwner }, payload);
101568
103124
  },
101569
103125
  onRdeskSignal: (payload, clientId, sessionId) => {
101570
103126
  const p = rdeskChannel.provider();
@@ -101657,7 +103213,7 @@ async function runDaemon(opts = {}) {
101657
103213
  if (appPid > 0 && appPid !== process.pid) {
101658
103214
  const quitMarker = () => {
101659
103215
  try {
101660
- return Number(readFileSync45(join69(daemonDir2(), "app-quit.marker"), "utf-8").trim()) || 0;
103216
+ return Number(readFileSync45(join70(daemonDir2(), "app-quit.marker"), "utf-8").trim()) || 0;
101661
103217
  } catch {
101662
103218
  return 0;
101663
103219
  }
@@ -101682,7 +103238,7 @@ async function runDaemon(opts = {}) {
101682
103238
  log9(`desktop app (pid ${appPid}) is gone with NO clean-quit marker \u2014 reporting`);
101683
103239
  const tail3 = (name) => {
101684
103240
  try {
101685
- const buf = readFileSync45(join69(daemonDir2(), name), "utf-8");
103241
+ const buf = readFileSync45(join70(daemonDir2(), name), "utf-8");
101686
103242
  return buf.length > 4096 ? buf.slice(-4096) : buf;
101687
103243
  } catch {
101688
103244
  return void 0;
@@ -101713,7 +103269,7 @@ async function runDaemon(opts = {}) {
101713
103269
  }
101714
103270
  try {
101715
103271
  const DAEMON_LOG_CAP = 2 * 1024 * 1024;
101716
- const daemonLogFile = join69(daemonDir2(), "daemon.log");
103272
+ const daemonLogFile = join70(daemonDir2(), "daemon.log");
101717
103273
  const capTimer = setInterval(() => {
101718
103274
  try {
101719
103275
  if (existsSync35(daemonLogFile) && statSync9(daemonLogFile).size > DAEMON_LOG_CAP) {
@@ -101765,17 +103321,17 @@ init_dist6();
101765
103321
  init_credentials();
101766
103322
  init_dist();
101767
103323
  var MESH_BASE = "/api/core/tesseract/mesh";
101768
- function fail2(code, detail) {
103324
+ function fail3(code, detail) {
101769
103325
  return { ok: false, code, detail };
101770
103326
  }
101771
- async function call(path6, init, auth = true) {
103327
+ async function call2(path6, init, auth = true) {
101772
103328
  const creds3 = auth ? readCredentials() : null;
101773
103329
  if (auth && !creds3) {
101774
- return fail2("not-signed-in", "sign in first: tesseract-agent login");
103330
+ return fail3("not-signed-in", "sign in first: tesseract-agent login");
101775
103331
  }
101776
103332
  const origin = creds3?.apiOrigin;
101777
103333
  if (!origin)
101778
- return fail2("not-signed-in", "no API origin is configured on this machine");
103334
+ return fail3("not-signed-in", "no API origin is configured on this machine");
101779
103335
  let res;
101780
103336
  try {
101781
103337
  res = await fetch(`${origin.replace(/\/$/, "")}${MESH_BASE}${path6}`, {
@@ -101787,7 +103343,7 @@ async function call(path6, init, auth = true) {
101787
103343
  ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
101788
103344
  });
101789
103345
  } catch (e) {
101790
- return fail2("network", e instanceof Error ? e.message : String(e));
103346
+ return fail3("network", e instanceof Error ? e.message : String(e));
101791
103347
  }
101792
103348
  const text9 = await res.text();
101793
103349
  if (!res.ok) {
@@ -101798,30 +103354,31 @@ async function call(path6, init, auth = true) {
101798
103354
  detail = Array.isArray(parsed.message) ? parsed.message.join("; ") : parsed.message;
101799
103355
  } catch {
101800
103356
  }
101801
- return fail2(res.status >= 500 ? "server" : "refused", detail);
103357
+ return fail3(res.status >= 500 ? "server" : "refused", detail);
101802
103358
  }
101803
103359
  try {
101804
103360
  return { ok: true, data: text9 ? JSON.parse(text9) : {} };
101805
103361
  } catch {
101806
- return fail2("server", "the server sent something that is not JSON");
103362
+ return fail3("server", "the server sent something that is not JSON");
101807
103363
  }
101808
103364
  }
101809
103365
  async function listMeshes() {
101810
- const r = await call("/meshes", { method: "GET" });
103366
+ const r = await call2("/meshes", { method: "GET" });
101811
103367
  return r.ok ? { ok: true, meshes: r.data } : r;
101812
103368
  }
101813
103369
  async function deleteMesh(args) {
101814
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}?confirm=${encodeURIComponent(args.confirm)}`, { method: "DELETE" });
103370
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}?confirm=${encodeURIComponent(args.confirm)}`, { method: "DELETE" });
101815
103371
  return r.ok ? { ok: true, deleted: r.data.deleted } : r;
101816
103372
  }
101817
103373
  async function createMesh(args = {}) {
101818
- const r = await call("/meshes", {
103374
+ const r = await call2("/meshes", {
101819
103375
  method: "POST",
101820
103376
  body: {
101821
103377
  ...args.name ? { name: args.name } : {},
101822
103378
  ...args.cidr ? { meshCidr4: args.cidr } : {},
101823
103379
  ...args.approvalMode ? { approvalMode: args.approvalMode } : {},
101824
103380
  ...args.allowExitNode !== void 0 ? { allowExitNode: args.allowExitNode } : {},
103381
+ ...args.fullTunnelDefault !== void 0 ? { fullTunnelDefault: args.fullTunnelDefault } : {},
101825
103382
  ...args.allowRelay !== void 0 ? { allowRelay: args.allowRelay } : {},
101826
103383
  ...args.magicDns !== void 0 ? { magicDns: args.magicDns } : {}
101827
103384
  }
@@ -101829,42 +103386,42 @@ async function createMesh(args = {}) {
101829
103386
  return r.ok ? { ok: true, ...r.data } : r;
101830
103387
  }
101831
103388
  async function joinToken(args) {
101832
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}/token`, { method: "GET" });
103389
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/token`, { method: "GET" });
101833
103390
  return r.ok ? { ok: true, token: r.data.token } : r;
101834
103391
  }
101835
103392
  async function rotateJoinToken(args) {
101836
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}/token/rotate`, { method: "POST", body: {} });
103393
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/token/rotate`, { method: "POST", body: {} });
101837
103394
  return r.ok ? { ok: true, token: r.data.token } : r;
101838
103395
  }
101839
103396
  async function approveNode(args) {
101840
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}/approve`, { method: "POST", body: {} });
103397
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}/approve`, { method: "POST", body: {} });
101841
103398
  return r.ok ? { ok: true, epoch: r.data.epoch } : r;
101842
103399
  }
101843
103400
  async function newJoinCode(args) {
101844
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}/codes`, { method: "POST", body: { uses: args.uses, ttlMinutes: args.ttlMinutes } });
103401
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/codes`, { method: "POST", body: { uses: args.uses, ttlMinutes: args.ttlMinutes } });
101845
103402
  return r.ok ? { ok: true, ...r.data } : r;
101846
103403
  }
101847
103404
  async function evictNode(args) {
101848
- const r = await call(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}`, { method: "DELETE", body: {} });
103405
+ const r = await call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes/${encodeURIComponent(args.nodeId)}`, { method: "DELETE", body: {} });
101849
103406
  return r.ok ? { ok: true, epoch: r.data.epoch } : r;
101850
103407
  }
101851
103408
  async function enrolWith(requested, post) {
101852
103409
  const name = normaliseNodeName(requested);
101853
103410
  if (!name) {
101854
- return fail2("bad-name", `"${requested}" cannot be a machine name \u2014 names are DNS labels, so letters, digits and hyphens only`);
103411
+ return fail3("bad-name", `"${requested}" cannot be a machine name \u2014 names are DNS labels, so letters, digits and hyphens only`);
101855
103412
  }
101856
103413
  const stat9 = await generateStaticKey();
101857
103414
  const sig = await generateSigningKey();
101858
103415
  const staticPrivate = await rawPrivate(stat9.privateKey);
101859
103416
  const sigPrivate = await rawPrivate(sig.privateKey);
101860
- const r = await post(hex4(stat9.publicRaw), hex4(sig.publicRaw), name);
103417
+ const r = await post(hex5(stat9.publicRaw), hex5(sig.publicRaw), name);
101861
103418
  if (!r.ok)
101862
103419
  return r;
101863
103420
  const cert = fromHexOrB64(r.data.cert);
101864
103421
  const genesis = fromHexOrB64(r.data.genesis);
101865
103422
  const meshId = meshIdOf(cert);
101866
103423
  if (!meshId)
101867
- return fail2("server", "the certificate the server returned is unreadable");
103424
+ return fail3("server", "the certificate the server returned is unreadable");
101868
103425
  let issuedName = name;
101869
103426
  try {
101870
103427
  issuedName = decodeCert(cert).details.name || name;
@@ -101873,8 +103430,14 @@ async function enrolWith(requested, post) {
101873
103430
  try {
101874
103431
  saveMesh(meshId, { genesis, cert, staticPrivate, sigPrivate });
101875
103432
  writeLocal(meshId, { joinedAt: Date.now(), enabled: true });
103433
+ if (r.data.bundle) {
103434
+ try {
103435
+ cacheBundle(fromHexOrB64(r.data.bundle), meshId);
103436
+ } catch {
103437
+ }
103438
+ }
101876
103439
  } catch (e) {
101877
- return fail2("disk", `the certificate was issued but could not be saved: ${e instanceof Error ? e.message : String(e)}. Ask an admin for a new join code \u2014 this one has been used.`);
103440
+ return fail3("disk", `the certificate was issued but could not be saved: ${e instanceof Error ? e.message : String(e)}. Ask an admin for a new join code \u2014 this one has been used.`);
101878
103441
  }
101879
103442
  return {
101880
103443
  ok: true,
@@ -101888,9 +103451,9 @@ async function enrolWith(requested, post) {
101888
103451
  };
101889
103452
  }
101890
103453
  async function enrol(args) {
101891
- return enrolWith(args.name, (staticPub, sigPub, name) => call(`/meshes/${encodeURIComponent(args.meshId)}/nodes`, {
103454
+ return enrolWith(args.name, (staticPub, sigPub, name) => call2(`/meshes/${encodeURIComponent(args.meshId)}/nodes`, {
101892
103455
  method: "POST",
101893
- body: { name, staticPub, sigPub }
103456
+ body: { name, staticPub, sigPub, ...args.exitNode === true ? { exitNode: true } : {} }
101894
103457
  }));
101895
103458
  }
101896
103459
  async function joinWithToken(args) {
@@ -101899,7 +103462,7 @@ async function joinWithToken(args) {
101899
103462
  async function postJoin(origin, body) {
101900
103463
  const base = origin ?? readCredentials()?.apiOrigin;
101901
103464
  if (!base) {
101902
- return fail2("not-signed-in", "this machine has never signed in \u2014 pass --origin https://\u2026 so it knows which server to ask");
103465
+ return fail3("not-signed-in", "this machine has never signed in \u2014 pass --origin https://\u2026 so it knows which server to ask");
101903
103466
  }
101904
103467
  let res;
101905
103468
  try {
@@ -101909,7 +103472,7 @@ async function postJoin(origin, body) {
101909
103472
  body: JSON.stringify(body)
101910
103473
  });
101911
103474
  } catch (e) {
101912
- return fail2("network", e instanceof Error ? e.message : String(e));
103475
+ return fail3("network", e instanceof Error ? e.message : String(e));
101913
103476
  }
101914
103477
  const text9 = await res.text();
101915
103478
  if (!res.ok) {
@@ -101920,7 +103483,7 @@ async function postJoin(origin, body) {
101920
103483
  detail = String(parsed.message);
101921
103484
  } catch {
101922
103485
  }
101923
- return fail2(res.status >= 500 ? "server" : "refused", detail);
103486
+ return fail3(res.status >= 500 ? "server" : "refused", detail);
101924
103487
  }
101925
103488
  return { ok: true, data: JSON.parse(text9) };
101926
103489
  }
@@ -101934,7 +103497,7 @@ async function rawPrivate(key2) {
101934
103497
  }
101935
103498
  return pkcs8.subarray(16);
101936
103499
  }
101937
- function hex4(b) {
103500
+ function hex5(b) {
101938
103501
  return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
101939
103502
  }
101940
103503
  function fromHexOrB64(s) {
@@ -101950,8 +103513,63 @@ function meshIdOf(cert) {
101950
103513
  return meshDirNameFromWireId(Array.from(cert.subarray(OFFSET, OFFSET + 32), (b) => b.toString(16).padStart(2, "0")).join(""));
101951
103514
  }
101952
103515
 
101953
- // ../../packages/host-core/dist/mesh/netd-client.js
101954
- var MAX_LINE = 1024 * 1024;
103516
+ // ../../packages/host-core/dist/mesh/full-tunnel.js
103517
+ function fullTunnelState(i) {
103518
+ const no2 = (reason) => ({ allowed: false, reason, warnings: [] });
103519
+ if (i.platform !== "linux") {
103520
+ const name = i.platform === "darwin" ? "macOS" : i.platform === "win32" ? "Windows" : i.platform;
103521
+ return no2(`Routing all traffic needs the network helper, which does not exist on ${name} yet.`);
103522
+ }
103523
+ if (!i.engineAvailable) {
103524
+ return no2("This build shipped without the network engine, so no traffic can be routed. That is a packaging fault \u2014 please report it.");
103525
+ }
103526
+ if (i.helperCode === "wire-version") {
103527
+ return no2("Update the network helper \u2014 this build speaks a newer protocol than the one installed.");
103528
+ }
103529
+ if (!i.helperAvailable) {
103530
+ return no2("Turn this network on to install the network helper \u2014 nothing can be routed until it is there.");
103531
+ }
103532
+ if (!i.hasBundle) {
103533
+ return no2("This machine has not received this network\u2019s policy yet, so nothing can be routed. It arrives from any other machine on the network.");
103534
+ }
103535
+ if (!i.networkAllows) {
103536
+ return no2("This network does not allow routing all traffic through it. An admin of the network chooses that.");
103537
+ }
103538
+ if (i.selfIsExitNode) {
103539
+ return no2("This machine is this network\u2019s way out to the internet, so it cannot route its own traffic through itself.");
103540
+ }
103541
+ if (i.exitNodes.length === 0) {
103542
+ return no2("No machine on this network offers to be the way out yet, so there is nowhere for the traffic to go.");
103543
+ }
103544
+ if (i.claimedBy) {
103545
+ return no2(`All traffic already goes through ${i.claimedBy}. A machine has one default route, so only one network can claim it.`);
103546
+ }
103547
+ if (!i.ownsNode) {
103548
+ return no2("The Tesseract app is running this network on this machine. Change this from there.");
103549
+ }
103550
+ if (i.pathToExit === "none") {
103551
+ return no2(`Waiting for a connection to ${i.exitNodes[0]}. All traffic cannot be routed until this machine can reach it.`);
103552
+ }
103553
+ const warnings = [];
103554
+ if (i.pathToExit === "relay") {
103555
+ warnings.push(`All traffic will go through ${i.exitNodes[0]} by way of a relay, so it will be slower than usual.`);
103556
+ }
103557
+ return { allowed: true, reason: null, warnings };
103558
+ }
103559
+ function bundleGrantsExitNode(bundle) {
103560
+ if (bundle === void 0 || bundle.length === 0)
103561
+ return false;
103562
+ try {
103563
+ const pki = (init_dist6(), __toCommonJS(dist_exports3));
103564
+ const decoded = pki.decodeSignedBundle(bundle);
103565
+ return decoded.bundle.rules.some((r) => (r.caps & pki.CAP_EXIT_NODE) !== 0);
103566
+ } catch {
103567
+ return false;
103568
+ }
103569
+ }
103570
+
103571
+ // ../../packages/host-core/dist/mesh/machine-owner.js
103572
+ init_credentials();
101955
103573
 
101956
103574
  // ../../packages/host-core/dist/service/exec.js
101957
103575
  import { execFile as execFile10, spawn as spawn14 } from "node:child_process";
@@ -101969,9 +103587,6 @@ function runInherit(cmd, args) {
101969
103587
  var UNIT = "tesseract-netd.service";
101970
103588
  var UNIT_PATH = `/etc/systemd/system/${UNIT}`;
101971
103589
 
101972
- // ../../packages/host-core/dist/mesh/machine-owner.js
101973
- init_credentials();
101974
-
101975
103590
  // ../../packages/host-core/dist/clipboard/clipboard-sync.js
101976
103591
  var MAX_IMAGE_BYTES3 = 10 * 1024 * 1024;
101977
103592
  var OVERSIZED_BYTES = 512 * 1024;
@@ -101985,7 +103600,7 @@ init_daemon_settings();
101985
103600
  init_credentials();
101986
103601
 
101987
103602
  // ../../packages/host-core/dist/service/index.js
101988
- import { platform as platform5 } from "node:os";
103603
+ import { platform as platform6 } from "node:os";
101989
103604
 
101990
103605
  // ../../packages/host-core/dist/service/launchd.js
101991
103606
  init_credentials();
@@ -102265,7 +103880,7 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
102265
103880
  // ../../packages/host-core/dist/service/index.js
102266
103881
  function getServiceController(instanceId) {
102267
103882
  const id = instanceId && instanceId.length ? instanceId : void 0;
102268
- switch (platform5()) {
103883
+ switch (platform6()) {
102269
103884
  case "darwin":
102270
103885
  return makeLaunchd(id);
102271
103886
  case "linux":
@@ -102523,12 +104138,12 @@ function isReleaseVersion(v) {
102523
104138
  return /^\d+\.\d+\.\d+/.test(v.trim());
102524
104139
  }
102525
104140
  function isNewer(latest, current) {
102526
- const parse3 = (v) => {
104141
+ const parse4 = (v) => {
102527
104142
  const m = /^v?(\d+)\.(\d+)\.(\d+)/.exec(v.trim());
102528
104143
  return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
102529
104144
  };
102530
- const a = parse3(latest);
102531
- const b = parse3(current);
104145
+ const a = parse4(latest);
104146
+ const b = parse4(current);
102532
104147
  if (!a || !b) return false;
102533
104148
  for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] > b[i];
102534
104149
  return false;
@@ -102646,12 +104261,12 @@ function startSelfUpdater(current) {
102646
104261
 
102647
104262
  // src/service.ts
102648
104263
  import { join as join75 } from "node:path";
102649
- import { platform as platform6 } from "node:os";
104264
+ import { platform as platform7 } from "node:os";
102650
104265
  import { existsSync as existsSync40, readFileSync as readFileSync46 } from "node:fs";
102651
104266
  function controller(instanceId) {
102652
104267
  const c = getServiceController(instanceId);
102653
104268
  if (!c) {
102654
- throw new Error(`tesseract-agent can't manage a background service on ${platform6()}. Run it in the foreground instead: \`tesseract-agent run\` (e.g. as a Docker entrypoint).`);
104269
+ throw new Error(`tesseract-agent can't manage a background service on ${platform7()}. Run it in the foreground instead: \`tesseract-agent run\` (e.g. as a Docker entrypoint).`);
102655
104270
  }
102656
104271
  return c;
102657
104272
  }
@@ -102732,7 +104347,9 @@ Running a network (needs a signed-in account):
102732
104347
  tesseract-agent net new [NAME] Create a network and print its join token.
102733
104348
  [--approve auto|admin] who may join: the token alone, or you say yes
102734
104349
  [--cidr A.B.C.D/L] address range (default 100.96.0.0/12)
102735
- [--exit-node] [--no-relay] [--no-dns] everything is optional and has a default
104350
+ [--exit-node] let machines route ALL traffic through it
104351
+ [--full-tunnel-default] ...and start new machines that way (needs --exit-node)
104352
+ [--no-relay] [--no-dns] everything is optional and has a default
102736
104353
  tesseract-agent net networks [--json] List your networks and their machines
102737
104354
  tesseract-agent net token MESH [--rotate] Show the join token again, or replace it
102738
104355
  tesseract-agent net approve MESH NODE Let a waiting machine on
@@ -102741,8 +104358,13 @@ Running a network (needs a signed-in account):
102741
104358
  Delete a network for good. Irreversible.
102742
104359
  tesseract-agent net code new MESH [--uses N] [--ttl MIN] [--json]
102743
104360
  A ONE-SHOT code, for anyone who wants one
102744
- tesseract-agent net join-me MESH [--name N]
104361
+ tesseract-agent net route-all [MESH] [--off]
104362
+ Route ALL of this machine's traffic through a
104363
+ network (the classic-VPN posture), or stop
104364
+ tesseract-agent net join-me MESH [--name N] [--exit-node]
102745
104365
  Join THIS machine to a network you run
104366
+ --exit-node offers this machine as everyone's
104367
+ way out to the internet (the network must allow it)
102746
104368
 
102747
104369
  Admin (needs the mesh CA, not a node):
102748
104370
  tesseract-agent net init --org NAME [--ca-dir DIR]
@@ -102898,7 +104520,7 @@ async function netCommand(rest, flags) {
102898
104520
  console.error(`net ${sub}: not enrolled in ${meshId}`);
102899
104521
  process.exit(1);
102900
104522
  }
102901
- writeLocal(meshId, { ...readLocal(meshId), enabled: sub === "up" });
104523
+ updateLocal(meshId, { enabled: sub === "up" });
102902
104524
  console.log(`${meshId} ${sub === "up" ? "enabled" : "disabled"}`);
102903
104525
  }
102904
104526
  console.log("Run `tesseract-agent restart` for this to take effect now.");
@@ -103008,11 +104630,22 @@ async function netCommand(rest, flags) {
103008
104630
  console.error("net new: --approve must be 'auto' or 'admin'");
103009
104631
  process.exit(1);
103010
104632
  }
104633
+ if (flags["full-tunnel-default"] === true && flags["exit-node"] !== true) {
104634
+ console.error(
104635
+ "net new: --full-tunnel-default needs --exit-node \u2014 the first is a default, the second is the permission it depends on"
104636
+ );
104637
+ process.exit(1);
104638
+ }
103011
104639
  const r = await createMesh({
103012
104640
  ...name ? { name } : {},
103013
104641
  ...str2(flags.cidr) ? { cidr: str2(flags.cidr) } : {},
103014
104642
  ...approve ? { approvalMode: approve } : {},
103015
104643
  ...flags["exit-node"] === true ? { allowExitNode: true } : {},
104644
+ // The DEFAULT half. Clamped to the permission server-side, but refuse it here too
104645
+ // rather than sending a combination that can never take effect — an operator who
104646
+ // typed only --full-tunnel-default has misunderstood which flag does what, and a
104647
+ // silent clamp would let them keep believing it.
104648
+ ...flags["full-tunnel-default"] === true ? { fullTunnelDefault: true } : {},
103016
104649
  ...flags["no-relay"] === true ? { allowRelay: false } : {},
103017
104650
  ...flags["no-dns"] === true ? { magicDns: false } : {}
103018
104651
  });
@@ -103129,7 +104762,11 @@ async function netCommand(rest, flags) {
103129
104762
  console.error("net join-me: that name cannot be used \u2014 letters, digits and hyphens only");
103130
104763
  process.exit(1);
103131
104764
  }
103132
- const r = await enrol({ meshId, name: nm });
104765
+ const r = await enrol({
104766
+ meshId,
104767
+ name: nm,
104768
+ ...flags["exit-node"] === true ? { exitNode: true } : {}
104769
+ });
103133
104770
  if (!r.ok) {
103134
104771
  console.error(`net join-me: ${r.detail}`);
103135
104772
  process.exit(1);
@@ -103138,6 +104775,48 @@ async function netCommand(rest, flags) {
103138
104775
  if (r.name !== nm) console.log(`(another machine here is already called "${nm}")`);
103139
104776
  return;
103140
104777
  }
104778
+ if (sub === "route-all") {
104779
+ const ids = listMeshIds();
104780
+ const target = rest[1] ?? str2(flags.mesh);
104781
+ const off = flags.off === true;
104782
+ if (!ids.length) {
104783
+ console.error("net route-all: this machine is not in any network");
104784
+ process.exit(1);
104785
+ }
104786
+ if (!target && ids.length > 1) {
104787
+ console.error("net route-all: name a network \u2014 this machine is in several");
104788
+ for (const meshId2 of ids) console.error(` ${meshId2}`);
104789
+ process.exit(1);
104790
+ }
104791
+ const meshId = target ?? ids[0];
104792
+ if (!ids.includes(meshId)) {
104793
+ console.error(`net route-all: not enrolled in ${meshId}`);
104794
+ process.exit(1);
104795
+ }
104796
+ const identity = loadMesh(meshId);
104797
+ const state3 = fullTunnelState({
104798
+ platform: process.platform,
104799
+ helperAvailable: await netdAvailable(),
104800
+ helperCode: null,
104801
+ engineAvailable: meshEngineStatus().available,
104802
+ hasBundle: identity?.bundle !== void 0 && identity.bundle.length > 0,
104803
+ networkAllows: bundleGrantsExitNode(identity?.bundle),
104804
+ exitNodes: [],
104805
+ selfIsExitNode: false,
104806
+ pathToExit: "none",
104807
+ claimedBy: ids.find((id) => id !== meshId && readLocal(id)?.fullTunnel === true) ?? null,
104808
+ ownsNode: true
104809
+ });
104810
+ if (!off && !state3.allowed) {
104811
+ console.error(`net route-all: ${state3.reason}`);
104812
+ process.exit(1);
104813
+ }
104814
+ updateLocal(meshId, { fullTunnel: !off });
104815
+ console.log(off ? `${meshId} all traffic no longer routed through this network` : `${meshId} ALL traffic from this machine will go through this network`);
104816
+ for (const w of state3.warnings) console.log(` ${w}`);
104817
+ console.log("Run `tesseract-agent restart` for this to take effect now.");
104818
+ return;
104819
+ }
103141
104820
  if (sub === "peers") {
103142
104821
  const s = readStatus();
103143
104822
  if (!s || s.stale) {