@rubytech/create-maxy-code 0.1.279 → 0.1.280

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 (122) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  3. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +42 -0
  4. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +60 -15
  5. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.d.ts +2 -0
  6. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.d.ts.map +1 -0
  7. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.js +54 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/e-sign-discoverable.test.js.map +1 -0
  9. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.d.ts +2 -0
  10. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.d.ts.map +1 -0
  11. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.js +19 -0
  12. package/payload/platform/plugins/admin/mcp/dist/content-producer-authoring-skills.js.map +1 -0
  13. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +2 -5
  15. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +2 -0
  17. package/payload/platform/plugins/admin/skills/access-manager/SKILL.md +2 -0
  18. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +2 -0
  19. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +2 -0
  20. package/payload/platform/plugins/admin/skills/capabilities-here/SKILL.md +2 -0
  21. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +2 -0
  22. package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +2 -0
  23. package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +2 -0
  24. package/payload/platform/plugins/admin/skills/investigate/SKILL.md +2 -0
  25. package/payload/platform/plugins/admin/skills/plainly/SKILL.md +2 -0
  26. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -0
  27. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +2 -0
  28. package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +2 -0
  29. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +2 -0
  30. package/payload/platform/plugins/admin/skills/qr-code/SKILL.md +2 -0
  31. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +2 -0
  32. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +2 -0
  33. package/payload/platform/plugins/admin/skills/specialist-management/SKILL.md +2 -0
  34. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +2 -0
  35. package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +2 -0
  36. package/payload/platform/plugins/admin/skills/task/SKILL.md +2 -0
  37. package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +2 -0
  38. package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +2 -0
  39. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +2 -0
  40. package/payload/platform/plugins/business-assistant/PLUGIN.md +2 -1
  41. package/payload/platform/plugins/business-assistant/{references/e-sign.md → skills/e-sign/SKILL.md} +9 -2
  42. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +2 -0
  43. package/payload/platform/plugins/deep-research/skills/academic-verify/SKILL.md +2 -0
  44. package/payload/platform/plugins/deep-research/skills/book-mirror/SKILL.md +2 -0
  45. package/payload/platform/plugins/deep-research/skills/data-research/SKILL.md +2 -0
  46. package/payload/platform/plugins/deep-research/skills/deep-research/SKILL.md +2 -0
  47. package/payload/platform/plugins/deep-research/skills/strategic-reading/SKILL.md +2 -0
  48. package/payload/platform/plugins/email/PLUGIN.md +2 -0
  49. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +42 -11
  50. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  51. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +123 -57
  52. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  53. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.d.ts.map +1 -1
  54. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js +4 -2
  55. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js.map +1 -1
  56. package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts.map +1 -1
  57. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js +18 -8
  58. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js.map +1 -1
  59. package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts.map +1 -1
  60. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js +18 -8
  61. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js.map +1 -1
  62. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +2 -0
  63. package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +2 -0
  64. package/payload/platform/plugins/graph-viewer/skills/render-graph/SKILL.md +2 -0
  65. package/payload/platform/plugins/linkedin-extension/skills/linkedin-extension/SKILL.md +2 -0
  66. package/payload/platform/plugins/memory/skills/archive-crawler/SKILL.md +2 -0
  67. package/payload/platform/plugins/memory/skills/challenge/SKILL.md +2 -0
  68. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +2 -0
  69. package/payload/platform/plugins/memory/skills/connect/SKILL.md +2 -0
  70. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +2 -0
  71. package/payload/platform/plugins/memory/skills/emerge/SKILL.md +2 -0
  72. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +2 -0
  73. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +3 -1
  74. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/__tests__/restatement-ladder.test.sh +21 -0
  75. package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +2 -0
  76. package/payload/platform/plugins/scheduling/skills/daily-prep/SKILL.md +2 -0
  77. package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +2 -0
  78. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +2 -0
  79. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -0
  80. package/payload/platform/plugins/work/skills/execute-task/SKILL.md +2 -0
  81. package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +2 -0
  82. package/payload/platform/scripts/lib/__tests__/admin-skills-bootstrap.test.sh +64 -0
  83. package/payload/platform/scripts/lib/admin-skills-bootstrap.sh +109 -0
  84. package/payload/platform/scripts/setup-account.sh +8 -0
  85. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  86. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +43 -11
  87. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  88. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  89. package/payload/platform/services/claude-session-manager/dist/http-server.js +74 -1
  90. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  91. package/payload/platform/services/claude-session-manager/dist/index.js +48 -2
  92. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  93. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.d.ts +19 -0
  94. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.d.ts.map +1 -0
  95. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.js +38 -0
  96. package/payload/platform/services/claude-session-manager/dist/liveness-divergence.js.map +1 -0
  97. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +8 -0
  98. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  99. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +12 -0
  100. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  101. package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts +11 -0
  102. package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts.map +1 -0
  103. package/payload/platform/services/claude-session-manager/dist/scope-record.js +81 -0
  104. package/payload/platform/services/claude-session-manager/dist/scope-record.js.map +1 -0
  105. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +10 -7
  106. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  107. package/payload/platform/services/whatsapp-channel/dist/notification.js +14 -14
  108. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  109. package/payload/platform/templates/agents/admin/IDENTITY.md +2 -6
  110. package/payload/server/public/assets/AdminShell-C6_5h1cC.js +1 -0
  111. package/payload/server/public/assets/{admin-xRCXEFNW.js → admin-BpnsTEa3.js} +1 -1
  112. package/payload/server/public/assets/{browser-DT2XfRpL.js → browser-fgBRZ5gK.js} +1 -1
  113. package/payload/server/public/assets/{data-Dr7XUvAx.js → data-Cuynp6Y6.js} +1 -1
  114. package/payload/server/public/assets/{graph-DOEjjQHD.js → graph-Ddg24bjy.js} +1 -1
  115. package/payload/server/public/assets/{whatsapp-cDxgZkbM.js → whatsapp-BE79pNh8.js} +1 -1
  116. package/payload/server/public/browser.html +2 -2
  117. package/payload/server/public/data.html +2 -2
  118. package/payload/server/public/graph.html +2 -2
  119. package/payload/server/public/index.html +2 -2
  120. package/payload/server/public/whatsapp.html +2 -2
  121. package/payload/server/server.js +338 -461
  122. package/payload/server/public/assets/AdminShell-DnH3kou-.js +0 -1
@@ -1201,8 +1201,8 @@ var serveStatic = (options = { root: "" }) => {
1201
1201
  };
1202
1202
 
1203
1203
  // server/index.ts
1204
- import { readFileSync as readFileSync24, existsSync as existsSync24, watchFile } from "fs";
1205
- import { resolve as resolve27, join as join19, basename as basename7 } from "path";
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
1206
  import { homedir as homedir2 } from "os";
1207
1207
  import { monitorEventLoopDelay } from "perf_hooks";
1208
1208
 
@@ -1763,7 +1763,7 @@ var credsSaveQueue = Promise.resolve();
1763
1763
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
1764
1764
  console.error(`${TAG2} draining credential save queue\u2026`);
1765
1765
  const timer2 = new Promise(
1766
- (resolve28) => setTimeout(() => resolve28("timeout"), timeoutMs)
1766
+ (resolve27) => setTimeout(() => resolve27("timeout"), timeoutMs)
1767
1767
  );
1768
1768
  const result = await Promise.race([
1769
1769
  credsSaveQueue.then(() => "drained"),
@@ -1891,11 +1891,11 @@ async function createWaSocket(opts) {
1891
1891
  return sock;
1892
1892
  }
1893
1893
  async function waitForConnection(sock) {
1894
- return new Promise((resolve28, reject) => {
1894
+ return new Promise((resolve27, reject) => {
1895
1895
  const handler = (update) => {
1896
1896
  if (update.connection === "open") {
1897
1897
  sock.ev.off("connection.update", handler);
1898
- resolve28();
1898
+ resolve27();
1899
1899
  }
1900
1900
  if (update.connection === "close") {
1901
1901
  sock.ev.off("connection.update", handler);
@@ -2009,14 +2009,14 @@ ${inspected}`;
2009
2009
  return inspect2(err, INSPECT_OPTS2);
2010
2010
  }
2011
2011
  function withTimeout(label, promise, timeoutMs) {
2012
- return new Promise((resolve28, reject) => {
2012
+ return new Promise((resolve27, reject) => {
2013
2013
  const timer2 = setTimeout(() => {
2014
2014
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
2015
2015
  }, timeoutMs);
2016
2016
  promise.then(
2017
2017
  (value) => {
2018
2018
  clearTimeout(timer2);
2019
- resolve28(value);
2019
+ resolve27(value);
2020
2020
  },
2021
2021
  (err) => {
2022
2022
  clearTimeout(timer2);
@@ -2601,8 +2601,8 @@ async function persistWhatsAppMessage(input) {
2601
2601
  const { givenName, familyName } = splitName(input.pushName);
2602
2602
  const prev = sessionWriteLocks.get(input.cacheKey);
2603
2603
  let release;
2604
- const mine = new Promise((resolve28) => {
2605
- release = resolve28;
2604
+ const mine = new Promise((resolve27) => {
2605
+ release = resolve27;
2606
2606
  });
2607
2607
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2608
2608
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -3069,6 +3069,14 @@ function createInboundDebouncer(opts) {
3069
3069
  return { enqueue, flush, destroy, registerPending };
3070
3070
  }
3071
3071
 
3072
+ // app/lib/whatsapp/inbound/combine-batch.ts
3073
+ function combineInboundBatch(entries) {
3074
+ const last = entries[entries.length - 1];
3075
+ const combinedText = entries.map((e) => e.text).filter(Boolean).join("\n");
3076
+ const media = entries.flatMap((e) => e.media);
3077
+ return { ...last, text: combinedText, media };
3078
+ }
3079
+
3072
3080
  // app/lib/whatsapp/opening-hours.ts
3073
3081
  var TAG10 = "[whatsapp:hours]";
3074
3082
  async function isBusinessOpen(accountId) {
@@ -3638,11 +3646,11 @@ async function connectWithReconnect(conn) {
3638
3646
  console.error(
3639
3647
  `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3640
3648
  );
3641
- await new Promise((resolve28) => {
3642
- const timer2 = setTimeout(resolve28, delay);
3649
+ await new Promise((resolve27) => {
3650
+ const timer2 = setTimeout(resolve27, delay);
3643
3651
  conn.abortController.signal.addEventListener("abort", () => {
3644
3652
  clearTimeout(timer2);
3645
- resolve28();
3653
+ resolve27();
3646
3654
  }, { once: true });
3647
3655
  });
3648
3656
  }
@@ -3650,16 +3658,16 @@ async function connectWithReconnect(conn) {
3650
3658
  }
3651
3659
  }
3652
3660
  function waitForDisconnectEvent(conn) {
3653
- return new Promise((resolve28) => {
3661
+ return new Promise((resolve27) => {
3654
3662
  if (!conn.sock) {
3655
- resolve28();
3663
+ resolve27();
3656
3664
  return;
3657
3665
  }
3658
3666
  const sock = conn.sock;
3659
3667
  const handler = (update) => {
3660
3668
  if (update.connection === "close") {
3661
3669
  sock.ev.off("connection.update", handler);
3662
- resolve28();
3670
+ resolve27();
3663
3671
  }
3664
3672
  };
3665
3673
  sock.ev.on("connection.update", handler);
@@ -3723,21 +3731,10 @@ function monitorInbound(conn) {
3723
3731
  },
3724
3732
  onFlush: (entries) => {
3725
3733
  if (!onInboundMessage) return;
3726
- if (entries.length === 1) {
3727
- onInboundMessage(entries[0]);
3728
- return;
3734
+ if (entries.length > 1) {
3735
+ console.error(`${TAG12} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
3729
3736
  }
3730
- console.error(`${TAG12} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
3731
- const last = entries[entries.length - 1];
3732
- const mediaEntry = entries.find((e) => e.mediaPath);
3733
- const combinedText = entries.map((e) => e.text).filter(Boolean).join("\n");
3734
- onInboundMessage({
3735
- ...last,
3736
- text: combinedText,
3737
- mediaPath: mediaEntry?.mediaPath ?? last.mediaPath,
3738
- mediaMimetype: mediaEntry?.mediaMimetype ?? last.mediaMimetype,
3739
- mediaType: mediaEntry?.mediaType ?? last.mediaType
3740
- });
3737
+ onInboundMessage(combineInboundBatch(entries));
3741
3738
  },
3742
3739
  onError: (err) => {
3743
3740
  console.error(`${TAG12} debounce flush error account=${conn.accountId}: ${String(err)}`);
@@ -3899,6 +3896,7 @@ async function handleInboundMessage(conn, msg) {
3899
3896
  groupJid: isGroup2 ? remoteJid : void 0,
3900
3897
  isOwnerMirror: true
3901
3898
  }),
3899
+ media: [],
3902
3900
  isOwnerMirror: true
3903
3901
  });
3904
3902
  return;
@@ -3928,8 +3926,8 @@ async function handleInboundMessage(conn, msg) {
3928
3926
  const conversationKey = isGroup ? remoteJid : senderPhone;
3929
3927
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
3930
3928
  let resolvePending;
3931
- const sttPending = new Promise((resolve28) => {
3932
- resolvePending = resolve28;
3929
+ const sttPending = new Promise((resolve27) => {
3930
+ resolvePending = resolve27;
3933
3931
  });
3934
3932
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
3935
3933
  try {
@@ -4010,9 +4008,7 @@ async function handleInboundMessage(conn, msg) {
4010
4008
  reply,
4011
4009
  composing,
4012
4010
  cacheKey,
4013
- mediaPath: mediaResult?.path,
4014
- mediaMimetype: mediaResult?.mimetype,
4015
- mediaType: extracted.mediaType,
4011
+ media: mediaResult?.path ? [{ path: mediaResult.path, type: extracted.mediaType, mimetype: mediaResult.mimetype }] : [],
4016
4012
  replyContext: extracted.quotedMessage
4017
4013
  };
4018
4014
  if (accessResult.agentType === "public") {
@@ -4338,20 +4334,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
4338
4334
 
4339
4335
  // server/routes/health.ts
4340
4336
  function checkPort(port2, timeoutMs = 500) {
4341
- return new Promise((resolve28) => {
4337
+ return new Promise((resolve27) => {
4342
4338
  const socket = createConnection2(port2, "127.0.0.1");
4343
4339
  socket.setTimeout(timeoutMs);
4344
4340
  socket.once("connect", () => {
4345
4341
  socket.destroy();
4346
- resolve28(true);
4342
+ resolve27(true);
4347
4343
  });
4348
4344
  socket.once("error", () => {
4349
4345
  socket.destroy();
4350
- resolve28(false);
4346
+ resolve27(false);
4351
4347
  });
4352
4348
  socket.once("timeout", () => {
4353
4349
  socket.destroy();
4354
- resolve28(false);
4350
+ resolve27(false);
4355
4351
  });
4356
4352
  });
4357
4353
  }
@@ -5426,12 +5422,12 @@ async function dispatchOnce(input) {
5426
5422
  });
5427
5423
  if (!entry) return { error: "spawn-failed" };
5428
5424
  entry.lastInboundAt = Date.now();
5429
- let resolve28;
5425
+ let resolve27;
5430
5426
  const turnPromise = new Promise((r) => {
5431
- resolve28 = r;
5427
+ resolve27 = r;
5432
5428
  });
5433
5429
  const listener = (text) => {
5434
- resolve28(text);
5430
+ resolve27(text);
5435
5431
  };
5436
5432
  entry.subscribers.add(listener);
5437
5433
  const writeAtMs = Date.now();
@@ -6269,8 +6265,8 @@ async function startLogin(opts) {
6269
6265
  await clearAuth(authDir);
6270
6266
  let resolveCode = null;
6271
6267
  let rejectCode = null;
6272
- const codePromise = new Promise((resolve28, reject) => {
6273
- resolveCode = resolve28;
6268
+ const codePromise = new Promise((resolve27, reject) => {
6269
+ resolveCode = resolve27;
6274
6270
  rejectCode = reject;
6275
6271
  });
6276
6272
  const codeTimer = setTimeout(
@@ -6994,7 +6990,6 @@ import { basename as basename2, dirname, join as join8, resolve as resolve9, sep
6994
6990
  import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
6995
6991
  import { join as join7, resolve as resolve8 } from "path";
6996
6992
  var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
6997
- var PID_FILE_RE = /^([0-9]+)\.json$/;
6998
6993
  var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
6999
6994
  var PUBLIC_ROLE = "public";
7000
6995
  var WEBCHAT_CHANNEL = "webchat";
@@ -7044,36 +7039,25 @@ function enumerateJsonls(projectsRoot) {
7044
7039
  }
7045
7040
  return out;
7046
7041
  }
7047
- function sessionIdToPidMap(configDir2) {
7042
+ async function fetchLiveSessions() {
7048
7043
  const out = /* @__PURE__ */ new Map();
7049
- const sessionsDir = join7(configDir2, "sessions");
7050
- let entries;
7044
+ let port2;
7051
7045
  try {
7052
- entries = readdirSync4(sessionsDir, { withFileTypes: true });
7046
+ port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "sidebar-sessions:live" });
7053
7047
  } catch {
7048
+ console.error("[admin-sessions-list] CLAUDE_SESSION_MANAGER_PORT unset; liveness unknown");
7054
7049
  return out;
7055
7050
  }
7056
- for (const entry of entries) {
7057
- if (!entry.isFile()) continue;
7058
- const m = entry.name.match(PID_FILE_RE);
7059
- if (!m) continue;
7060
- const pid = Number(m[1]);
7061
- if (!Number.isFinite(pid) || pid <= 0) continue;
7062
- let body;
7063
- try {
7064
- body = readFileSync8(join7(sessionsDir, entry.name), "utf8");
7065
- } catch {
7066
- continue;
7067
- }
7068
- let parsed;
7069
- try {
7070
- parsed = JSON.parse(body);
7071
- } catch {
7072
- continue;
7051
+ try {
7052
+ const res = await fetch(`http://127.0.0.1:${port2}/live-sessions`);
7053
+ if (!res.ok) {
7054
+ console.error(`[admin-sessions-list] live-sessions status=${res.status}; liveness unknown`);
7055
+ return out;
7073
7056
  }
7074
- if (!parsed || typeof parsed !== "object") continue;
7075
- const sid = parsed.sessionId;
7076
- if (typeof sid === "string" && sid.length > 0) out.set(sid, pid);
7057
+ const body = await res.json();
7058
+ for (const s of body.sessions) out.set(s.sessionId, s.pid);
7059
+ } catch (err) {
7060
+ console.error(`[admin-sessions-list] live-sessions fetch failed: ${err instanceof Error ? err.message : String(err)}; liveness unknown`);
7077
7061
  }
7078
7062
  return out;
7079
7063
  }
@@ -7179,7 +7163,7 @@ app4.get("/", requireAdminSession, async (c) => {
7179
7163
  }
7180
7164
  const projectsRoot = join7(configDir2, "projects");
7181
7165
  const jsonls = enumerateJsonls(projectsRoot);
7182
- const pidsBySession = sessionIdToPidMap(configDir2);
7166
+ const liveSessions = await fetchLiveSessions();
7183
7167
  const accountDir = accountId ? resolve8(ACCOUNTS_DIR, accountId) : null;
7184
7168
  const userTitles = loadUserTitles(accountDir);
7185
7169
  const rows = [];
@@ -7206,8 +7190,8 @@ app4.get("/", requireAdminSession, async (c) => {
7206
7190
  } catch {
7207
7191
  continue;
7208
7192
  }
7209
- const pid = pidsBySession.get(sessionId) ?? null;
7210
- const live = pid !== null;
7193
+ const live = liveSessions.has(sessionId);
7194
+ const pid = live ? liveSessions.get(sessionId) ?? null : null;
7211
7195
  const resolved = resolveTitle(body, sessionId, userTitles);
7212
7196
  titleSourceCounts[resolved.source] += 1;
7213
7197
  const metaPath = join7(projectDir, `${sessionId}.meta.json`);
@@ -8892,11 +8876,11 @@ app13.delete("/:id", requireAdminSession, async (c) => {
8892
8876
  const owned = await verifyConversationOwnership(sessionId, accountId);
8893
8877
  if (!owned) return c.json({ error: "Conversation not found" }, 404);
8894
8878
  const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "admin-conversation-delete" });
8895
- const managerBase5 = `http://127.0.0.1:${managerPort}`;
8879
+ const managerBase7 = `http://127.0.0.1:${managerPort}`;
8896
8880
  const outcome = await cascadeAdminConversationDelete({
8897
8881
  sessionId,
8898
8882
  accountId,
8899
- managerBase: managerBase5
8883
+ managerBase: managerBase7
8900
8884
  });
8901
8885
  if (outcome.ok) return c.json({ ok: true, claudeSessionIds: outcome.claudeSessionIds });
8902
8886
  if (outcome.reason === "pty-still-alive") {
@@ -12564,7 +12548,7 @@ app20.post("/", requireAdminSession, async (c) => {
12564
12548
  return c.json({ error: "AdminConversation node is missing sessionId" }, 500);
12565
12549
  }
12566
12550
  const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "graph-page-cascade" });
12567
- const managerBase5 = `http://127.0.0.1:${managerPort}`;
12551
+ const managerBase7 = `http://127.0.0.1:${managerPort}`;
12568
12552
  try {
12569
12553
  await session.close();
12570
12554
  } catch {
@@ -12572,7 +12556,7 @@ app20.post("/", requireAdminSession, async (c) => {
12572
12556
  const outcome = await cascadeAdminConversationDelete({
12573
12557
  sessionId,
12574
12558
  accountId,
12575
- managerBase: managerBase5
12559
+ managerBase: managerBase7
12576
12560
  });
12577
12561
  const elapsed2 = Date.now() - started;
12578
12562
  const labelSummary2 = preflightLabels.join(",");
@@ -13126,106 +13110,60 @@ function isWithin(target, root) {
13126
13110
  var sidebar_artefacts_default = app24;
13127
13111
 
13128
13112
  // server/routes/admin/session-delete.ts
13129
- import { existsSync as existsSync18, readdirSync as readdirSync10, readFileSync as readFileSync17, unlinkSync as unlinkSync2 } from "fs";
13130
- import { join as join16, resolve as resolve19 } from "path";
13131
13113
  var app25 = new Hono();
13132
13114
  var SESSION_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13133
- var PID_FILE_RE2 = /^([0-9]+)\.json$/;
13134
- var SIGTERM_WAIT_MS = 2e3;
13135
- var SIGKILL_WAIT_MS = 1e3;
13136
- var POLL_INTERVAL_MS = 50;
13137
- function findPidForSession(configDir2, sessionId) {
13138
- const sessionsDir = join16(configDir2, "sessions");
13139
- let entries;
13115
+ function managerBase4() {
13116
+ const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "session-delete:wrapper" });
13117
+ return `http://127.0.0.1:${port2}`;
13118
+ }
13119
+ app25.post("/", requireAdminSession, async (c) => {
13120
+ let body;
13140
13121
  try {
13141
- entries = readdirSync10(sessionsDir, { withFileTypes: true });
13122
+ body = await c.req.json();
13142
13123
  } catch {
13143
- return null;
13124
+ return c.json({ error: "invalid JSON body" }, 400);
13144
13125
  }
13145
- for (const entry of entries) {
13146
- if (!entry.isFile()) continue;
13147
- const m = entry.name.match(PID_FILE_RE2);
13148
- if (!m) continue;
13149
- const pid = Number(m[1]);
13150
- if (!Number.isFinite(pid) || pid <= 0) continue;
13151
- let body;
13152
- try {
13153
- body = readFileSync17(join16(sessionsDir, entry.name), "utf8");
13154
- } catch {
13155
- continue;
13156
- }
13157
- let parsed;
13158
- try {
13159
- parsed = JSON.parse(body);
13160
- } catch {
13161
- continue;
13162
- }
13163
- if (!parsed || typeof parsed !== "object") continue;
13164
- if (parsed.sessionId === sessionId) return pid;
13126
+ const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
13127
+ if (!SESSION_ID_RE3.test(sessionId)) {
13128
+ return c.json({ error: "sessionId must be a v4 UUID" }, 400);
13165
13129
  }
13166
- return null;
13167
- }
13168
- function isPidAlive(pid) {
13130
+ const base = managerBase4();
13169
13131
  try {
13170
- process.kill(pid, 0);
13171
- return true;
13132
+ const stop = await fetch(`${base}/${sessionId}/stop`, { method: "POST" });
13133
+ if (stop.status !== 204 && stop.status !== 200 && stop.status !== 404) {
13134
+ console.error(`[session-delete] sessionId=${sessionId} stop-status=${stop.status}`);
13135
+ return c.json({ error: `stop-failed-${stop.status}` }, 502);
13136
+ }
13172
13137
  } catch (err) {
13173
- const code = err.code;
13174
- if (code === "ESRCH") return false;
13175
- return true;
13138
+ console.error(`[session-delete] sessionId=${sessionId} stop-unreachable err=${err instanceof Error ? err.message : String(err)}`);
13139
+ return c.json({ error: "manager-unreachable" }, 502);
13176
13140
  }
13177
- }
13178
- function sleep2(ms) {
13179
- return new Promise((resolve28) => setTimeout(resolve28, ms));
13180
- }
13181
- function sendSignal(pid, signal) {
13141
+ let del;
13182
13142
  try {
13183
- process.kill(pid, signal);
13184
- return true;
13143
+ del = await fetch(`${base}/${sessionId}`, { method: "DELETE" });
13185
13144
  } catch (err) {
13186
- const code = err.code;
13187
- if (code === "ESRCH") return true;
13188
- return false;
13145
+ console.error(`[session-delete] sessionId=${sessionId} delete-unreachable err=${err instanceof Error ? err.message : String(err)}`);
13146
+ return c.json({ error: "manager-unreachable" }, 502);
13189
13147
  }
13190
- }
13191
- async function killAndWait(pid) {
13192
- const startedAt = Date.now();
13193
- let escalated = false;
13194
- const termSent = sendSignal(pid, "SIGTERM");
13195
- const termDeadline = Date.now() + SIGTERM_WAIT_MS;
13196
- while (Date.now() < termDeadline) {
13197
- if (!isPidAlive(pid)) {
13198
- return {
13199
- pidKilled: termSent ? "true" : "false",
13200
- waitForExitMs: Date.now() - startedAt,
13201
- escalatedToSIGKILL: false,
13202
- exited: true
13203
- };
13204
- }
13205
- await sleep2(POLL_INTERVAL_MS);
13206
- }
13207
- escalated = true;
13208
- sendSignal(pid, "SIGKILL");
13209
- const killDeadline = Date.now() + SIGKILL_WAIT_MS;
13210
- while (Date.now() < killDeadline) {
13211
- if (!isPidAlive(pid)) {
13212
- return {
13213
- pidKilled: "true",
13214
- waitForExitMs: Date.now() - startedAt,
13215
- escalatedToSIGKILL: true,
13216
- exited: true
13217
- };
13218
- }
13219
- await sleep2(POLL_INTERVAL_MS);
13148
+ if (del.status === 204) {
13149
+ console.log(`[session-delete] sessionId=${sessionId} deleted`);
13150
+ return c.json({ deleted: true });
13220
13151
  }
13221
- return {
13222
- pidKilled: "false",
13223
- waitForExitMs: Date.now() - startedAt,
13224
- escalatedToSIGKILL: escalated,
13225
- exited: false
13226
- };
13152
+ if (del.status === 404) return c.json({ deleted: false, error: "no-transcript" }, 404);
13153
+ if (del.status === 409) return c.json({ deleted: false, error: "pty-still-alive" }, 409);
13154
+ console.error(`[session-delete] sessionId=${sessionId} delete-status=${del.status}`);
13155
+ return c.json({ error: `manager-status-${del.status}` }, 502);
13156
+ });
13157
+ var session_delete_default = app25;
13158
+
13159
+ // server/routes/admin/session-stop.ts
13160
+ var app26 = new Hono();
13161
+ var SESSION_ID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13162
+ function managerBase5() {
13163
+ const port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "session-stop:wrapper" });
13164
+ return `http://127.0.0.1:${port2}`;
13227
13165
  }
13228
- app25.post("/", requireAdminSession, async (c) => {
13166
+ app26.post("/", requireAdminSession, async (c) => {
13229
13167
  let body;
13230
13168
  try {
13231
13169
  body = await c.req.json();
@@ -13233,91 +13171,33 @@ app25.post("/", requireAdminSession, async (c) => {
13233
13171
  return c.json({ error: "invalid JSON body" }, 400);
13234
13172
  }
13235
13173
  const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
13236
- const projectDir = typeof body.projectDir === "string" ? body.projectDir : "";
13237
- if (!SESSION_ID_RE3.test(sessionId)) {
13174
+ if (!SESSION_ID_RE4.test(sessionId)) {
13238
13175
  return c.json({ error: "sessionId must be a v4 UUID" }, 400);
13239
13176
  }
13240
- if (!projectDir) {
13241
- return c.json({ error: "projectDir is required" }, 400);
13242
- }
13243
- const configDir2 = process.env.CLAUDE_CONFIG_DIR;
13244
- if (!configDir2) {
13245
- return c.json({ error: "CLAUDE_CONFIG_DIR not set" }, 500);
13246
- }
13247
- const projectsRoot = resolve19(join16(configDir2, "projects")) + "/";
13248
- const resolvedProject = resolve19(projectDir) + "/";
13249
- if (!resolvedProject.startsWith(projectsRoot)) {
13250
- console.error(`[sessions-delete] reject reason=projectDir-outside-tree projectDir=${projectDir}`);
13251
- return c.json({ error: "projectDir is not under CLAUDE_CONFIG_DIR/projects/" }, 400);
13252
- }
13253
- const jsonlPath = join16(projectDir, `${sessionId}.jsonl`);
13254
- const sidecarPath = join16(projectDir, `${sessionId}.meta.json`);
13255
- const pid = findPidForSession(configDir2, sessionId);
13256
- let pidKilled = "absent";
13257
- let waitForExitMs = 0;
13258
- let escalatedToSIGKILL = false;
13259
- if (pid !== null) {
13260
- const r = await killAndWait(pid);
13261
- pidKilled = r.pidKilled;
13262
- waitForExitMs = r.waitForExitMs;
13263
- escalatedToSIGKILL = r.escalatedToSIGKILL;
13264
- if (!r.exited) {
13265
- console.error(
13266
- `[sessions-delete] kill-failed sessionId=${sessionId} pid=${pid} waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
13267
- );
13268
- return c.json(
13269
- { error: "kill-failed", pid, waitForExitMs, escalatedToSIGKILL },
13270
- 500
13271
- );
13272
- }
13273
- }
13274
- let deleted = false;
13177
+ let res;
13275
13178
  try {
13276
- if (existsSync18(jsonlPath)) {
13277
- unlinkSync2(jsonlPath);
13278
- deleted = true;
13279
- }
13179
+ res = await fetch(`${managerBase5()}/${sessionId}/stop`, { method: "POST" });
13280
13180
  } catch (err) {
13281
- const msg = err instanceof Error ? err.message : String(err);
13282
- console.error(`[sessions-delete] unlink-failed path=${jsonlPath} err=${msg}`);
13283
- console.log(
13284
- `[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=false waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
13285
- );
13286
- return c.json({ error: `unlink failed: ${msg}` }, 500);
13287
- }
13288
- try {
13289
- if (existsSync18(sidecarPath)) unlinkSync2(sidecarPath);
13290
- } catch {
13291
- }
13292
- if (pid !== null) {
13293
- try {
13294
- const pidFile = join16(configDir2, "sessions", `${pid}.json`);
13295
- if (existsSync18(pidFile)) unlinkSync2(pidFile);
13296
- } catch {
13297
- }
13181
+ console.error(`[session-stop] sessionId=${sessionId} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
13182
+ return c.json({ error: "manager-unreachable" }, 502);
13298
13183
  }
13299
- if (existsSync18(jsonlPath)) {
13300
- console.error(`[sessions-delete] resurrection jsonlPath=${jsonlPath} sessionId=${sessionId}`);
13301
- return c.json(
13302
- { error: "jsonl-resurrected", jsonlPath, pidKilled, waitForExitMs, escalatedToSIGKILL },
13303
- 500
13304
- );
13184
+ if (res.status === 204 || res.status === 200 || res.status === 404) {
13185
+ console.log(`[session-stop] sessionId=${sessionId} stopped manager-status=${res.status}`);
13186
+ return c.json({ stopped: true });
13305
13187
  }
13306
- console.log(
13307
- `[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=${deleted} waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
13308
- );
13309
- return c.json({ deleted, pidKilled, jsonlPath, waitForExitMs, escalatedToSIGKILL });
13188
+ console.error(`[session-stop] sessionId=${sessionId} manager-status=${res.status}`);
13189
+ return c.json({ error: `manager-status-${res.status}` }, 502);
13310
13190
  });
13311
- var session_delete_default = app25;
13191
+ var session_stop_default = app26;
13312
13192
 
13313
13193
  // server/routes/admin/session-rc-spawn.ts
13314
- var app26 = new Hono();
13315
- function managerBase4() {
13194
+ var app27 = new Hono();
13195
+ function managerBase6() {
13316
13196
  const port2 = process.env.CLAUDE_SESSION_MANAGER_PORT;
13317
13197
  if (!port2) throw new Error("CLAUDE_SESSION_MANAGER_PORT is not set");
13318
13198
  return `http://127.0.0.1:${port2}`;
13319
13199
  }
13320
- app26.post("/", requireAdminSession, async (c) => {
13200
+ app27.post("/", requireAdminSession, async (c) => {
13321
13201
  let body;
13322
13202
  try {
13323
13203
  body = await c.req.json();
@@ -13329,7 +13209,7 @@ app26.post("/", requireAdminSession, async (c) => {
13329
13209
  if (typeof body.name === "string" && body.name.length > 0) payload.name = body.name;
13330
13210
  let res;
13331
13211
  try {
13332
- res = await fetch(`${managerBase4()}/rc-spawn`, {
13212
+ res = await fetch(`${managerBase6()}/rc-spawn`, {
13333
13213
  method: "POST",
13334
13214
  headers: { "content-type": "application/json" },
13335
13215
  body: JSON.stringify(payload)
@@ -13351,7 +13231,7 @@ app26.post("/", requireAdminSession, async (c) => {
13351
13231
  }
13352
13232
  return c.json(parsed ?? {});
13353
13233
  });
13354
- var session_rc_spawn_default = app26;
13234
+ var session_rc_spawn_default = app27;
13355
13235
 
13356
13236
  // server/routes/admin/system-stats.ts
13357
13237
  import { readFile as readFile5 } from "fs/promises";
@@ -13448,8 +13328,8 @@ async function sample() {
13448
13328
  if (process.platform === "linux") return sampleLinux();
13449
13329
  return sampleOsFallback();
13450
13330
  }
13451
- var app27 = new Hono();
13452
- app27.get("/", async (c) => {
13331
+ var app28 = new Hono();
13332
+ app28.get("/", async (c) => {
13453
13333
  const started = Date.now();
13454
13334
  if (!inflight) {
13455
13335
  inflight = sample().finally(() => {
@@ -13472,27 +13352,27 @@ app27.get("/", async (c) => {
13472
13352
  return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
13473
13353
  }
13474
13354
  });
13475
- var system_stats_default = app27;
13355
+ var system_stats_default = app28;
13476
13356
 
13477
13357
  // server/routes/admin/health.ts
13478
- import { existsSync as existsSync19, readFileSync as readFileSync18 } from "fs";
13479
- import { resolve as resolve20, join as join17 } from "path";
13480
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
13358
+ import { existsSync as existsSync18, readFileSync as readFileSync17 } from "fs";
13359
+ import { resolve as resolve19, join as join16 } from "path";
13360
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
13481
13361
  var brandHostname = "maxy";
13482
- var brandJsonPath = join17(PLATFORM_ROOT6, "config", "brand.json");
13483
- if (existsSync19(brandJsonPath)) {
13362
+ var brandJsonPath = join16(PLATFORM_ROOT6, "config", "brand.json");
13363
+ if (existsSync18(brandJsonPath)) {
13484
13364
  try {
13485
- const brand = JSON.parse(readFileSync18(brandJsonPath, "utf-8"));
13365
+ const brand = JSON.parse(readFileSync17(brandJsonPath, "utf-8"));
13486
13366
  if (brand.hostname) brandHostname = brand.hostname;
13487
13367
  } catch {
13488
13368
  }
13489
13369
  }
13490
- var VERSION_FILE = resolve20(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
13370
+ var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
13491
13371
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
13492
13372
  var PROBE_TIMEOUT_MS = 1e3;
13493
13373
  function readVersion() {
13494
- if (!existsSync19(VERSION_FILE)) return "unknown";
13495
- return readFileSync18(VERSION_FILE, "utf-8").trim() || "unknown";
13374
+ if (!existsSync18(VERSION_FILE)) return "unknown";
13375
+ return readFileSync17(VERSION_FILE, "utf-8").trim() || "unknown";
13496
13376
  }
13497
13377
  async function probeConversationDb() {
13498
13378
  let session;
@@ -13517,8 +13397,8 @@ async function probeConversationDb() {
13517
13397
  });
13518
13398
  }
13519
13399
  }
13520
- var app28 = new Hono();
13521
- app28.get("/", async (c) => {
13400
+ var app29 = new Hono();
13401
+ app29.get("/", async (c) => {
13522
13402
  const version = readVersion();
13523
13403
  const probe = await probeConversationDb();
13524
13404
  const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
@@ -13540,7 +13420,7 @@ app28.get("/", async (c) => {
13540
13420
  uptimeMs
13541
13421
  });
13542
13422
  });
13543
- var health_default2 = app28;
13423
+ var health_default2 = app29;
13544
13424
 
13545
13425
  // server/routes/admin/linkedin-ingest.ts
13546
13426
  import { randomUUID as randomUUID9 } from "crypto";
@@ -13642,8 +13522,8 @@ function buildInitialMessage(env) {
13642
13522
  }
13643
13523
  return header;
13644
13524
  }
13645
- var app29 = new Hono();
13646
- app29.post("/", requireAdminSession, async (c) => {
13525
+ var app30 = new Hono();
13526
+ app30.post("/", requireAdminSession, async (c) => {
13647
13527
  let body;
13648
13528
  try {
13649
13529
  body = await c.req.json();
@@ -13688,7 +13568,7 @@ app29.post("/", requireAdminSession, async (c) => {
13688
13568
  );
13689
13569
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
13690
13570
  });
13691
- var linkedin_ingest_default = app29;
13571
+ var linkedin_ingest_default = app30;
13692
13572
 
13693
13573
  // server/routes/admin/post-turn-context.ts
13694
13574
  import neo4j2 from "neo4j-driver";
@@ -13730,8 +13610,8 @@ function pruneProperties(raw) {
13730
13610
  }
13731
13611
  return out;
13732
13612
  }
13733
- var app30 = new Hono();
13734
- app30.get("/", async (c) => {
13613
+ var app31 = new Hono();
13614
+ app31.get("/", async (c) => {
13735
13615
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13736
13616
  if (!isLoopbackAddr2(remoteAddr)) {
13737
13617
  console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -13791,7 +13671,7 @@ app30.get("/", async (c) => {
13791
13671
  await session.close();
13792
13672
  }
13793
13673
  });
13794
- var post_turn_context_default = app30;
13674
+ var post_turn_context_default = app31;
13795
13675
 
13796
13676
  // server/routes/admin/public-session-context.ts
13797
13677
  import neo4j3 from "neo4j-driver";
@@ -13833,8 +13713,8 @@ function pruneProperties2(raw) {
13833
13713
  }
13834
13714
  return out;
13835
13715
  }
13836
- var app31 = new Hono();
13837
- app31.get("/", async (c) => {
13716
+ var app32 = new Hono();
13717
+ app32.get("/", async (c) => {
13838
13718
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13839
13719
  if (!isLoopbackAddr3(remoteAddr)) {
13840
13720
  console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -13893,15 +13773,15 @@ app31.get("/", async (c) => {
13893
13773
  await session.close();
13894
13774
  }
13895
13775
  });
13896
- var public_session_context_default = app31;
13776
+ var public_session_context_default = app32;
13897
13777
 
13898
13778
  // server/routes/admin/public-session-exit.ts
13899
13779
  var TAG26 = "[public-session-exit-route]";
13900
13780
  function isLoopbackAddr4(addr) {
13901
13781
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
13902
13782
  }
13903
- var app32 = new Hono();
13904
- app32.post("/", async (c) => {
13783
+ var app33 = new Hono();
13784
+ app33.post("/", async (c) => {
13905
13785
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13906
13786
  if (!isLoopbackAddr4(remoteAddr)) {
13907
13787
  console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -13928,15 +13808,15 @@ app32.post("/", async (c) => {
13928
13808
  handlePublicSessionExit(sessionId);
13929
13809
  return c.json({ ok: true });
13930
13810
  });
13931
- var public_session_exit_default = app32;
13811
+ var public_session_exit_default = app33;
13932
13812
 
13933
13813
  // server/routes/admin/access-session-evict.ts
13934
13814
  var TAG27 = "[access-session-evict]";
13935
13815
  function isLoopbackAddr5(addr) {
13936
13816
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
13937
13817
  }
13938
- var app33 = new Hono();
13939
- app33.post("/", async (c) => {
13818
+ var app34 = new Hono();
13819
+ app34.post("/", async (c) => {
13940
13820
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
13941
13821
  if (!isLoopbackAddr5(remoteAddr)) {
13942
13822
  console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -13964,11 +13844,11 @@ app33.post("/", async (c) => {
13964
13844
  console.log(`${TAG27} grantId=${grantId} dropped=${dropped}`);
13965
13845
  return c.json({ ok: true, dropped });
13966
13846
  });
13967
- var access_session_evict_default = app33;
13847
+ var access_session_evict_default = app34;
13968
13848
 
13969
13849
  // server/routes/admin/browser.ts
13970
- var app34 = new Hono();
13971
- app34.post("/launch", requireAdminSession, async (c) => {
13850
+ var app35 = new Hono();
13851
+ app35.post("/launch", requireAdminSession, async (c) => {
13972
13852
  try {
13973
13853
  const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
13974
13854
  console.error(`[admin/browser/launch] op=request transport=${transport}`);
@@ -13996,52 +13876,53 @@ app34.post("/launch", requireAdminSession, async (c) => {
13996
13876
  );
13997
13877
  }
13998
13878
  });
13999
- var browser_default = app34;
13879
+ var browser_default = app35;
14000
13880
 
14001
13881
  // server/routes/admin/index.ts
14002
- var app35 = new Hono();
14003
- app35.route("/session", session_default);
14004
- app35.route("/logs", logs_default);
14005
- app35.route("/claude-info", claude_info_default);
14006
- app35.route("/attachment", attachment_default);
14007
- app35.route("/agents", agents_default);
14008
- app35.route("/sessions", sessions_default);
14009
- app35.route("/claude-sessions", claude_sessions_default);
14010
- app35.route("/log-ingest", log_ingest_default);
14011
- app35.route("/events", events_default);
14012
- app35.route("/files", files_default);
14013
- app35.route("/graph-search", graph_search_default);
14014
- app35.route("/graph-subgraph", graph_subgraph_default);
14015
- app35.route("/graph-delete", graph_delete_default);
14016
- app35.route("/graph-restore", graph_restore_default);
14017
- app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
14018
- app35.route("/graph-default-view", graph_default_view_default);
14019
- app35.route("/sidebar-artefacts", sidebar_artefacts_default);
14020
- app35.route("/sidebar-sessions", sidebar_sessions_default);
14021
- app35.route("/session-delete", session_delete_default);
14022
- app35.route("/browser", browser_default);
14023
- app35.route("/session-rc-spawn", session_rc_spawn_default);
14024
- app35.route("/system-stats", system_stats_default);
14025
- app35.route("/health-brand", health_default2);
14026
- app35.route("/linkedin-ingest", linkedin_ingest_default);
14027
- app35.route("/post-turn-context", post_turn_context_default);
14028
- app35.route("/public-session-context", public_session_context_default);
14029
- app35.route("/public-session-exit", public_session_exit_default);
14030
- app35.route("/access-session-evict", access_session_evict_default);
14031
- var admin_default = app35;
13882
+ var app36 = new Hono();
13883
+ app36.route("/session", session_default);
13884
+ app36.route("/logs", logs_default);
13885
+ app36.route("/claude-info", claude_info_default);
13886
+ app36.route("/attachment", attachment_default);
13887
+ app36.route("/agents", agents_default);
13888
+ app36.route("/sessions", sessions_default);
13889
+ app36.route("/claude-sessions", claude_sessions_default);
13890
+ app36.route("/log-ingest", log_ingest_default);
13891
+ app36.route("/events", events_default);
13892
+ app36.route("/files", files_default);
13893
+ app36.route("/graph-search", graph_search_default);
13894
+ app36.route("/graph-subgraph", graph_subgraph_default);
13895
+ app36.route("/graph-delete", graph_delete_default);
13896
+ app36.route("/graph-restore", graph_restore_default);
13897
+ app36.route("/graph-labels-in-graph", graph_labels_in_graph_default);
13898
+ app36.route("/graph-default-view", graph_default_view_default);
13899
+ app36.route("/sidebar-artefacts", sidebar_artefacts_default);
13900
+ app36.route("/sidebar-sessions", sidebar_sessions_default);
13901
+ app36.route("/session-delete", session_delete_default);
13902
+ app36.route("/session-stop", session_stop_default);
13903
+ app36.route("/browser", browser_default);
13904
+ app36.route("/session-rc-spawn", session_rc_spawn_default);
13905
+ app36.route("/system-stats", system_stats_default);
13906
+ app36.route("/health-brand", health_default2);
13907
+ app36.route("/linkedin-ingest", linkedin_ingest_default);
13908
+ app36.route("/post-turn-context", post_turn_context_default);
13909
+ app36.route("/public-session-context", public_session_context_default);
13910
+ app36.route("/public-session-exit", public_session_exit_default);
13911
+ app36.route("/access-session-evict", access_session_evict_default);
13912
+ var admin_default = app36;
14032
13913
 
14033
13914
  // app/lib/access-gate.ts
14034
13915
  import neo4j4 from "neo4j-driver";
14035
- import { readFileSync as readFileSync19 } from "fs";
14036
- import { resolve as resolve21 } from "path";
13916
+ import { readFileSync as readFileSync18 } from "fs";
13917
+ import { resolve as resolve20 } from "path";
14037
13918
  import { randomUUID as randomUUID10 } from "crypto";
14038
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
13919
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
14039
13920
  var driver = null;
14040
13921
  function readPassword() {
14041
13922
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
14042
- const passwordFile = resolve21(PLATFORM_ROOT7, "config/.neo4j-password");
13923
+ const passwordFile = resolve20(PLATFORM_ROOT7, "config/.neo4j-password");
14043
13924
  try {
14044
- return readFileSync19(passwordFile, "utf-8").trim();
13925
+ return readFileSync18(passwordFile, "utf-8").trim();
14045
13926
  } catch {
14046
13927
  throw new Error(
14047
13928
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -14242,8 +14123,8 @@ async function generateNewMagicToken(grantId) {
14242
14123
  var TAG28 = "[access-verify]";
14243
14124
  var MINT_TAG = "[access-session-mint]";
14244
14125
  var COOKIE_NAME = "__access_session";
14245
- var app36 = new Hono();
14246
- app36.post("/", async (c) => {
14126
+ var app37 = new Hono();
14127
+ app37.post("/", async (c) => {
14247
14128
  const ip = c.var.clientIp || "unknown";
14248
14129
  let body;
14249
14130
  try {
@@ -14325,13 +14206,13 @@ app36.post("/", async (c) => {
14325
14206
  displayName: grant.displayName
14326
14207
  });
14327
14208
  });
14328
- var verify_token_default = app36;
14209
+ var verify_token_default = app37;
14329
14210
 
14330
14211
  // app/lib/access-email.ts
14331
14212
  import { spawn as spawn2 } from "child_process";
14332
- import { resolve as resolve22 } from "path";
14333
- var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
14334
- var SEND_SCRIPT = resolve22(
14213
+ import { resolve as resolve21 } from "path";
14214
+ var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
14215
+ var SEND_SCRIPT = resolve21(
14335
14216
  PLATFORM_ROOT8,
14336
14217
  "plugins",
14337
14218
  "email",
@@ -14388,9 +14269,9 @@ async function sendMagicLinkEmail(payload) {
14388
14269
 
14389
14270
  // server/routes/access/request-magic-link.ts
14390
14271
  var TAG29 = "[access-request-link]";
14391
- var app37 = new Hono();
14272
+ var app38 = new Hono();
14392
14273
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
14393
- app37.post("/", async (c) => {
14274
+ app38.post("/", async (c) => {
14394
14275
  let body;
14395
14276
  try {
14396
14277
  body = await c.req.json();
@@ -14464,17 +14345,17 @@ app37.post("/", async (c) => {
14464
14345
  );
14465
14346
  return c.json({ message: VISITOR_MESSAGE }, 200);
14466
14347
  });
14467
- var request_magic_link_default = app37;
14348
+ var request_magic_link_default = app38;
14468
14349
 
14469
14350
  // server/routes/access/index.ts
14470
- var app38 = new Hono();
14471
- app38.route("/verify-token", verify_token_default);
14472
- app38.route("/request-magic-link", request_magic_link_default);
14473
- var access_default = app38;
14351
+ var app39 = new Hono();
14352
+ app39.route("/verify-token", verify_token_default);
14353
+ app39.route("/request-magic-link", request_magic_link_default);
14354
+ var access_default = app39;
14474
14355
 
14475
14356
  // server/routes/sites.ts
14476
- import { existsSync as existsSync20, readFileSync as readFileSync20, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
14477
- import { resolve as resolve23 } from "path";
14357
+ import { existsSync as existsSync19, readFileSync as readFileSync19, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
14358
+ import { resolve as resolve22 } from "path";
14478
14359
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
14479
14360
  var MIME = {
14480
14361
  ".html": "text/html; charset=utf-8",
@@ -14505,8 +14386,8 @@ function getExt(p) {
14505
14386
  if (idx < p.lastIndexOf("/")) return "";
14506
14387
  return p.slice(idx).toLowerCase();
14507
14388
  }
14508
- var app39 = new Hono();
14509
- app39.get("/:rel{.*}", (c) => {
14389
+ var app40 = new Hono();
14390
+ app40.get("/:rel{.*}", (c) => {
14510
14391
  const reqPath = c.req.path;
14511
14392
  const rawRel = c.req.param("rel") ?? "";
14512
14393
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -14531,15 +14412,15 @@ app39.get("/:rel{.*}", (c) => {
14531
14412
  }
14532
14413
  segments.push(seg);
14533
14414
  }
14534
- const rootDir = resolve23(account.accountDir, "sites");
14535
- let filePath = segments.length === 0 ? rootDir : resolve23(rootDir, ...segments);
14415
+ const rootDir = resolve22(account.accountDir, "sites");
14416
+ let filePath = segments.length === 0 ? rootDir : resolve22(rootDir, ...segments);
14536
14417
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
14537
14418
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
14538
14419
  return c.text("Forbidden", 403);
14539
14420
  }
14540
14421
  let stat7;
14541
14422
  try {
14542
- stat7 = existsSync20(filePath) ? statSync9(filePath) : null;
14423
+ stat7 = existsSync19(filePath) ? statSync9(filePath) : null;
14543
14424
  } catch {
14544
14425
  stat7 = null;
14545
14426
  }
@@ -14552,13 +14433,13 @@ app39.get("/:rel{.*}", (c) => {
14552
14433
  return c.redirect(target, 301);
14553
14434
  }
14554
14435
  if (stat7?.isDirectory()) {
14555
- filePath = resolve23(filePath, "index.html");
14436
+ filePath = resolve22(filePath, "index.html");
14556
14437
  }
14557
14438
  if (!filePath.startsWith(rootDir + "/")) {
14558
14439
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
14559
14440
  return c.text("Forbidden", 403);
14560
14441
  }
14561
- if (!existsSync20(filePath)) {
14442
+ if (!existsSync19(filePath)) {
14562
14443
  console.error(`[sites] not-found path=${reqPath} status=404`);
14563
14444
  return c.text("Not found", 404);
14564
14445
  }
@@ -14577,7 +14458,7 @@ app39.get("/:rel{.*}", (c) => {
14577
14458
  }
14578
14459
  let body;
14579
14460
  try {
14580
- body = readFileSync20(realPath);
14461
+ body = readFileSync19(realPath);
14581
14462
  } catch (err) {
14582
14463
  const code = err?.code;
14583
14464
  if (code === "EISDIR") {
@@ -14609,11 +14490,11 @@ app39.get("/:rel{.*}", (c) => {
14609
14490
  "X-Content-Type-Options": "nosniff"
14610
14491
  });
14611
14492
  });
14612
- var sites_default = app39;
14493
+ var sites_default = app40;
14613
14494
 
14614
14495
  // app/lib/visitor-token.ts
14615
14496
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
14616
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync21, writeFileSync as writeFileSync7 } from "fs";
14497
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync20, writeFileSync as writeFileSync7 } from "fs";
14617
14498
  import { dirname as dirname5 } from "path";
14618
14499
  var TOKEN_PREFIX = "v1.";
14619
14500
  var SECRET_BYTES = 32;
@@ -14622,7 +14503,7 @@ var cachedSecret = null;
14622
14503
  function getSecret() {
14623
14504
  if (cachedSecret) return cachedSecret;
14624
14505
  try {
14625
- const hex2 = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14506
+ const hex2 = readFileSync20(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14626
14507
  if (hex2.length === SECRET_BYTES * 2) {
14627
14508
  cachedSecret = Buffer.from(hex2, "hex");
14628
14509
  return cachedSecret;
@@ -14636,7 +14517,7 @@ function getSecret() {
14636
14517
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
14637
14518
  } catch {
14638
14519
  }
14639
- const hex = readFileSync21(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14520
+ const hex = readFileSync20(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
14640
14521
  cachedSecret = Buffer.from(hex, "hex");
14641
14522
  return cachedSecret;
14642
14523
  }
@@ -14689,8 +14570,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
14689
14570
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
14690
14571
 
14691
14572
  // app/lib/brand-config.ts
14692
- import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
14693
- import { join as join18 } from "path";
14573
+ import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
14574
+ import { join as join17 } from "path";
14694
14575
  var cached2 = null;
14695
14576
  var cachedAttempted = false;
14696
14577
  function readBrandConfig() {
@@ -14698,10 +14579,10 @@ function readBrandConfig() {
14698
14579
  cachedAttempted = true;
14699
14580
  const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
14700
14581
  if (!platformRoot2) return null;
14701
- const brandPath = join18(platformRoot2, "config", "brand.json");
14702
- if (!existsSync21(brandPath)) return null;
14582
+ const brandPath = join17(platformRoot2, "config", "brand.json");
14583
+ if (!existsSync20(brandPath)) return null;
14703
14584
  try {
14704
- cached2 = JSON.parse(readFileSync22(brandPath, "utf-8"));
14585
+ cached2 = JSON.parse(readFileSync21(brandPath, "utf-8"));
14705
14586
  return cached2;
14706
14587
  } catch {
14707
14588
  return null;
@@ -14709,7 +14590,7 @@ function readBrandConfig() {
14709
14590
  }
14710
14591
 
14711
14592
  // server/routes/visitor-consent.ts
14712
- var app40 = new Hono();
14593
+ var app41 = new Hono();
14713
14594
  var CONSENT_COOKIE_NAME = "mxy_consent";
14714
14595
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
14715
14596
  var DEFAULT_CONSENT_COPY = {
@@ -14754,17 +14635,17 @@ function siteSlugFromReferer(referer) {
14754
14635
  return "";
14755
14636
  }
14756
14637
  }
14757
- app40.options("/consent", (c) => {
14638
+ app41.options("/consent", (c) => {
14758
14639
  const origin = getOrigin(c);
14759
14640
  setCorsHeaders(c, origin);
14760
14641
  return c.body(null, 204);
14761
14642
  });
14762
- app40.options("/brand-config", (c) => {
14643
+ app41.options("/brand-config", (c) => {
14763
14644
  const origin = getOrigin(c);
14764
14645
  setCorsHeaders(c, origin);
14765
14646
  return c.body(null, 204);
14766
14647
  });
14767
- app40.post("/consent", async (c) => {
14648
+ app41.post("/consent", async (c) => {
14768
14649
  const origin = getOrigin(c);
14769
14650
  setCorsHeaders(c, origin);
14770
14651
  let raw;
@@ -14804,7 +14685,7 @@ app40.post("/consent", async (c) => {
14804
14685
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
14805
14686
  return c.body(null, 204);
14806
14687
  });
14807
- app40.get("/brand-config", (c) => {
14688
+ app41.get("/brand-config", (c) => {
14808
14689
  const origin = getOrigin(c);
14809
14690
  setCorsHeaders(c, origin);
14810
14691
  const brand = readBrandConfig();
@@ -14814,7 +14695,7 @@ app40.get("/brand-config", (c) => {
14814
14695
  c.header("Cache-Control", "public, max-age=300");
14815
14696
  return c.json({ consent: { copy, palette } });
14816
14697
  });
14817
- var visitor_consent_default = app40;
14698
+ var visitor_consent_default = app41;
14818
14699
 
14819
14700
  // server/routes/listings.ts
14820
14701
  function getCookie(headerValue, name) {
@@ -14841,8 +14722,8 @@ function appendConsentParams(pageUrl, token) {
14841
14722
  }
14842
14723
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
14843
14724
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
14844
- var app41 = new Hono();
14845
- app41.get("/:slug/click", async (c) => {
14725
+ var app42 = new Hono();
14726
+ app42.get("/:slug/click", async (c) => {
14846
14727
  const slug = c.req.param("slug") ?? "";
14847
14728
  const rawSession = c.req.query("session") ?? "";
14848
14729
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -14906,10 +14787,10 @@ app41.get("/:slug/click", async (c) => {
14906
14787
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
14907
14788
  return c.redirect(redirectUrl, 302);
14908
14789
  });
14909
- var listings_default = app41;
14790
+ var listings_default = app42;
14910
14791
 
14911
14792
  // server/routes/visitor-event.ts
14912
- var app42 = new Hono();
14793
+ var app43 = new Hono();
14913
14794
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
14914
14795
  var buckets = /* @__PURE__ */ new Map();
14915
14796
  var RATE_LIMIT = 60;
@@ -14976,12 +14857,12 @@ function originAllowed(origin, allowlist) {
14976
14857
  return false;
14977
14858
  }
14978
14859
  }
14979
- app42.options("/event", (c) => {
14860
+ app43.options("/event", (c) => {
14980
14861
  const origin = getOrigin2(c);
14981
14862
  setCorsHeaders2(c, origin);
14982
14863
  return c.body(null, 204);
14983
14864
  });
14984
- app42.post("/event", async (c) => {
14865
+ app43.post("/event", async (c) => {
14985
14866
  const origin = getOrigin2(c);
14986
14867
  setCorsHeaders2(c, origin);
14987
14868
  const ua = c.req.header("user-agent") ?? "";
@@ -15186,17 +15067,17 @@ async function writeEvent(opts) {
15186
15067
  );
15187
15068
  }
15188
15069
  }
15189
- var visitor_event_default = app42;
15070
+ var visitor_event_default = app43;
15190
15071
 
15191
15072
  // server/routes/session.ts
15192
- import { resolve as resolve24 } from "path";
15193
- import { existsSync as existsSync22, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
15073
+ import { resolve as resolve23 } from "path";
15074
+ import { existsSync as existsSync21, writeFileSync as writeFileSync8, mkdirSync as mkdirSync5 } from "fs";
15194
15075
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
15195
15076
  function writeBrandingCache(accountId, agentSlug, branding) {
15196
15077
  try {
15197
- const cacheDir = resolve24(MAXY_DIR, "branding-cache", accountId);
15078
+ const cacheDir = resolve23(MAXY_DIR, "branding-cache", accountId);
15198
15079
  mkdirSync5(cacheDir, { recursive: true });
15199
- writeFileSync8(resolve24(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
15080
+ writeFileSync8(resolve23(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
15200
15081
  } catch (err) {
15201
15082
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
15202
15083
  }
@@ -15232,8 +15113,8 @@ function withVisitorCookie(response, visitorId) {
15232
15113
  headers
15233
15114
  });
15234
15115
  }
15235
- var app43 = new Hono();
15236
- app43.post("/", async (c) => {
15116
+ var app44 = new Hono();
15117
+ app44.post("/", async (c) => {
15237
15118
  let body;
15238
15119
  try {
15239
15120
  body = await c.req.json();
@@ -15284,8 +15165,8 @@ app43.post("/", async (c) => {
15284
15165
  }
15285
15166
  let agentConfig = null;
15286
15167
  if (account) {
15287
- const agentDir = resolve24(account.accountDir, "agents", agentSlug);
15288
- if (!existsSync22(agentDir) || !existsSync22(resolve24(agentDir, "config.json"))) {
15168
+ const agentDir = resolve23(account.accountDir, "agents", agentSlug);
15169
+ if (!existsSync21(agentDir) || !existsSync21(resolve23(agentDir, "config.json"))) {
15289
15170
  return c.json({ error: "Agent not found" }, 404);
15290
15171
  }
15291
15172
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -15444,7 +15325,7 @@ app43.post("/", async (c) => {
15444
15325
  newVisitorId
15445
15326
  );
15446
15327
  });
15447
- var session_default2 = app43;
15328
+ var session_default2 = app44;
15448
15329
 
15449
15330
  // app/lib/graph-health.ts
15450
15331
  var import_dist4 = __toESM(require_dist3(), 1);
@@ -15565,7 +15446,7 @@ function startGraphHealthTimer() {
15565
15446
 
15566
15447
  // app/lib/file-watcher.ts
15567
15448
  import * as fsp2 from "fs/promises";
15568
- import { resolve as resolve25, sep as sep7 } from "path";
15449
+ import { resolve as resolve24, sep as sep7 } from "path";
15569
15450
  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;
15570
15451
  var DEFAULT_COALESCE_MS = 500;
15571
15452
  var ROOTS = ["uploads", "accounts"];
@@ -15584,7 +15465,7 @@ async function startFileWatcher(opts = {}) {
15584
15465
  const dropFn = opts.drop ?? dropFileIndex;
15585
15466
  for (const r of ROOTS) {
15586
15467
  try {
15587
- await fsp2.mkdir(resolve25(dataRoot, r), { recursive: true });
15468
+ await fsp2.mkdir(resolve24(dataRoot, r), { recursive: true });
15588
15469
  } catch (err) {
15589
15470
  console.error(
15590
15471
  `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
@@ -15605,7 +15486,7 @@ async function startFileWatcher(opts = {}) {
15605
15486
  timers.set(relativePath, t);
15606
15487
  }
15607
15488
  async function runHook(relativePath, accountId) {
15608
- const absolute = resolve25(dataRoot, relativePath);
15489
+ const absolute = resolve24(dataRoot, relativePath);
15609
15490
  let exists = false;
15610
15491
  try {
15611
15492
  const st = await fsp2.stat(absolute);
@@ -15629,7 +15510,7 @@ async function startFileWatcher(opts = {}) {
15629
15510
  }
15630
15511
  }
15631
15512
  async function watchRoot(rootName) {
15632
- const absRoot = resolve25(dataRoot, rootName);
15513
+ const absRoot = resolve24(dataRoot, rootName);
15633
15514
  try {
15634
15515
  const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
15635
15516
  for await (const event of iter) {
@@ -15939,8 +15820,8 @@ var streamSSE = (c, cb, onError) => {
15939
15820
 
15940
15821
  // app/lib/whatsapp/gateway/routes.ts
15941
15822
  function createWaChannelRoutes(deps) {
15942
- const app45 = new Hono();
15943
- app45.get("/wa-channel/inbound", (c) => {
15823
+ const app46 = new Hono();
15824
+ app46.get("/wa-channel/inbound", (c) => {
15944
15825
  const senderId = c.req.query("senderId");
15945
15826
  if (!senderId) return c.json({ error: "senderId required" }, 400);
15946
15827
  return streamSSE(c, async (stream2) => {
@@ -15958,7 +15839,7 @@ function createWaChannelRoutes(deps) {
15958
15839
  }
15959
15840
  });
15960
15841
  });
15961
- app45.post("/wa-channel/reply", async (c) => {
15842
+ app46.post("/wa-channel/reply", async (c) => {
15962
15843
  const body = await c.req.json().catch(() => null);
15963
15844
  const senderId = body?.senderId;
15964
15845
  const text = body?.text;
@@ -15977,7 +15858,7 @@ function createWaChannelRoutes(deps) {
15977
15858
  console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
15978
15859
  return c.json({ ok: true });
15979
15860
  });
15980
- app45.post("/wa-channel/ready", async (c) => {
15861
+ app46.post("/wa-channel/ready", async (c) => {
15981
15862
  const body = await c.req.json().catch(() => null);
15982
15863
  const senderId = body?.senderId;
15983
15864
  if (typeof senderId !== "string") {
@@ -15986,7 +15867,7 @@ function createWaChannelRoutes(deps) {
15986
15867
  deps.onReady?.(senderId);
15987
15868
  return c.json({ ok: true });
15988
15869
  });
15989
- app45.post("/wa-channel/received", async (c) => {
15870
+ app46.post("/wa-channel/received", async (c) => {
15990
15871
  const body = await c.req.json().catch(() => null);
15991
15872
  const senderId = body?.senderId;
15992
15873
  const waMessageId = body?.waMessageId;
@@ -15996,7 +15877,7 @@ function createWaChannelRoutes(deps) {
15996
15877
  deps.onReceived?.(senderId, waMessageId);
15997
15878
  return c.json({ ok: true });
15998
15879
  });
15999
- return app45;
15880
+ return app46;
16000
15881
  }
16001
15882
 
16002
15883
  // app/lib/whatsapp/gateway/wa-gateway.ts
@@ -16057,17 +15938,15 @@ var WaGateway = class {
16057
15938
  const bytes = Buffer.byteLength(input.text, "utf8");
16058
15939
  const hadSubscriber = this.hub.hasSubscriber(input.senderId);
16059
15940
  const willDeliverNow = this.hub.isReady(input.senderId);
16060
- const hasFileMedia = !!input.mediaPath && input.mediaType !== "audio";
16061
- const mediaField = hasFileMedia ? `media=${input.mediaType} mediaPath=${input.mediaPath}` : input.mediaType === "audio" ? "media=audio mediaPath=transcribed" : "media=none";
15941
+ const openable = input.media.filter((m) => m.type !== "audio");
15942
+ const mediaField = openable.length > 0 ? `media=${openable.map((m) => m.type).join(",")} mediaPaths=${openable.map((m) => m.path).join(",")}` : input.media.some((m) => m.type === "audio") ? "media=audio mediaPath=transcribed" : "media=none";
16062
15943
  this.replies.set(input.senderId, input.reply);
16063
15944
  this.hub.deliver(
16064
15945
  {
16065
15946
  senderId: input.senderId,
16066
15947
  text: input.text,
16067
15948
  waMessageId: `wa-${++this.seq}`,
16068
- mediaPath: input.mediaPath,
16069
- mediaType: input.mediaType,
16070
- mediaMimetype: input.mediaMimetype
15949
+ media: input.media
16071
15950
  },
16072
15951
  Date.now()
16073
15952
  );
@@ -16191,8 +16070,8 @@ function broadcastAdminShutdown(reason) {
16191
16070
 
16192
16071
  // ../lib/entitlement/src/index.ts
16193
16072
  import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
16194
- import { existsSync as existsSync23, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
16195
- import { resolve as resolve26 } from "path";
16073
+ import { existsSync as existsSync22, readFileSync as readFileSync22, statSync as statSync10 } from "fs";
16074
+ import { resolve as resolve25 } from "path";
16196
16075
 
16197
16076
  // ../lib/entitlement/src/canonicalize.ts
16198
16077
  function canonicalize(value) {
@@ -16227,7 +16106,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
16227
16106
  var GRACE_DAYS = 7;
16228
16107
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
16229
16108
  function pubkeyPath(brand) {
16230
- return resolve26(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
16109
+ return resolve25(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
16231
16110
  }
16232
16111
  var memo = null;
16233
16112
  function memoKey(mtimeMs, account) {
@@ -16239,8 +16118,8 @@ function resolveEntitlement(brand, account) {
16239
16118
  if (brand.commercialMode !== true) {
16240
16119
  return logResolved(implicitTrust(account), null);
16241
16120
  }
16242
- const entitlementPath = resolve26(brand.configDir, "entitlement.json");
16243
- if (!existsSync23(entitlementPath)) {
16121
+ const entitlementPath = resolve25(brand.configDir, "entitlement.json");
16122
+ if (!existsSync22(entitlementPath)) {
16244
16123
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
16245
16124
  }
16246
16125
  const stat7 = statSync10(entitlementPath);
@@ -16255,7 +16134,7 @@ function resolveEntitlement(brand, account) {
16255
16134
  function verifyAndResolve(brand, entitlementPath, account) {
16256
16135
  let pubkeyPem;
16257
16136
  try {
16258
- pubkeyPem = readFileSync23(pubkeyPath(brand), "utf-8");
16137
+ pubkeyPem = readFileSync22(pubkeyPath(brand), "utf-8");
16259
16138
  } catch (err) {
16260
16139
  return logResolved(anonymousFallback("pubkey-missing"), {
16261
16140
  reason: "pubkey-missing"
@@ -16269,7 +16148,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
16269
16148
  }
16270
16149
  let envelope;
16271
16150
  try {
16272
- envelope = JSON.parse(readFileSync23(entitlementPath, "utf-8"));
16151
+ envelope = JSON.parse(readFileSync22(entitlementPath, "utf-8"));
16273
16152
  } catch {
16274
16153
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
16275
16154
  }
@@ -16430,14 +16309,14 @@ function clientFrom(c) {
16430
16309
  );
16431
16310
  }
16432
16311
  var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
16433
- var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join19(PLATFORM_ROOT9, "config", "brand.json") : "";
16312
+ var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join18(PLATFORM_ROOT9, "config", "brand.json") : "";
16434
16313
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
16435
- if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
16314
+ if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
16436
16315
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
16437
16316
  }
16438
- if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
16317
+ if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
16439
16318
  try {
16440
- const parsed = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
16319
+ const parsed = JSON.parse(readFileSync23(BRAND_JSON_PATH, "utf-8"));
16441
16320
  BRAND = { ...BRAND, ...parsed };
16442
16321
  } catch (err) {
16443
16322
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -16456,11 +16335,11 @@ var brandLoginOpts = {
16456
16335
  bodyFont: BRAND.defaultFonts?.body,
16457
16336
  logoContainsName: !!BRAND.logoContainsName
16458
16337
  };
16459
- var ALIAS_DOMAINS_PATH = join19(homedir2(), BRAND.configDir, "alias-domains.json");
16338
+ var ALIAS_DOMAINS_PATH = join18(homedir2(), BRAND.configDir, "alias-domains.json");
16460
16339
  function loadAliasDomains() {
16461
16340
  try {
16462
- if (!existsSync24(ALIAS_DOMAINS_PATH)) return null;
16463
- const parsed = JSON.parse(readFileSync24(ALIAS_DOMAINS_PATH, "utf-8"));
16341
+ if (!existsSync23(ALIAS_DOMAINS_PATH)) return null;
16342
+ const parsed = JSON.parse(readFileSync23(ALIAS_DOMAINS_PATH, "utf-8"));
16464
16343
  if (!Array.isArray(parsed)) {
16465
16344
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
16466
16345
  return null;
@@ -16484,10 +16363,10 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
16484
16363
  function isPublicHost(host) {
16485
16364
  return host.startsWith("public.") || aliasDomains.has(host);
16486
16365
  }
16487
- var app44 = new Hono();
16366
+ var app45 = new Hono();
16488
16367
  var waGateway = new WaGateway({
16489
16368
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
16490
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
16369
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve26(process.env.MAXY_PLATFORM_ROOT ?? join18(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
16491
16370
  ensureChannelSession: async ({ accountId, senderId, gatewayUrl, serverPath }) => {
16492
16371
  const userId = resolveAdminUserId({ accountId, senderPhone: senderId }) ?? void 0;
16493
16372
  console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${userId ?? "owner-fallback"}`);
@@ -16502,10 +16381,10 @@ var waGateway = new WaGateway({
16502
16381
  }
16503
16382
  }
16504
16383
  });
16505
- app44.route("/", waGateway.routes());
16384
+ app45.route("/", waGateway.routes());
16506
16385
  waGateway.startSweeper();
16507
- app44.use("*", clientIpMiddleware);
16508
- app44.use("*", async (c, next) => {
16386
+ app45.use("*", clientIpMiddleware);
16387
+ app45.use("*", async (c, next) => {
16509
16388
  await next();
16510
16389
  c.header("X-Content-Type-Options", "nosniff");
16511
16390
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -16515,7 +16394,7 @@ app44.use("*", async (c, next) => {
16515
16394
  );
16516
16395
  });
16517
16396
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
16518
- app44.use("*", async (c, next) => {
16397
+ app45.use("*", async (c, next) => {
16519
16398
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
16520
16399
  await next();
16521
16400
  return;
@@ -16533,7 +16412,7 @@ app44.use("*", async (c, next) => {
16533
16412
  });
16534
16413
  }
16535
16414
  });
16536
- app44.use("*", async (c, next) => {
16415
+ app45.use("*", async (c, next) => {
16537
16416
  const host = (c.req.header("host") ?? "").split(":")[0];
16538
16417
  if (!isPublicHost(host)) {
16539
16418
  await next();
@@ -16564,7 +16443,7 @@ function resolveRemoteAuthOpts() {
16564
16443
  return brandLoginOpts;
16565
16444
  }
16566
16445
  var MAX_LOGIN_BODY = 8 * 1024;
16567
- app44.post("/__remote-auth/login", async (c) => {
16446
+ app45.post("/__remote-auth/login", async (c) => {
16568
16447
  const client = clientFrom(c);
16569
16448
  const clientIp = client.ip || "unknown";
16570
16449
  if (!requestIsTlsTerminated(c)) {
@@ -16609,7 +16488,7 @@ app44.post("/__remote-auth/login", async (c) => {
16609
16488
  }
16610
16489
  });
16611
16490
  });
16612
- app44.get("/__remote-auth/logout", (c) => {
16491
+ app45.get("/__remote-auth/logout", (c) => {
16613
16492
  const client = clientFrom(c);
16614
16493
  const clientIp = client.ip || "unknown";
16615
16494
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -16622,7 +16501,7 @@ app44.get("/__remote-auth/logout", (c) => {
16622
16501
  }
16623
16502
  });
16624
16503
  });
16625
- app44.post("/__remote-auth/change-password", async (c) => {
16504
+ app45.post("/__remote-auth/change-password", async (c) => {
16626
16505
  const client = clientFrom(c);
16627
16506
  const clientIp = client.ip || "unknown";
16628
16507
  const rateLimited = checkRateLimit(client);
@@ -16673,13 +16552,13 @@ app44.post("/__remote-auth/change-password", async (c) => {
16673
16552
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
16674
16553
  }
16675
16554
  });
16676
- app44.get("/__remote-auth/setup", (c) => {
16555
+ app45.get("/__remote-auth/setup", (c) => {
16677
16556
  if (isRemoteAuthConfigured()) {
16678
16557
  return c.redirect("/");
16679
16558
  }
16680
16559
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
16681
16560
  });
16682
- app44.post("/__remote-auth/set-initial-password", async (c) => {
16561
+ app45.post("/__remote-auth/set-initial-password", async (c) => {
16683
16562
  if (isRemoteAuthConfigured()) {
16684
16563
  return c.redirect("/");
16685
16564
  }
@@ -16717,10 +16596,10 @@ app44.post("/__remote-auth/set-initial-password", async (c) => {
16717
16596
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
16718
16597
  }
16719
16598
  });
16720
- app44.get("/api/remote-auth/status", (c) => {
16599
+ app45.get("/api/remote-auth/status", (c) => {
16721
16600
  return c.json({ configured: isRemoteAuthConfigured() });
16722
16601
  });
16723
- app44.post("/api/remote-auth/set-password", async (c) => {
16602
+ app45.post("/api/remote-auth/set-password", async (c) => {
16724
16603
  let body;
16725
16604
  try {
16726
16605
  body = await c.req.json();
@@ -16751,9 +16630,9 @@ app44.post("/api/remote-auth/set-password", async (c) => {
16751
16630
  return c.json({ error: "Failed to save password" }, 500);
16752
16631
  }
16753
16632
  });
16754
- app44.route("/api/_client-error", client_error_default);
16633
+ app45.route("/api/_client-error", client_error_default);
16755
16634
  console.log("[client-error-route] mounted");
16756
- app44.use("*", async (c, next) => {
16635
+ app45.use("*", async (c, next) => {
16757
16636
  const host = (c.req.header("host") ?? "").split(":")[0];
16758
16637
  const path2 = c.req.path;
16759
16638
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -16786,14 +16665,14 @@ app44.use("*", async (c, next) => {
16786
16665
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
16787
16666
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
16788
16667
  });
16789
- app44.route("/api/health", health_default);
16790
- app44.route("/api/chat", chat_default);
16791
- app44.route("/api/whatsapp", whatsapp_default);
16792
- app44.route("/api/whatsapp-reader", whatsapp_reader_default);
16793
- app44.route("/api/onboarding", onboarding_default);
16794
- app44.route("/api/admin", admin_default);
16795
- app44.route("/api/access", access_default);
16796
- app44.route("/api/session", session_default2);
16668
+ app45.route("/api/health", health_default);
16669
+ app45.route("/api/chat", chat_default);
16670
+ app45.route("/api/whatsapp", whatsapp_default);
16671
+ app45.route("/api/whatsapp-reader", whatsapp_reader_default);
16672
+ app45.route("/api/onboarding", onboarding_default);
16673
+ app45.route("/api/admin", admin_default);
16674
+ app45.route("/api/access", access_default);
16675
+ app45.route("/api/session", session_default2);
16797
16676
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
16798
16677
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
16799
16678
  var IMAGE_MIME = {
@@ -16805,7 +16684,7 @@ var IMAGE_MIME = {
16805
16684
  ".svg": "image/svg+xml",
16806
16685
  ".ico": "image/x-icon"
16807
16686
  };
16808
- app44.get("/agent-assets/:slug/:filename", (c) => {
16687
+ app45.get("/agent-assets/:slug/:filename", (c) => {
16809
16688
  const slug = c.req.param("slug");
16810
16689
  const filename = c.req.param("filename");
16811
16690
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -16821,26 +16700,26 @@ app44.get("/agent-assets/:slug/:filename", (c) => {
16821
16700
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
16822
16701
  return c.text("Not found", 404);
16823
16702
  }
16824
- const filePath = resolve27(account.accountDir, "agents", slug, "assets", filename);
16825
- const expectedDir = resolve27(account.accountDir, "agents", slug, "assets");
16703
+ const filePath = resolve26(account.accountDir, "agents", slug, "assets", filename);
16704
+ const expectedDir = resolve26(account.accountDir, "agents", slug, "assets");
16826
16705
  if (!filePath.startsWith(expectedDir + "/")) {
16827
16706
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
16828
16707
  return c.text("Forbidden", 403);
16829
16708
  }
16830
- if (!existsSync24(filePath)) {
16709
+ if (!existsSync23(filePath)) {
16831
16710
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
16832
16711
  return c.text("Not found", 404);
16833
16712
  }
16834
16713
  const ext = "." + filename.split(".").pop()?.toLowerCase();
16835
16714
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
16836
16715
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
16837
- const body = readFileSync24(filePath);
16716
+ const body = readFileSync23(filePath);
16838
16717
  return c.body(body, 200, {
16839
16718
  "Content-Type": contentType,
16840
16719
  "Cache-Control": "public, max-age=3600"
16841
16720
  });
16842
16721
  });
16843
- app44.get("/generated/:filename", (c) => {
16722
+ app45.get("/generated/:filename", (c) => {
16844
16723
  const filename = c.req.param("filename");
16845
16724
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
16846
16725
  console.error(`[generated] serve file=${filename} status=403`);
@@ -16851,35 +16730,35 @@ app44.get("/generated/:filename", (c) => {
16851
16730
  console.error(`[generated] serve file=${filename} status=404`);
16852
16731
  return c.text("Not found", 404);
16853
16732
  }
16854
- const filePath = resolve27(account.accountDir, "generated", filename);
16855
- const expectedDir = resolve27(account.accountDir, "generated");
16733
+ const filePath = resolve26(account.accountDir, "generated", filename);
16734
+ const expectedDir = resolve26(account.accountDir, "generated");
16856
16735
  if (!filePath.startsWith(expectedDir + "/")) {
16857
16736
  console.error(`[generated] serve file=${filename} status=403`);
16858
16737
  return c.text("Forbidden", 403);
16859
16738
  }
16860
- if (!existsSync24(filePath)) {
16739
+ if (!existsSync23(filePath)) {
16861
16740
  console.error(`[generated] serve file=${filename} status=404`);
16862
16741
  return c.text("Not found", 404);
16863
16742
  }
16864
16743
  const ext = "." + filename.split(".").pop()?.toLowerCase();
16865
16744
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
16866
16745
  console.log(`[generated] serve file=${filename} status=200`);
16867
- const body = readFileSync24(filePath);
16746
+ const body = readFileSync23(filePath);
16868
16747
  return c.body(body, 200, {
16869
16748
  "Content-Type": contentType,
16870
16749
  "Cache-Control": "public, max-age=86400"
16871
16750
  });
16872
16751
  });
16873
- app44.route("/sites", sites_default);
16874
- app44.route("/listings", listings_default);
16875
- app44.route("/v", visitor_event_default);
16876
- app44.route("/v", visitor_consent_default);
16752
+ app45.route("/sites", sites_default);
16753
+ app45.route("/listings", listings_default);
16754
+ app45.route("/v", visitor_event_default);
16755
+ app45.route("/v", visitor_consent_default);
16877
16756
  var htmlCache = /* @__PURE__ */ new Map();
16878
16757
  var brandLogoPath = "/brand/maxy-monochrome.png";
16879
16758
  var brandIconPath = "/brand/maxy-monochrome.png";
16880
- if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
16759
+ if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
16881
16760
  try {
16882
- const fullBrand = JSON.parse(readFileSync24(BRAND_JSON_PATH, "utf-8"));
16761
+ const fullBrand = JSON.parse(readFileSync23(BRAND_JSON_PATH, "utf-8"));
16883
16762
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
16884
16763
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
16885
16764
  } catch {
@@ -16896,9 +16775,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
16896
16775
  function readInstalledVersion() {
16897
16776
  try {
16898
16777
  if (!PLATFORM_ROOT9) return "unknown";
16899
- const versionFile = join19(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
16900
- if (!existsSync24(versionFile)) return "unknown";
16901
- const content = readFileSync24(versionFile, "utf-8").trim();
16778
+ const versionFile = join18(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
16779
+ if (!existsSync23(versionFile)) return "unknown";
16780
+ const content = readFileSync23(versionFile, "utf-8").trim();
16902
16781
  return content || "unknown";
16903
16782
  } catch {
16904
16783
  return "unknown";
@@ -16939,7 +16818,7 @@ var clientErrorReporterScript = `<script>
16939
16818
  function cachedHtml(file) {
16940
16819
  let html = htmlCache.get(file);
16941
16820
  if (!html) {
16942
- html = readFileSync24(resolve27(process.cwd(), "public", file), "utf-8");
16821
+ html = readFileSync23(resolve26(process.cwd(), "public", file), "utf-8");
16943
16822
  const productNameEsc = escapeHtml(BRAND.productName);
16944
16823
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
16945
16824
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -16955,13 +16834,13 @@ ${clientErrorReporterScript}
16955
16834
  }
16956
16835
  var brandedHtmlCache = /* @__PURE__ */ new Map();
16957
16836
  function loadBrandingCache(agentSlug) {
16958
- const configDir2 = join19(homedir2(), BRAND.configDir);
16837
+ const configDir2 = join18(homedir2(), BRAND.configDir);
16959
16838
  try {
16960
16839
  const accountId = getDefaultAccountId();
16961
16840
  if (!accountId) return null;
16962
- const cachePath = join19(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
16963
- if (!existsSync24(cachePath)) return null;
16964
- return JSON.parse(readFileSync24(cachePath, "utf-8"));
16841
+ const cachePath = join18(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
16842
+ if (!existsSync23(cachePath)) return null;
16843
+ return JSON.parse(readFileSync23(cachePath, "utf-8"));
16965
16844
  } catch {
16966
16845
  return null;
16967
16846
  }
@@ -17004,7 +16883,7 @@ function escapeHtml(s) {
17004
16883
  function agentUnavailableHtml() {
17005
16884
  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>`;
17006
16885
  }
17007
- app44.get("/", (c) => {
16886
+ app45.get("/", (c) => {
17008
16887
  const host = (c.req.header("host") ?? "").split(":")[0];
17009
16888
  if (isPublicHost(host)) {
17010
16889
  const defaultSlug = resolveDefaultSlug();
@@ -17020,12 +16899,12 @@ app44.get("/", (c) => {
17020
16899
  }
17021
16900
  return c.html(cachedHtml("index.html"));
17022
16901
  });
17023
- app44.get("/public", (c) => {
16902
+ app45.get("/public", (c) => {
17024
16903
  const host = (c.req.header("host") ?? "").split(":")[0];
17025
16904
  if (isPublicHost(host)) return c.text("Not found", 404);
17026
16905
  return c.html(cachedHtml("public.html"));
17027
16906
  });
17028
- app44.get("/chat", (c) => {
16907
+ app45.get("/chat", (c) => {
17029
16908
  const host = (c.req.header("host") ?? "").split(":")[0];
17030
16909
  if (isPublicHost(host)) return c.text("Not found", 404);
17031
16910
  return c.html(cachedHtml("public.html"));
@@ -17044,12 +16923,12 @@ async function logViewerFetch(c, next) {
17044
16923
  duration_ms: Date.now() - start
17045
16924
  });
17046
16925
  }
17047
- app44.use("/vnc-viewer.html", logViewerFetch);
17048
- app44.use("/vnc-popout.html", logViewerFetch);
17049
- app44.get("/vnc-popout.html", (c) => {
16926
+ app45.use("/vnc-viewer.html", logViewerFetch);
16927
+ app45.use("/vnc-popout.html", logViewerFetch);
16928
+ app45.get("/vnc-popout.html", (c) => {
17050
16929
  let html = htmlCache.get("vnc-popout.html");
17051
16930
  if (!html) {
17052
- html = readFileSync24(resolve27(process.cwd(), "public", "vnc-popout.html"), "utf-8");
16931
+ html = readFileSync23(resolve26(process.cwd(), "public", "vnc-popout.html"), "utf-8");
17053
16932
  const name = escapeHtml(BRAND.productName);
17054
16933
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
17055
16934
  html = html.replace("</head>", ` ${brandScript}
@@ -17059,7 +16938,7 @@ app44.get("/vnc-popout.html", (c) => {
17059
16938
  }
17060
16939
  return c.html(html);
17061
16940
  });
17062
- app44.post("/api/vnc/client-event", async (c) => {
16941
+ app45.post("/api/vnc/client-event", async (c) => {
17063
16942
  let body;
17064
16943
  try {
17065
16944
  body = await c.req.json();
@@ -17080,30 +16959,30 @@ app44.post("/api/vnc/client-event", async (c) => {
17080
16959
  });
17081
16960
  return c.json({ ok: true });
17082
16961
  });
17083
- app44.get("/g/:slug", (c) => {
16962
+ app45.get("/g/:slug", (c) => {
17084
16963
  return c.html(brandedPublicHtml());
17085
16964
  });
17086
- app44.get("/graph", (c) => {
16965
+ app45.get("/graph", (c) => {
17087
16966
  const host = (c.req.header("host") ?? "").split(":")[0];
17088
16967
  if (isPublicHost(host)) return c.text("Not found", 404);
17089
16968
  return c.html(cachedHtml("graph.html"));
17090
16969
  });
17091
- app44.get("/sessions", (c) => {
16970
+ app45.get("/sessions", (c) => {
17092
16971
  const host = (c.req.header("host") ?? "").split(":")[0];
17093
16972
  if (isPublicHost(host)) return c.text("Not found", 404);
17094
16973
  return c.html(cachedHtml("sessions.html"));
17095
16974
  });
17096
- app44.get("/data", (c) => {
16975
+ app45.get("/data", (c) => {
17097
16976
  const host = (c.req.header("host") ?? "").split(":")[0];
17098
16977
  if (isPublicHost(host)) return c.text("Not found", 404);
17099
16978
  return c.html(cachedHtml("data.html"));
17100
16979
  });
17101
- app44.get("/browser", (c) => {
16980
+ app45.get("/browser", (c) => {
17102
16981
  const host = (c.req.header("host") ?? "").split(":")[0];
17103
16982
  if (isPublicHost(host)) return c.text("Not found", 404);
17104
16983
  return c.html(cachedHtml("browser.html"));
17105
16984
  });
17106
- app44.get("/:slug", async (c, next) => {
16985
+ app45.get("/:slug", async (c, next) => {
17107
16986
  const slug = c.req.param("slug");
17108
16987
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
17109
16988
  const account = resolveAccount();
@@ -17118,13 +16997,13 @@ app44.get("/:slug", async (c, next) => {
17118
16997
  await next();
17119
16998
  });
17120
16999
  if (brandFaviconPath !== "/favicon.ico") {
17121
- app44.get("/favicon.ico", (c) => {
17000
+ app45.get("/favicon.ico", (c) => {
17122
17001
  c.header("Cache-Control", "public, max-age=300");
17123
17002
  return c.redirect(brandFaviconPath, 302);
17124
17003
  });
17125
17004
  }
17126
- app44.use("/*", serveStatic({ root: "./public" }));
17127
- app44.all("*", (c) => {
17005
+ app45.use("/*", serveStatic({ root: "./public" }));
17006
+ app45.all("*", (c) => {
17128
17007
  const host = (c.req.header("host") ?? "").split(":")[0];
17129
17008
  const path2 = c.req.path;
17130
17009
  if (isPublicHost(host)) {
@@ -17138,7 +17017,7 @@ app44.all("*", (c) => {
17138
17017
  });
17139
17018
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
17140
17019
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
17141
- var httpServer = serve({ fetch: app44.fetch, port, hostname });
17020
+ var httpServer = serve({ fetch: app45.fetch, port, hostname });
17142
17021
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
17143
17022
  startAuthHealthHeartbeat();
17144
17023
  {
@@ -17176,7 +17055,7 @@ for (const m of SUBAPP_MANIFEST) {
17176
17055
  }
17177
17056
  try {
17178
17057
  const registered = [];
17179
- for (const r of app44.routes ?? []) {
17058
+ for (const r of app45.routes ?? []) {
17180
17059
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
17181
17060
  if (AGENT_SLUG_PATTERN.test(r.path)) {
17182
17061
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -17204,11 +17083,11 @@ try {
17204
17083
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
17205
17084
  async function runAdminUserReconcileTick() {
17206
17085
  try {
17207
- if (!existsSync24(USERS_FILE)) {
17086
+ if (!existsSync23(USERS_FILE)) {
17208
17087
  console.error("[adminuser-self-heal] skip reason=no-users-file");
17209
17088
  return;
17210
17089
  }
17211
- const usersRaw = readFileSync24(USERS_FILE, "utf-8").trim();
17090
+ const usersRaw = readFileSync23(USERS_FILE, "utf-8").trim();
17212
17091
  if (!usersRaw) {
17213
17092
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
17214
17093
  return;
@@ -17315,7 +17194,7 @@ if (bootAccountConfig?.whatsapp) {
17315
17194
  }
17316
17195
  init({
17317
17196
  configDir: configDirForWhatsApp,
17318
- platformRoot: resolve27(process.env.MAXY_PLATFORM_ROOT ?? join19(__dirname, "..")),
17197
+ platformRoot: resolve26(process.env.MAXY_PLATFORM_ROOT ?? join18(__dirname, "..")),
17319
17198
  accountConfig: bootAccountConfig,
17320
17199
  onMessage: async (msg) => {
17321
17200
  if (msg.isOwnerMirror) {
@@ -17326,9 +17205,9 @@ init({
17326
17205
  console.error(`[whatsapp:route] dropped reason=non-admin-sender senderId=${msg.senderPhone} agentType=${msg.agentType}`);
17327
17206
  return;
17328
17207
  }
17329
- const hasFileMedia = !!msg.mediaPath && msg.mediaType !== "audio";
17208
+ const hasFileMedia = msg.media.some((m) => m.type !== "audio");
17330
17209
  if (!msg.text && !hasFileMedia) {
17331
- console.error(`[whatsapp:route] dropped reason=no-text-no-media senderId=${msg.senderPhone} media=${msg.mediaType ?? "none"}`);
17210
+ console.error(`[whatsapp:route] dropped reason=no-text-no-media senderId=${msg.senderPhone} mediaCount=${msg.media.length}`);
17332
17211
  return;
17333
17212
  }
17334
17213
  try {
@@ -17339,9 +17218,7 @@ init({
17339
17218
  senderId: msg.senderPhone,
17340
17219
  text: msg.text,
17341
17220
  reply: msg.reply,
17342
- mediaPath: msg.mediaPath,
17343
- mediaType: msg.mediaType,
17344
- mediaMimetype: msg.mediaMimetype
17221
+ media: msg.media
17345
17222
  });
17346
17223
  } catch (err) {
17347
17224
  console.error(