@rubytech/create-maxy-code 0.1.193 → 0.1.194

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.193",
3
+ "version": "0.1.194",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -127,13 +127,15 @@ The share is **LAN-only**: it binds to the loopback and your Pi's Wi-Fi/Ethernet
127
127
 
128
128
  **Credentials:** SMB user is `admin`; password is your {{productName}} PIN. The installer wires the sync so every time you set or rotate the PIN in the admin UI, the SMB password updates with it.
129
129
 
130
- **macOS Finder**: Press `Cmd-K` from any Finder window, type `smb://<hostname>.local` (use the hostname your installer printed for example `smb://maxy-code.local` or `smb://realagent-code.local`), click Connect, sign in as `admin` with your PIN. The share appears in the Finder sidebar; drag-and-drop works in both directions.
130
+ The SMB username is the Linux user that owns the install on the device — `admin` on a Pi or a Hetzner box, your own Linux user (for example `neo`) on a self-hosted laptop install. The password is your {{productName}} PIN. Changing the PIN in the admin UI re-syncs the SMB password for that same Unix user automatically.
131
131
 
132
- **Windows Explorer**: Open File Explorer, type `\\<hostname>.local\<brand>` in the address bar (for example `\\maxy-code.local\maxy-code`), press Enter, sign in as `admin` with your PIN. To keep it across reboots, right-click "Map network drive".
132
+ **macOS Finder**: Press `Cmd-K` from any Finder window, type `smb://<hostname>.local` (use the hostname your installer printed — for example `smb://maxy-code.local` or `smb://realagent-code.local`), click Connect, sign in as the install owner with your PIN. The share appears in the Finder sidebar; drag-and-drop works in both directions.
133
133
 
134
- **iOS Files**: Open Files tap the `…` menu (top-right) "Connect to Server" enter `smb://<hostname>.local` "Registered User" username `admin`, password is your PIN.
134
+ **Windows Explorer**: Open File Explorer, type `\\<hostname>.local\<brand>` in the address bar (for example `\\maxy-code.local\maxy-code`), press Enter, sign in as the install owner with your PIN. To keep it across reboots, right-click → "Map network drive".
135
135
 
136
- **Android (Solid Explorer, CX File Explorer)**: Add a new connection of type SMB / Network. Host = `<hostname>.local`, share = `<brand>` (same as your install folder name), user = `admin`, password = your PIN.
136
+ **iOS Files**: Open Files tap the `…` menu (top-right) "Connect to Server" enter `smb://<hostname>.local` "Registered User" username is the install owner, password is your PIN.
137
+
138
+ **Android (Solid Explorer, CX File Explorer)**: Add a new connection of type SMB / Network. Host = `<hostname>.local`, share = `<brand>` (same as your install folder name), user = the install owner, password = your PIN.
137
139
 
138
140
  **Troubleshooting:** if the mount fails with "logon failure", change your PIN in the admin UI and try again — that re-triggers the smbpasswd sync. If the share doesn't show up at all, your client may need `<hostname>.local` resolved by mDNS — try the Pi's LAN IP address as a fallback (`smb://192.168.1.50` on macOS, `\\192.168.1.50\<brand>` on Windows).
139
141
 
@@ -2705,6 +2705,7 @@ var BIN_DIR = resolve(MAXY_DIR, "bin");
2705
2705
  var REMOTE_PASSWORD_FILE = resolve(MAXY_DIR, ".remote-password");
2706
2706
  var REMOTE_SESSION_SECRET_FILE = resolve(MAXY_DIR, "credentials", "remote-session-secret");
2707
2707
  var ADMIN_SESSION_SECRET_FILE = resolve(MAXY_DIR, "credentials", "admin-session-secret");
2708
+ var INSTALL_OWNER_FILE = resolve(MAXY_DIR, ".install-owner");
2708
2709
  var TELEGRAM_WEBHOOK_SECRET_FILE = resolve(MAXY_DIR, ".telegram-webhook-secret");
2709
2710
  var TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE = resolve(MAXY_DIR, ".telegram-admin-webhook-secret");
2710
2711
  var VISITOR_TOKEN_SECRET_FILE = resolve(MAXY_DIR, "credentials", "visitor-token-secret");
