@moxxy/cli 0.8.2 → 0.9.0

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.
package/dist/bin.js CHANGED
@@ -134374,13 +134374,14 @@ async function createWebSocketTransportServer(opts) {
134374
134374
  const host = opts.host ?? "127.0.0.1";
134375
134375
  const maxConnections = opts.maxConnections ?? DEFAULT_MAX_CONNECTIONS;
134376
134376
  let currentToken = opts.authToken;
134377
+ let currentAllowedOrigins = opts.allowedOrigins ?? [];
134377
134378
  let connections = 0;
134378
134379
  const wss = new import_websocket_server.default({
134379
134380
  host,
134380
134381
  port: opts.port,
134381
134382
  maxPayload: opts.maxPayloadBytes ?? 64 * 1024 * 1024,
134382
134383
  verifyClient: (info) => {
134383
- if (!checkWsOrigin(info.req, opts.allowedOrigins)) {
134384
+ if (!checkWsOrigin(info.req, currentAllowedOrigins)) {
134384
134385
  console.warn(`[moxxy] ws bridge: rejected browser-origin upgrade (Origin: ${String(info.req.headers.origin)})`);
134385
134386
  return false;
134386
134387
  }
@@ -134420,6 +134421,9 @@ async function createWebSocketTransportServer(opts) {
134420
134421
  for (const client of wss.clients)
134421
134422
  client.terminate();
134422
134423
  },
134424
+ setAllowedOrigins(origins) {
134425
+ currentAllowedOrigins = [...origins];
134426
+ },
134423
134427
  clientCount() {
134424
134428
  return connections;
134425
134429
  },
@@ -135994,6 +135998,17 @@ var REMOTE_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
135994
135998
  "session.setMode",
135995
135999
  "session.newSession",
135996
136000
  "session.runCommand",
136001
+ // Multi-session conversations: list/create/switch/rename are conversation-
136002
+ // scoped — the same trust class as `session.newSession` (already allowed),
136003
+ // and what a paired phone needs to mirror the desktop's session list.
136004
+ // `sessions.remove` is deliberately NOT here: it deletes on-disk state
136005
+ // (the runner's session JSONL + the chat NDJSON transcript), a destructive
136006
+ // host mutation in the same class as `desks.remove`, which is also
136007
+ // host-only.
136008
+ "sessions.list",
136009
+ "sessions.create",
136010
+ "sessions.setActive",
136011
+ "sessions.rename",
135997
136012
  // Voice input (capability-probed; transcribe fails coded without a transcriber).
135998
136013
  "session.hasTranscriber",
135999
136014
  "session.transcribe",
@@ -136129,6 +136144,20 @@ var ipcInputSchemas = {
136129
136144
  id: z.string().min(1).max(256),
136130
136145
  name: z.string().min(1).max(200)
136131
136146
  }),
136147
+ // Sessions: create/rename persist the name into the desks JSON (bound it
136148
+ // like desks.create/rename); setActive spawns a runner and remove deletes
136149
+ // the session's on-disk logs, so their ids are bounded too. These commands
136150
+ // are also served to remote (WS) clients, so the bounds are load-bearing.
136151
+ "sessions.create": z.object({
136152
+ deskId: z.string().min(1).max(256).optional(),
136153
+ name: z.string().min(1).max(200).optional()
136154
+ }).optional(),
136155
+ "sessions.setActive": z.object({ id: z.string().min(1).max(256) }),
136156
+ "sessions.remove": z.object({ id: z.string().min(1).max(256) }),
136157
+ "sessions.rename": z.object({
136158
+ id: z.string().min(1).max(256),
136159
+ name: z.string().min(1).max(200)
136160
+ }),
136132
136161
  // Whitelist the fields a renderer may write — `version` is managed by
136133
136162
  // the main process; unknown keys are rejected (.strict()).
136134
136163
  "prefs.update": z.object({
@@ -136136,7 +136165,8 @@ var ipcInputSchemas = {
136136
136165
  clerkUserId: z.string().max(256).nullable().optional(),
136137
136166
  clerkDisplayName: z.string().max(256).nullable().optional(),
136138
136167
  signedInAt: z.number().nullable().optional(),
136139
- mobileGatewayEnabled: z.boolean().optional()
136168
+ mobileGatewayEnabled: z.boolean().optional(),
136169
+ theme: z.enum(["light", "dark", "system"]).optional()
136140
136170
  }).strict(),
136141
136171
  // Mobile-gateway control. Both no-arg variants pin the payload to "nothing"
136142
136172
  // so a hostile caller can't smuggle args; setEnabled is a strict boolean.
@@ -136524,14 +136554,41 @@ function isWildcardHost(host) {
136524
136554
  const h3 = host.trim().toLowerCase();
136525
136555
  return h3 === "0.0.0.0" || h3 === "::" || h3 === "[::]";
136526
136556
  }
136557
+ var VIRTUAL_IFACE = /^(?:utun|tun|tap|ppp|ipsec|wg|zt|ts|tailscale|vmnet|vnic|bridge|docker|veth|awdl|llw|ap|anpi)\d*$/i;
136558
+ function isLinkLocalV4(ip) {
136559
+ return ip.startsWith("169.254.");
136560
+ }
136561
+ function isRfc1918(ip) {
136562
+ if (ip.startsWith("10.") || ip.startsWith("192.168."))
136563
+ return true;
136564
+ const m3 = /^172\.(\d{1,3})\./.exec(ip);
136565
+ return m3 !== null && Number(m3[1]) >= 16 && Number(m3[1]) <= 31;
136566
+ }
136567
+ function isCgnat(ip) {
136568
+ const m3 = /^100\.(\d{1,3})\./.exec(ip);
136569
+ return m3 !== null && Number(m3[1]) >= 64 && Number(m3[1]) <= 127;
136570
+ }
136527
136571
  function lanHost(fallback) {
136528
- for (const list of Object.values(os5__default.networkInterfaces())) {
136572
+ let best = null;
136573
+ for (const [name, list] of Object.entries(os5__default.networkInterfaces())) {
136529
136574
  for (const ni of list ?? []) {
136530
- if (ni.family === "IPv4" && !ni.internal)
136531
- return ni.address;
136575
+ if (ni.family !== "IPv4" || ni.internal)
136576
+ continue;
136577
+ const virtual = VIRTUAL_IFACE.test(name);
136578
+ let rank;
136579
+ if (isLinkLocalV4(ni.address))
136580
+ rank = 5;
136581
+ else if (isRfc1918(ni.address))
136582
+ rank = virtual ? 3 : 1;
136583
+ else if (isCgnat(ni.address))
136584
+ rank = 4;
136585
+ else
136586
+ rank = virtual ? 4 : 2;
136587
+ if (!best || rank < best.rank)
136588
+ best = { address: ni.address, rank };
136532
136589
  }
136533
136590
  }
136534
- return fallback;
136591
+ return best?.address ?? fallback;
136535
136592
  }
136536
136593
  function advertisedHost(bindHost) {
136537
136594
  if (isWildcardHost(bindHost))
@@ -136547,6 +136604,20 @@ function buildConnectUrl(opts) {
136547
136604
  }
136548
136605
  return `ws://${opts.localHost}:${opts.port}/?t=${t2}`;
136549
136606
  }
136607
+ function connectUrlOrigin(url2) {
136608
+ const u2 = new URL(url2);
136609
+ const secure = u2.protocol === "wss:" || u2.protocol === "https:";
136610
+ return `${secure ? "https" : "http"}://${u2.host}`;
136611
+ }
136612
+ function advertisedOrigins(bindHost, port) {
136613
+ return [
136614
+ .../* @__PURE__ */ new Set([
136615
+ connectUrlOrigin(`ws://${advertisedHost(bindHost)}:${port}`),
136616
+ `http://127.0.0.1:${port}`,
136617
+ `http://localhost:${port}`
136618
+ ])
136619
+ ];
136620
+ }
136550
136621
 
136551
136622
  // ../plugin-channel-mobile/dist/tunnel.js
136552
136623
  function normalizeTunnelChoice(raw) {
@@ -136631,10 +136702,12 @@ var MobileChannel = class {
136631
136702
  this.host = host;
136632
136703
  host.register();
136633
136704
  host.wire();
136705
+ const localOrigins = advertisedOrigins(this.bindHost, this.port);
136634
136706
  const server = await startWsBridge(bus, {
136635
136707
  port: this.port,
136636
136708
  host: this.bindHost,
136637
136709
  authToken: this.token,
136710
+ allowedOrigins: localOrigins,
136638
136711
  // Back-compat ONLY: the QR this channel prints embeds the token as `?t=`
136639
136712
  // (pairing payload); current apps strip it and authenticate via the
136640
136713
  // Sec-WebSocket-Protocol bearer entry, but older installed builds still
@@ -136649,6 +136722,7 @@ var MobileChannel = class {
136649
136722
  try {
136650
136723
  this.tunnel = await provider.open({ port: this.port, host: this.bindHost });
136651
136724
  tunnelUrl = this.tunnel.url;
136725
+ server.setAllowedOrigins([...localOrigins, connectUrlOrigin(tunnelUrl)]);
136652
136726
  this.logger?.info?.("mobile tunnel open", { provider: provider.name, url: tunnelUrl });
136653
136727
  } catch (err) {
136654
136728
  this.logger?.warn?.("mobile tunnel failed; using the local URL", {