@rubytech/create-maxy-code 0.1.282 → 0.1.284

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 (45) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/config/brand.json +0 -1
  3. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js +3 -3
  4. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-search.test.js.map +1 -1
  5. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -4
  6. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +28 -4
  7. package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +1 -1
  8. package/payload/platform/plugins/cloudflare/PLUGIN.md +5 -5
  9. package/payload/platform/plugins/cloudflare/references/api.md +78 -38
  10. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +27 -21
  11. package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +3 -2
  12. package/payload/platform/plugins/cloudflare/references/hosting-sites.md +7 -5
  13. package/payload/platform/plugins/cloudflare/references/manual-setup.md +3 -2
  14. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +6 -6
  15. package/payload/platform/plugins/docs/references/telegram-guide.md +3 -3
  16. package/payload/platform/plugins/telegram/PLUGIN.md +7 -2
  17. package/payload/platform/plugins/telegram/mcp/dist/index.js +66 -11
  18. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
  19. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts +6 -0
  20. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.d.ts.map +1 -0
  21. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js +20 -0
  22. package/payload/platform/plugins/telegram/mcp/dist/lib/account-token.js.map +1 -0
  23. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts +21 -0
  24. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.d.ts.map +1 -0
  25. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js +52 -0
  26. package/payload/platform/plugins/telegram/mcp/dist/lib/account-write.js.map +1 -0
  27. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -1
  28. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +5 -2
  29. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -1
  30. package/payload/platform/plugins/telegram/references/setup-guide.md +10 -7
  31. package/payload/platform/plugins/telegram/skills/configure/SKILL.md +79 -0
  32. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/http-server.js +17 -0
  34. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  35. package/payload/server/public/assets/AdminShell-8Y7-maNi.js +1 -0
  36. package/payload/server/public/assets/{admin-0_VxffD5.js → admin-DyuZ4NT5.js} +1 -1
  37. package/payload/server/public/assets/{browser-Cxjkhtsk.js → browser-XrVAUQdG.js} +1 -1
  38. package/payload/server/public/assets/{data-BOgwOWnw.js → data-tcu3MXmK.js} +1 -1
  39. package/payload/server/public/assets/{graph-BqD2GjQd.js → graph-I4GyC2MW.js} +1 -1
  40. package/payload/server/public/browser.html +2 -2
  41. package/payload/server/public/data.html +2 -2
  42. package/payload/server/public/graph.html +2 -2
  43. package/payload/server/public/index.html +2 -2
  44. package/payload/server/server.js +827 -531
  45. package/payload/server/public/assets/AdminShell-FO766lOW.js +0 -1
@@ -1201,9 +1201,9 @@ var serveStatic = (options = { root: "" }) => {
1201
1201
  };
1202
1202
 
1203
1203
  // server/index.ts
1204
- import { readFileSync as readFileSync23, existsSync as existsSync23, watchFile } from "fs";
1205
- import { resolve as resolve26, join as join18, basename as basename7 } from "path";
1206
- import { homedir as homedir2 } from "os";
1204
+ import { readFileSync as readFileSync24, existsSync as existsSync24, watchFile } from "fs";
1205
+ import { resolve as resolve27, join as join19, basename as basename7 } from "path";
1206
+ import { homedir as homedir3 } from "os";
1207
1207
  import { monitorEventLoopDelay } from "perf_hooks";
1208
1208
 
1209
1209
  // app/lib/agent-slug-pattern.ts
@@ -1560,6 +1560,36 @@ var WhatsAppConfigSchema = z.object({
1560
1560
  message: 'dmPolicy="open" requires allowFrom to include "*"'
1561
1561
  });
1562
1562
  });
1563
+ function parseWhatsAppConfigTolerant(raw) {
1564
+ const first = WhatsAppConfigSchema.safeParse(raw);
1565
+ if (first.success) {
1566
+ return { ok: true, data: first.data, droppedKeys: [] };
1567
+ }
1568
+ const issues = first.error.issues;
1569
+ const onlyUnknownKeys = issues.length > 0 && issues.every((i) => i.code === "unrecognized_keys");
1570
+ if (!onlyUnknownKeys) {
1571
+ return { ok: false, error: first.error };
1572
+ }
1573
+ const clone = JSON.parse(JSON.stringify(raw));
1574
+ const droppedKeys = [];
1575
+ for (const issue of issues) {
1576
+ if (issue.code !== "unrecognized_keys") continue;
1577
+ const container = issue.path.reduce(
1578
+ (acc, seg) => acc && typeof acc === "object" ? acc[seg] : void 0,
1579
+ clone
1580
+ );
1581
+ if (!container || typeof container !== "object") continue;
1582
+ for (const key of issue.keys) {
1583
+ delete container[key];
1584
+ droppedKeys.push([...issue.path, key].join("."));
1585
+ }
1586
+ }
1587
+ const second = WhatsAppConfigSchema.safeParse(clone);
1588
+ if (second.success) {
1589
+ return { ok: true, data: second.data, droppedKeys };
1590
+ }
1591
+ return { ok: false, error: second.error };
1592
+ }
1563
1593
 
1564
1594
  // app/lib/whatsapp/auth-store.ts
1565
1595
  import fsSync from "fs";
@@ -1751,7 +1781,7 @@ var credsSaveQueue = Promise.resolve();
1751
1781
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
1752
1782
  console.error(`${TAG2} draining credential save queue\u2026`);
1753
1783
  const timer2 = new Promise(
1754
- (resolve27) => setTimeout(() => resolve27("timeout"), timeoutMs)
1784
+ (resolve28) => setTimeout(() => resolve28("timeout"), timeoutMs)
1755
1785
  );
1756
1786
  const result = await Promise.race([
1757
1787
  credsSaveQueue.then(() => "drained"),
@@ -1879,11 +1909,11 @@ async function createWaSocket(opts) {
1879
1909
  return sock;
1880
1910
  }
1881
1911
  async function waitForConnection(sock) {
1882
- return new Promise((resolve27, reject) => {
1912
+ return new Promise((resolve28, reject) => {
1883
1913
  const handler = (update) => {
1884
1914
  if (update.connection === "open") {
1885
1915
  sock.ev.off("connection.update", handler);
1886
- resolve27();
1916
+ resolve28();
1887
1917
  }
1888
1918
  if (update.connection === "close") {
1889
1919
  sock.ev.off("connection.update", handler);
@@ -1997,14 +2027,14 @@ ${inspected}`;
1997
2027
  return inspect2(err, INSPECT_OPTS2);
1998
2028
  }
1999
2029
  function withTimeout(label, promise, timeoutMs) {
2000
- return new Promise((resolve27, reject) => {
2030
+ return new Promise((resolve28, reject) => {
2001
2031
  const timer2 = setTimeout(() => {
2002
2032
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
2003
2033
  }, timeoutMs);
2004
2034
  promise.then(
2005
2035
  (value) => {
2006
2036
  clearTimeout(timer2);
2007
- resolve27(value);
2037
+ resolve28(value);
2008
2038
  },
2009
2039
  (err) => {
2010
2040
  clearTimeout(timer2);
@@ -2559,8 +2589,8 @@ async function persistWhatsAppMessage(input) {
2559
2589
  const { givenName, familyName } = splitName(input.pushName);
2560
2590
  const prev = sessionWriteLocks.get(input.cacheKey);
2561
2591
  let release;
2562
- const mine = new Promise((resolve27) => {
2563
- release = resolve27;
2592
+ const mine = new Promise((resolve28) => {
2593
+ release = resolve28;
2564
2594
  });
2565
2595
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2566
2596
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -3500,13 +3530,20 @@ function loadConfig(accountConfig) {
3500
3530
  const raw = accountConfig?.whatsapp;
3501
3531
  if (raw && typeof raw === "object") {
3502
3532
  const wa = raw;
3503
- const parsed = WhatsAppConfigSchema.safeParse(wa);
3504
- if (parsed.success) {
3505
- whatsAppConfig = parsed.data;
3533
+ const result = parseWhatsAppConfigTolerant(wa);
3534
+ if (result.ok) {
3535
+ whatsAppConfig = result.data;
3536
+ if (result.droppedKeys.length > 0) {
3537
+ console.error(`${TAG12} config: dropped unknown keys=[${result.droppedKeys.join(",")}] preserved known config`);
3538
+ }
3506
3539
  } else {
3507
- console.error(`${TAG12} config validation failed: ${parsed.error.message}`);
3540
+ console.error(`${TAG12} config validation failed: ${result.error.message}`);
3508
3541
  whatsAppConfig = {};
3509
3542
  }
3543
+ const diskAdmin = Array.isArray(wa.adminPhones) ? wa.adminPhones : [];
3544
+ if (diskAdmin.length > 0 && (whatsAppConfig.adminPhones?.length ?? 0) === 0) {
3545
+ console.error(`${TAG12} WARN adminPhones present on disk but empty after load`);
3546
+ }
3510
3547
  }
3511
3548
  } catch (err) {
3512
3549
  console.error(`${TAG12} config load error: ${String(err)}`);
@@ -3614,11 +3651,11 @@ async function connectWithReconnect(conn) {
3614
3651
  console.error(
3615
3652
  `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3616
3653
  );
3617
- await new Promise((resolve27) => {
3618
- const timer2 = setTimeout(resolve27, delay);
3654
+ await new Promise((resolve28) => {
3655
+ const timer2 = setTimeout(resolve28, delay);
3619
3656
  conn.abortController.signal.addEventListener("abort", () => {
3620
3657
  clearTimeout(timer2);
3621
- resolve27();
3658
+ resolve28();
3622
3659
  }, { once: true });
3623
3660
  });
3624
3661
  }
@@ -3626,16 +3663,16 @@ async function connectWithReconnect(conn) {
3626
3663
  }
3627
3664
  }
3628
3665
  function waitForDisconnectEvent(conn) {
3629
- return new Promise((resolve27) => {
3666
+ return new Promise((resolve28) => {
3630
3667
  if (!conn.sock) {
3631
- resolve27();
3668
+ resolve28();
3632
3669
  return;
3633
3670
  }
3634
3671
  const sock = conn.sock;
3635
3672
  const handler = (update) => {
3636
3673
  if (update.connection === "close") {
3637
3674
  sock.ev.off("connection.update", handler);
3638
- resolve27();
3675
+ resolve28();
3639
3676
  }
3640
3677
  };
3641
3678
  sock.ev.on("connection.update", handler);
@@ -3863,8 +3900,8 @@ async function handleInboundMessage(conn, msg) {
3863
3900
  const conversationKey = isGroup ? remoteJid : senderPhone;
3864
3901
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
3865
3902
  let resolvePending;
3866
- const sttPending = new Promise((resolve27) => {
3867
- resolvePending = resolve27;
3903
+ const sttPending = new Promise((resolve28) => {
3904
+ resolvePending = resolve28;
3868
3905
  });
3869
3906
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
3870
3907
  try {
@@ -4255,20 +4292,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
4255
4292
 
4256
4293
  // server/routes/health.ts
4257
4294
  function checkPort(port2, timeoutMs = 500) {
4258
- return new Promise((resolve27) => {
4295
+ return new Promise((resolve28) => {
4259
4296
  const socket = createConnection2(port2, "127.0.0.1");
4260
4297
  socket.setTimeout(timeoutMs);
4261
4298
  socket.once("connect", () => {
4262
4299
  socket.destroy();
4263
- resolve27(true);
4300
+ resolve28(true);
4264
4301
  });
4265
4302
  socket.once("error", () => {
4266
4303
  socket.destroy();
4267
- resolve27(false);
4304
+ resolve28(false);
4268
4305
  });
4269
4306
  socket.once("timeout", () => {
4270
4307
  socket.destroy();
4271
- resolve27(false);
4308
+ resolve28(false);
4272
4309
  });
4273
4310
  });
4274
4311
  }
@@ -5356,12 +5393,12 @@ async function dispatchOnce(input) {
5356
5393
  });
5357
5394
  if (!entry) return { error: "spawn-failed" };
5358
5395
  entry.lastInboundAt = Date.now();
5359
- let resolve27;
5396
+ let resolve28;
5360
5397
  const turnPromise = new Promise((r) => {
5361
- resolve27 = r;
5398
+ resolve28 = r;
5362
5399
  });
5363
5400
  const listener = (text) => {
5364
- resolve27(text);
5401
+ resolve28(text);
5365
5402
  };
5366
5403
  entry.subscribers.add(listener);
5367
5404
  const writeAtMs = Date.now();
@@ -5979,6 +6016,35 @@ function getConfig(accountDir) {
5979
6016
  return null;
5980
6017
  }
5981
6018
  }
6019
+ function migrateRemovedConfigKeys(accountDir) {
6020
+ try {
6021
+ const config = readConfig(accountDir);
6022
+ const wa = config.whatsapp;
6023
+ if (!wa || typeof wa !== "object") return { dropped: [] };
6024
+ const result = parseWhatsAppConfigTolerant(wa);
6025
+ if (!result.ok || result.droppedKeys.length === 0) return { dropped: [] };
6026
+ const block = wa;
6027
+ for (const dotted of result.droppedKeys) {
6028
+ const segs = dotted.split(".");
6029
+ const key = segs.pop();
6030
+ const container = segs.reduce(
6031
+ (acc, seg) => acc && typeof acc === "object" ? acc[seg] : void 0,
6032
+ block
6033
+ );
6034
+ if (container && typeof container === "object") {
6035
+ delete container[key];
6036
+ }
6037
+ }
6038
+ writeConfig(accountDir, config);
6039
+ console.error(
6040
+ `${TAG17} migration: stripped unknown keys=[${result.droppedKeys.join(",")}] from account.json`
6041
+ );
6042
+ return { dropped: result.droppedKeys };
6043
+ } catch (err) {
6044
+ console.error(`${TAG17} migration failed: ${String(err)}`);
6045
+ return { dropped: [] };
6046
+ }
6047
+ }
5982
6048
 
5983
6049
  // app/lib/whatsapp/login.ts
5984
6050
  var TAG18 = "[whatsapp:login]";
@@ -6118,8 +6184,8 @@ async function startLogin(opts) {
6118
6184
  await clearAuth(authDir);
6119
6185
  let resolveCode = null;
6120
6186
  let rejectCode = null;
6121
- const codePromise = new Promise((resolve27, reject) => {
6122
- resolveCode = resolve27;
6187
+ const codePromise = new Promise((resolve28, reject) => {
6188
+ resolveCode = resolve28;
6123
6189
  rejectCode = reject;
6124
6190
  });
6125
6191
  const codeTimer = setTimeout(
@@ -6830,7 +6896,7 @@ function enumerateJsonls(projectsRoot) {
6830
6896
  }
6831
6897
  for (const entry of entries) {
6832
6898
  if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
6833
- out.push({ path: join7(slugDir, entry.name), isSubagent: false });
6899
+ out.push({ path: join7(slugDir, entry.name), isSubagent: false, archived: false });
6834
6900
  } else if (entry.isDirectory() && entry.name === "subagents") {
6835
6901
  const subDir = join7(slugDir, entry.name);
6836
6902
  let subEntries;
@@ -6843,7 +6909,22 @@ function enumerateJsonls(projectsRoot) {
6843
6909
  }
6844
6910
  for (const sub of subEntries) {
6845
6911
  if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
6846
- out.push({ path: join7(subDir, sub.name), isSubagent: true });
6912
+ out.push({ path: join7(subDir, sub.name), isSubagent: true, archived: false });
6913
+ }
6914
+ }
6915
+ } else if (entry.isDirectory() && entry.name === "archive") {
6916
+ const archiveDir = join7(slugDir, entry.name);
6917
+ let archiveEntries;
6918
+ try {
6919
+ archiveEntries = readdirSync4(archiveDir, { withFileTypes: true });
6920
+ } catch (err) {
6921
+ const code = err.code ?? "unknown";
6922
+ console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
6923
+ continue;
6924
+ }
6925
+ for (const arc of archiveEntries) {
6926
+ if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
6927
+ out.push({ path: join7(archiveDir, arc.name), isSubagent: false, archived: true });
6847
6928
  }
6848
6929
  }
6849
6930
  }
@@ -6983,8 +7064,9 @@ app4.get("/", requireAdminSession, async (c) => {
6983
7064
  let liveCount = 0;
6984
7065
  let subagentCount = 0;
6985
7066
  let nonResumableCount = 0;
7067
+ let archivedCount = 0;
6986
7068
  const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
6987
- for (const { path: path2, isSubagent } of jsonls) {
7069
+ for (const { path: path2, isSubagent, archived } of jsonls) {
6988
7070
  const lastSlash = path2.lastIndexOf("/");
6989
7071
  const base = path2.slice(lastSlash + 1);
6990
7072
  const projectDir = path2.slice(0, lastSlash);
@@ -7019,15 +7101,17 @@ app4.get("/", requireAdminSession, async (c) => {
7019
7101
  pid,
7020
7102
  projectDir,
7021
7103
  bridgeIds,
7022
- resumable
7104
+ resumable,
7105
+ archived
7023
7106
  });
7024
7107
  if (live) liveCount += 1;
7025
7108
  if (isSubagent) subagentCount += 1;
7026
7109
  if (!resumable) nonResumableCount += 1;
7110
+ if (archived) archivedCount += 1;
7027
7111
  }
7028
7112
  rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
7029
7113
  console.log(
7030
- `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} nonResumable=${nonResumableCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
7114
+ `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} nonResumable=${nonResumableCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
7031
7115
  );
7032
7116
  return c.json({ sessions: rows, accountId });
7033
7117
  });
@@ -7239,14 +7323,168 @@ app5.get("/stream", requireAdminSession, (c) => {
7239
7323
  });
7240
7324
  var whatsapp_reader_default = app5;
7241
7325
 
7326
+ // server/routes/telegram.ts
7327
+ import { homedir } from "os";
7328
+ import { resolve as resolve10, join as join9 } from "path";
7329
+ import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
7330
+
7331
+ // app/lib/telegram/access-control.ts
7332
+ function checkTelegramAccess(params) {
7333
+ const { senderId, botType, config } = params;
7334
+ if (botType === "admin") {
7335
+ const adminUsers = config.adminUsers ?? [];
7336
+ if (adminUsers.includes(senderId)) {
7337
+ return { allowed: true, reason: "admin-binding", agentType: "admin" };
7338
+ }
7339
+ return { allowed: false, reason: "not-admin-user", agentType: "admin" };
7340
+ }
7341
+ const policy = config.dmPolicy ?? "disabled";
7342
+ switch (policy) {
7343
+ case "open":
7344
+ return { allowed: true, reason: "dm-policy-open", agentType: "public" };
7345
+ case "allowlist": {
7346
+ const allowFrom = config.allowFrom ?? [];
7347
+ if (allowFrom.includes(senderId)) {
7348
+ return { allowed: true, reason: "allowlist-match", agentType: "public" };
7349
+ }
7350
+ return { allowed: false, reason: "not-in-allowlist", agentType: "public" };
7351
+ }
7352
+ case "disabled":
7353
+ return { allowed: false, reason: "dm-policy-disabled", agentType: "public" };
7354
+ default:
7355
+ return { allowed: false, reason: "unknown-dm-policy", agentType: "public" };
7356
+ }
7357
+ }
7358
+
7359
+ // app/lib/telegram/route-inbound.ts
7360
+ function routeTelegramUpdate(input) {
7361
+ const m = input.update.message;
7362
+ if (!m || typeof m.from?.id !== "number" || typeof m.chat?.id !== "number") {
7363
+ return { kind: "ignore", reason: "no-message" };
7364
+ }
7365
+ if (typeof m.text !== "string" || m.text.length === 0) {
7366
+ return { kind: "ignore", reason: "no-text" };
7367
+ }
7368
+ const access = checkTelegramAccess({ senderId: m.from.id, botType: input.botType, config: input.config });
7369
+ if (!access.allowed) {
7370
+ return { kind: "denied", reason: access.reason, agentType: access.agentType };
7371
+ }
7372
+ return { kind: "dispatch", senderId: String(m.from.id), chatId: m.chat.id, text: m.text, agentType: access.agentType };
7373
+ }
7374
+
7375
+ // server/routes/telegram.ts
7376
+ var TAG21 = "[telegram-inbound]";
7377
+ var DISPATCH_TIMEOUT_MS = 12e4;
7378
+ function configDirName() {
7379
+ const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve10(process.cwd(), "..");
7380
+ const brandPath = join9(platformRoot2, "config", "brand.json");
7381
+ if (existsSync6(brandPath)) {
7382
+ try {
7383
+ return JSON.parse(readFileSync10(brandPath, "utf-8")).configDir ?? ".maxy";
7384
+ } catch {
7385
+ }
7386
+ }
7387
+ return ".maxy";
7388
+ }
7389
+ function secretPath(botType) {
7390
+ const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
7391
+ return resolve10(homedir(), configDirName(), filename);
7392
+ }
7393
+ async function sendTelegram(botToken, chatId, text) {
7394
+ try {
7395
+ const res = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
7396
+ method: "POST",
7397
+ headers: { "Content-Type": "application/json" },
7398
+ body: JSON.stringify({ chat_id: chatId, text })
7399
+ });
7400
+ const data = await res.json();
7401
+ return data.ok ? { ok: true } : { ok: false, error: data.description ?? "send failed" };
7402
+ } catch (e) {
7403
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
7404
+ }
7405
+ }
7406
+ var app6 = new Hono();
7407
+ app6.post("/", async (c) => {
7408
+ const botParam = c.req.query("bot");
7409
+ const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
7410
+ if (!botType) {
7411
+ console.error(`${TAG21} op=reject reason=missing-bot-param`);
7412
+ return c.json({ ok: false }, 400);
7413
+ }
7414
+ const sp = secretPath(botType);
7415
+ if (!existsSync6(sp)) {
7416
+ console.error(`${TAG21} op=reject reason=no-secret-file botType=${botType}`);
7417
+ return c.json({ ok: false }, 401);
7418
+ }
7419
+ const expected = readFileSync10(sp, "utf-8").trim();
7420
+ const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
7421
+ if (got !== expected) {
7422
+ console.error(`${TAG21} op=reject reason=bad-secret botType=${botType}`);
7423
+ return c.json({ ok: false }, 401);
7424
+ }
7425
+ let update;
7426
+ try {
7427
+ update = await c.req.json();
7428
+ } catch {
7429
+ return c.json({ ok: true }, 200);
7430
+ }
7431
+ const account = resolveAccount();
7432
+ if (!account) {
7433
+ console.error(`${TAG21} op=reject reason=no-account`);
7434
+ return c.json({ ok: true }, 200);
7435
+ }
7436
+ const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
7437
+ if (decision.kind === "ignore") {
7438
+ console.error(`${TAG21} op=ignore reason=${decision.reason}`);
7439
+ return c.json({ ok: true }, 200);
7440
+ }
7441
+ if (decision.kind === "denied") {
7442
+ console.error(`${TAG21} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
7443
+ return c.json({ ok: true }, 200);
7444
+ }
7445
+ const role = decision.agentType === "admin" ? "admin" : "public";
7446
+ const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
7447
+ if (!agentSlug) {
7448
+ console.error(`${TAG21} op=reject reason=no-default-agent`);
7449
+ return c.json({ ok: true }, 200);
7450
+ }
7451
+ console.error(`${TAG21} op=update accountId=${account.accountId} from=${decision.senderId}`);
7452
+ const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
7453
+ const { senderId, chatId, text } = decision;
7454
+ void (async () => {
7455
+ const result = await dispatchOnce({
7456
+ accountId: account.accountId,
7457
+ senderId,
7458
+ role,
7459
+ channel: "telegram",
7460
+ agentSlug,
7461
+ text,
7462
+ timeoutMs: DISPATCH_TIMEOUT_MS
7463
+ });
7464
+ if ("error" in result) {
7465
+ console.error(`${TAG21} op=dispatch-failed from=${senderId} error=${result.error}`);
7466
+ return;
7467
+ }
7468
+ if (!botToken) {
7469
+ const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
7470
+ console.error(`${TAG21} op=reply-dropped reason=${reason} botType=${botType}`);
7471
+ return;
7472
+ }
7473
+ const sent = await sendTelegram(botToken, chatId, result.turnText);
7474
+ console.error(`${TAG21} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
7475
+ })();
7476
+ return c.json({ ok: true }, 200);
7477
+ });
7478
+ var telegram_default = app6;
7479
+
7242
7480
  // server/routes/onboarding.ts
7243
7481
  import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
7244
- import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync6, writeSync, existsSync as existsSync7, readFileSync as readFileSync11, unlinkSync } from "fs";
7482
+ import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync6, writeSync, existsSync as existsSync8, readFileSync as readFileSync12, unlinkSync } from "fs";
7245
7483
  import { createHash as createHash2, randomUUID as randomUUID7 } from "crypto";
7246
7484
 
7247
7485
  // ../lib/admins-write/src/index.ts
7248
- import { existsSync as existsSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5, renameSync, mkdirSync as mkdirSync2, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
7249
- import { dirname as dirname2, join as join9 } from "path";
7486
+ import { existsSync as existsSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync5, renameSync, mkdirSync as mkdirSync2, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
7487
+ import { dirname as dirname2, join as join10 } from "path";
7250
7488
  function logLine(input, result) {
7251
7489
  const userIdShort = input.userId.slice(0, 8);
7252
7490
  console.error(
@@ -7263,8 +7501,8 @@ function writeAdminEntry(input) {
7263
7501
  const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
7264
7502
  try {
7265
7503
  let users = [];
7266
- if (existsSync6(input.usersFile)) {
7267
- const raw = readFileSync10(input.usersFile, "utf-8").trim();
7504
+ if (existsSync7(input.usersFile)) {
7505
+ const raw = readFileSync11(input.usersFile, "utf-8").trim();
7268
7506
  if (raw) {
7269
7507
  const parsed = JSON.parse(raw);
7270
7508
  if (!Array.isArray(parsed)) {
@@ -7288,11 +7526,11 @@ function writeAdminEntry(input) {
7288
7526
  return result;
7289
7527
  }
7290
7528
  try {
7291
- const accountJsonPath = join9(input.accountDir, "account.json");
7292
- if (!existsSync6(accountJsonPath)) {
7529
+ const accountJsonPath = join10(input.accountDir, "account.json");
7530
+ if (!existsSync7(accountJsonPath)) {
7293
7531
  throw new Error(`account.json not found at ${accountJsonPath}`);
7294
7532
  }
7295
- const config = JSON.parse(readFileSync10(accountJsonPath, "utf-8"));
7533
+ const config = JSON.parse(readFileSync11(accountJsonPath, "utf-8"));
7296
7534
  const admins = config.admins ?? [];
7297
7535
  if (admins.some((a) => a.userId === input.userId)) {
7298
7536
  result.accountJsonResult = "noop";
@@ -7316,9 +7554,9 @@ function checkAdminAuthInvariant(input) {
7316
7554
  usersWithoutAccount: []
7317
7555
  };
7318
7556
  const usersUserIds = /* @__PURE__ */ new Set();
7319
- if (existsSync6(input.usersFile)) {
7557
+ if (existsSync7(input.usersFile)) {
7320
7558
  try {
7321
- const raw = readFileSync10(input.usersFile, "utf-8").trim();
7559
+ const raw = readFileSync11(input.usersFile, "utf-8").trim();
7322
7560
  if (raw) {
7323
7561
  const users = JSON.parse(raw);
7324
7562
  for (const u of users) {
@@ -7331,7 +7569,7 @@ function checkAdminAuthInvariant(input) {
7331
7569
  }
7332
7570
  }
7333
7571
  const accountUserIds = /* @__PURE__ */ new Set();
7334
- if (existsSync6(input.accountsDir)) {
7572
+ if (existsSync7(input.accountsDir)) {
7335
7573
  let entries;
7336
7574
  try {
7337
7575
  entries = readdirSync5(input.accountsDir);
@@ -7343,17 +7581,17 @@ function checkAdminAuthInvariant(input) {
7343
7581
  }
7344
7582
  for (const entry of entries) {
7345
7583
  if (entry.startsWith(".")) continue;
7346
- const accountDir = join9(input.accountsDir, entry);
7584
+ const accountDir = join10(input.accountsDir, entry);
7347
7585
  try {
7348
7586
  if (!statSync4(accountDir).isDirectory()) continue;
7349
7587
  } catch {
7350
7588
  continue;
7351
7589
  }
7352
- const accountJsonPath = join9(accountDir, "account.json");
7353
- if (!existsSync6(accountJsonPath)) continue;
7590
+ const accountJsonPath = join10(accountDir, "account.json");
7591
+ if (!existsSync7(accountJsonPath)) continue;
7354
7592
  let admins = [];
7355
7593
  try {
7356
- const config = JSON.parse(readFileSync10(accountJsonPath, "utf-8"));
7594
+ const config = JSON.parse(readFileSync11(accountJsonPath, "utf-8"));
7357
7595
  admins = config.admins ?? [];
7358
7596
  } catch (err) {
7359
7597
  const msg = err instanceof Error ? err.message : String(err);
@@ -7393,8 +7631,8 @@ function hashPin(pin) {
7393
7631
  return createHash2("sha256").update(pin).digest("hex");
7394
7632
  }
7395
7633
  function readUsersFile() {
7396
- if (!existsSync7(USERS_FILE)) return null;
7397
- const raw = readFileSync11(USERS_FILE, "utf-8").trim();
7634
+ if (!existsSync8(USERS_FILE)) return null;
7635
+ const raw = readFileSync12(USERS_FILE, "utf-8").trim();
7398
7636
  if (!raw) return [];
7399
7637
  return JSON.parse(raw);
7400
7638
  }
@@ -7424,11 +7662,11 @@ async function waitForAuthPage(timeoutMs = 2e4) {
7424
7662
  }
7425
7663
  return false;
7426
7664
  }
7427
- var app6 = new Hono();
7428
- app6.get("/claude-auth", async (c) => {
7665
+ var app7 = new Hono();
7666
+ app7.get("/claude-auth", async (c) => {
7429
7667
  return c.json({ authenticated: await checkAuthStatus() });
7430
7668
  });
7431
- app6.post("/claude-auth", async (c) => {
7669
+ app7.post("/claude-auth", async (c) => {
7432
7670
  let body = {};
7433
7671
  try {
7434
7672
  body = await c.req.json();
@@ -7492,7 +7730,7 @@ app6.post("/claude-auth", async (c) => {
7492
7730
  await waitForAuthPage(2e4);
7493
7731
  return c.json({ started: true, transport });
7494
7732
  });
7495
- app6.post("/set-pin", async (c) => {
7733
+ app7.post("/set-pin", async (c) => {
7496
7734
  let existingUsers = null;
7497
7735
  try {
7498
7736
  existingUsers = readUsersFile();
@@ -7548,9 +7786,9 @@ app6.post("/set-pin", async (c) => {
7548
7786
  console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
7549
7787
  if (process.platform === "linux") {
7550
7788
  let installOwner = null;
7551
- if (existsSync7(INSTALL_OWNER_FILE)) {
7789
+ if (existsSync8(INSTALL_OWNER_FILE)) {
7552
7790
  try {
7553
- const raw = readFileSync11(INSTALL_OWNER_FILE, "utf-8").trim();
7791
+ const raw = readFileSync12(INSTALL_OWNER_FILE, "utf-8").trim();
7554
7792
  if (raw.length > 0) installOwner = raw;
7555
7793
  } catch (err) {
7556
7794
  console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
@@ -7594,7 +7832,7 @@ ${body.pin}
7594
7832
  }
7595
7833
  return c.json({ ok: true });
7596
7834
  });
7597
- app6.delete("/set-pin", async (c) => {
7835
+ app7.delete("/set-pin", async (c) => {
7598
7836
  let users = null;
7599
7837
  try {
7600
7838
  users = readUsersFile();
@@ -7628,12 +7866,12 @@ app6.delete("/set-pin", async (c) => {
7628
7866
  }
7629
7867
  return c.json({ ok: true });
7630
7868
  });
7631
- var onboarding_default = app6;
7869
+ var onboarding_default = app7;
7632
7870
 
7633
7871
  // server/routes/client-error.ts
7634
- import { appendFileSync, existsSync as existsSync8, renameSync as renameSync2, statSync as statSync5 } from "fs";
7635
- import { join as join10 } from "path";
7636
- var CLIENT_ERRORS_LOG = join10(LOG_DIR, "client-errors.log");
7872
+ import { appendFileSync, existsSync as existsSync9, renameSync as renameSync2, statSync as statSync5 } from "fs";
7873
+ import { join as join11 } from "path";
7874
+ var CLIENT_ERRORS_LOG = join11(LOG_DIR, "client-errors.log");
7637
7875
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
7638
7876
  var MAX_BODY_SIZE = 8 * 1024;
7639
7877
  var MAX_STACK_LEN = 2e3;
@@ -7676,7 +7914,7 @@ function stackHead(stack) {
7676
7914
  }
7677
7915
  function rotateIfNeeded() {
7678
7916
  try {
7679
- if (!existsSync8(CLIENT_ERRORS_LOG)) return;
7917
+ if (!existsSync9(CLIENT_ERRORS_LOG)) return;
7680
7918
  const stats = statSync5(CLIENT_ERRORS_LOG);
7681
7919
  if (stats.size < MAX_LOG_SIZE) return;
7682
7920
  renameSync2(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
@@ -7684,8 +7922,8 @@ function rotateIfNeeded() {
7684
7922
  console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
7685
7923
  }
7686
7924
  }
7687
- var app7 = new Hono();
7688
- app7.post("/", async (c) => {
7925
+ var app8 = new Hono();
7926
+ app8.post("/", async (c) => {
7689
7927
  const client = resolveClientIp(
7690
7928
  c.env?.incoming?.socket?.remoteAddress,
7691
7929
  c.req.header("x-forwarded-for")
@@ -7787,21 +8025,21 @@ app7.post("/", async (c) => {
7787
8025
  }
7788
8026
  return c.json({ ok: true });
7789
8027
  });
7790
- var client_error_default = app7;
8028
+ var client_error_default = app8;
7791
8029
 
7792
8030
  // server/routes/admin/session.ts
7793
8031
  import { randomUUID as randomUUID8 } from "crypto";
7794
8032
 
7795
8033
  // app/lib/admin-identity/pin-validator.ts
7796
8034
  import { createHash as createHash3 } from "crypto";
7797
- import { existsSync as existsSync9, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
7798
- import { join as join11 } from "path";
8035
+ import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync6, statSync as statSync6 } from "fs";
8036
+ import { join as join12 } from "path";
7799
8037
  function hashPin2(pin) {
7800
8038
  return createHash3("sha256").update(pin).digest("hex");
7801
8039
  }
7802
8040
  function readUsersFile2(usersFilePath) {
7803
- if (!existsSync9(usersFilePath)) return null;
7804
- const raw = readFileSync12(usersFilePath, "utf-8").trim();
8041
+ if (!existsSync10(usersFilePath)) return null;
8042
+ const raw = readFileSync13(usersFilePath, "utf-8").trim();
7805
8043
  if (!raw) return [];
7806
8044
  return JSON.parse(raw);
7807
8045
  }
@@ -7820,7 +8058,7 @@ function validatePin(pin, usersFilePath) {
7820
8058
  function scanForOrphanedAccountAdmins(users, accountsDir) {
7821
8059
  const known = new Set(users.map((u) => u.userId));
7822
8060
  const orphans = [];
7823
- if (!existsSync9(accountsDir)) return orphans;
8061
+ if (!existsSync10(accountsDir)) return orphans;
7824
8062
  let entries;
7825
8063
  try {
7826
8064
  entries = readdirSync6(accountsDir);
@@ -7829,16 +8067,16 @@ function scanForOrphanedAccountAdmins(users, accountsDir) {
7829
8067
  }
7830
8068
  for (const entry of entries) {
7831
8069
  if (entry.startsWith(".")) continue;
7832
- const accountDir = join11(accountsDir, entry);
8070
+ const accountDir = join12(accountsDir, entry);
7833
8071
  try {
7834
8072
  if (!statSync6(accountDir).isDirectory()) continue;
7835
8073
  } catch {
7836
8074
  continue;
7837
8075
  }
7838
- const accountJsonPath = join11(accountDir, "account.json");
7839
- if (!existsSync9(accountJsonPath)) continue;
8076
+ const accountJsonPath = join12(accountDir, "account.json");
8077
+ if (!existsSync10(accountJsonPath)) continue;
7840
8078
  try {
7841
- const config = JSON.parse(readFileSync12(accountJsonPath, "utf-8"));
8079
+ const config = JSON.parse(readFileSync13(accountJsonPath, "utf-8"));
7842
8080
  const admins = config.admins ?? [];
7843
8081
  for (const a of admins) {
7844
8082
  if (typeof a.userId === "string" && !known.has(a.userId)) orphans.push(a.userId);
@@ -7905,8 +8143,8 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
7905
8143
  sessionId: initialSessionId
7906
8144
  };
7907
8145
  }
7908
- var app8 = new Hono();
7909
- app8.get("/", async (c) => {
8146
+ var app9 = new Hono();
8147
+ app9.get("/", async (c) => {
7910
8148
  const signedSessionToken = c.req.query("session_key");
7911
8149
  if (!signedSessionToken) {
7912
8150
  return c.json({ error: "Invalid or expired admin session" }, 401);
@@ -7952,7 +8190,7 @@ app8.get("/", async (c) => {
7952
8190
  sessionId: getSessionIdForSession(cacheKey) ?? null
7953
8191
  });
7954
8192
  });
7955
- app8.post("/", async (c) => {
8193
+ app9.post("/", async (c) => {
7956
8194
  let body;
7957
8195
  try {
7958
8196
  body = await c.req.json();
@@ -8015,21 +8253,21 @@ app8.post("/", async (c) => {
8015
8253
  const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
8016
8254
  return c.json(payload);
8017
8255
  });
8018
- var session_default = app8;
8256
+ var session_default = app9;
8019
8257
 
8020
8258
  // server/routes/admin/logs.ts
8021
- import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync7 } from "fs";
8022
- import { resolve as resolve10, basename as basename3 } from "path";
8259
+ import { existsSync as existsSync12, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
8260
+ import { resolve as resolve11, basename as basename3 } from "path";
8023
8261
 
8024
8262
  // app/lib/logs-read-resolve.ts
8025
- import { existsSync as existsSync10 } from "fs";
8026
- import { join as join12 } from "path";
8263
+ import { existsSync as existsSync11 } from "fs";
8264
+ import { join as join13 } from "path";
8027
8265
  function resolveSessionLogPaths(filename, logDirs) {
8028
8266
  const tried = [filename];
8029
8267
  const hits = [];
8030
8268
  for (const dir of logDirs) {
8031
- const fullPath = join12(dir, filename);
8032
- if (existsSync10(fullPath)) {
8269
+ const fullPath = join13(dir, filename);
8270
+ if (existsSync11(fullPath)) {
8033
8271
  hits.push({ path: fullPath, dir });
8034
8272
  }
8035
8273
  }
@@ -8038,15 +8276,15 @@ function resolveSessionLogPaths(filename, logDirs) {
8038
8276
 
8039
8277
  // server/routes/admin/logs.ts
8040
8278
  var TAIL_BYTES = 8192;
8041
- var app9 = new Hono();
8042
- app9.get("/", async (c) => {
8279
+ var app10 = new Hono();
8280
+ app10.get("/", async (c) => {
8043
8281
  const fileParam = c.req.query("file");
8044
8282
  const typeParam = c.req.query("type");
8045
8283
  const sessionIdParam = c.req.query("sessionId");
8046
8284
  const cacheKeyParam = c.req.query("cacheKey");
8047
8285
  const download = c.req.query("download") === "1";
8048
8286
  const account = resolveAccount();
8049
- const accountLogDir = account ? resolve10(account.accountDir, "logs") : null;
8287
+ const accountLogDir = account ? resolve11(account.accountDir, "logs") : null;
8050
8288
  const logDirs = [];
8051
8289
  if (accountLogDir) logDirs.push(accountLogDir);
8052
8290
  logDirs.push(LOG_DIR);
@@ -8054,10 +8292,10 @@ app9.get("/", async (c) => {
8054
8292
  const safe = basename3(fileParam);
8055
8293
  const searched = [];
8056
8294
  for (const dir of logDirs) {
8057
- const filePath = resolve10(dir, safe);
8295
+ const filePath = resolve11(dir, safe);
8058
8296
  searched.push(filePath);
8059
8297
  try {
8060
- const buffer = readFileSync13(filePath);
8298
+ const buffer = readFileSync14(filePath);
8061
8299
  const onDiskBytes = statSync7(filePath).size;
8062
8300
  const headers = {
8063
8301
  "Content-Type": "text/plain; charset=utf-8",
@@ -8122,7 +8360,7 @@ app9.get("/", async (c) => {
8122
8360
  console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
8123
8361
  try {
8124
8362
  const filename = basename3(hit.path);
8125
- const buffer = readFileSync13(hit.path);
8363
+ const buffer = readFileSync14(hit.path);
8126
8364
  const onDiskBytes = statSync7(hit.path).size;
8127
8365
  const headers = {
8128
8366
  "Content-Type": "text/plain; charset=utf-8",
@@ -8157,7 +8395,7 @@ app9.get("/", async (c) => {
8157
8395
  const seen = /* @__PURE__ */ new Set();
8158
8396
  const logs = {};
8159
8397
  for (const dir of logDirs) {
8160
- if (!existsSync11(dir)) continue;
8398
+ if (!existsSync12(dir)) continue;
8161
8399
  let files;
8162
8400
  try {
8163
8401
  files = readdirSync7(dir).filter((f) => f.endsWith(".log"));
@@ -8166,10 +8404,10 @@ app9.get("/", async (c) => {
8166
8404
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
8167
8405
  continue;
8168
8406
  }
8169
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve10(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
8407
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve11(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
8170
8408
  seen.add(name);
8171
8409
  try {
8172
- const content = readFileSync13(resolve10(dir, name));
8410
+ const content = readFileSync14(resolve11(dir, name));
8173
8411
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
8174
8412
  logs[name] = tail.trim() || "(empty)";
8175
8413
  } catch (err) {
@@ -8181,12 +8419,12 @@ app9.get("/", async (c) => {
8181
8419
  }
8182
8420
  return c.json({ logs });
8183
8421
  });
8184
- var logs_default = app9;
8422
+ var logs_default = app10;
8185
8423
 
8186
8424
  // server/routes/admin/claude-info.ts
8187
8425
  import { execFileSync as execFileSync3 } from "child_process";
8188
- var app10 = new Hono();
8189
- app10.get("/", (c) => {
8426
+ var app11 = new Hono();
8427
+ app11.get("/", (c) => {
8190
8428
  let version = "unknown";
8191
8429
  try {
8192
8430
  const raw = execFileSync3("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
@@ -8204,14 +8442,14 @@ app10.get("/", (c) => {
8204
8442
  const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
8205
8443
  return c.json({ version, account, model, thinkingView });
8206
8444
  });
8207
- var claude_info_default = app10;
8445
+ var claude_info_default = app11;
8208
8446
 
8209
8447
  // server/routes/admin/attachment.ts
8210
8448
  import { readFile as readFile2, readdir } from "fs/promises";
8211
- import { existsSync as existsSync12 } from "fs";
8212
- import { resolve as resolve11 } from "path";
8213
- var app11 = new Hono();
8214
- app11.get("/:attachmentId", requireAdminSession, async (c) => {
8449
+ import { existsSync as existsSync13 } from "fs";
8450
+ import { resolve as resolve12 } from "path";
8451
+ var app12 = new Hono();
8452
+ app12.get("/:attachmentId", requireAdminSession, async (c) => {
8215
8453
  const attachmentId = c.req.param("attachmentId");
8216
8454
  const cacheKey = c.var.cacheKey;
8217
8455
  const accountId = getAccountIdForSession(cacheKey);
@@ -8221,12 +8459,12 @@ app11.get("/:attachmentId", requireAdminSession, async (c) => {
8221
8459
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
8222
8460
  return new Response("Not found", { status: 404 });
8223
8461
  }
8224
- const dir = resolve11(ATTACHMENTS_ROOT, accountId, attachmentId);
8225
- if (!existsSync12(dir)) {
8462
+ const dir = resolve12(ATTACHMENTS_ROOT, accountId, attachmentId);
8463
+ if (!existsSync13(dir)) {
8226
8464
  return new Response("Not found", { status: 404 });
8227
8465
  }
8228
- const metaPath = resolve11(dir, `${attachmentId}.meta.json`);
8229
- if (!existsSync12(metaPath)) {
8466
+ const metaPath = resolve12(dir, `${attachmentId}.meta.json`);
8467
+ if (!existsSync13(metaPath)) {
8230
8468
  return new Response("Not found", { status: 404 });
8231
8469
  }
8232
8470
  let meta;
@@ -8240,7 +8478,7 @@ app11.get("/:attachmentId", requireAdminSession, async (c) => {
8240
8478
  if (!dataFile) {
8241
8479
  return new Response("Not found", { status: 404 });
8242
8480
  }
8243
- const filePath = resolve11(dir, dataFile);
8481
+ const filePath = resolve12(dir, dataFile);
8244
8482
  const buffer = await readFile2(filePath);
8245
8483
  return new Response(new Uint8Array(buffer), {
8246
8484
  headers: {
@@ -8250,27 +8488,27 @@ app11.get("/:attachmentId", requireAdminSession, async (c) => {
8250
8488
  }
8251
8489
  });
8252
8490
  });
8253
- var attachment_default = app11;
8491
+ var attachment_default = app12;
8254
8492
 
8255
8493
  // server/routes/admin/agents.ts
8256
- import { resolve as resolve12 } from "path";
8257
- import { readdirSync as readdirSync8, readFileSync as readFileSync14, existsSync as existsSync13, rmSync } from "fs";
8258
- var app12 = new Hono();
8259
- app12.get("/", (c) => {
8494
+ import { resolve as resolve13 } from "path";
8495
+ import { readdirSync as readdirSync8, readFileSync as readFileSync15, existsSync as existsSync14, rmSync } from "fs";
8496
+ var app13 = new Hono();
8497
+ app13.get("/", (c) => {
8260
8498
  const account = resolveAccount();
8261
8499
  if (!account) return c.json({ agents: [] });
8262
- const agentsDir = resolve12(account.accountDir, "agents");
8263
- if (!existsSync13(agentsDir)) return c.json({ agents: [] });
8500
+ const agentsDir = resolve13(account.accountDir, "agents");
8501
+ if (!existsSync14(agentsDir)) return c.json({ agents: [] });
8264
8502
  const agents = [];
8265
8503
  try {
8266
8504
  const entries = readdirSync8(agentsDir, { withFileTypes: true });
8267
8505
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
8268
8506
  if (!entry.isDirectory()) continue;
8269
8507
  if (entry.name === "admin") continue;
8270
- const configPath2 = resolve12(agentsDir, entry.name, "config.json");
8271
- if (!existsSync13(configPath2)) continue;
8508
+ const configPath2 = resolve13(agentsDir, entry.name, "config.json");
8509
+ if (!existsSync14(configPath2)) continue;
8272
8510
  try {
8273
- const config = JSON.parse(readFileSync14(configPath2, "utf-8"));
8511
+ const config = JSON.parse(readFileSync15(configPath2, "utf-8"));
8274
8512
  agents.push({
8275
8513
  slug: entry.name,
8276
8514
  displayName: config.displayName ?? entry.name,
@@ -8286,7 +8524,7 @@ app12.get("/", (c) => {
8286
8524
  }
8287
8525
  return c.json({ agents });
8288
8526
  });
8289
- app12.delete("/:slug", async (c) => {
8527
+ app13.delete("/:slug", async (c) => {
8290
8528
  const slug = c.req.param("slug");
8291
8529
  const account = resolveAccount();
8292
8530
  if (!account) return c.json({ error: "No account resolved" }, 400);
@@ -8296,8 +8534,8 @@ app12.delete("/:slug", async (c) => {
8296
8534
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
8297
8535
  return c.json({ error: "Invalid agent slug" }, 400);
8298
8536
  }
8299
- const agentDir = resolve12(account.accountDir, "agents", slug);
8300
- if (!existsSync13(agentDir)) {
8537
+ const agentDir = resolve13(account.accountDir, "agents", slug);
8538
+ if (!existsSync14(agentDir)) {
8301
8539
  return c.json({ error: "Agent not found" }, 404);
8302
8540
  }
8303
8541
  try {
@@ -8316,7 +8554,7 @@ app12.delete("/:slug", async (c) => {
8316
8554
  return c.json({ error: "Failed to delete agent" }, 500);
8317
8555
  }
8318
8556
  });
8319
- app12.post("/:slug/project", async (c) => {
8557
+ app13.post("/:slug/project", async (c) => {
8320
8558
  const slug = c.req.param("slug");
8321
8559
  const account = resolveAccount();
8322
8560
  if (!account) return c.json({ error: "No account resolved" }, 400);
@@ -8326,8 +8564,8 @@ app12.post("/:slug/project", async (c) => {
8326
8564
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
8327
8565
  return c.json({ error: "Invalid agent slug" }, 400);
8328
8566
  }
8329
- const agentDir = resolve12(account.accountDir, "agents", slug);
8330
- if (!existsSync13(agentDir)) {
8567
+ const agentDir = resolve13(account.accountDir, "agents", slug);
8568
+ if (!existsSync14(agentDir)) {
8331
8569
  return c.json({ error: "Agent not found on disk" }, 404);
8332
8570
  }
8333
8571
  try {
@@ -8338,12 +8576,12 @@ app12.post("/:slug/project", async (c) => {
8338
8576
  return c.json({ error: `Projection failed: ${msg}` }, 500);
8339
8577
  }
8340
8578
  });
8341
- var agents_default = app12;
8579
+ var agents_default = app13;
8342
8580
 
8343
8581
  // server/routes/admin/sessions.ts
8344
8582
  import crypto2 from "crypto";
8345
8583
  import { resolve as resolvePath } from "path";
8346
- import { existsSync as existsSync14, mkdirSync as mkdirSync3, createWriteStream } from "fs";
8584
+ import { existsSync as existsSync15, mkdirSync as mkdirSync3, createWriteStream } from "fs";
8347
8585
 
8348
8586
  // ../lib/admin-conversation-purge/src/index.ts
8349
8587
  async function purgeAdminConversationJsonls(args) {
@@ -8481,7 +8719,7 @@ var replayJsonl = (..._args) => null;
8481
8719
  var resolveJsonlPath = (..._args) => null;
8482
8720
 
8483
8721
  // server/routes/admin/sessions.ts
8484
- import { homedir } from "os";
8722
+ import { homedir as homedir2 } from "os";
8485
8723
 
8486
8724
  // app/lib/claude-agent/component-attachment.ts
8487
8725
  var pickComponentBytes = (..._args) => null;
@@ -8503,7 +8741,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
8503
8741
  let reason = null;
8504
8742
  if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
8505
8743
  else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
8506
- else if (!existsSync14(a.storagePath)) reason = "missing-file";
8744
+ else if (!existsSync15(a.storagePath)) reason = "missing-file";
8507
8745
  if (reason) {
8508
8746
  invalid++;
8509
8747
  try {
@@ -8610,8 +8848,8 @@ function formatAge(updatedAtStr) {
8610
8848
  return "unknown";
8611
8849
  }
8612
8850
  }
8613
- var app13 = new Hono();
8614
- app13.get("/", requireAdminSession, async (c) => {
8851
+ var app14 = new Hono();
8852
+ app14.get("/", requireAdminSession, async (c) => {
8615
8853
  const cacheKey = c.var.cacheKey;
8616
8854
  const accountId = getAccountIdForSession(cacheKey);
8617
8855
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
@@ -8641,7 +8879,7 @@ app13.get("/", requireAdminSession, async (c) => {
8641
8879
  return c.json({ error: "Failed to fetch sessions" }, 500);
8642
8880
  }
8643
8881
  });
8644
- app13.post("/new", requireAdminSession, async (c) => {
8882
+ app14.post("/new", requireAdminSession, async (c) => {
8645
8883
  const oldCacheKey = c.var.cacheKey;
8646
8884
  console.log(`[admin-chat] new-conversation outcome=ingress cacheKey=${oldCacheKey.slice(0, 8)}`);
8647
8885
  const accountId = getAccountIdForSession(oldCacheKey);
@@ -8658,7 +8896,7 @@ app13.post("/new", requireAdminSession, async (c) => {
8658
8896
  console.log(`[admin-chat] new-conversation outcome=ok oldKey=${oldCacheKey.slice(0, 8)} newKey=${newCacheKey.slice(0, 8)}`);
8659
8897
  return c.json({ session_key: newSignedSessionToken, sessionId: null });
8660
8898
  });
8661
- app13.post("/switch", requireAdminSession, async (c) => {
8899
+ app14.post("/switch", requireAdminSession, async (c) => {
8662
8900
  const cacheKey = c.var.cacheKey;
8663
8901
  const accountId = getAccountIdForSession(cacheKey);
8664
8902
  const userId = getUserIdForSession(cacheKey);
@@ -8686,7 +8924,7 @@ app13.post("/switch", requireAdminSession, async (c) => {
8686
8924
  console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetSessionId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
8687
8925
  return c.json({ session_key: targetSignedSessionToken, sessionId: targetSessionId });
8688
8926
  });
8689
- app13.delete("/:id", requireAdminSession, async (c) => {
8927
+ app14.delete("/:id", requireAdminSession, async (c) => {
8690
8928
  const sessionId = c.req.param("id");
8691
8929
  const cacheKey = c.var.cacheKey;
8692
8930
  const accountId = getAccountIdForSession(cacheKey);
@@ -8731,7 +8969,7 @@ app13.delete("/:id", requireAdminSession, async (c) => {
8731
8969
  500
8732
8970
  );
8733
8971
  });
8734
- app13.post("/:id/resume", async (c) => {
8972
+ app14.post("/:id/resume", async (c) => {
8735
8973
  const sessionId = c.req.param("id");
8736
8974
  const t0 = Date.now();
8737
8975
  const signedSessionToken = c.req.query("session_key") ?? "";
@@ -8796,7 +9034,7 @@ app13.post("/:id/resume", async (c) => {
8796
9034
  return c.json({ error: "Failed to load conversation messages" }, 500);
8797
9035
  }
8798
9036
  if (persistedAgentSessionId) {
8799
- const jsonlPath = resolveJsonlPath(homedir(), resolvePath(ACCOUNTS_DIR, accountId), persistedAgentSessionId);
9037
+ const jsonlPath = resolveJsonlPath(homedir2(), resolvePath(ACCOUNTS_DIR, accountId), persistedAgentSessionId);
8800
9038
  const replay = replayJsonl(jsonlPath);
8801
9039
  jsonlMissing = replay.jsonlMissing;
8802
9040
  jsonlMalformedLines = replay.malformedLines;
@@ -9000,7 +9238,7 @@ app13.post("/:id/resume", async (c) => {
9000
9238
  }
9001
9239
  });
9002
9240
  });
9003
- app13.put("/:id/label", requireAdminSession, async (c) => {
9241
+ app14.put("/:id/label", requireAdminSession, async (c) => {
9004
9242
  const sessionId = c.req.param("id");
9005
9243
  const cacheKey = c.var.cacheKey;
9006
9244
  let body;
@@ -9026,11 +9264,11 @@ app13.put("/:id/label", requireAdminSession, async (c) => {
9026
9264
  return c.json({ error: "Failed to rename session" }, 500);
9027
9265
  }
9028
9266
  });
9029
- var sessions_default = app13;
9267
+ var sessions_default = app14;
9030
9268
 
9031
9269
  // app/lib/claude-agent/spawn-context.ts
9032
- import { existsSync as existsSync15, readFileSync as readFileSync15, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
9033
- import { dirname as dirname3, resolve as resolve13, join as join13 } from "path";
9270
+ import { existsSync as existsSync16, readFileSync as readFileSync16, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
9271
+ import { dirname as dirname3, resolve as resolve14, join as join14 } from "path";
9034
9272
  async function resolveOwnerProfileBlock(accountId, userId) {
9035
9273
  if (!userId) return { ok: false, reason: "missing-user-id" };
9036
9274
  try {
@@ -9059,14 +9297,14 @@ function frontmatterField(manifest, field) {
9059
9297
  function extractPluginToolDescriptions(pluginDir) {
9060
9298
  const out = /* @__PURE__ */ new Map();
9061
9299
  const candidates = [
9062
- join13(pluginDir, "mcp/dist/index.js"),
9063
- join13(pluginDir, "mcp/src/index.ts")
9300
+ join14(pluginDir, "mcp/dist/index.js"),
9301
+ join14(pluginDir, "mcp/src/index.ts")
9064
9302
  ];
9065
9303
  let raw = null;
9066
9304
  for (const path2 of candidates) {
9067
- if (!existsSync15(path2)) continue;
9305
+ if (!existsSync16(path2)) continue;
9068
9306
  try {
9069
- raw = readFileSync15(path2, "utf-8");
9307
+ raw = readFileSync16(path2, "utf-8");
9070
9308
  break;
9071
9309
  } catch {
9072
9310
  }
@@ -9115,24 +9353,24 @@ function parseSkillPathsFromFrontmatter(fm) {
9115
9353
  }
9116
9354
  function listPluginDirs() {
9117
9355
  const out = /* @__PURE__ */ new Map();
9118
- const platformPlugins = resolve13(PLATFORM_ROOT, "plugins");
9119
- if (existsSync15(platformPlugins)) {
9356
+ const platformPlugins = resolve14(PLATFORM_ROOT, "plugins");
9357
+ if (existsSync16(platformPlugins)) {
9120
9358
  for (const name of readdirSync9(platformPlugins)) {
9121
- const dir = join13(platformPlugins, name);
9359
+ const dir = join14(platformPlugins, name);
9122
9360
  try {
9123
9361
  if (statSync8(dir).isDirectory()) out.set(name, dir);
9124
9362
  } catch {
9125
9363
  }
9126
9364
  }
9127
9365
  }
9128
- const premiumRoot = resolve13(dirname3(PLATFORM_ROOT), "premium-plugins");
9129
- if (existsSync15(premiumRoot)) {
9366
+ const premiumRoot = resolve14(dirname3(PLATFORM_ROOT), "premium-plugins");
9367
+ if (existsSync16(premiumRoot)) {
9130
9368
  for (const bundle of readdirSync9(premiumRoot)) {
9131
- const bundlePlugins = join13(premiumRoot, bundle, "plugins");
9132
- if (!existsSync15(bundlePlugins)) continue;
9369
+ const bundlePlugins = join14(premiumRoot, bundle, "plugins");
9370
+ if (!existsSync16(bundlePlugins)) continue;
9133
9371
  try {
9134
9372
  for (const name of readdirSync9(bundlePlugins)) {
9135
- const dir = join13(bundlePlugins, name);
9373
+ const dir = join14(bundlePlugins, name);
9136
9374
  try {
9137
9375
  if (statSync8(dir).isDirectory()) out.set(name, dir);
9138
9376
  } catch {
@@ -9145,10 +9383,10 @@ function listPluginDirs() {
9145
9383
  return out;
9146
9384
  }
9147
9385
  function readEnabledPlugins(accountId) {
9148
- const accountFile = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
9149
- if (!existsSync15(accountFile)) return /* @__PURE__ */ new Set();
9386
+ const accountFile = resolve14(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
9387
+ if (!existsSync16(accountFile)) return /* @__PURE__ */ new Set();
9150
9388
  try {
9151
- const parsed = JSON.parse(readFileSync15(accountFile, "utf-8"));
9389
+ const parsed = JSON.parse(readFileSync16(accountFile, "utf-8"));
9152
9390
  return new Set(
9153
9391
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
9154
9392
  );
@@ -9157,10 +9395,10 @@ function readEnabledPlugins(accountId) {
9157
9395
  }
9158
9396
  }
9159
9397
  function readFrontmatter(path2) {
9160
- if (!existsSync15(path2)) return null;
9398
+ if (!existsSync16(path2)) return null;
9161
9399
  let raw;
9162
9400
  try {
9163
- raw = readFileSync15(path2, "utf-8");
9401
+ raw = readFileSync16(path2, "utf-8");
9164
9402
  } catch {
9165
9403
  return null;
9166
9404
  }
@@ -9175,7 +9413,7 @@ function computeActivePlugins(accountId) {
9175
9413
  for (const name of Array.from(enabled).sort()) {
9176
9414
  const dir = pluginDirs.get(name);
9177
9415
  if (!dir) continue;
9178
- const fm = readFrontmatter(join13(dir, "PLUGIN.md"));
9416
+ const fm = readFrontmatter(join14(dir, "PLUGIN.md"));
9179
9417
  if (!fm) continue;
9180
9418
  const description = frontmatterField(`---
9181
9419
  ${fm}
@@ -9192,7 +9430,7 @@ ${fm}
9192
9430
  `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
9193
9431
  );
9194
9432
  if (toolNames.length > 0 && descMap.size === 0) {
9195
- const hasSource = existsSync15(join13(dir, "mcp/dist/index.js")) || existsSync15(join13(dir, "mcp/src/index.ts"));
9433
+ const hasSource = existsSync16(join14(dir, "mcp/dist/index.js")) || existsSync16(join14(dir, "mcp/src/index.ts"));
9196
9434
  if (hasSource) {
9197
9435
  console.warn(
9198
9436
  `[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
@@ -9202,7 +9440,7 @@ ${fm}
9202
9440
  const skillPaths = parseSkillPathsFromFrontmatter(fm);
9203
9441
  const skills = [];
9204
9442
  for (const relPath of skillPaths) {
9205
- const skillPath = join13(dir, relPath);
9443
+ const skillPath = join14(dir, relPath);
9206
9444
  const skillFm = readFrontmatter(skillPath);
9207
9445
  if (!skillFm) continue;
9208
9446
  const skillName = frontmatterField(`---
@@ -9218,8 +9456,8 @@ ${skillFm}
9218
9456
  return out;
9219
9457
  }
9220
9458
  function computeSpecialistDomains(accountId) {
9221
- const specialistsDir = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
9222
- if (!existsSync15(specialistsDir)) return [];
9459
+ const specialistsDir = resolve14(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
9460
+ if (!existsSync16(specialistsDir)) return [];
9223
9461
  let entries;
9224
9462
  try {
9225
9463
  entries = readdirSync9(specialistsDir);
@@ -9246,7 +9484,7 @@ function computeSpecialistDomains(accountId) {
9246
9484
  const out = [];
9247
9485
  for (const file of entries.sort()) {
9248
9486
  if (!file.endsWith(".md")) continue;
9249
- const fm = readFrontmatter(join13(specialistsDir, file));
9487
+ const fm = readFrontmatter(join14(specialistsDir, file));
9250
9488
  if (!fm) continue;
9251
9489
  const wrapped = `---
9252
9490
  ${fm}
@@ -9264,11 +9502,11 @@ ${fm}
9264
9502
  return out;
9265
9503
  }
9266
9504
  function computeDormantPlugins(accountId) {
9267
- const accountFile = resolve13(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
9268
- if (!existsSync15(accountFile)) return [];
9505
+ const accountFile = resolve14(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
9506
+ if (!existsSync16(accountFile)) return [];
9269
9507
  let enabled;
9270
9508
  try {
9271
- const raw = readFileSync15(accountFile, "utf-8");
9509
+ const raw = readFileSync16(accountFile, "utf-8");
9272
9510
  const parsed = JSON.parse(raw);
9273
9511
  enabled = new Set(
9274
9512
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
@@ -9279,8 +9517,8 @@ function computeDormantPlugins(accountId) {
9279
9517
  );
9280
9518
  return [];
9281
9519
  }
9282
- const pluginsDir = resolve13(PLATFORM_ROOT, "plugins");
9283
- if (!existsSync15(pluginsDir)) return [];
9520
+ const pluginsDir = resolve14(PLATFORM_ROOT, "plugins");
9521
+ if (!existsSync16(pluginsDir)) return [];
9284
9522
  let entries;
9285
9523
  try {
9286
9524
  entries = readdirSync9(pluginsDir);
@@ -9290,11 +9528,11 @@ function computeDormantPlugins(accountId) {
9290
9528
  const out = [];
9291
9529
  for (const name of entries) {
9292
9530
  if (enabled.has(name)) continue;
9293
- const manifestPath = resolve13(pluginsDir, name, "PLUGIN.md");
9294
- if (!existsSync15(manifestPath)) continue;
9531
+ const manifestPath = resolve14(pluginsDir, name, "PLUGIN.md");
9532
+ if (!existsSync16(manifestPath)) continue;
9295
9533
  let manifest;
9296
9534
  try {
9297
- manifest = readFileSync15(manifestPath, "utf-8");
9535
+ manifest = readFileSync16(manifestPath, "utf-8");
9298
9536
  } catch {
9299
9537
  continue;
9300
9538
  }
@@ -9308,13 +9546,13 @@ function computeDormantPlugins(accountId) {
9308
9546
  }
9309
9547
 
9310
9548
  // server/routes/admin/claude-sessions.ts
9311
- import { existsSync as existsSync16, readFileSync as readFileSync16 } from "fs";
9312
- import { resolve as resolve14 } from "path";
9549
+ import { existsSync as existsSync17, readFileSync as readFileSync17 } from "fs";
9550
+ import { resolve as resolve15 } from "path";
9313
9551
  function readTunnelState(brandConfigDir) {
9314
9552
  const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
9315
- if (!existsSync16(statePath)) return null;
9553
+ if (!existsSync17(statePath)) return null;
9316
9554
  try {
9317
- const parsed = JSON.parse(readFileSync16(statePath, "utf-8"));
9555
+ const parsed = JSON.parse(readFileSync17(statePath, "utf-8"));
9318
9556
  const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
9319
9557
  const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
9320
9558
  const domain = typeof parsed.domain === "string" ? parsed.domain : null;
@@ -9325,10 +9563,10 @@ function readTunnelState(brandConfigDir) {
9325
9563
  }
9326
9564
  }
9327
9565
  function resolveTunnelUrl() {
9328
- const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
9566
+ const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
9329
9567
  let brand;
9330
9568
  try {
9331
- brand = JSON.parse(readFileSync16(resolve14(platformRoot2, "config", "brand.json"), "utf-8"));
9569
+ brand = JSON.parse(readFileSync17(resolve15(platformRoot2, "config", "brand.json"), "utf-8"));
9332
9570
  } catch {
9333
9571
  return null;
9334
9572
  }
@@ -9339,7 +9577,7 @@ function resolveTunnelUrl() {
9339
9577
  if (!state) return null;
9340
9578
  return `https://${hostname2}.${state.domain}`;
9341
9579
  }
9342
- var TAG21 = "[claude-session-manager:wrapper]";
9580
+ var TAG22 = "[claude-session-manager:wrapper]";
9343
9581
  async function refuseIfClaudeAuthDead(c, route, sessionId) {
9344
9582
  const auth = await ensureAuth();
9345
9583
  if (auth.status !== "dead" && auth.status !== "missing") return null;
@@ -9351,18 +9589,18 @@ async function refuseIfClaudeAuthDead(c, route, sessionId) {
9351
9589
  503
9352
9590
  );
9353
9591
  }
9354
- var app14 = new Hono();
9592
+ var app15 = new Hono();
9355
9593
  async function performSpawnWithInitialMessage(args) {
9356
9594
  const ownerStart = Date.now();
9357
9595
  const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
9358
9596
  const ownerMs = Date.now() - ownerStart;
9359
9597
  const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
9360
- console.log(`${TAG21} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
9598
+ console.log(`${TAG22} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
9361
9599
  const dormantPlugins = computeDormantPlugins(args.senderId);
9362
9600
  const activePlugins = computeActivePlugins(args.senderId);
9363
9601
  const specialistDomains = computeSpecialistDomains(args.senderId);
9364
9602
  const tunnelUrl = resolveTunnelUrl();
9365
- console.log(`${TAG21} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
9603
+ console.log(`${TAG22} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
9366
9604
  const upstreamPayload = JSON.stringify({
9367
9605
  senderId: args.senderId,
9368
9606
  // Task 205 — pass userId through to the manager so it lands as
@@ -9389,24 +9627,24 @@ async function performSpawnWithInitialMessage(args) {
9389
9627
  // unshapely values.
9390
9628
  conversationNodeId: args.conversationNodeId
9391
9629
  });
9392
- console.log(`${TAG21} forward-spawn-start managerBase=${managerBase3("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
9630
+ console.log(`${TAG22} forward-spawn-start managerBase=${managerBase3("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
9393
9631
  const forwardStart = Date.now();
9394
9632
  const upstream = await fetch(`${managerBase3("claude-session-manager:wrapper")}/public-spawn`, {
9395
9633
  method: "POST",
9396
9634
  headers: { "content-type": "application/json" },
9397
9635
  body: upstreamPayload
9398
9636
  }).catch((err) => {
9399
- console.error(`${TAG21} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
9637
+ console.error(`${TAG22} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
9400
9638
  return null;
9401
9639
  });
9402
9640
  if (!upstream) return {
9403
9641
  response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
9404
9642
  claudeSessionId: null
9405
9643
  };
9406
- console.log(`${TAG21} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
9644
+ console.log(`${TAG22} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
9407
9645
  if (args.initialMessage) {
9408
9646
  const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
9409
- console.log(`${TAG21} initial-message-inlined bytes=${inputBytes}`);
9647
+ console.log(`${TAG22} initial-message-inlined bytes=${inputBytes}`);
9410
9648
  }
9411
9649
  const bodyText = await upstream.text().catch(() => "");
9412
9650
  let claudeSessionId = null;
@@ -9428,8 +9666,8 @@ function mintTranscriptEdge(sessionId, claudeSessionId, accountId) {
9428
9666
  if (!sessionId || !claudeSessionId) return;
9429
9667
  void linkConversationTranscript(sessionId, claudeSessionId, accountId);
9430
9668
  }
9431
- app14.use("*", requireAdminSession);
9432
- app14.post("/", async (c) => {
9669
+ app15.use("*", requireAdminSession);
9670
+ app15.post("/", async (c) => {
9433
9671
  const routeStart = Date.now();
9434
9672
  const cacheKey = c.get("cacheKey") ?? "";
9435
9673
  let body = {};
@@ -9441,7 +9679,7 @@ app14.post("/", async (c) => {
9441
9679
  if (refusal) return refusal;
9442
9680
  const senderId = getAccountIdForSession(cacheKey) ?? "";
9443
9681
  if (!senderId) {
9444
- console.error(`${TAG21} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
9682
+ console.error(`${TAG22} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
9445
9683
  return c.json({ error: "admin-account-not-resolved" }, 500);
9446
9684
  }
9447
9685
  const userId = getUserIdForSession(cacheKey) ?? void 0;
@@ -9450,7 +9688,7 @@ app14.post("/", async (c) => {
9450
9688
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
9451
9689
  const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
9452
9690
  const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
9453
- console.log(`${TAG21} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
9691
+ console.log(`${TAG22} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
9454
9692
  const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
9455
9693
  const { response, claudeSessionId } = await performSpawnWithInitialMessage({
9456
9694
  senderId,
@@ -9469,24 +9707,24 @@ app14.post("/", async (c) => {
9469
9707
  claudeSessionId,
9470
9708
  senderId
9471
9709
  );
9472
- console.log(`${TAG21} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
9710
+ console.log(`${TAG22} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
9473
9711
  return response;
9474
9712
  });
9475
- var claude_sessions_default = app14;
9713
+ var claude_sessions_default = app15;
9476
9714
 
9477
9715
  // server/routes/admin/log-ingest.ts
9478
- var TAG22 = "[log-ingest]";
9716
+ var TAG23 = "[log-ingest]";
9479
9717
  var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
9480
9718
  var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
9481
9719
  var MAX_LINE_BYTES = 4096;
9482
- var app15 = new Hono();
9720
+ var app16 = new Hono();
9483
9721
  function isLoopbackAddr(addr) {
9484
9722
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
9485
9723
  }
9486
- app15.post("/", async (c) => {
9724
+ app16.post("/", async (c) => {
9487
9725
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
9488
9726
  if (!isLoopbackAddr(remoteAddr)) {
9489
- console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
9727
+ console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
9490
9728
  return c.json({ error: "log-ingest-loopback-only" }, 403);
9491
9729
  }
9492
9730
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -9495,7 +9733,7 @@ app15.post("/", async (c) => {
9495
9733
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
9496
9734
  const offender = tokens.find((t) => !isLoopbackAddr(t));
9497
9735
  if (offender !== void 0) {
9498
- console.error(`${TAG22} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
9736
+ console.error(`${TAG23} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
9499
9737
  return c.json({ error: "log-ingest-loopback-only" }, 403);
9500
9738
  }
9501
9739
  }
@@ -9526,7 +9764,7 @@ app15.post("/", async (c) => {
9526
9764
  else console.log(formatted);
9527
9765
  return c.json({ ok: true }, 200);
9528
9766
  });
9529
- var log_ingest_default = app15;
9767
+ var log_ingest_default = app16;
9530
9768
 
9531
9769
  // server/routes/admin/events.ts
9532
9770
  var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
@@ -9535,20 +9773,20 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
9535
9773
  "device-url:vnc-surface-shown",
9536
9774
  "device-url:malformed"
9537
9775
  ]);
9538
- var app16 = new Hono();
9539
- app16.post("/", async (c) => {
9540
- const TAG30 = "[admin:events]";
9776
+ var app17 = new Hono();
9777
+ app17.post("/", async (c) => {
9778
+ const TAG31 = "[admin:events]";
9541
9779
  let body;
9542
9780
  try {
9543
9781
  body = await c.req.json();
9544
9782
  } catch (err) {
9545
9783
  const detail = err instanceof Error ? err.message : String(err);
9546
- console.error(`${TAG30} reject reason=body-not-json detail=${detail}`);
9784
+ console.error(`${TAG31} reject reason=body-not-json detail=${detail}`);
9547
9785
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
9548
9786
  }
9549
9787
  const event = typeof body.event === "string" ? body.event : "";
9550
9788
  if (!ALLOWED_EVENTS.has(event)) {
9551
- console.error(`${TAG30} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9789
+ console.error(`${TAG31} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9552
9790
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
9553
9791
  }
9554
9792
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -9567,21 +9805,21 @@ app16.post("/", async (c) => {
9567
9805
  console.error(`[${event}] ${formatted}`);
9568
9806
  return c.json({ ok: true });
9569
9807
  });
9570
- var events_default = app16;
9808
+ var events_default = app17;
9571
9809
 
9572
9810
  // server/routes/admin/files.ts
9573
9811
  import { createReadStream as createReadStream2 } from "fs";
9574
9812
  import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
9575
9813
  import { realpathSync as realpathSync4 } from "fs";
9576
- import { basename as basename5, dirname as dirname4, join as join15, resolve as resolve17, sep as sep5 } from "path";
9814
+ import { basename as basename5, dirname as dirname4, join as join16, resolve as resolve18, sep as sep5 } from "path";
9577
9815
  import { Readable as Readable2 } from "stream";
9578
9816
 
9579
9817
  // app/lib/data-path.ts
9580
9818
  import { realpathSync as realpathSync3 } from "fs";
9581
- import { resolve as resolve15, normalize, sep as sep3, relative } from "path";
9582
- var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "../platform");
9583
- var DATA_ROOT = resolve15(PLATFORM_ROOT5, "..", "data");
9584
- var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve15(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
9819
+ import { resolve as resolve16, normalize, sep as sep3, relative } from "path";
9820
+ var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve16(process.cwd(), "../platform");
9821
+ var DATA_ROOT = resolve16(PLATFORM_ROOT5, "..", "data");
9822
+ var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve16(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
9585
9823
  var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
9586
9824
  var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9587
9825
  function crossesForeignAccountPartition(relPath, accountId) {
@@ -9594,7 +9832,7 @@ function crossesForeignAccountPartition(relPath, accountId) {
9594
9832
  }
9595
9833
  function resolveUnderRoot(raw, rootAbs, rootLabel) {
9596
9834
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
9597
- const absolute = resolve15(rootAbs, cleaned);
9835
+ const absolute = resolve16(rootAbs, cleaned);
9598
9836
  let rootReal;
9599
9837
  try {
9600
9838
  rootReal = realpathSync3(rootAbs);
@@ -9953,7 +10191,7 @@ async function cascadeDeleteDocument(params) {
9953
10191
 
9954
10192
  // app/lib/file-index.ts
9955
10193
  import * as fsp from "fs/promises";
9956
- import { resolve as resolve16, relative as relative2, join as join14, basename as basename4, extname as extname2, sep as sep4 } from "path";
10194
+ import { resolve as resolve17, relative as relative2, join as join15, basename as basename4, extname as extname2, sep as sep4 } from "path";
9957
10195
  import { tmpdir as tmpdir2 } from "os";
9958
10196
  import { execFile as execFile2 } from "child_process";
9959
10197
  import { promisify as promisify2 } from "util";
@@ -10024,7 +10262,7 @@ async function extractPdf(absolute) {
10024
10262
  return stdout.trim();
10025
10263
  }
10026
10264
  async function ocrPdf(absolute) {
10027
- const outPdf = join14(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
10265
+ const outPdf = join15(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
10028
10266
  try {
10029
10267
  await execFileAsync2(
10030
10268
  "ocrmypdf",
@@ -10086,7 +10324,7 @@ async function readDisplayName(absolute) {
10086
10324
  const stem = dot === -1 ? base : base.slice(0, dot);
10087
10325
  if (base === `${stem}.meta.json`) return null;
10088
10326
  try {
10089
- const raw = await fsp.readFile(join14(dir, `${stem}.meta.json`), "utf-8");
10327
+ const raw = await fsp.readFile(join15(dir, `${stem}.meta.json`), "utf-8");
10090
10328
  const meta = JSON.parse(raw);
10091
10329
  const dn = meta.displayName ?? meta.filename;
10092
10330
  return typeof dn === "string" && dn.length > 0 ? dn : null;
@@ -10106,7 +10344,7 @@ async function walkSubtree(root, dataRoot, out) {
10106
10344
  let clean = true;
10107
10345
  for (const entry of entries) {
10108
10346
  if (entry.isSymbolicLink()) continue;
10109
- const abs = join14(root, entry.name);
10347
+ const abs = join15(root, entry.name);
10110
10348
  if (entry.isDirectory()) {
10111
10349
  const sub = await walkSubtree(abs, dataRoot, out);
10112
10350
  if (!sub.clean) clean = false;
@@ -10261,8 +10499,8 @@ async function reconcileFileIndex(accountId, opts) {
10261
10499
  return withSession(opts, async (session) => {
10262
10500
  const walked = [];
10263
10501
  const subtreeRoots = [
10264
- resolve16(dataRoot, "uploads", accountId),
10265
- resolve16(dataRoot, "accounts", accountId)
10502
+ resolve17(dataRoot, "uploads", accountId),
10503
+ resolve17(dataRoot, "accounts", accountId)
10266
10504
  ];
10267
10505
  let clean = true;
10268
10506
  for (const root of subtreeRoots) {
@@ -10343,7 +10581,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
10343
10581
  async function indexFile(accountId, relativePath, opts) {
10344
10582
  const dataRoot = opts?.dataRoot ?? DATA_ROOT;
10345
10583
  const embed2 = opts?.embed ?? embed;
10346
- const absolute = resolve16(dataRoot, relativePath);
10584
+ const absolute = resolve17(dataRoot, relativePath);
10347
10585
  await withSession(opts, async (session) => {
10348
10586
  const st = await fsp.stat(absolute);
10349
10587
  const wf = {
@@ -10377,7 +10615,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
10377
10615
  var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10378
10616
  async function readMeta(absDir, baseName) {
10379
10617
  try {
10380
- const raw = await readFile4(join15(absDir, `${baseName}.meta.json`), "utf8");
10618
+ const raw = await readFile4(join16(absDir, `${baseName}.meta.json`), "utf8");
10381
10619
  const parsed = JSON.parse(raw);
10382
10620
  if (typeof parsed?.filename === "string") {
10383
10621
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -10388,7 +10626,7 @@ async function readMeta(absDir, baseName) {
10388
10626
  }
10389
10627
  async function readAccountNames() {
10390
10628
  const map = /* @__PURE__ */ new Map();
10391
- const accountsDir = resolve17(DATA_ROOT, "accounts");
10629
+ const accountsDir = resolve18(DATA_ROOT, "accounts");
10392
10630
  let names;
10393
10631
  try {
10394
10632
  names = await readdir3(accountsDir);
@@ -10397,7 +10635,7 @@ async function readAccountNames() {
10397
10635
  }
10398
10636
  for (const name of names) {
10399
10637
  if (!UUID_RE3.test(name)) continue;
10400
- const configPath2 = resolve17(accountsDir, name, "account.json");
10638
+ const configPath2 = resolve18(accountsDir, name, "account.json");
10401
10639
  try {
10402
10640
  const raw = await readFile4(configPath2, "utf8");
10403
10641
  const parsed = JSON.parse(raw);
@@ -10415,7 +10653,7 @@ async function readAccountNames() {
10415
10653
  }
10416
10654
  async function enrich(absolute, entry, accountNames) {
10417
10655
  if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
10418
- const meta = await readMeta(join15(absolute, entry.name), entry.name);
10656
+ const meta = await readMeta(join16(absolute, entry.name), entry.name);
10419
10657
  if (meta?.filename) {
10420
10658
  entry.displayName = meta.filename;
10421
10659
  entry.mimeType = meta.mimeType;
@@ -10475,8 +10713,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
10475
10713
  await session.close();
10476
10714
  }
10477
10715
  }
10478
- var app17 = new Hono();
10479
- app17.get("/", requireAdminSession, async (c) => {
10716
+ var app18 = new Hono();
10717
+ app18.get("/", requireAdminSession, async (c) => {
10480
10718
  const cacheKey = c.var.cacheKey;
10481
10719
  const accountId = getAccountIdForSession(cacheKey);
10482
10720
  if (!accountId) {
@@ -10513,7 +10751,7 @@ app17.get("/", requireAdminSession, async (c) => {
10513
10751
  continue;
10514
10752
  }
10515
10753
  try {
10516
- const entryPath = join15(absolute, name);
10754
+ const entryPath = join16(absolute, name);
10517
10755
  const s = await stat4(entryPath);
10518
10756
  entries.push({
10519
10757
  name,
@@ -10542,7 +10780,7 @@ app17.get("/", requireAdminSession, async (c) => {
10542
10780
  return c.json({ error: message }, 500);
10543
10781
  }
10544
10782
  });
10545
- app17.get("/download", requireAdminSession, async (c) => {
10783
+ app18.get("/download", requireAdminSession, async (c) => {
10546
10784
  const cacheKey = c.var.cacheKey;
10547
10785
  const accountId = getAccountIdForSession(cacheKey);
10548
10786
  if (!accountId) {
@@ -10606,7 +10844,7 @@ app17.get("/download", requireAdminSession, async (c) => {
10606
10844
  return c.json({ error: message }, 500);
10607
10845
  }
10608
10846
  });
10609
- app17.post("/upload", requireAdminSession, async (c) => {
10847
+ app18.post("/upload", requireAdminSession, async (c) => {
10610
10848
  const cacheKey = c.var.cacheKey;
10611
10849
  const accountId = getAccountIdForSession(cacheKey);
10612
10850
  if (!accountId) {
@@ -10638,8 +10876,8 @@ app17.post("/upload", requireAdminSession, async (c) => {
10638
10876
  }
10639
10877
  const safeName = basename5(file.name).replace(/[\0/\\]/g, "_");
10640
10878
  const finalName = `${Date.now()}-${safeName}`;
10641
- const destDir = resolve17(DATA_ROOT, "uploads", accountId);
10642
- const destPath = resolve17(destDir, finalName);
10879
+ const destDir = resolve18(DATA_ROOT, "uploads", accountId);
10880
+ const destPath = resolve18(destDir, finalName);
10643
10881
  try {
10644
10882
  await mkdir3(destDir, { recursive: true });
10645
10883
  const dataRootReal = realpathSync4(DATA_ROOT);
@@ -10667,7 +10905,7 @@ app17.post("/upload", requireAdminSession, async (c) => {
10667
10905
  mimeType: file.type
10668
10906
  });
10669
10907
  });
10670
- app17.delete("/", requireAdminSession, async (c) => {
10908
+ app18.delete("/", requireAdminSession, async (c) => {
10671
10909
  const cacheKey = c.var.cacheKey;
10672
10910
  const accountId = getAccountIdForSession(cacheKey);
10673
10911
  if (!accountId) {
@@ -10704,7 +10942,7 @@ app17.delete("/", requireAdminSession, async (c) => {
10704
10942
  }
10705
10943
  const dot = base.lastIndexOf(".");
10706
10944
  const stem = dot === -1 ? base : base.slice(0, dot);
10707
- const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join15(dirname4(absolute), `${stem}.meta.json`) : null;
10945
+ const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join16(dirname4(absolute), `${stem}.meta.json`) : null;
10708
10946
  await unlink2(absolute);
10709
10947
  if (sidecarPath) {
10710
10948
  try {
@@ -10743,7 +10981,7 @@ app17.delete("/", requireAdminSession, async (c) => {
10743
10981
  return c.json({ error: message }, 500);
10744
10982
  }
10745
10983
  });
10746
- var files_default = app17;
10984
+ var files_default = app18;
10747
10985
 
10748
10986
  // ../lib/graph-search/src/index.ts
10749
10987
  var import_dist = __toESM(require_dist());
@@ -11508,8 +11746,8 @@ var DEFAULT_LIMIT = 20;
11508
11746
  var MAX_LIMIT = 2e3;
11509
11747
  var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
11510
11748
  var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
11511
- var app18 = new Hono();
11512
- app18.get("/", requireAdminSession, async (c) => {
11749
+ var app19 = new Hono();
11750
+ app19.get("/", requireAdminSession, async (c) => {
11513
11751
  const cacheKey = c.var.cacheKey;
11514
11752
  const q = (c.req.query("q") ?? "").trim();
11515
11753
  const rawLimit = c.req.query("limit");
@@ -11645,7 +11883,7 @@ app18.get("/", requireAdminSession, async (c) => {
11645
11883
  await session.close();
11646
11884
  }
11647
11885
  });
11648
- var graph_search_default = app18;
11886
+ var graph_search_default = app19;
11649
11887
 
11650
11888
  // server/routes/admin/graph-subgraph.ts
11651
11889
  import neo4j from "neo4j-driver";
@@ -11723,8 +11961,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
11723
11961
  "otpCode",
11724
11962
  "cacheKey"
11725
11963
  ]);
11726
- var app19 = new Hono();
11727
- app19.get("/", requireAdminSession, async (c) => {
11964
+ var app20 = new Hono();
11965
+ app20.get("/", requireAdminSession, async (c) => {
11728
11966
  const cacheKey = c.var.cacheKey;
11729
11967
  const accountId = getAccountIdForSession(cacheKey);
11730
11968
  if (!accountId) {
@@ -12307,12 +12545,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
12307
12545
  }
12308
12546
  return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
12309
12547
  }
12310
- var graph_subgraph_default = app19;
12548
+ var graph_subgraph_default = app20;
12311
12549
 
12312
12550
  // server/routes/admin/graph-delete.ts
12313
12551
  var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
12314
- var app20 = new Hono();
12315
- app20.post("/", requireAdminSession, async (c) => {
12552
+ var app21 = new Hono();
12553
+ app21.post("/", requireAdminSession, async (c) => {
12316
12554
  const cacheKey = c.var.cacheKey;
12317
12555
  const accountId = getAccountIdForSession(cacheKey);
12318
12556
  if (!accountId) {
@@ -12474,11 +12712,11 @@ app20.post("/", requireAdminSession, async (c) => {
12474
12712
  }
12475
12713
  }
12476
12714
  });
12477
- var graph_delete_default = app20;
12715
+ var graph_delete_default = app21;
12478
12716
 
12479
12717
  // server/routes/admin/graph-restore.ts
12480
- var app21 = new Hono();
12481
- app21.post("/", requireAdminSession, async (c) => {
12718
+ var app22 = new Hono();
12719
+ app22.post("/", requireAdminSession, async (c) => {
12482
12720
  const cacheKey = c.var.cacheKey;
12483
12721
  const accountId = getAccountIdForSession(cacheKey);
12484
12722
  if (!accountId) {
@@ -12542,11 +12780,11 @@ app21.post("/", requireAdminSession, async (c) => {
12542
12780
  }
12543
12781
  }
12544
12782
  });
12545
- var graph_restore_default = app21;
12783
+ var graph_restore_default = app22;
12546
12784
 
12547
12785
  // server/routes/admin/graph-labels-in-graph.ts
12548
- var app22 = new Hono();
12549
- app22.get("/", requireAdminSession, async (c) => {
12786
+ var app23 = new Hono();
12787
+ app23.get("/", requireAdminSession, async (c) => {
12550
12788
  const cacheKey = c.var.cacheKey;
12551
12789
  const accountId = getAccountIdForSession(cacheKey);
12552
12790
  if (!accountId) {
@@ -12612,11 +12850,11 @@ var LABELS_IN_GRAPH_CYPHER = `
12612
12850
  sum(halfEdges) AS relDegree
12613
12851
  RETURN label, nodeCount, relDegree
12614
12852
  `;
12615
- var graph_labels_in_graph_default = app22;
12853
+ var graph_labels_in_graph_default = app23;
12616
12854
 
12617
12855
  // server/routes/admin/graph-default-view.ts
12618
- var app23 = new Hono();
12619
- app23.get("/", requireAdminSession, async (c) => {
12856
+ var app24 = new Hono();
12857
+ app24.get("/", requireAdminSession, async (c) => {
12620
12858
  const cacheKey = c.var.cacheKey;
12621
12859
  const accountId = getAccountIdForSession(cacheKey);
12622
12860
  const userId = getUserIdForSession(cacheKey);
@@ -12654,7 +12892,7 @@ app23.get("/", requireAdminSession, async (c) => {
12654
12892
  }
12655
12893
  }
12656
12894
  });
12657
- app23.put("/", requireAdminSession, async (c) => {
12895
+ app24.put("/", requireAdminSession, async (c) => {
12658
12896
  const cacheKey = c.var.cacheKey;
12659
12897
  const accountId = getAccountIdForSession(cacheKey);
12660
12898
  const userId = getUserIdForSession(cacheKey);
@@ -12743,20 +12981,20 @@ var WRITE_CYPHER = `
12743
12981
  p.updatedAt = $updatedAt
12744
12982
  RETURN p.labels AS labels
12745
12983
  `;
12746
- var graph_default_view_default = app23;
12984
+ var graph_default_view_default = app24;
12747
12985
 
12748
12986
  // server/routes/admin/sidebar-artefacts.ts
12749
12987
  import { readdir as readdir4, stat as stat5 } from "fs/promises";
12750
- import { resolve as resolve18, relative as relative3, isAbsolute, sep as sep6, basename as basename6 } from "path";
12751
- import { existsSync as existsSync17 } from "fs";
12988
+ import { resolve as resolve19, relative as relative3, isAbsolute, sep as sep6, basename as basename6 } from "path";
12989
+ import { existsSync as existsSync18 } from "fs";
12752
12990
  var LIMIT = 50;
12753
12991
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
12754
12992
  function toDataRootRelPath(absPath) {
12755
12993
  if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep6)) return null;
12756
12994
  return relative3(DATA_ROOT, absPath);
12757
12995
  }
12758
- var app24 = new Hono();
12759
- app24.get("/", requireAdminSession, async (c) => {
12996
+ var app25 = new Hono();
12997
+ app25.get("/", requireAdminSession, async (c) => {
12760
12998
  const cacheKey = c.var.cacheKey;
12761
12999
  const accountId = getAccountIdForSession(cacheKey);
12762
13000
  if (!accountId) {
@@ -12767,7 +13005,7 @@ app24.get("/", requireAdminSession, async (c) => {
12767
13005
  if (accountFiles === null) {
12768
13006
  return c.json({ error: "Failed to load artefacts" }, 500);
12769
13007
  }
12770
- const accountDir = resolve18(ACCOUNTS_DIR, accountId);
13008
+ const accountDir = resolve19(ACCOUNTS_DIR, accountId);
12771
13009
  const agents = await fetchAgentTemplateRows(accountDir);
12772
13010
  const artefacts = [...accountFiles, ...agents].sort(
12773
13011
  (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
@@ -12818,8 +13056,8 @@ async function fetchAccountFileArtefacts(accountId) {
12818
13056
  async function fetchAgentTemplateRows(accountDir) {
12819
13057
  const rows = [];
12820
13058
  for (const filename of ADMIN_AGENT_FILES) {
12821
- const overridePath = resolve18(accountDir, "agents", "admin", filename);
12822
- const bundledPath = resolve18(PLATFORM_ROOT, "templates", "agents", "admin", filename);
13059
+ const overridePath = resolve19(accountDir, "agents", "admin", filename);
13060
+ const bundledPath = resolve19(PLATFORM_ROOT, "templates", "agents", "admin", filename);
12823
13061
  const labelStem = filename.replace(/\.md$/, "");
12824
13062
  const row = await readAgentTemplateRow({
12825
13063
  id: `agent-template:admin:${filename}`,
@@ -12832,12 +13070,12 @@ async function fetchAgentTemplateRows(accountDir) {
12832
13070
  });
12833
13071
  if (row) rows.push(row);
12834
13072
  }
12835
- const overrideDir = resolve18(accountDir, "specialists", "agents");
12836
- const bundledDir = resolve18(PLATFORM_ROOT, "templates", "specialists", "agents");
13073
+ const overrideDir = resolve19(accountDir, "specialists", "agents");
13074
+ const bundledDir = resolve19(PLATFORM_ROOT, "templates", "specialists", "agents");
12837
13075
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
12838
13076
  for (const filename of specialistNames) {
12839
- const overridePath = resolve18(overrideDir, filename);
12840
- const bundledPath = resolve18(bundledDir, filename);
13077
+ const overridePath = resolve19(overrideDir, filename);
13078
+ const bundledPath = resolve19(bundledDir, filename);
12841
13079
  const row = await readAgentTemplateRow({
12842
13080
  id: `agent-template:specialist:${filename}`,
12843
13081
  displayName: filename.replace(/\.md$/, ""),
@@ -12854,7 +13092,7 @@ async function fetchAgentTemplateRows(accountDir) {
12854
13092
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
12855
13093
  const names = /* @__PURE__ */ new Set();
12856
13094
  for (const dir of [overrideDir, bundledDir]) {
12857
- if (!existsSync17(dir)) continue;
13095
+ if (!existsSync18(dir)) continue;
12858
13096
  try {
12859
13097
  const entries = await readdir4(dir);
12860
13098
  for (const entry of entries) {
@@ -12869,7 +13107,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
12869
13107
  }
12870
13108
  async function readAgentTemplateRow(inp) {
12871
13109
  let chosenPath = null;
12872
- if (existsSync17(inp.overridePath)) {
13110
+ if (existsSync18(inp.overridePath)) {
12873
13111
  try {
12874
13112
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
12875
13113
  chosenPath = inp.overridePath;
@@ -12880,7 +13118,7 @@ async function readAgentTemplateRow(inp) {
12880
13118
  );
12881
13119
  return null;
12882
13120
  }
12883
- } else if (existsSync17(inp.bundledPath)) {
13121
+ } else if (existsSync18(inp.bundledPath)) {
12884
13122
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
12885
13123
  console.error(
12886
13124
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -12919,11 +13157,11 @@ function isWithin(target, root) {
12919
13157
  const rel = relative3(root, target);
12920
13158
  return !rel.startsWith("..") && !isAbsolute(rel);
12921
13159
  }
12922
- var sidebar_artefacts_default = app24;
13160
+ var sidebar_artefacts_default = app25;
12923
13161
 
12924
13162
  // server/routes/admin/session-delete.ts
12925
- var app25 = new Hono();
12926
- app25.post("/", requireAdminSession, async (c) => {
13163
+ var app26 = new Hono();
13164
+ app26.post("/", requireAdminSession, async (c) => {
12927
13165
  let body;
12928
13166
  try {
12929
13167
  body = await c.req.json();
@@ -12961,11 +13199,11 @@ app25.post("/", requireAdminSession, async (c) => {
12961
13199
  console.error(`[session-delete] sessionId=${sessionId} delete-status=${del.status}`);
12962
13200
  return c.json({ error: `manager-status-${del.status}` }, 502);
12963
13201
  });
12964
- var session_delete_default = app25;
13202
+ var session_delete_default = app26;
12965
13203
 
12966
13204
  // server/routes/admin/session-stop.ts
12967
- var app26 = new Hono();
12968
- app26.post("/", requireAdminSession, async (c) => {
13205
+ var app27 = new Hono();
13206
+ app27.post("/", requireAdminSession, async (c) => {
12969
13207
  let body;
12970
13208
  try {
12971
13209
  body = await c.req.json();
@@ -12990,11 +13228,63 @@ app26.post("/", requireAdminSession, async (c) => {
12990
13228
  console.error(`[session-stop] sessionId=${sessionId} manager-status=${res.status}`);
12991
13229
  return c.json({ error: `manager-status-${res.status}` }, 502);
12992
13230
  });
12993
- var session_stop_default = app26;
13231
+ var session_stop_default = app27;
13232
+
13233
+ // server/routes/admin/session-archive.ts
13234
+ var app28 = new Hono();
13235
+ app28.post("/", requireAdminSession, async (c) => {
13236
+ let body;
13237
+ try {
13238
+ body = await c.req.json();
13239
+ } catch {
13240
+ return c.json({ error: "invalid JSON body" }, 400);
13241
+ }
13242
+ const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
13243
+ if (!SESSION_ID_RE2.test(sessionId)) {
13244
+ return c.json({ error: "sessionId must be a v4 UUID" }, 400);
13245
+ }
13246
+ const mode = body.mode;
13247
+ if (mode !== "archive" && mode !== "unarchive") {
13248
+ return c.json({ error: "mode must be 'archive' or 'unarchive'" }, 400);
13249
+ }
13250
+ let res;
13251
+ try {
13252
+ res = await fetch(`${managerBase3("session-archive:wrapper")}/${sessionId}/archive`, {
13253
+ method: "POST",
13254
+ headers: { "Content-Type": "application/json" },
13255
+ body: JSON.stringify({ mode })
13256
+ });
13257
+ } catch (err) {
13258
+ console.error(`[session-archive] sessionId=${sessionId} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
13259
+ return c.json({ error: "manager-unreachable" }, 502);
13260
+ }
13261
+ if (res.status === 200) {
13262
+ const dir = mode === "archive" ? "top\u2192archive" : "archive\u2192top";
13263
+ console.log(`[session-archive] sessionId=${sessionId.slice(0, 8)} moved ${dir}`);
13264
+ return c.json({ archived: mode === "archive" });
13265
+ }
13266
+ if (res.status === 409) {
13267
+ console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} pty-still-alive`);
13268
+ return c.json({ error: "pty-still-alive", detail: "end the session before archiving" }, 409);
13269
+ }
13270
+ if (res.status === 404) {
13271
+ console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} session-not-found`);
13272
+ return c.json({ error: "session-not-found" }, 404);
13273
+ }
13274
+ if (res.status === 500) {
13275
+ const body2 = await res.json().catch(() => ({}));
13276
+ const detail = typeof body2.detail === "string" ? body2.detail : body2.error ?? "archive-failed";
13277
+ console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} archive-failed detail=${detail}`);
13278
+ return c.json({ error: "archive-failed", detail }, 502);
13279
+ }
13280
+ console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
13281
+ return c.json({ error: `manager-status-${res.status}` }, 502);
13282
+ });
13283
+ var session_archive_default = app28;
12994
13284
 
12995
13285
  // server/routes/admin/session-rc-spawn.ts
12996
- var app27 = new Hono();
12997
- app27.post("/", requireAdminSession, async (c) => {
13286
+ var app29 = new Hono();
13287
+ app29.post("/", requireAdminSession, async (c) => {
12998
13288
  let body;
12999
13289
  try {
13000
13290
  body = await c.req.json();
@@ -13028,7 +13318,7 @@ app27.post("/", requireAdminSession, async (c) => {
13028
13318
  }
13029
13319
  return c.json(parsed ?? {});
13030
13320
  });
13031
- var session_rc_spawn_default = app27;
13321
+ var session_rc_spawn_default = app29;
13032
13322
 
13033
13323
  // server/routes/admin/system-stats.ts
13034
13324
  import { readFile as readFile5 } from "fs/promises";
@@ -13125,8 +13415,8 @@ async function sample() {
13125
13415
  if (process.platform === "linux") return sampleLinux();
13126
13416
  return sampleOsFallback();
13127
13417
  }
13128
- var app28 = new Hono();
13129
- app28.get("/", async (c) => {
13418
+ var app30 = new Hono();
13419
+ app30.get("/", async (c) => {
13130
13420
  const started = Date.now();
13131
13421
  if (!inflight) {
13132
13422
  inflight = sample().finally(() => {
@@ -13149,27 +13439,27 @@ app28.get("/", async (c) => {
13149
13439
  return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
13150
13440
  }
13151
13441
  });
13152
- var system_stats_default = app28;
13442
+ var system_stats_default = app30;
13153
13443
 
13154
13444
  // server/routes/admin/health.ts
13155
- import { existsSync as existsSync18, readFileSync as readFileSync17 } from "fs";
13156
- import { resolve as resolve19, join as join16 } from "path";
13157
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
13445
+ import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
13446
+ import { resolve as resolve20, join as join17 } from "path";
13447
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
13158
13448
  var brandHostname = "maxy";
13159
- var brandJsonPath = join16(PLATFORM_ROOT6, "config", "brand.json");
13160
- if (existsSync18(brandJsonPath)) {
13449
+ var brandJsonPath = join17(PLATFORM_ROOT6, "config", "brand.json");
13450
+ if (existsSync19(brandJsonPath)) {
13161
13451
  try {
13162
- const brand = JSON.parse(readFileSync17(brandJsonPath, "utf-8"));
13452
+ const brand = JSON.parse(readFileSync18(brandJsonPath, "utf-8"));
13163
13453
  if (brand.hostname) brandHostname = brand.hostname;
13164
13454
  } catch {
13165
13455
  }
13166
13456
  }
13167
- var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
13457
+ var VERSION_FILE = resolve20(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
13168
13458
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
13169
13459
  var PROBE_TIMEOUT_MS = 1e3;
13170
13460
  function readVersion() {
13171
- if (!existsSync18(VERSION_FILE)) return "unknown";
13172
- return readFileSync17(VERSION_FILE, "utf-8").trim() || "unknown";
13461
+ if (!existsSync19(VERSION_FILE)) return "unknown";
13462
+ return readFileSync18(VERSION_FILE, "utf-8").trim() || "unknown";
13173
13463
  }
13174
13464
  async function probeConversationDb() {
13175
13465
  let session;
@@ -13194,8 +13484,8 @@ async function probeConversationDb() {
13194
13484
  });
13195
13485
  }
13196
13486
  }
13197
- var app29 = new Hono();
13198
- app29.get("/", async (c) => {
13487
+ var app31 = new Hono();
13488
+ app31.get("/", async (c) => {
13199
13489
  const version = readVersion();
13200
13490
  const probe = await probeConversationDb();
13201
13491
  const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
@@ -13217,11 +13507,11 @@ app29.get("/", async (c) => {
13217
13507
  uptimeMs
13218
13508
  });
13219
13509
  });
13220
- var health_default2 = app29;
13510
+ var health_default2 = app31;
13221
13511
 
13222
13512
  // server/routes/admin/linkedin-ingest.ts
13223
13513
  import { randomUUID as randomUUID9 } from "crypto";
13224
- var TAG23 = "[linkedin-ingest-route]";
13514
+ var TAG24 = "[linkedin-ingest-route]";
13225
13515
  var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
13226
13516
  var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
13227
13517
  var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
@@ -13319,35 +13609,35 @@ function buildInitialMessage(env) {
13319
13609
  }
13320
13610
  return header;
13321
13611
  }
13322
- var app30 = new Hono();
13323
- app30.post("/", requireAdminSession, async (c) => {
13612
+ var app32 = new Hono();
13613
+ app32.post("/", requireAdminSession, async (c) => {
13324
13614
  let body;
13325
13615
  try {
13326
13616
  body = await c.req.json();
13327
13617
  } catch {
13328
- console.error(TAG23 + " rejected status=400 reason=schema:body-not-json");
13618
+ console.error(TAG24 + " rejected status=400 reason=schema:body-not-json");
13329
13619
  return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
13330
13620
  }
13331
13621
  const v = validate(body);
13332
13622
  if (!v.ok) {
13333
- console.error(TAG23 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
13623
+ console.error(TAG24 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
13334
13624
  return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
13335
13625
  }
13336
13626
  const envelope = v.envelope;
13337
13627
  const cacheKey = c.var.cacheKey ?? "";
13338
13628
  const senderId = getAccountIdForSession(cacheKey) ?? "";
13339
13629
  if (!senderId) {
13340
- console.error(TAG23 + " rejected status=500 reason=admin-account-not-resolved");
13630
+ console.error(TAG24 + " rejected status=500 reason=admin-account-not-resolved");
13341
13631
  return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
13342
13632
  }
13343
13633
  const payloadBytes = JSON.stringify(envelope).length;
13344
13634
  console.log(
13345
- TAG23 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
13635
+ TAG24 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
13346
13636
  );
13347
13637
  const initialMessage = buildInitialMessage(envelope);
13348
13638
  const spawnStart = Date.now();
13349
13639
  const sessionId = randomUUID9();
13350
- console.log(TAG23 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
13640
+ console.log(TAG24 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
13351
13641
  const spawned = await managerRcSpawn({
13352
13642
  sessionId,
13353
13643
  initialMessage,
@@ -13356,20 +13646,20 @@ app30.post("/", requireAdminSession, async (c) => {
13356
13646
  });
13357
13647
  if ("error" in spawned) {
13358
13648
  console.error(
13359
- TAG23 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
13649
+ TAG24 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
13360
13650
  );
13361
13651
  return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
13362
13652
  }
13363
13653
  console.log(
13364
- TAG23 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
13654
+ TAG24 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
13365
13655
  );
13366
13656
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
13367
13657
  });
13368
- var linkedin_ingest_default = app30;
13658
+ var linkedin_ingest_default = app32;
13369
13659
 
13370
13660
  // server/routes/admin/post-turn-context.ts
13371
13661
  import neo4j2 from "neo4j-driver";
13372
- var TAG24 = "[post-turn-context]";
13662
+ var TAG25 = "[post-turn-context]";
13373
13663
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
13374
13664
  "embedding",
13375
13665
  "passwordHash",
@@ -13407,11 +13697,11 @@ function pruneProperties(raw) {
13407
13697
  }
13408
13698
  return out;
13409
13699
  }
13410
- var app31 = new Hono();
13411
- app31.get("/", async (c) => {
13700
+ var app33 = new Hono();
13701
+ app33.get("/", async (c) => {
13412
13702
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13413
13703
  if (!isLoopbackAddr2(remoteAddr)) {
13414
- console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13704
+ console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13415
13705
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
13416
13706
  }
13417
13707
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -13420,7 +13710,7 @@ app31.get("/", async (c) => {
13420
13710
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
13421
13711
  const offender = tokens.find((t) => !isLoopbackAddr2(t));
13422
13712
  if (offender !== void 0) {
13423
- console.error(`${TAG24} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13713
+ console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13424
13714
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
13425
13715
  }
13426
13716
  }
@@ -13452,7 +13742,7 @@ app31.get("/", async (c) => {
13452
13742
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
13453
13743
  const total = Date.now() - started;
13454
13744
  console.log(
13455
- `${TAG24} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
13745
+ `${TAG25} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
13456
13746
  );
13457
13747
  return c.json({
13458
13748
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -13461,18 +13751,18 @@ app31.get("/", async (c) => {
13461
13751
  const elapsed = Date.now() - started;
13462
13752
  const message = err instanceof Error ? err.message : String(err);
13463
13753
  console.error(
13464
- `${TAG24} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
13754
+ `${TAG25} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
13465
13755
  );
13466
13756
  return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
13467
13757
  } finally {
13468
13758
  await session.close();
13469
13759
  }
13470
13760
  });
13471
- var post_turn_context_default = app31;
13761
+ var post_turn_context_default = app33;
13472
13762
 
13473
13763
  // server/routes/admin/public-session-context.ts
13474
13764
  import neo4j3 from "neo4j-driver";
13475
- var TAG25 = "[public-session-context]";
13765
+ var TAG26 = "[public-session-context]";
13476
13766
  var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
13477
13767
  "embedding",
13478
13768
  "passwordHash",
@@ -13510,11 +13800,11 @@ function pruneProperties2(raw) {
13510
13800
  }
13511
13801
  return out;
13512
13802
  }
13513
- var app32 = new Hono();
13514
- app32.get("/", async (c) => {
13803
+ var app34 = new Hono();
13804
+ app34.get("/", async (c) => {
13515
13805
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13516
13806
  if (!isLoopbackAddr3(remoteAddr)) {
13517
- console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13807
+ console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13518
13808
  return c.json({ error: "public-session-context-loopback-only" }, 403);
13519
13809
  }
13520
13810
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -13523,7 +13813,7 @@ app32.get("/", async (c) => {
13523
13813
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
13524
13814
  const offender = tokens.find((t) => !isLoopbackAddr3(t));
13525
13815
  if (offender !== void 0) {
13526
- console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13816
+ console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13527
13817
  return c.json({ error: "public-session-context-loopback-only" }, 403);
13528
13818
  }
13529
13819
  }
@@ -13554,7 +13844,7 @@ app32.get("/", async (c) => {
13554
13844
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
13555
13845
  const total = Date.now() - started;
13556
13846
  console.log(
13557
- `${TAG25} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
13847
+ `${TAG26} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
13558
13848
  );
13559
13849
  return c.json({
13560
13850
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -13563,25 +13853,25 @@ app32.get("/", async (c) => {
13563
13853
  const elapsed = Date.now() - started;
13564
13854
  const message = err instanceof Error ? err.message : String(err);
13565
13855
  console.error(
13566
- `${TAG25} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
13856
+ `${TAG26} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
13567
13857
  );
13568
13858
  return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
13569
13859
  } finally {
13570
13860
  await session.close();
13571
13861
  }
13572
13862
  });
13573
- var public_session_context_default = app32;
13863
+ var public_session_context_default = app34;
13574
13864
 
13575
13865
  // server/routes/admin/public-session-exit.ts
13576
- var TAG26 = "[public-session-exit-route]";
13866
+ var TAG27 = "[public-session-exit-route]";
13577
13867
  function isLoopbackAddr4(addr) {
13578
13868
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
13579
13869
  }
13580
- var app33 = new Hono();
13581
- app33.post("/", async (c) => {
13870
+ var app35 = new Hono();
13871
+ app35.post("/", async (c) => {
13582
13872
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13583
13873
  if (!isLoopbackAddr4(remoteAddr)) {
13584
- console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13874
+ console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13585
13875
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
13586
13876
  }
13587
13877
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -13590,7 +13880,7 @@ app33.post("/", async (c) => {
13590
13880
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
13591
13881
  const offender = tokens.find((t) => !isLoopbackAddr4(t));
13592
13882
  if (offender !== void 0) {
13593
- console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13883
+ console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13594
13884
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
13595
13885
  }
13596
13886
  }
@@ -13605,18 +13895,18 @@ app33.post("/", async (c) => {
13605
13895
  handlePublicSessionExit(sessionId);
13606
13896
  return c.json({ ok: true });
13607
13897
  });
13608
- var public_session_exit_default = app33;
13898
+ var public_session_exit_default = app35;
13609
13899
 
13610
13900
  // server/routes/admin/access-session-evict.ts
13611
- var TAG27 = "[access-session-evict]";
13901
+ var TAG28 = "[access-session-evict]";
13612
13902
  function isLoopbackAddr5(addr) {
13613
13903
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
13614
13904
  }
13615
- var app34 = new Hono();
13616
- app34.post("/", async (c) => {
13905
+ var app36 = new Hono();
13906
+ app36.post("/", async (c) => {
13617
13907
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13618
13908
  if (!isLoopbackAddr5(remoteAddr)) {
13619
- console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13909
+ console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
13620
13910
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
13621
13911
  }
13622
13912
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -13625,7 +13915,7 @@ app34.post("/", async (c) => {
13625
13915
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
13626
13916
  const offender = tokens.find((t) => !isLoopbackAddr5(t));
13627
13917
  if (offender !== void 0) {
13628
- console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13918
+ console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
13629
13919
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
13630
13920
  }
13631
13921
  }
@@ -13638,14 +13928,14 @@ app34.post("/", async (c) => {
13638
13928
  const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
13639
13929
  if (!grantId) return c.json({ error: "grantId required" }, 400);
13640
13930
  const dropped = evictAccessSessionsByGrant(grantId);
13641
- console.log(`${TAG27} grantId=${grantId} dropped=${dropped}`);
13931
+ console.log(`${TAG28} grantId=${grantId} dropped=${dropped}`);
13642
13932
  return c.json({ ok: true, dropped });
13643
13933
  });
13644
- var access_session_evict_default = app34;
13934
+ var access_session_evict_default = app36;
13645
13935
 
13646
13936
  // server/routes/admin/browser.ts
13647
- var app35 = new Hono();
13648
- app35.post("/launch", requireAdminSession, async (c) => {
13937
+ var app37 = new Hono();
13938
+ app37.post("/launch", requireAdminSession, async (c) => {
13649
13939
  try {
13650
13940
  const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
13651
13941
  console.error(`[admin/browser/launch] op=request transport=${transport}`);
@@ -13673,53 +13963,54 @@ app35.post("/launch", requireAdminSession, async (c) => {
13673
13963
  );
13674
13964
  }
13675
13965
  });
13676
- var browser_default = app35;
13966
+ var browser_default = app37;
13677
13967
 
13678
13968
  // server/routes/admin/index.ts
13679
- var app36 = new Hono();
13680
- app36.route("/session", session_default);
13681
- app36.route("/logs", logs_default);
13682
- app36.route("/claude-info", claude_info_default);
13683
- app36.route("/attachment", attachment_default);
13684
- app36.route("/agents", agents_default);
13685
- app36.route("/sessions", sessions_default);
13686
- app36.route("/claude-sessions", claude_sessions_default);
13687
- app36.route("/log-ingest", log_ingest_default);
13688
- app36.route("/events", events_default);
13689
- app36.route("/files", files_default);
13690
- app36.route("/graph-search", graph_search_default);
13691
- app36.route("/graph-subgraph", graph_subgraph_default);
13692
- app36.route("/graph-delete", graph_delete_default);
13693
- app36.route("/graph-restore", graph_restore_default);
13694
- app36.route("/graph-labels-in-graph", graph_labels_in_graph_default);
13695
- app36.route("/graph-default-view", graph_default_view_default);
13696
- app36.route("/sidebar-artefacts", sidebar_artefacts_default);
13697
- app36.route("/sidebar-sessions", sidebar_sessions_default);
13698
- app36.route("/session-delete", session_delete_default);
13699
- app36.route("/session-stop", session_stop_default);
13700
- app36.route("/browser", browser_default);
13701
- app36.route("/session-rc-spawn", session_rc_spawn_default);
13702
- app36.route("/system-stats", system_stats_default);
13703
- app36.route("/health-brand", health_default2);
13704
- app36.route("/linkedin-ingest", linkedin_ingest_default);
13705
- app36.route("/post-turn-context", post_turn_context_default);
13706
- app36.route("/public-session-context", public_session_context_default);
13707
- app36.route("/public-session-exit", public_session_exit_default);
13708
- app36.route("/access-session-evict", access_session_evict_default);
13709
- var admin_default = app36;
13969
+ var app38 = new Hono();
13970
+ app38.route("/session", session_default);
13971
+ app38.route("/logs", logs_default);
13972
+ app38.route("/claude-info", claude_info_default);
13973
+ app38.route("/attachment", attachment_default);
13974
+ app38.route("/agents", agents_default);
13975
+ app38.route("/sessions", sessions_default);
13976
+ app38.route("/claude-sessions", claude_sessions_default);
13977
+ app38.route("/log-ingest", log_ingest_default);
13978
+ app38.route("/events", events_default);
13979
+ app38.route("/files", files_default);
13980
+ app38.route("/graph-search", graph_search_default);
13981
+ app38.route("/graph-subgraph", graph_subgraph_default);
13982
+ app38.route("/graph-delete", graph_delete_default);
13983
+ app38.route("/graph-restore", graph_restore_default);
13984
+ app38.route("/graph-labels-in-graph", graph_labels_in_graph_default);
13985
+ app38.route("/graph-default-view", graph_default_view_default);
13986
+ app38.route("/sidebar-artefacts", sidebar_artefacts_default);
13987
+ app38.route("/sidebar-sessions", sidebar_sessions_default);
13988
+ app38.route("/session-delete", session_delete_default);
13989
+ app38.route("/session-stop", session_stop_default);
13990
+ app38.route("/session-archive", session_archive_default);
13991
+ app38.route("/browser", browser_default);
13992
+ app38.route("/session-rc-spawn", session_rc_spawn_default);
13993
+ app38.route("/system-stats", system_stats_default);
13994
+ app38.route("/health-brand", health_default2);
13995
+ app38.route("/linkedin-ingest", linkedin_ingest_default);
13996
+ app38.route("/post-turn-context", post_turn_context_default);
13997
+ app38.route("/public-session-context", public_session_context_default);
13998
+ app38.route("/public-session-exit", public_session_exit_default);
13999
+ app38.route("/access-session-evict", access_session_evict_default);
14000
+ var admin_default = app38;
13710
14001
 
13711
14002
  // app/lib/access-gate.ts
13712
14003
  import neo4j4 from "neo4j-driver";
13713
- import { readFileSync as readFileSync18 } from "fs";
13714
- import { resolve as resolve20 } from "path";
14004
+ import { readFileSync as readFileSync19 } from "fs";
14005
+ import { resolve as resolve21 } from "path";
13715
14006
  import { randomUUID as randomUUID10 } from "crypto";
13716
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
14007
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
13717
14008
  var driver = null;
13718
14009
  function readPassword() {
13719
14010
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
13720
- const passwordFile = resolve20(PLATFORM_ROOT7, "config/.neo4j-password");
14011
+ const passwordFile = resolve21(PLATFORM_ROOT7, "config/.neo4j-password");
13721
14012
  try {
13722
- return readFileSync18(passwordFile, "utf-8").trim();
14013
+ return readFileSync19(passwordFile, "utf-8").trim();
13723
14014
  } catch {
13724
14015
  throw new Error(
13725
14016
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -13917,11 +14208,11 @@ async function generateNewMagicToken(grantId) {
13917
14208
  }
13918
14209
 
13919
14210
  // server/routes/access/verify-token.ts
13920
- var TAG28 = "[access-verify]";
14211
+ var TAG29 = "[access-verify]";
13921
14212
  var MINT_TAG = "[access-session-mint]";
13922
14213
  var COOKIE_NAME = "__access_session";
13923
- var app37 = new Hono();
13924
- app37.post("/", async (c) => {
14214
+ var app39 = new Hono();
14215
+ app39.post("/", async (c) => {
13925
14216
  const ip = c.var.clientIp || "unknown";
13926
14217
  let body;
13927
14218
  try {
@@ -13936,39 +14227,39 @@ app37.post("/", async (c) => {
13936
14227
  }
13937
14228
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
13938
14229
  if (rateMsg) {
13939
- console.error(`${TAG28} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
14230
+ console.error(`${TAG29} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
13940
14231
  return c.json({ error: rateMsg }, 429);
13941
14232
  }
13942
14233
  const grant = await findGrantByMagicToken(token);
13943
14234
  if (!grant) {
13944
14235
  recordAccessFailedAttempt(ip, agentSlug);
13945
- console.error(`${TAG28} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
14236
+ console.error(`${TAG29} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
13946
14237
  return c.json({ error: "invalid-or-expired-link" }, 401);
13947
14238
  }
13948
14239
  if (grant.agentSlug !== agentSlug) {
13949
14240
  recordAccessFailedAttempt(ip, agentSlug);
13950
14241
  console.error(
13951
- `${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
14242
+ `${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
13952
14243
  );
13953
14244
  return c.json({ error: "invalid-or-expired-link" }, 401);
13954
14245
  }
13955
14246
  if (grant.status === "expired" || grant.status === "revoked") {
13956
14247
  recordAccessFailedAttempt(ip, agentSlug);
13957
14248
  console.error(
13958
- `${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
14249
+ `${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
13959
14250
  );
13960
14251
  return c.json({ error: "access-no-longer-valid" }, 401);
13961
14252
  }
13962
14253
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
13963
14254
  recordAccessFailedAttempt(ip, agentSlug);
13964
14255
  console.error(
13965
- `${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
14256
+ `${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
13966
14257
  );
13967
14258
  return c.json({ error: "access-no-longer-valid" }, 401);
13968
14259
  }
13969
14260
  if (!grant.sliceToken) {
13970
14261
  console.error(
13971
- `${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
14262
+ `${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
13972
14263
  );
13973
14264
  return c.json({ error: "grant-misconfigured" }, 500);
13974
14265
  }
@@ -13984,12 +14275,12 @@ app37.post("/", async (c) => {
13984
14275
  await consumeMagicTokenAndActivate(grant.grantId);
13985
14276
  } catch (err) {
13986
14277
  console.error(
13987
- `${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
14278
+ `${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
13988
14279
  );
13989
14280
  return c.json({ error: "verification-failed" }, 500);
13990
14281
  }
13991
14282
  clearAccessRateLimit(ip, agentSlug);
13992
- console.log(`${TAG28} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
14283
+ console.log(`${TAG29} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
13993
14284
  console.log(
13994
14285
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
13995
14286
  );
@@ -14003,13 +14294,13 @@ app37.post("/", async (c) => {
14003
14294
  displayName: grant.displayName
14004
14295
  });
14005
14296
  });
14006
- var verify_token_default = app37;
14297
+ var verify_token_default = app39;
14007
14298
 
14008
14299
  // app/lib/access-email.ts
14009
14300
  import { spawn as spawn2 } from "child_process";
14010
- import { resolve as resolve21 } from "path";
14011
- var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
14012
- var SEND_SCRIPT = resolve21(
14301
+ import { resolve as resolve22 } from "path";
14302
+ var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
14303
+ var SEND_SCRIPT = resolve22(
14013
14304
  PLATFORM_ROOT8,
14014
14305
  "plugins",
14015
14306
  "email",
@@ -14065,10 +14356,10 @@ async function sendMagicLinkEmail(payload) {
14065
14356
  }
14066
14357
 
14067
14358
  // server/routes/access/request-magic-link.ts
14068
- var TAG29 = "[access-request-link]";
14069
- var app38 = new Hono();
14359
+ var TAG30 = "[access-request-link]";
14360
+ var app40 = new Hono();
14070
14361
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
14071
- app38.post("/", async (c) => {
14362
+ app40.post("/", async (c) => {
14072
14363
  let body;
14073
14364
  try {
14074
14365
  body = await c.req.json();
@@ -14082,18 +14373,18 @@ app38.post("/", async (c) => {
14082
14373
  }
14083
14374
  const rateMsg = checkRequestLinkRateLimit(contactValue);
14084
14375
  if (rateMsg) {
14085
- console.error(`${TAG29} contactValue=${maskContact(contactValue)} result=rate-limited`);
14376
+ console.error(`${TAG30} contactValue=${maskContact(contactValue)} result=rate-limited`);
14086
14377
  return c.json({ error: rateMsg }, 429);
14087
14378
  }
14088
14379
  recordRequestLinkAttempt(contactValue);
14089
14380
  const accountId = process.env.ACCOUNT_ID ?? "";
14090
14381
  if (!accountId) {
14091
- console.error(`${TAG29} contactValue=${maskContact(contactValue)} result=no-account-id`);
14382
+ console.error(`${TAG30} contactValue=${maskContact(contactValue)} result=no-account-id`);
14092
14383
  return c.json({ message: VISITOR_MESSAGE }, 200);
14093
14384
  }
14094
14385
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
14095
14386
  if (!grant) {
14096
- console.log(`${TAG29} contactValue=${maskContact(contactValue)} result=notfound`);
14387
+ console.log(`${TAG30} contactValue=${maskContact(contactValue)} result=notfound`);
14097
14388
  return c.json({ message: VISITOR_MESSAGE }, 200);
14098
14389
  }
14099
14390
  let token;
@@ -14101,7 +14392,7 @@ app38.post("/", async (c) => {
14101
14392
  token = await generateNewMagicToken(grant.grantId);
14102
14393
  } catch (err) {
14103
14394
  console.error(
14104
- `${TAG29} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
14395
+ `${TAG30} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
14105
14396
  );
14106
14397
  return c.json({ message: VISITOR_MESSAGE }, 200);
14107
14398
  }
@@ -14133,26 +14424,26 @@ app38.post("/", async (c) => {
14133
14424
  });
14134
14425
  if (!sendResult.ok) {
14135
14426
  console.error(
14136
- `${TAG29} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
14427
+ `${TAG30} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
14137
14428
  );
14138
14429
  return c.json({ message: VISITOR_MESSAGE }, 200);
14139
14430
  }
14140
14431
  console.log(
14141
- `${TAG29} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
14432
+ `${TAG30} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
14142
14433
  );
14143
14434
  return c.json({ message: VISITOR_MESSAGE }, 200);
14144
14435
  });
14145
- var request_magic_link_default = app38;
14436
+ var request_magic_link_default = app40;
14146
14437
 
14147
14438
  // server/routes/access/index.ts
14148
- var app39 = new Hono();
14149
- app39.route("/verify-token", verify_token_default);
14150
- app39.route("/request-magic-link", request_magic_link_default);
14151
- var access_default = app39;
14439
+ var app41 = new Hono();
14440
+ app41.route("/verify-token", verify_token_default);
14441
+ app41.route("/request-magic-link", request_magic_link_default);
14442
+ var access_default = app41;
14152
14443
 
14153
14444
  // server/routes/sites.ts
14154
- import { existsSync as existsSync19, readFileSync as readFileSync19, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
14155
- import { resolve as resolve22 } from "path";
14445
+ import { existsSync as existsSync20, readFileSync as readFileSync20, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
14446
+ import { resolve as resolve23 } from "path";
14156
14447
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
14157
14448
  var MIME = {
14158
14449
  ".html": "text/html; charset=utf-8",
@@ -14183,8 +14474,8 @@ function getExt(p) {
14183
14474
  if (idx < p.lastIndexOf("/")) return "";
14184
14475
  return p.slice(idx).toLowerCase();
14185
14476
  }
14186
- var app40 = new Hono();
14187
- app40.get("/:rel{.*}", (c) => {
14477
+ var app42 = new Hono();
14478
+ app42.get("/:rel{.*}", (c) => {
14188
14479
  const reqPath = c.req.path;
14189
14480
  const rawRel = c.req.param("rel") ?? "";
14190
14481
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -14209,15 +14500,15 @@ app40.get("/:rel{.*}", (c) => {
14209
14500
  }
14210
14501
  segments.push(seg);
14211
14502
  }
14212
- const rootDir = resolve22(account.accountDir, "sites");
14213
- let filePath = segments.length === 0 ? rootDir : resolve22(rootDir, ...segments);
14503
+ const rootDir = resolve23(account.accountDir, "sites");
14504
+ let filePath = segments.length === 0 ? rootDir : resolve23(rootDir, ...segments);
14214
14505
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
14215
14506
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
14216
14507
  return c.text("Forbidden", 403);
14217
14508
  }
14218
14509
  let stat7;
14219
14510
  try {
14220
- stat7 = existsSync19(filePath) ? statSync9(filePath) : null;
14511
+ stat7 = existsSync20(filePath) ? statSync9(filePath) : null;
14221
14512
  } catch {
14222
14513
  stat7 = null;
14223
14514
  }
@@ -14230,13 +14521,13 @@ app40.get("/:rel{.*}", (c) => {
14230
14521
  return c.redirect(target, 301);
14231
14522
  }
14232
14523
  if (stat7?.isDirectory()) {
14233
- filePath = resolve22(filePath, "index.html");
14524
+ filePath = resolve23(filePath, "index.html");
14234
14525
  }
14235
14526
  if (!filePath.startsWith(rootDir + "/")) {
14236
14527
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
14237
14528
  return c.text("Forbidden", 403);
14238
14529
  }
14239
- if (!existsSync19(filePath)) {
14530
+ if (!existsSync20(filePath)) {
14240
14531
  console.error(`[sites] not-found path=${reqPath} status=404`);
14241
14532
  return c.text("Not found", 404);
14242
14533
  }
@@ -14255,7 +14546,7 @@ app40.get("/:rel{.*}", (c) => {
14255
14546
  }
14256
14547
  let body;
14257
14548
  try {
14258
- body = readFileSync19(realPath);
14549
+ body = readFileSync20(realPath);
14259
14550
  } catch (err) {
14260
14551
  const code = err?.code;
14261
14552
  if (code === "EISDIR") {
@@ -14287,11 +14578,11 @@ app40.get("/:rel{.*}", (c) => {
14287
14578
  "X-Content-Type-Options": "nosniff"
14288
14579
  });
14289
14580
  });
14290
- var sites_default = app40;
14581
+ var sites_default = app42;
14291
14582
 
14292
14583
  // app/lib/visitor-token.ts
14293
14584
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
14294
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync20, writeFileSync as writeFileSync7 } from "fs";
14585
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync21, writeFileSync as writeFileSync7 } from "fs";
14295
14586
  import { dirname as dirname5 } from "path";
14296
14587
  var TOKEN_PREFIX = "v1.";
14297
14588
  var SECRET_BYTES = 32;
@@ -14300,7 +14591,7 @@ var cachedSecret = null;
14300
14591
  function getSecret() {
14301
14592
  if (cachedSecret) return cachedSecret;
14302
14593
  try {
14303
- const hex2 = readFileSync20(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14594
+ const hex2 = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14304
14595
  if (hex2.length === SECRET_BYTES * 2) {
14305
14596
  cachedSecret = Buffer.from(hex2, "hex");
14306
14597
  return cachedSecret;
@@ -14314,7 +14605,7 @@ function getSecret() {
14314
14605
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
14315
14606
  } catch {
14316
14607
  }
14317
- const hex = readFileSync20(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14608
+ const hex = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14318
14609
  cachedSecret = Buffer.from(hex, "hex");
14319
14610
  return cachedSecret;
14320
14611
  }
@@ -14367,8 +14658,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
14367
14658
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
14368
14659
 
14369
14660
  // app/lib/brand-config.ts
14370
- import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
14371
- import { join as join17 } from "path";
14661
+ import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
14662
+ import { join as join18 } from "path";
14372
14663
  var cached2 = null;
14373
14664
  var cachedAttempted = false;
14374
14665
  function readBrandConfig() {
@@ -14376,10 +14667,10 @@ function readBrandConfig() {
14376
14667
  cachedAttempted = true;
14377
14668
  const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
14378
14669
  if (!platformRoot2) return null;
14379
- const brandPath = join17(platformRoot2, "config", "brand.json");
14380
- if (!existsSync20(brandPath)) return null;
14670
+ const brandPath = join18(platformRoot2, "config", "brand.json");
14671
+ if (!existsSync21(brandPath)) return null;
14381
14672
  try {
14382
- cached2 = JSON.parse(readFileSync21(brandPath, "utf-8"));
14673
+ cached2 = JSON.parse(readFileSync22(brandPath, "utf-8"));
14383
14674
  return cached2;
14384
14675
  } catch {
14385
14676
  return null;
@@ -14387,7 +14678,7 @@ function readBrandConfig() {
14387
14678
  }
14388
14679
 
14389
14680
  // server/routes/visitor-consent.ts
14390
- var app41 = new Hono();
14681
+ var app43 = new Hono();
14391
14682
  var CONSENT_COOKIE_NAME = "mxy_consent";
14392
14683
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
14393
14684
  var DEFAULT_CONSENT_COPY = {
@@ -14432,17 +14723,17 @@ function siteSlugFromReferer(referer) {
14432
14723
  return "";
14433
14724
  }
14434
14725
  }
14435
- app41.options("/consent", (c) => {
14726
+ app43.options("/consent", (c) => {
14436
14727
  const origin = getOrigin(c);
14437
14728
  setCorsHeaders(c, origin);
14438
14729
  return c.body(null, 204);
14439
14730
  });
14440
- app41.options("/brand-config", (c) => {
14731
+ app43.options("/brand-config", (c) => {
14441
14732
  const origin = getOrigin(c);
14442
14733
  setCorsHeaders(c, origin);
14443
14734
  return c.body(null, 204);
14444
14735
  });
14445
- app41.post("/consent", async (c) => {
14736
+ app43.post("/consent", async (c) => {
14446
14737
  const origin = getOrigin(c);
14447
14738
  setCorsHeaders(c, origin);
14448
14739
  let raw;
@@ -14482,7 +14773,7 @@ app41.post("/consent", async (c) => {
14482
14773
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
14483
14774
  return c.body(null, 204);
14484
14775
  });
14485
- app41.get("/brand-config", (c) => {
14776
+ app43.get("/brand-config", (c) => {
14486
14777
  const origin = getOrigin(c);
14487
14778
  setCorsHeaders(c, origin);
14488
14779
  const brand = readBrandConfig();
@@ -14492,7 +14783,7 @@ app41.get("/brand-config", (c) => {
14492
14783
  c.header("Cache-Control", "public, max-age=300");
14493
14784
  return c.json({ consent: { copy, palette } });
14494
14785
  });
14495
- var visitor_consent_default = app41;
14786
+ var visitor_consent_default = app43;
14496
14787
 
14497
14788
  // server/routes/listings.ts
14498
14789
  function getCookie(headerValue, name) {
@@ -14519,8 +14810,8 @@ function appendConsentParams(pageUrl, token) {
14519
14810
  }
14520
14811
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
14521
14812
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
14522
- var app42 = new Hono();
14523
- app42.get("/:slug/click", async (c) => {
14813
+ var app44 = new Hono();
14814
+ app44.get("/:slug/click", async (c) => {
14524
14815
  const slug = c.req.param("slug") ?? "";
14525
14816
  const rawSession = c.req.query("session") ?? "";
14526
14817
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -14584,10 +14875,10 @@ app42.get("/:slug/click", async (c) => {
14584
14875
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
14585
14876
  return c.redirect(redirectUrl, 302);
14586
14877
  });
14587
- var listings_default = app42;
14878
+ var listings_default = app44;
14588
14879
 
14589
14880
  // server/routes/visitor-event.ts
14590
- var app43 = new Hono();
14881
+ var app45 = new Hono();
14591
14882
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
14592
14883
  var buckets = /* @__PURE__ */ new Map();
14593
14884
  var RATE_LIMIT = 60;
@@ -14654,12 +14945,12 @@ function originAllowed(origin, allowlist) {
14654
14945
  return false;
14655
14946
  }
14656
14947
  }
14657
- app43.options("/event", (c) => {
14948
+ app45.options("/event", (c) => {
14658
14949
  const origin = getOrigin2(c);
14659
14950
  setCorsHeaders2(c, origin);
14660
14951
  return c.body(null, 204);
14661
14952
  });
14662
- app43.post("/event", async (c) => {
14953
+ app45.post("/event", async (c) => {
14663
14954
  const origin = getOrigin2(c);
14664
14955
  setCorsHeaders2(c, origin);
14665
14956
  const ua = c.req.header("user-agent") ?? "";
@@ -14864,17 +15155,17 @@ async function writeEvent(opts) {
14864
15155
  );
14865
15156
  }
14866
15157
  }
14867
- var visitor_event_default = app43;
15158
+ var visitor_event_default = app45;
14868
15159
 
14869
15160
  // server/routes/session.ts
14870
- import { resolve as resolve23 } from "path";
14871
- import { existsSync as existsSync21, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
15161
+ import { resolve as resolve24 } from "path";
15162
+ import { existsSync as existsSync22, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
14872
15163
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14873
15164
  function writeBrandingCache(accountId, agentSlug, branding) {
14874
15165
  try {
14875
- const cacheDir = resolve23(MAXY_DIR, "branding-cache", accountId);
15166
+ const cacheDir = resolve24(MAXY_DIR, "branding-cache", accountId);
14876
15167
  mkdirSync5(cacheDir, { recursive: true });
14877
- writeFileSync8(resolve23(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
15168
+ writeFileSync8(resolve24(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
14878
15169
  } catch (err) {
14879
15170
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
14880
15171
  }
@@ -14910,8 +15201,8 @@ function withVisitorCookie(response, visitorId) {
14910
15201
  headers
14911
15202
  });
14912
15203
  }
14913
- var app44 = new Hono();
14914
- app44.post("/", async (c) => {
15204
+ var app46 = new Hono();
15205
+ app46.post("/", async (c) => {
14915
15206
  let body;
14916
15207
  try {
14917
15208
  body = await c.req.json();
@@ -14962,8 +15253,8 @@ app44.post("/", async (c) => {
14962
15253
  }
14963
15254
  let agentConfig = null;
14964
15255
  if (account) {
14965
- const agentDir = resolve23(account.accountDir, "agents", agentSlug);
14966
- if (!existsSync21(agentDir) || !existsSync21(resolve23(agentDir, "config.json"))) {
15256
+ const agentDir = resolve24(account.accountDir, "agents", agentSlug);
15257
+ if (!existsSync22(agentDir) || !existsSync22(resolve24(agentDir, "config.json"))) {
14967
15258
  return c.json({ error: "Agent not found" }, 404);
14968
15259
  }
14969
15260
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -15122,7 +15413,7 @@ app44.post("/", async (c) => {
15122
15413
  newVisitorId
15123
15414
  );
15124
15415
  });
15125
- var session_default2 = app44;
15416
+ var session_default2 = app46;
15126
15417
 
15127
15418
  // app/lib/graph-health.ts
15128
15419
  var import_dist4 = __toESM(require_dist3(), 1);
@@ -15243,7 +15534,7 @@ function startGraphHealthTimer() {
15243
15534
 
15244
15535
  // app/lib/file-watcher.ts
15245
15536
  import * as fsp2 from "fs/promises";
15246
- import { resolve as resolve24, sep as sep7 } from "path";
15537
+ import { resolve as resolve25, sep as sep7 } from "path";
15247
15538
  var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
15248
15539
  var DEFAULT_COALESCE_MS = 500;
15249
15540
  var ROOTS = ["uploads", "accounts"];
@@ -15262,7 +15553,7 @@ async function startFileWatcher(opts = {}) {
15262
15553
  const dropFn = opts.drop ?? dropFileIndex;
15263
15554
  for (const r of ROOTS) {
15264
15555
  try {
15265
- await fsp2.mkdir(resolve24(dataRoot, r), { recursive: true });
15556
+ await fsp2.mkdir(resolve25(dataRoot, r), { recursive: true });
15266
15557
  } catch (err) {
15267
15558
  console.error(
15268
15559
  `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
@@ -15283,7 +15574,7 @@ async function startFileWatcher(opts = {}) {
15283
15574
  timers.set(relativePath, t);
15284
15575
  }
15285
15576
  async function runHook(relativePath, accountId) {
15286
- const absolute = resolve24(dataRoot, relativePath);
15577
+ const absolute = resolve25(dataRoot, relativePath);
15287
15578
  let exists = false;
15288
15579
  try {
15289
15580
  const st = await fsp2.stat(absolute);
@@ -15307,7 +15598,7 @@ async function startFileWatcher(opts = {}) {
15307
15598
  }
15308
15599
  }
15309
15600
  async function watchRoot(rootName) {
15310
- const absRoot = resolve24(dataRoot, rootName);
15601
+ const absRoot = resolve25(dataRoot, rootName);
15311
15602
  try {
15312
15603
  const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
15313
15604
  for await (const event of iter) {
@@ -15612,8 +15903,8 @@ var streamSSE = (c, cb, onError) => {
15612
15903
 
15613
15904
  // app/lib/whatsapp/gateway/routes.ts
15614
15905
  function createWaChannelRoutes(deps) {
15615
- const app46 = new Hono();
15616
- app46.get("/wa-channel/inbound", (c) => {
15906
+ const app48 = new Hono();
15907
+ app48.get("/wa-channel/inbound", (c) => {
15617
15908
  const senderId = c.req.query("senderId");
15618
15909
  if (!senderId) return c.json({ error: "senderId required" }, 400);
15619
15910
  return streamSSE(c, async (stream2) => {
@@ -15631,7 +15922,7 @@ function createWaChannelRoutes(deps) {
15631
15922
  }
15632
15923
  });
15633
15924
  });
15634
- app46.post("/wa-channel/reply", async (c) => {
15925
+ app48.post("/wa-channel/reply", async (c) => {
15635
15926
  const body = await c.req.json().catch(() => null);
15636
15927
  const senderId = body?.senderId;
15637
15928
  const text = body?.text;
@@ -15652,7 +15943,7 @@ function createWaChannelRoutes(deps) {
15652
15943
  console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
15653
15944
  return c.json({ ok: true });
15654
15945
  });
15655
- app46.post("/wa-channel/ready", async (c) => {
15946
+ app48.post("/wa-channel/ready", async (c) => {
15656
15947
  const body = await c.req.json().catch(() => null);
15657
15948
  const senderId = body?.senderId;
15658
15949
  if (typeof senderId !== "string") {
@@ -15661,7 +15952,7 @@ function createWaChannelRoutes(deps) {
15661
15952
  deps.onReady?.(senderId);
15662
15953
  return c.json({ ok: true });
15663
15954
  });
15664
- app46.post("/wa-channel/received", async (c) => {
15955
+ app48.post("/wa-channel/received", async (c) => {
15665
15956
  const body = await c.req.json().catch(() => null);
15666
15957
  const senderId = body?.senderId;
15667
15958
  const waMessageId = body?.waMessageId;
@@ -15671,7 +15962,7 @@ function createWaChannelRoutes(deps) {
15671
15962
  deps.onReceived?.(senderId, waMessageId);
15672
15963
  return c.json({ ok: true });
15673
15964
  });
15674
- return app46;
15965
+ return app48;
15675
15966
  }
15676
15967
 
15677
15968
  // app/lib/whatsapp/gateway/wa-gateway.ts
@@ -15864,8 +16155,8 @@ function broadcastAdminShutdown(reason) {
15864
16155
 
15865
16156
  // ../lib/entitlement/src/index.ts
15866
16157
  import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
15867
- import { existsSync as existsSync22, readFileSync as readFileSync22, statSync as statSync10 } from "fs";
15868
- import { resolve as resolve25 } from "path";
16158
+ import { existsSync as existsSync23, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
16159
+ import { resolve as resolve26 } from "path";
15869
16160
 
15870
16161
  // ../lib/entitlement/src/canonicalize.ts
15871
16162
  function canonicalize(value) {
@@ -15900,7 +16191,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
15900
16191
  var GRACE_DAYS = 7;
15901
16192
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
15902
16193
  function pubkeyPath(brand) {
15903
- return resolve25(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
16194
+ return resolve26(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
15904
16195
  }
15905
16196
  var memo = null;
15906
16197
  function memoKey(mtimeMs, account) {
@@ -15912,8 +16203,8 @@ function resolveEntitlement(brand, account) {
15912
16203
  if (brand.commercialMode !== true) {
15913
16204
  return logResolved(implicitTrust(account), null);
15914
16205
  }
15915
- const entitlementPath = resolve25(brand.configDir, "entitlement.json");
15916
- if (!existsSync22(entitlementPath)) {
16206
+ const entitlementPath = resolve26(brand.configDir, "entitlement.json");
16207
+ if (!existsSync23(entitlementPath)) {
15917
16208
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
15918
16209
  }
15919
16210
  const stat7 = statSync10(entitlementPath);
@@ -15928,7 +16219,7 @@ function resolveEntitlement(brand, account) {
15928
16219
  function verifyAndResolve(brand, entitlementPath, account) {
15929
16220
  let pubkeyPem;
15930
16221
  try {
15931
- pubkeyPem = readFileSync22(pubkeyPath(brand), "utf-8");
16222
+ pubkeyPem = readFileSync23(pubkeyPath(brand), "utf-8");
15932
16223
  } catch (err) {
15933
16224
  return logResolved(anonymousFallback("pubkey-missing"), {
15934
16225
  reason: "pubkey-missing"
@@ -15942,7 +16233,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
15942
16233
  }
15943
16234
  let envelope;
15944
16235
  try {
15945
- envelope = JSON.parse(readFileSync22(entitlementPath, "utf-8"));
16236
+ envelope = JSON.parse(readFileSync23(entitlementPath, "utf-8"));
15946
16237
  } catch {
15947
16238
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
15948
16239
  }
@@ -16103,14 +16394,14 @@ function clientFrom(c) {
16103
16394
  );
16104
16395
  }
16105
16396
  var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
16106
- var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join18(PLATFORM_ROOT9, "config", "brand.json") : "";
16397
+ var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join19(PLATFORM_ROOT9, "config", "brand.json") : "";
16107
16398
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
16108
- if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
16399
+ if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
16109
16400
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
16110
16401
  }
16111
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
16402
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
16112
16403
  try {
16113
- const parsed = JSON.parse(readFileSync23(BRAND_JSON_PATH, "utf-8"));
16404
+ const parsed = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
16114
16405
  BRAND = { ...BRAND, ...parsed };
16115
16406
  } catch (err) {
16116
16407
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -16129,11 +16420,11 @@ var brandLoginOpts = {
16129
16420
  bodyFont: BRAND.defaultFonts?.body,
16130
16421
  logoContainsName: !!BRAND.logoContainsName
16131
16422
  };
16132
- var ALIAS_DOMAINS_PATH = join18(homedir2(), BRAND.configDir, "alias-domains.json");
16423
+ var ALIAS_DOMAINS_PATH = join19(homedir3(), BRAND.configDir, "alias-domains.json");
16133
16424
  function loadAliasDomains() {
16134
16425
  try {
16135
- if (!existsSync23(ALIAS_DOMAINS_PATH)) return null;
16136
- const parsed = JSON.parse(readFileSync23(ALIAS_DOMAINS_PATH, "utf-8"));
16426
+ if (!existsSync24(ALIAS_DOMAINS_PATH)) return null;
16427
+ const parsed = JSON.parse(readFileSync24(ALIAS_DOMAINS_PATH, "utf-8"));
16137
16428
  if (!Array.isArray(parsed)) {
16138
16429
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
16139
16430
  return null;
@@ -16157,10 +16448,10 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
16157
16448
  function isPublicHost(host) {
16158
16449
  return host.startsWith("public.") || aliasDomains.has(host);
16159
16450
  }
16160
- var app45 = new Hono();
16451
+ var app47 = new Hono();
16161
16452
  var waGateway = new WaGateway({
16162
16453
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
16163
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve26(process.env.MAXY_PLATFORM_ROOT ?? join18(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
16454
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
16164
16455
  ensureChannelSession: async ({ accountId, senderId, gatewayUrl, serverPath }) => {
16165
16456
  const userId = resolveAdminUserId({ accountId, senderPhone: senderId }) ?? void 0;
16166
16457
  console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
@@ -16180,10 +16471,10 @@ var waGateway = new WaGateway({
16180
16471
  }
16181
16472
  }
16182
16473
  });
16183
- app45.route("/", waGateway.routes());
16474
+ app47.route("/", waGateway.routes());
16184
16475
  waGateway.startSweeper();
16185
- app45.use("*", clientIpMiddleware);
16186
- app45.use("*", async (c, next) => {
16476
+ app47.use("*", clientIpMiddleware);
16477
+ app47.use("*", async (c, next) => {
16187
16478
  await next();
16188
16479
  c.header("X-Content-Type-Options", "nosniff");
16189
16480
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -16193,7 +16484,7 @@ app45.use("*", async (c, next) => {
16193
16484
  );
16194
16485
  });
16195
16486
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
16196
- app45.use("*", async (c, next) => {
16487
+ app47.use("*", async (c, next) => {
16197
16488
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
16198
16489
  await next();
16199
16490
  return;
@@ -16211,7 +16502,7 @@ app45.use("*", async (c, next) => {
16211
16502
  });
16212
16503
  }
16213
16504
  });
16214
- app45.use("*", async (c, next) => {
16505
+ app47.use("*", async (c, next) => {
16215
16506
  const host = (c.req.header("host") ?? "").split(":")[0];
16216
16507
  if (!isPublicHost(host)) {
16217
16508
  await next();
@@ -16242,7 +16533,7 @@ function resolveRemoteAuthOpts() {
16242
16533
  return brandLoginOpts;
16243
16534
  }
16244
16535
  var MAX_LOGIN_BODY = 8 * 1024;
16245
- app45.post("/__remote-auth/login", async (c) => {
16536
+ app47.post("/__remote-auth/login", async (c) => {
16246
16537
  const client = clientFrom(c);
16247
16538
  const clientIp = client.ip || "unknown";
16248
16539
  if (!requestIsTlsTerminated(c)) {
@@ -16287,7 +16578,7 @@ app45.post("/__remote-auth/login", async (c) => {
16287
16578
  }
16288
16579
  });
16289
16580
  });
16290
- app45.get("/__remote-auth/logout", (c) => {
16581
+ app47.get("/__remote-auth/logout", (c) => {
16291
16582
  const client = clientFrom(c);
16292
16583
  const clientIp = client.ip || "unknown";
16293
16584
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -16300,7 +16591,7 @@ app45.get("/__remote-auth/logout", (c) => {
16300
16591
  }
16301
16592
  });
16302
16593
  });
16303
- app45.post("/__remote-auth/change-password", async (c) => {
16594
+ app47.post("/__remote-auth/change-password", async (c) => {
16304
16595
  const client = clientFrom(c);
16305
16596
  const clientIp = client.ip || "unknown";
16306
16597
  const rateLimited = checkRateLimit(client);
@@ -16351,13 +16642,13 @@ app45.post("/__remote-auth/change-password", async (c) => {
16351
16642
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
16352
16643
  }
16353
16644
  });
16354
- app45.get("/__remote-auth/setup", (c) => {
16645
+ app47.get("/__remote-auth/setup", (c) => {
16355
16646
  if (isRemoteAuthConfigured()) {
16356
16647
  return c.redirect("/");
16357
16648
  }
16358
16649
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
16359
16650
  });
16360
- app45.post("/__remote-auth/set-initial-password", async (c) => {
16651
+ app47.post("/__remote-auth/set-initial-password", async (c) => {
16361
16652
  if (isRemoteAuthConfigured()) {
16362
16653
  return c.redirect("/");
16363
16654
  }
@@ -16395,10 +16686,10 @@ app45.post("/__remote-auth/set-initial-password", async (c) => {
16395
16686
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
16396
16687
  }
16397
16688
  });
16398
- app45.get("/api/remote-auth/status", (c) => {
16689
+ app47.get("/api/remote-auth/status", (c) => {
16399
16690
  return c.json({ configured: isRemoteAuthConfigured() });
16400
16691
  });
16401
- app45.post("/api/remote-auth/set-password", async (c) => {
16692
+ app47.post("/api/remote-auth/set-password", async (c) => {
16402
16693
  let body;
16403
16694
  try {
16404
16695
  body = await c.req.json();
@@ -16429,9 +16720,9 @@ app45.post("/api/remote-auth/set-password", async (c) => {
16429
16720
  return c.json({ error: "Failed to save password" }, 500);
16430
16721
  }
16431
16722
  });
16432
- app45.route("/api/_client-error", client_error_default);
16723
+ app47.route("/api/_client-error", client_error_default);
16433
16724
  console.log("[client-error-route] mounted");
16434
- app45.use("*", async (c, next) => {
16725
+ app47.use("*", async (c, next) => {
16435
16726
  const host = (c.req.header("host") ?? "").split(":")[0];
16436
16727
  const path2 = c.req.path;
16437
16728
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -16464,14 +16755,15 @@ app45.use("*", async (c, next) => {
16464
16755
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
16465
16756
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
16466
16757
  });
16467
- app45.route("/api/health", health_default);
16468
- app45.route("/api/chat", chat_default);
16469
- app45.route("/api/whatsapp", whatsapp_default);
16470
- app45.route("/api/whatsapp-reader", whatsapp_reader_default);
16471
- app45.route("/api/onboarding", onboarding_default);
16472
- app45.route("/api/admin", admin_default);
16473
- app45.route("/api/access", access_default);
16474
- app45.route("/api/session", session_default2);
16758
+ app47.route("/api/health", health_default);
16759
+ app47.route("/api/chat", chat_default);
16760
+ app47.route("/api/whatsapp", whatsapp_default);
16761
+ app47.route("/api/whatsapp-reader", whatsapp_reader_default);
16762
+ app47.route("/api/telegram", telegram_default);
16763
+ app47.route("/api/onboarding", onboarding_default);
16764
+ app47.route("/api/admin", admin_default);
16765
+ app47.route("/api/access", access_default);
16766
+ app47.route("/api/session", session_default2);
16475
16767
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
16476
16768
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
16477
16769
  var IMAGE_MIME = {
@@ -16483,7 +16775,7 @@ var IMAGE_MIME = {
16483
16775
  ".svg": "image/svg+xml",
16484
16776
  ".ico": "image/x-icon"
16485
16777
  };
16486
- app45.get("/agent-assets/:slug/:filename", (c) => {
16778
+ app47.get("/agent-assets/:slug/:filename", (c) => {
16487
16779
  const slug = c.req.param("slug");
16488
16780
  const filename = c.req.param("filename");
16489
16781
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -16499,26 +16791,26 @@ app45.get("/agent-assets/:slug/:filename", (c) => {
16499
16791
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
16500
16792
  return c.text("Not found", 404);
16501
16793
  }
16502
- const filePath = resolve26(account.accountDir, "agents", slug, "assets", filename);
16503
- const expectedDir = resolve26(account.accountDir, "agents", slug, "assets");
16794
+ const filePath = resolve27(account.accountDir, "agents", slug, "assets", filename);
16795
+ const expectedDir = resolve27(account.accountDir, "agents", slug, "assets");
16504
16796
  if (!filePath.startsWith(expectedDir + "/")) {
16505
16797
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
16506
16798
  return c.text("Forbidden", 403);
16507
16799
  }
16508
- if (!existsSync23(filePath)) {
16800
+ if (!existsSync24(filePath)) {
16509
16801
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
16510
16802
  return c.text("Not found", 404);
16511
16803
  }
16512
16804
  const ext = "." + filename.split(".").pop()?.toLowerCase();
16513
16805
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
16514
16806
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
16515
- const body = readFileSync23(filePath);
16807
+ const body = readFileSync24(filePath);
16516
16808
  return c.body(body, 200, {
16517
16809
  "Content-Type": contentType,
16518
16810
  "Cache-Control": "public, max-age=3600"
16519
16811
  });
16520
16812
  });
16521
- app45.get("/generated/:filename", (c) => {
16813
+ app47.get("/generated/:filename", (c) => {
16522
16814
  const filename = c.req.param("filename");
16523
16815
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
16524
16816
  console.error(`[generated] serve file=${filename} status=403`);
@@ -16529,35 +16821,35 @@ app45.get("/generated/:filename", (c) => {
16529
16821
  console.error(`[generated] serve file=${filename} status=404`);
16530
16822
  return c.text("Not found", 404);
16531
16823
  }
16532
- const filePath = resolve26(account.accountDir, "generated", filename);
16533
- const expectedDir = resolve26(account.accountDir, "generated");
16824
+ const filePath = resolve27(account.accountDir, "generated", filename);
16825
+ const expectedDir = resolve27(account.accountDir, "generated");
16534
16826
  if (!filePath.startsWith(expectedDir + "/")) {
16535
16827
  console.error(`[generated] serve file=${filename} status=403`);
16536
16828
  return c.text("Forbidden", 403);
16537
16829
  }
16538
- if (!existsSync23(filePath)) {
16830
+ if (!existsSync24(filePath)) {
16539
16831
  console.error(`[generated] serve file=${filename} status=404`);
16540
16832
  return c.text("Not found", 404);
16541
16833
  }
16542
16834
  const ext = "." + filename.split(".").pop()?.toLowerCase();
16543
16835
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
16544
16836
  console.log(`[generated] serve file=${filename} status=200`);
16545
- const body = readFileSync23(filePath);
16837
+ const body = readFileSync24(filePath);
16546
16838
  return c.body(body, 200, {
16547
16839
  "Content-Type": contentType,
16548
16840
  "Cache-Control": "public, max-age=86400"
16549
16841
  });
16550
16842
  });
16551
- app45.route("/sites", sites_default);
16552
- app45.route("/listings", listings_default);
16553
- app45.route("/v", visitor_event_default);
16554
- app45.route("/v", visitor_consent_default);
16843
+ app47.route("/sites", sites_default);
16844
+ app47.route("/listings", listings_default);
16845
+ app47.route("/v", visitor_event_default);
16846
+ app47.route("/v", visitor_consent_default);
16555
16847
  var htmlCache = /* @__PURE__ */ new Map();
16556
16848
  var brandLogoPath = "/brand/maxy-monochrome.png";
16557
16849
  var brandIconPath = "/brand/maxy-monochrome.png";
16558
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
16850
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
16559
16851
  try {
16560
- const fullBrand = JSON.parse(readFileSync23(BRAND_JSON_PATH, "utf-8"));
16852
+ const fullBrand = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
16561
16853
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
16562
16854
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
16563
16855
  } catch {
@@ -16574,9 +16866,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
16574
16866
  function readInstalledVersion() {
16575
16867
  try {
16576
16868
  if (!PLATFORM_ROOT9) return "unknown";
16577
- const versionFile = join18(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
16578
- if (!existsSync23(versionFile)) return "unknown";
16579
- const content = readFileSync23(versionFile, "utf-8").trim();
16869
+ const versionFile = join19(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
16870
+ if (!existsSync24(versionFile)) return "unknown";
16871
+ const content = readFileSync24(versionFile, "utf-8").trim();
16580
16872
  return content || "unknown";
16581
16873
  } catch {
16582
16874
  return "unknown";
@@ -16617,7 +16909,7 @@ var clientErrorReporterScript = `<script>
16617
16909
  function cachedHtml(file) {
16618
16910
  let html = htmlCache.get(file);
16619
16911
  if (!html) {
16620
- html = readFileSync23(resolve26(process.cwd(), "public", file), "utf-8");
16912
+ html = readFileSync24(resolve27(process.cwd(), "public", file), "utf-8");
16621
16913
  const productNameEsc = escapeHtml(BRAND.productName);
16622
16914
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
16623
16915
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -16633,13 +16925,13 @@ ${clientErrorReporterScript}
16633
16925
  }
16634
16926
  var brandedHtmlCache = /* @__PURE__ */ new Map();
16635
16927
  function loadBrandingCache(agentSlug) {
16636
- const configDir2 = join18(homedir2(), BRAND.configDir);
16928
+ const configDir2 = join19(homedir3(), BRAND.configDir);
16637
16929
  try {
16638
16930
  const accountId = getDefaultAccountId();
16639
16931
  if (!accountId) return null;
16640
- const cachePath = join18(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
16641
- if (!existsSync23(cachePath)) return null;
16642
- return JSON.parse(readFileSync23(cachePath, "utf-8"));
16932
+ const cachePath = join19(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
16933
+ if (!existsSync24(cachePath)) return null;
16934
+ return JSON.parse(readFileSync24(cachePath, "utf-8"));
16643
16935
  } catch {
16644
16936
  return null;
16645
16937
  }
@@ -16682,7 +16974,7 @@ function escapeHtml(s) {
16682
16974
  function agentUnavailableHtml() {
16683
16975
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
16684
16976
  }
16685
- app45.get("/", (c) => {
16977
+ app47.get("/", (c) => {
16686
16978
  const host = (c.req.header("host") ?? "").split(":")[0];
16687
16979
  if (isPublicHost(host)) {
16688
16980
  const defaultSlug = resolveDefaultSlug();
@@ -16698,12 +16990,12 @@ app45.get("/", (c) => {
16698
16990
  }
16699
16991
  return c.html(cachedHtml("index.html"));
16700
16992
  });
16701
- app45.get("/public", (c) => {
16993
+ app47.get("/public", (c) => {
16702
16994
  const host = (c.req.header("host") ?? "").split(":")[0];
16703
16995
  if (isPublicHost(host)) return c.text("Not found", 404);
16704
16996
  return c.html(cachedHtml("public.html"));
16705
16997
  });
16706
- app45.get("/chat", (c) => {
16998
+ app47.get("/chat", (c) => {
16707
16999
  const host = (c.req.header("host") ?? "").split(":")[0];
16708
17000
  if (isPublicHost(host)) return c.text("Not found", 404);
16709
17001
  return c.html(cachedHtml("public.html"));
@@ -16722,12 +17014,12 @@ async function logViewerFetch(c, next) {
16722
17014
  duration_ms: Date.now() - start
16723
17015
  });
16724
17016
  }
16725
- app45.use("/vnc-viewer.html", logViewerFetch);
16726
- app45.use("/vnc-popout.html", logViewerFetch);
16727
- app45.get("/vnc-popout.html", (c) => {
17017
+ app47.use("/vnc-viewer.html", logViewerFetch);
17018
+ app47.use("/vnc-popout.html", logViewerFetch);
17019
+ app47.get("/vnc-popout.html", (c) => {
16728
17020
  let html = htmlCache.get("vnc-popout.html");
16729
17021
  if (!html) {
16730
- html = readFileSync23(resolve26(process.cwd(), "public", "vnc-popout.html"), "utf-8");
17022
+ html = readFileSync24(resolve27(process.cwd(), "public", "vnc-popout.html"), "utf-8");
16731
17023
  const name = escapeHtml(BRAND.productName);
16732
17024
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
16733
17025
  html = html.replace("</head>", ` ${brandScript}
@@ -16737,7 +17029,7 @@ app45.get("/vnc-popout.html", (c) => {
16737
17029
  }
16738
17030
  return c.html(html);
16739
17031
  });
16740
- app45.post("/api/vnc/client-event", async (c) => {
17032
+ app47.post("/api/vnc/client-event", async (c) => {
16741
17033
  let body;
16742
17034
  try {
16743
17035
  body = await c.req.json();
@@ -16758,30 +17050,30 @@ app45.post("/api/vnc/client-event", async (c) => {
16758
17050
  });
16759
17051
  return c.json({ ok: true });
16760
17052
  });
16761
- app45.get("/g/:slug", (c) => {
17053
+ app47.get("/g/:slug", (c) => {
16762
17054
  return c.html(brandedPublicHtml());
16763
17055
  });
16764
- app45.get("/graph", (c) => {
17056
+ app47.get("/graph", (c) => {
16765
17057
  const host = (c.req.header("host") ?? "").split(":")[0];
16766
17058
  if (isPublicHost(host)) return c.text("Not found", 404);
16767
17059
  return c.html(cachedHtml("graph.html"));
16768
17060
  });
16769
- app45.get("/sessions", (c) => {
17061
+ app47.get("/sessions", (c) => {
16770
17062
  const host = (c.req.header("host") ?? "").split(":")[0];
16771
17063
  if (isPublicHost(host)) return c.text("Not found", 404);
16772
17064
  return c.html(cachedHtml("sessions.html"));
16773
17065
  });
16774
- app45.get("/data", (c) => {
17066
+ app47.get("/data", (c) => {
16775
17067
  const host = (c.req.header("host") ?? "").split(":")[0];
16776
17068
  if (isPublicHost(host)) return c.text("Not found", 404);
16777
17069
  return c.html(cachedHtml("data.html"));
16778
17070
  });
16779
- app45.get("/browser", (c) => {
17071
+ app47.get("/browser", (c) => {
16780
17072
  const host = (c.req.header("host") ?? "").split(":")[0];
16781
17073
  if (isPublicHost(host)) return c.text("Not found", 404);
16782
17074
  return c.html(cachedHtml("browser.html"));
16783
17075
  });
16784
- app45.get("/:slug", async (c, next) => {
17076
+ app47.get("/:slug", async (c, next) => {
16785
17077
  const slug = c.req.param("slug");
16786
17078
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
16787
17079
  const account = resolveAccount();
@@ -16796,13 +17088,13 @@ app45.get("/:slug", async (c, next) => {
16796
17088
  await next();
16797
17089
  });
16798
17090
  if (brandFaviconPath !== "/favicon.ico") {
16799
- app45.get("/favicon.ico", (c) => {
17091
+ app47.get("/favicon.ico", (c) => {
16800
17092
  c.header("Cache-Control", "public, max-age=300");
16801
17093
  return c.redirect(brandFaviconPath, 302);
16802
17094
  });
16803
17095
  }
16804
- app45.use("/*", serveStatic({ root: "./public" }));
16805
- app45.all("*", (c) => {
17096
+ app47.use("/*", serveStatic({ root: "./public" }));
17097
+ app47.all("*", (c) => {
16806
17098
  const host = (c.req.header("host") ?? "").split(":")[0];
16807
17099
  const path2 = c.req.path;
16808
17100
  if (isPublicHost(host)) {
@@ -16816,7 +17108,7 @@ app45.all("*", (c) => {
16816
17108
  });
16817
17109
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
16818
17110
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
16819
- var httpServer = serve({ fetch: app45.fetch, port, hostname });
17111
+ var httpServer = serve({ fetch: app47.fetch, port, hostname });
16820
17112
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
16821
17113
  startAuthHealthHeartbeat();
16822
17114
  {
@@ -16839,6 +17131,7 @@ var SUBAPP_MANIFEST = [
16839
17131
  { prefix: "/api/chat", file: "server/routes/chat.ts", subapp: chat_default },
16840
17132
  { prefix: "/api/whatsapp", file: "server/routes/whatsapp.ts", subapp: whatsapp_default },
16841
17133
  { prefix: "/api/whatsapp-reader", file: "server/routes/whatsapp-reader.ts", subapp: whatsapp_reader_default },
17134
+ { prefix: "/api/telegram", file: "server/routes/telegram.ts", subapp: telegram_default },
16842
17135
  { prefix: "/api/onboarding", file: "server/routes/onboarding.ts", subapp: onboarding_default },
16843
17136
  { prefix: "/api/admin", file: "server/routes/admin/index.ts", subapp: admin_default },
16844
17137
  { prefix: "/api/access", file: "server/routes/access/index.ts", subapp: access_default },
@@ -16854,7 +17147,7 @@ for (const m of SUBAPP_MANIFEST) {
16854
17147
  }
16855
17148
  try {
16856
17149
  const registered = [];
16857
- for (const r of app45.routes ?? []) {
17150
+ for (const r of app47.routes ?? []) {
16858
17151
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
16859
17152
  if (AGENT_SLUG_PATTERN.test(r.path)) {
16860
17153
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -16882,11 +17175,11 @@ try {
16882
17175
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
16883
17176
  async function runAdminUserReconcileTick() {
16884
17177
  try {
16885
- if (!existsSync23(USERS_FILE)) {
17178
+ if (!existsSync24(USERS_FILE)) {
16886
17179
  console.error("[adminuser-self-heal] skip reason=no-users-file");
16887
17180
  return;
16888
17181
  }
16889
- const usersRaw = readFileSync23(USERS_FILE, "utf-8").trim();
17182
+ const usersRaw = readFileSync24(USERS_FILE, "utf-8").trim();
16890
17183
  if (!usersRaw) {
16891
17184
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
16892
17185
  return;
@@ -16936,6 +17229,9 @@ try {
16936
17229
  }
16937
17230
  var configDirForWhatsApp = basename7(MAXY_DIR) || ".maxy";
16938
17231
  var bootAccount = resolveAccount();
17232
+ if (bootAccount) {
17233
+ migrateRemovedConfigKeys(bootAccount.accountDir);
17234
+ }
16939
17235
  var bootAccountConfig = bootAccount?.config;
16940
17236
  var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
16941
17237
  var bootEntitlement = bootAccountConfig ? resolveEntitlement(
@@ -16993,7 +17289,7 @@ if (bootAccountConfig?.whatsapp) {
16993
17289
  }
16994
17290
  init({
16995
17291
  configDir: configDirForWhatsApp,
16996
- platformRoot: resolve26(process.env.MAXY_PLATFORM_ROOT ?? join18(__dirname, "..")),
17292
+ platformRoot: resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, "..")),
16997
17293
  accountConfig: bootAccountConfig,
16998
17294
  onMessage: async (msg) => {
16999
17295
  if (msg.isOwnerMirror) {