@@ -5454,6 +5455,7 @@ export {
5454
5455
  USERS_FILE,
5455
5456
  LOG_DIR,
5456
5457
  BIN_DIR,
5458
+ INSTALL_OWNER_FILE,
5457
5459
  VISITOR_TOKEN_SECRET_FILE,
5458
5460
  CLAUDE_CREDENTIALS_FILE,
5459
5461
  vncLog,
@@ -14,7 +14,7 @@ import {
14
14
  sanitizeClientCorrId,
15
15
  vncLog,
16
16
  websockifyLog
17
- } from "./chunk-WWD4TCJJ.js";
17
+ } from "./chunk-EXIPYITB.js";
18
18
  import "./chunk-PFF6I7KP.js";
19
19
 
20
20
  // server/edge.ts
@@ -9,6 +9,7 @@ import {
9
9
  COMMERCIAL_MODE,
10
10
  GREETING_DIRECTIVE,
11
11
  Hono,
12
+ INSTALL_OWNER_FILE,
12
13
  LOG_DIR,
13
14
  MAXY_DIR,
14
15
  PLATFORM_ROOT,
@@ -83,7 +84,7 @@ import {
83
84
  vncLog,
84
85
  walkPremiumBundles,
85
86
  writeAdminUserAndPerson
86
- } from "./chunk-WWD4TCJJ.js";
87
+ } from "./chunk-EXIPYITB.js";
87
88
  import {
88
89
  __commonJS,
89
90
  __toESM
@@ -815,8 +816,8 @@ var serveStatic = (options = { root: "" }) => {
815
816
  };
816
817
 
817
818
  // server/index.ts
818
- import { readFileSync as readFileSync20, existsSync as existsSync21, watchFile } from "fs";
819
- import { resolve as resolve23, join as join15, basename as basename6 } from "path";
819
+ import { readFileSync as readFileSync21, existsSync as existsSync21, watchFile } from "fs";
820
+ import { resolve as resolve23, join as join16, basename as basename6 } from "path";
820
821
  import { homedir as homedir2 } from "os";
821
822
  import { monitorEventLoopDelay } from "perf_hooks";
822
823
 
@@ -6325,19 +6326,32 @@ app4.post("/set-pin", async (c) => {
6325
6326
  }
6326
6327
  console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
6327
6328
  if (process.platform === "linux") {
6328
- const smbProc = spawnSync2("sudo", ["-n", "smbpasswd", "-a", "-s", "admin"], {
6329
- input: `${body.pin}
6329
+ let installOwner = null;
6330
+ if (existsSync6(INSTALL_OWNER_FILE)) {
6331
+ try {
6332
+ const raw = readFileSync8(INSTALL_OWNER_FILE, "utf-8").trim();
6333
+ if (raw.length > 0) installOwner = raw;
6334
+ } catch (err) {
6335
+ console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
6336
+ }
6337
+ }
6338
+ if (!installOwner) {
6339
+ console.error(`[set-pin] smbpasswd sync failed owner=<unknown> rc=-1 reason=install-owner-file-missing path=${INSTALL_OWNER_FILE}`);
6340
+ } else {
6341
+ const smbProc = spawnSync2("sudo", ["-n", "smbpasswd", "-a", "-s", installOwner], {
6342
+ input: `${body.pin}
6330
6343
  ${body.pin}
6331
6344
  `,
6332
- stdio: ["pipe", "pipe", "pipe"],
6333
- encoding: "utf-8",
6334
- timeout: 1e4
6335
- });
6336
- if (smbProc.status === 0) {
6337
- console.log(`[set-pin] smb-password-synced userId=${userId.slice(0, 8)}\u2026`);
6338
- } else {
6339
- const stderr = (smbProc.stderr ?? "").trim().slice(0, 200);
6340
- console.error(`[set-pin] smb-password-sync-failed exit=${smbProc.status} stderr=${JSON.stringify(stderr)}`);
6345
+ stdio: ["pipe", "pipe", "pipe"],
6346
+ encoding: "utf-8",
6347
+ timeout: 1e4
6348
+ });
6349
+ if (smbProc.status === 0) {
6350
+ console.log(`[set-pin] smbpasswd sync ok owner=${installOwner} userId=${userId.slice(0, 8)}\u2026`);
6351
+ } else {
6352
+ const stderr = (smbProc.stderr ?? "").trim().slice(0, 200);
6353
+ console.error(`[set-pin] smbpasswd sync failed owner=${installOwner} rc=${smbProc.status} stderr=${JSON.stringify(stderr)}`);
6354
+ }
6341
6355
  }
6342
6356
  } else {
6343
6357
  console.log(`[set-pin] smb-password-sync-skipped reason=non-linux platform=${process.platform}`);
@@ -11781,53 +11795,87 @@ function relPath(absPath, root) {
11781
11795
  var sidebar_artefact_save_default = app23;
11782
11796
 
11783
11797
  // server/routes/admin/sidebar-sessions.ts
11798
+ import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
11799
+ import { join as join13 } from "path";
11800
+ var RC_URL_RE = /https:\/\/claude\.ai\/code\/session_[A-Za-z0-9_-]+/;
11801
+ var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
11802
+ var TITLE_MAX = 80;
11784
11803
  var app24 = new Hono();
11804
+ function projectsDirForAccount(accountId) {
11805
+ const configDir2 = process.env.CLAUDE_CONFIG_DIR;
11806
+ if (!configDir2) return null;
11807
+ const accountCwd = join13(DATA_ROOT, "accounts", accountId);
11808
+ const slug = accountCwd.replace(/\//g, "-");
11809
+ return join13(configDir2, "projects", slug);
11810
+ }
11811
+ function firstUserMessage(body) {
11812
+ for (const line of body.split("\n")) {
11813
+ if (!line || line[0] !== "{") continue;
11814
+ let parsed;
11815
+ try {
11816
+ parsed = JSON.parse(line);
11817
+ } catch {
11818
+ continue;
11819
+ }
11820
+ if (!parsed || typeof parsed !== "object") continue;
11821
+ const row = parsed;
11822
+ if (row.type !== "user" || !row.message || row.message.role !== "user") continue;
11823
+ const content = row.message.content;
11824
+ if (typeof content !== "string") continue;
11825
+ const trimmed = content.trim().replace(/\s+/g, " ");
11826
+ if (!trimmed) continue;
11827
+ return trimmed.length > TITLE_MAX ? trimmed.slice(0, TITLE_MAX - 1) + "\u2026" : trimmed;
11828
+ }
11829
+ return null;
11830
+ }
11785
11831
  app24.get("/", requireAdminSession, async (c) => {
11786
11832
  const cacheKey = c.var.cacheKey;
11787
11833
  const accountId = getAccountIdForSession(cacheKey);
11788
11834
  if (!accountId) {
11789
11835
  return c.json({ error: "Account not found for session" }, 401);
11790
11836
  }
11791
- const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "admin-sessions-list" });
11792
- const url = `http://127.0.0.1:${port2}/list?senderId=${encodeURIComponent(accountId)}`;
11793
- let upstream = null;
11794
- try {
11795
- upstream = await fetch(url);
11796
- } catch (err) {
11797
- const message = err instanceof Error ? err.message : String(err);
11798
- console.error(`[admin-sessions-list] account=${accountId} fetch-failed error="${message}"`);
11799
- return c.json({ error: "session-manager-unreachable" }, 503);
11837
+ const projectsDir = projectsDirForAccount(accountId);
11838
+ if (!projectsDir) {
11839
+ console.error(`[admin-sessions-list] account=${accountId} no-claude-config-dir`);
11840
+ return c.json({ sessions: [] });
11800
11841
  }
11801
- if (!upstream.ok) {
11802
- console.error(`[admin-sessions-list] account=${accountId} upstream-status=${upstream.status}`);
11803
- return c.json({ error: "session-manager-error", status: upstream.status }, 502);
11804
- }
11805
- let payloads;
11842
+ let entries;
11806
11843
  try {
11807
- payloads = await upstream.json();
11844
+ entries = readdirSync8(projectsDir);
11808
11845
  } catch (err) {
11846
+ const code = err.code;
11847
+ if (code === "ENOENT") {
11848
+ console.log(`[admin-sessions-list] account=${accountId} rows=0 reason=no-projects-dir`);
11849
+ return c.json({ sessions: [] });
11850
+ }
11809
11851
  const message = err instanceof Error ? err.message : String(err);
11810
- console.error(`[admin-sessions-list] account=${accountId} parse-failed error="${message}"`);
11811
- return c.json({ error: "session-manager-bad-body" }, 502);
11812
- }
11813
- if (!Array.isArray(payloads)) {
11814
- console.error(`[admin-sessions-list] account=${accountId} bad-shape=not-array`);
11815
- return c.json({ error: "session-manager-bad-body" }, 502);
11852
+ console.error(`[admin-sessions-list] account=${accountId} readdir-failed error="${message}"`);
11853
+ return c.json({ error: "projects-dir-unreadable" }, 500);
11816
11854
  }
11817
11855
  const rows = [];
11818
- for (const p of payloads) {
11819
- const sessionId = typeof p.sessionId === "string" ? p.sessionId : null;
11820
- const capturedUrl = typeof p.url === "string" ? p.url : null;
11821
- const startedAt = typeof p.startedAt === "string" ? p.startedAt : null;
11822
- if (!sessionId || !capturedUrl || !startedAt) continue;
11823
- const displayName = typeof p.displayName === "string" && p.displayName.length > 0 ? p.displayName : sessionId.slice(0, 8);
11856
+ for (const name of entries) {
11857
+ if (!SESSION_ID_RE.test(name)) continue;
11858
+ const sessionId = name.slice(0, -".jsonl".length);
11859
+ const path2 = join13(projectsDir, name);
11860
+ let body;
11861
+ let mtimeMs;
11862
+ try {
11863
+ body = readFileSync14(path2, "utf8");
11864
+ mtimeMs = statSync7(path2).mtimeMs;
11865
+ } catch {
11866
+ continue;
11867
+ }
11868
+ const urlMatch = body.match(RC_URL_RE);
11869
+ if (!urlMatch) continue;
11870
+ const title = firstUserMessage(body) ?? sessionId.slice(0, 8);
11824
11871
  rows.push({
11825
11872
  sessionId,
11826
- title: displayName,
11827
- url: capturedUrl,
11828
- capturedAt: startedAt
11873
+ title,
11874
+ url: urlMatch[0],
11875
+ capturedAt: new Date(mtimeMs).toISOString()
11829
11876
  });
11830
11877
  }
11878
+ rows.sort((a, b) => a.capturedAt < b.capturedAt ? 1 : -1);
11831
11879
  console.log(`[admin-sessions-list] account=${accountId} rows=${rows.length}`);
11832
11880
  return c.json({ sessions: rows });
11833
11881
  });
@@ -11955,14 +12003,14 @@ app25.get("/", async (c) => {
11955
12003
  var system_stats_default = app25;
11956
12004
 
11957
12005
  // server/routes/admin/health.ts
11958
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
11959
- import { resolve as resolve17, join as join13 } from "path";
12006
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "fs";
12007
+ import { resolve as resolve17, join as join14 } from "path";
11960
12008
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
11961
12009
  var brandHostname = "maxy";
11962
- var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
12010
+ var brandJsonPath = join14(PLATFORM_ROOT6, "config", "brand.json");
11963
12011
  if (existsSync17(brandJsonPath)) {
11964
12012
  try {
11965
- const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
12013
+ const brand = JSON.parse(readFileSync15(brandJsonPath, "utf-8"));
11966
12014
  if (brand.hostname) brandHostname = brand.hostname;
11967
12015
  } catch {
11968
12016
  }
@@ -11972,7 +12020,7 @@ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
11972
12020
  var PROBE_TIMEOUT_MS = 1e3;
11973
12021
  function readVersion() {
11974
12022
  if (!existsSync17(VERSION_FILE)) return "unknown";
11975
- return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
12023
+ return readFileSync15(VERSION_FILE, "utf-8").trim() || "unknown";
11976
12024
  }
11977
12025
  async function probeConversationDb() {
11978
12026
  let session;
@@ -12481,7 +12529,7 @@ var admin_default = app32;
12481
12529
 
12482
12530
  // app/lib/access-gate.ts
12483
12531
  import neo4j4 from "neo4j-driver";
12484
- import { readFileSync as readFileSync15 } from "fs";
12532
+ import { readFileSync as readFileSync16 } from "fs";
12485
12533
  import { resolve as resolve18 } from "path";
12486
12534
  import { randomUUID as randomUUID8 } from "crypto";
12487
12535
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
@@ -12490,7 +12538,7 @@ function readPassword() {
12490
12538
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
12491
12539
  const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
12492
12540
  try {
12493
- return readFileSync15(passwordFile, "utf-8").trim();
12541
+ return readFileSync16(passwordFile, "utf-8").trim();
12494
12542
  } catch {
12495
12543
  throw new Error(
12496
12544
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -12922,7 +12970,7 @@ app35.route("/request-magic-link", request_magic_link_default);
12922
12970
  var access_default = app35;
12923
12971
 
12924
12972
  // server/routes/sites.ts
12925
- import { existsSync as existsSync18, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
12973
+ import { existsSync as existsSync18, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
12926
12974
  import { resolve as resolve20 } from "path";
12927
12975
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12928
12976
  var MIME = {
@@ -12988,7 +13036,7 @@ app36.get("/:rel{.*}", (c) => {
12988
13036
  }
12989
13037
  let stat8;
12990
13038
  try {
12991
- stat8 = existsSync18(filePath) ? statSync7(filePath) : null;
13039
+ stat8 = existsSync18(filePath) ? statSync8(filePath) : null;
12992
13040
  } catch {
12993
13041
  stat8 = null;
12994
13042
  }
@@ -13026,7 +13074,7 @@ app36.get("/:rel{.*}", (c) => {
13026
13074
  }
13027
13075
  let body;
13028
13076
  try {
13029
- body = readFileSync16(realPath);
13077
+ body = readFileSync17(realPath);
13030
13078
  } catch (err) {
13031
13079
  const code = err?.code;
13032
13080
  if (code === "EISDIR") {
@@ -13062,7 +13110,7 @@ var sites_default = app36;
13062
13110
 
13063
13111
  // app/lib/visitor-token.ts
13064
13112
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
13065
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
13113
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync18, writeFileSync as writeFileSync6 } from "fs";
13066
13114
  import { dirname as dirname4 } from "path";
13067
13115
  var TOKEN_PREFIX = "v1.";
13068
13116
  var SECRET_BYTES = 32;
@@ -13071,7 +13119,7 @@ var cachedSecret = null;
13071
13119
  function getSecret() {
13072
13120
  if (cachedSecret) return cachedSecret;
13073
13121
  try {
13074
- const hex2 = readFileSync17(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
13122
+ const hex2 = readFileSync18(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
13075
13123
  if (hex2.length === SECRET_BYTES * 2) {
13076
13124
  cachedSecret = Buffer.from(hex2, "hex");
13077
13125
  return cachedSecret;
@@ -13085,7 +13133,7 @@ function getSecret() {
13085
13133
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
13086
13134
  } catch {
13087
13135
  }
13088
- const hex = readFileSync17(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
13136
+ const hex = readFileSync18(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
13089
13137
  cachedSecret = Buffer.from(hex, "hex");
13090
13138
  return cachedSecret;
13091
13139
  }
@@ -13138,8 +13186,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
13138
13186
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
13139
13187
 
13140
13188
  // app/lib/brand-config.ts
13141
- import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
13142
- import { join as join14 } from "path";
13189
+ import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
13190
+ import { join as join15 } from "path";
13143
13191
  var cached2 = null;
13144
13192
  var cachedAttempted = false;
13145
13193
  function readBrandConfig() {
@@ -13147,10 +13195,10 @@ function readBrandConfig() {
13147
13195
  cachedAttempted = true;
13148
13196
  const platformRoot = process.env.MAXY_PLATFORM_ROOT;
13149
13197
  if (!platformRoot) return null;
13150
- const brandPath = join14(platformRoot, "config", "brand.json");
13198
+ const brandPath = join15(platformRoot, "config", "brand.json");
13151
13199
  if (!existsSync19(brandPath)) return null;
13152
13200
  try {
13153
- cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
13201
+ cached2 = JSON.parse(readFileSync19(brandPath, "utf-8"));
13154
13202
  return cached2;
13155
13203
  } catch {
13156
13204
  return null;
@@ -13882,7 +13930,7 @@ function broadcastAdminShutdown(reason) {
13882
13930
 
13883
13931
  // ../lib/entitlement/src/index.ts
13884
13932
  import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
13885
- import { existsSync as existsSync20, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
13933
+ import { existsSync as existsSync20, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
13886
13934
  import { resolve as resolve22 } from "path";
13887
13935
 
13888
13936
  // ../lib/entitlement/src/canonicalize.ts
@@ -13934,7 +13982,7 @@ function resolveEntitlement(brand, account) {
13934
13982
  if (!existsSync20(entitlementPath)) {
13935
13983
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
13936
13984
  }
13937
- const stat8 = statSync8(entitlementPath);
13985
+ const stat8 = statSync9(entitlementPath);
13938
13986
  const key = memoKey(stat8.mtimeMs, account);
13939
13987
  if (memo && memo.key === key) {
13940
13988
  return memo.result;
@@ -13946,7 +13994,7 @@ function resolveEntitlement(brand, account) {
13946
13994
  function verifyAndResolve(brand, entitlementPath, account) {
13947
13995
  let pubkeyPem;
13948
13996
  try {
13949
- pubkeyPem = readFileSync19(pubkeyPath(brand), "utf-8");
13997
+ pubkeyPem = readFileSync20(pubkeyPath(brand), "utf-8");
13950
13998
  } catch (err) {
13951
13999
  return logResolved(anonymousFallback("pubkey-missing"), {
13952
14000
  reason: "pubkey-missing"
@@ -13960,7 +14008,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
13960
14008
  }
13961
14009
  let envelope;
13962
14010
  try {
13963
- envelope = JSON.parse(readFileSync19(entitlementPath, "utf-8"));
14011
+ envelope = JSON.parse(readFileSync20(entitlementPath, "utf-8"));
13964
14012
  } catch {
13965
14013
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
13966
14014
  }
@@ -14121,14 +14169,14 @@ function clientFrom(c) {
14121
14169
  );
14122
14170
  }
14123
14171
  var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
14124
- var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
14172
+ var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join16(PLATFORM_ROOT9, "config", "brand.json") : "";
14125
14173
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
14126
14174
  if (BRAND_JSON_PATH && !existsSync21(BRAND_JSON_PATH)) {
14127
14175
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
14128
14176
  }
14129
14177
  if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
14130
14178
  try {
14131
- const parsed = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
14179
+ const parsed = JSON.parse(readFileSync21(BRAND_JSON_PATH, "utf-8"));
14132
14180
  BRAND = { ...BRAND, ...parsed };
14133
14181
  } catch (err) {
14134
14182
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -14147,11 +14195,11 @@ var brandLoginOpts = {
14147
14195
  bodyFont: BRAND.defaultFonts?.body,
14148
14196
  logoContainsName: !!BRAND.logoContainsName
14149
14197
  };
14150
- var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
14198
+ var ALIAS_DOMAINS_PATH = join16(homedir2(), BRAND.configDir, "alias-domains.json");
14151
14199
  function loadAliasDomains() {
14152
14200
  try {
14153
14201
  if (!existsSync21(ALIAS_DOMAINS_PATH)) return null;
14154
- const parsed = JSON.parse(readFileSync20(ALIAS_DOMAINS_PATH, "utf-8"));
14202
+ const parsed = JSON.parse(readFileSync21(ALIAS_DOMAINS_PATH, "utf-8"));
14155
14203
  if (!Array.isArray(parsed)) {
14156
14204
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
14157
14205
  return null;
@@ -14528,7 +14576,7 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
14528
14576
  const ext = "." + filename.split(".").pop()?.toLowerCase();
14529
14577
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
14530
14578
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
14531
- const body = readFileSync20(filePath);
14579
+ const body = readFileSync21(filePath);
14532
14580
  return c.body(body, 200, {
14533
14581
  "Content-Type": contentType,
14534
14582
  "Cache-Control": "public, max-age=3600"
@@ -14558,7 +14606,7 @@ app40.get("/generated/:filename", (c) => {
14558
14606
  const ext = "." + filename.split(".").pop()?.toLowerCase();
14559
14607
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
14560
14608
  console.log(`[generated] serve file=${filename} status=200`);
14561
- const body = readFileSync20(filePath);
14609
+ const body = readFileSync21(filePath);
14562
14610
  return c.body(body, 200, {
14563
14611
  "Content-Type": contentType,
14564
14612
  "Cache-Control": "public, max-age=86400"
@@ -14573,7 +14621,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
14573
14621
  var brandIconPath = "/brand/maxy-monochrome.png";
14574
14622
  if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
14575
14623
  try {
14576
- const fullBrand = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
14624
+ const fullBrand = JSON.parse(readFileSync21(BRAND_JSON_PATH, "utf-8"));
14577
14625
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
14578
14626
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
14579
14627
  } catch {
@@ -14590,9 +14638,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
14590
14638
  function readInstalledVersion() {
14591
14639
  try {
14592
14640
  if (!PLATFORM_ROOT9) return "unknown";
14593
- const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
14641
+ const versionFile = join16(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
14594
14642
  if (!existsSync21(versionFile)) return "unknown";
14595
- const content = readFileSync20(versionFile, "utf-8").trim();
14643
+ const content = readFileSync21(versionFile, "utf-8").trim();
14596
14644
  return content || "unknown";
14597
14645
  } catch {
14598
14646
  return "unknown";
@@ -14633,7 +14681,7 @@ var clientErrorReporterScript = `<script>
14633
14681
  function cachedHtml(file) {
14634
14682
  let html = htmlCache.get(file);
14635
14683
  if (!html) {
14636
- html = readFileSync20(resolve23(process.cwd(), "public", file), "utf-8");
14684
+ html = readFileSync21(resolve23(process.cwd(), "public", file), "utf-8");
14637
14685
  const productNameEsc = escapeHtml(BRAND.productName);
14638
14686
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
14639
14687
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -14649,26 +14697,26 @@ ${clientErrorReporterScript}
14649
14697
  }
14650
14698
  var brandedHtmlCache = /* @__PURE__ */ new Map();
14651
14699
  function loadBrandingCache(agentSlug) {
14652
- const configDir2 = join15(homedir2(), BRAND.configDir);
14700
+ const configDir2 = join16(homedir2(), BRAND.configDir);
14653
14701
  try {
14654
- const accountJsonPath = join15(configDir2, "account.json");
14702
+ const accountJsonPath = join16(configDir2, "account.json");
14655
14703
  if (!existsSync21(accountJsonPath)) return null;
14656
- const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
14704
+ const account = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
14657
14705
  const accountId = account.accountId;
14658
14706
  if (!accountId) return null;
14659
- const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
14707
+ const cachePath = join16(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
14660
14708
  if (!existsSync21(cachePath)) return null;
14661
- return JSON.parse(readFileSync20(cachePath, "utf-8"));
14709
+ return JSON.parse(readFileSync21(cachePath, "utf-8"));
14662
14710
  } catch {
14663
14711
  return null;
14664
14712
  }
14665
14713
  }
14666
14714
  function resolveDefaultSlug() {
14667
14715
  try {
14668
- const configDir2 = join15(homedir2(), BRAND.configDir);
14669
- const accountJsonPath = join15(configDir2, "account.json");
14716
+ const configDir2 = join16(homedir2(), BRAND.configDir);
14717
+ const accountJsonPath = join16(configDir2, "account.json");
14670
14718
  if (!existsSync21(accountJsonPath)) return null;
14671
- const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
14719
+ const account = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
14672
14720
  return account.defaultAgent || null;
14673
14721
  } catch {
14674
14722
  return null;
@@ -14741,7 +14789,7 @@ app40.use("/vnc-popout.html", logViewerFetch);
14741
14789
  app40.get("/vnc-popout.html", (c) => {
14742
14790
  let html = htmlCache.get("vnc-popout.html");
14743
14791
  if (!html) {
14744
- html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
14792
+ html = readFileSync21(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
14745
14793
  const name = escapeHtml(BRAND.productName);
14746
14794
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
14747
14795
  html = html.replace("</head>", ` ${brandScript}
@@ -14867,7 +14915,7 @@ try {
14867
14915
  (async () => {
14868
14916
  try {
14869
14917
  if (!existsSync21(USERS_FILE)) return;
14870
- const usersRaw = readFileSync20(USERS_FILE, "utf-8").trim();
14918
+ const usersRaw = readFileSync21(USERS_FILE, "utf-8").trim();
14871
14919
  if (!usersRaw) return;
14872
14920
  const users = JSON.parse(usersRaw);
14873
14921
  const userId = users[0]?.userId;
@@ -14962,7 +15010,7 @@ if (bootAccountConfig?.whatsapp) {
14962
15010
  }
14963
15011
  init({
14964
15012
  configDir: configDirForWhatsApp,
14965
- platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
15013
+ platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join16(__dirname, "..")),
14966
15014
  accountConfig: bootAccountConfig,
14967
15015
  onMessage: async (msg) => {
14968
15016
  if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {