@rubytech/create-maxy-code 0.1.442 → 0.1.444

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 (84) hide show
  1. package/dist/__tests__/converge-client-admins.test.js +50 -0
  2. package/dist/converge-client-admins.js +67 -0
  3. package/dist/index.js +8 -0
  4. package/package.json +1 -1
  5. package/payload/platform/docs/superpowers/plans/2026-07-13-account-schema-ontology-projection.md +547 -0
  6. package/payload/platform/docs/superpowers/plans/2026-07-14-graph-top-level-labels-ontology-single-source.md +458 -0
  7. package/payload/platform/docs/superpowers/specs/2026-07-13-account-schema-ontology-projection-design.md +178 -0
  8. package/payload/platform/docs/superpowers/specs/2026-07-14-graph-top-level-labels-ontology-single-source-design.md +119 -0
  9. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  10. package/payload/platform/plugins/admin/PLUGIN.md +7 -1
  11. package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +19 -2
  12. package/payload/platform/plugins/admin/mcp/dist/index.js +165 -24
  13. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +37 -7
  15. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
  16. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +85 -7
  17. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
  18. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +9 -5
  19. package/payload/platform/plugins/docs/references/admin-session.md +2 -0
  20. package/payload/platform/plugins/docs/references/admin-ui.md +5 -1
  21. package/payload/platform/plugins/docs/references/cross-account-authority.md +3 -3
  22. package/payload/platform/plugins/memory/PLUGIN.md +2 -0
  23. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js +12 -0
  24. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js.map +1 -1
  25. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts +9 -1
  26. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts.map +1 -1
  27. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js +19 -2
  28. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js.map +1 -1
  29. package/payload/platform/plugins/memory/references/schema-estate-agent.md +8 -3
  30. package/payload/platform/plugins/outlook/references/auth.md +8 -0
  31. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +3 -0
  32. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-attachment-suffix.test.d.ts +2 -0
  33. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-attachment-suffix.test.d.ts.map +1 -0
  34. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-attachment-suffix.test.js +44 -0
  35. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/format-attachment-suffix.test.js.map +1 -0
  36. package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts +7 -0
  37. package/payload/platform/plugins/whatsapp/mcp/dist/format.d.ts.map +1 -1
  38. package/payload/platform/plugins/whatsapp/mcp/dist/format.js +27 -0
  39. package/payload/platform/plugins/whatsapp/mcp/dist/format.js.map +1 -1
  40. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +6 -19
  41. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  42. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +3 -1
  43. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -1
  44. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +10 -7
  45. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -1
  46. package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +58 -0
  47. package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +6 -0
  48. package/payload/platform/scripts/lib/account-schema-owned-dirs.py +143 -10
  49. package/payload/platform/scripts/lib/provision-account-dir.sh +5 -0
  50. package/payload/platform/scripts/name-glsmith-owner.sh +239 -0
  51. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
  53. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  54. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -0
  55. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  56. package/payload/platform/services/claude-session-manager/dist/http-server.js +99 -8
  57. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  58. package/payload/platform/services/claude-session-manager/dist/index.js +0 -13
  59. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  60. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +8 -0
  61. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
  62. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +11 -0
  63. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
  64. package/payload/platform/services/claude-session-manager/dist/passive-admin-assignment.d.ts +20 -0
  65. package/payload/platform/services/claude-session-manager/dist/passive-admin-assignment.d.ts.map +1 -0
  66. package/payload/platform/services/claude-session-manager/dist/passive-admin-assignment.js +66 -0
  67. package/payload/platform/services/claude-session-manager/dist/passive-admin-assignment.js.map +1 -0
  68. package/payload/platform/services/claude-session-manager/dist/passive-spawn-tools-tail.d.ts +19 -0
  69. package/payload/platform/services/claude-session-manager/dist/passive-spawn-tools-tail.d.ts.map +1 -0
  70. package/payload/platform/services/claude-session-manager/dist/passive-spawn-tools-tail.js +50 -0
  71. package/payload/platform/services/claude-session-manager/dist/passive-spawn-tools-tail.js.map +1 -0
  72. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  73. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +14 -1
  74. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  75. package/payload/server/public/assets/{chat-DhD-NES_.js → chat-Dq-X-ia8.js} +1 -1
  76. package/payload/server/public/assets/{operator-zcIfeB14.js → operator-88m0DMl2.js} +1 -1
  77. package/payload/server/public/assets/page-BRfxFXyi.js +32 -0
  78. package/payload/server/public/assets/{public-C0ehZCdE.js → public-BX2MjsFY.js} +1 -1
  79. package/payload/server/public/chat.html +2 -2
  80. package/payload/server/public/operator.html +2 -2
  81. package/payload/server/public/public.html +2 -2
  82. package/payload/server/server.js +406 -182
  83. package/payload/platform/plugins/memory/references/schema-trades.md +0 -34
  84. package/payload/server/public/assets/page-6fCnIb45.js +0 -32
@@ -1413,10 +1413,10 @@ var serveStatic = (options = { root: "" }) => {
1413
1413
  };
1414
1414
 
1415
1415
  // server/index.ts
1416
- import { readFileSync as readFileSync36, existsSync as existsSync35, watchFile } from "fs";
1416
+ import { readFileSync as readFileSync37, existsSync as existsSync35, watchFile } from "fs";
1417
1417
  import { spawn as spawn3 } from "child_process";
1418
1418
  import { createHash as createHash7 } from "crypto";
1419
- import { resolve as resolve33, join as join36, basename as basename12 } from "path";
1419
+ import { resolve as resolve34, join as join37, basename as basename12 } from "path";
1420
1420
  import { homedir as homedir4 } from "os";
1421
1421
  import { monitorEventLoopDelay } from "perf_hooks";
1422
1422
 
@@ -2129,7 +2129,7 @@ var credsSaveQueue = Promise.resolve();
2129
2129
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
2130
2130
  console.error(`${TAG2} draining credential save queue\u2026`);
2131
2131
  const timer2 = new Promise(
2132
- (resolve34) => setTimeout(() => resolve34("timeout"), timeoutMs)
2132
+ (resolve35) => setTimeout(() => resolve35("timeout"), timeoutMs)
2133
2133
  );
2134
2134
  const result = await Promise.race([
2135
2135
  credsSaveQueue.then(() => "drained"),
@@ -2292,11 +2292,11 @@ async function createWaSocket(opts) {
2292
2292
  return sock;
2293
2293
  }
2294
2294
  async function waitForConnection(sock) {
2295
- return new Promise((resolve34, reject) => {
2295
+ return new Promise((resolve35, reject) => {
2296
2296
  const handler = (update) => {
2297
2297
  if (update.connection === "open") {
2298
2298
  sock.ev.off("connection.update", handler);
2299
- resolve34();
2299
+ resolve35();
2300
2300
  }
2301
2301
  if (update.connection === "close") {
2302
2302
  sock.ev.off("connection.update", handler);
@@ -2401,7 +2401,7 @@ import { inspect as inspect2 } from "util";
2401
2401
 
2402
2402
  // app/lib/whatsapp/with-timeout.ts
2403
2403
  function withTimeout(label, promise, timeoutMs) {
2404
- return new Promise((resolve34, reject) => {
2404
+ return new Promise((resolve35, reject) => {
2405
2405
  const timer2 = setTimeout(() => {
2406
2406
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
2407
2407
  }, timeoutMs);
@@ -2409,7 +2409,7 @@ function withTimeout(label, promise, timeoutMs) {
2409
2409
  promise.then(
2410
2410
  (value) => {
2411
2411
  clearTimeout(timer2);
2412
- resolve34(value);
2412
+ resolve35(value);
2413
2413
  },
2414
2414
  (err) => {
2415
2415
  clearTimeout(timer2);
@@ -3489,10 +3489,10 @@ function readConversationSummaries(platformAccountId) {
3489
3489
  } catch {
3490
3490
  continue;
3491
3491
  }
3492
- const cached2 = summaryCache.get(file);
3493
- if (cached2 && cached2.size === size && cached2.mtimeMs === mtimeMs) {
3492
+ const cached3 = summaryCache.get(file);
3493
+ if (cached3 && cached3.size === size && cached3.mtimeMs === mtimeMs) {
3494
3494
  cacheHits++;
3495
- out.set(remoteJid, cached2.summary);
3495
+ out.set(remoteJid, cached3.summary);
3496
3496
  continue;
3497
3497
  }
3498
3498
  let summary;
@@ -3556,8 +3556,8 @@ async function persistWhatsAppMessage(input) {
3556
3556
  const { givenName, familyName } = splitName(input.pushName);
3557
3557
  const prev = sessionWriteLocks.get(input.cacheKey);
3558
3558
  let release;
3559
- const mine = new Promise((resolve34) => {
3560
- release = resolve34;
3559
+ const mine = new Promise((resolve35) => {
3560
+ release = resolve35;
3561
3561
  });
3562
3562
  const chained = (prev ?? Promise.resolve()).then(() => mine);
3563
3563
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -3700,8 +3700,8 @@ import { resolve as resolve3 } from "path";
3700
3700
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3701
3701
  var cache = /* @__PURE__ */ new Map();
3702
3702
  function enumerateValidAccountIds(accountsDir) {
3703
- const cached2 = cache.get(accountsDir);
3704
- if (cached2 !== void 0) return cached2;
3703
+ const cached3 = cache.get(accountsDir);
3704
+ if (cached3 !== void 0) return cached3;
3705
3705
  let names;
3706
3706
  try {
3707
3707
  names = readdirSync2(accountsDir);
@@ -4179,8 +4179,9 @@ function resolveStoredAttachment(accountId, attachmentId) {
4179
4179
  return null;
4180
4180
  }
4181
4181
  if (!meta || typeof meta !== "object") return null;
4182
- const { filename, mimeType } = meta;
4182
+ const { filename, mimeType, sizeBytes } = meta;
4183
4183
  if (typeof filename !== "string" || typeof mimeType !== "string") return null;
4184
+ const resolvedSizeBytes = typeof sizeBytes === "number" ? sizeBytes : void 0;
4184
4185
  let entries;
4185
4186
  try {
4186
4187
  entries = readdirSync3(dir, { withFileTypes: true });
@@ -4191,7 +4192,7 @@ function resolveStoredAttachment(accountId, attachmentId) {
4191
4192
  if (!dataFile) return null;
4192
4193
  const readableSibling = `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`;
4193
4194
  const readableTextPath = entries.some((e) => e.isFile() && e.name === readableSibling) ? resolve6(dir, readableSibling) : void 0;
4194
- return { attachmentId, filename, mimeType, path: resolve6(dir, dataFile.name), readableTextPath };
4195
+ return { attachmentId, filename, mimeType, sizeBytes: resolvedSizeBytes, path: resolve6(dir, dataFile.name), readableTextPath };
4195
4196
  }
4196
4197
  async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes, buffer, explicitId) {
4197
4198
  const attachmentId = explicitId ?? randomUUID3();
@@ -5259,11 +5260,11 @@ async function connectWithReconnect(conn) {
5259
5260
  console.error(
5260
5261
  `${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
5261
5262
  );
5262
- await new Promise((resolve34) => {
5263
- const timer2 = setTimeout(resolve34, delay);
5263
+ await new Promise((resolve35) => {
5264
+ const timer2 = setTimeout(resolve35, delay);
5264
5265
  conn.abortController.signal.addEventListener("abort", () => {
5265
5266
  clearTimeout(timer2);
5266
- resolve34();
5267
+ resolve35();
5267
5268
  }, { once: true });
5268
5269
  });
5269
5270
  }
@@ -5271,16 +5272,16 @@ async function connectWithReconnect(conn) {
5271
5272
  }
5272
5273
  }
5273
5274
  function waitForDisconnectEvent(conn) {
5274
- return new Promise((resolve34) => {
5275
+ return new Promise((resolve35) => {
5275
5276
  if (!conn.sock) {
5276
- resolve34();
5277
+ resolve35();
5277
5278
  return;
5278
5279
  }
5279
5280
  const sock = conn.sock;
5280
5281
  const handler = (update) => {
5281
5282
  if (update.connection === "close") {
5282
5283
  sock.ev.off("connection.update", handler);
5283
- resolve34();
5284
+ resolve35();
5284
5285
  }
5285
5286
  };
5286
5287
  sock.ev.on("connection.update", handler);
@@ -5602,8 +5603,8 @@ async function handleInboundMessage(conn, msg) {
5602
5603
  const conversationKey = isGroup ? remoteJid : senderPhone;
5603
5604
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
5604
5605
  let resolvePending;
5605
- const sttPending = new Promise((resolve34) => {
5606
- resolvePending = resolve34;
5606
+ const sttPending = new Promise((resolve35) => {
5607
+ resolvePending = resolve35;
5607
5608
  });
5608
5609
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
5609
5610
  try {
@@ -6031,20 +6032,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
6031
6032
 
6032
6033
  // server/routes/health.ts
6033
6034
  function checkPort(port2, timeoutMs = 500) {
6034
- return new Promise((resolve34) => {
6035
+ return new Promise((resolve35) => {
6035
6036
  const socket = createConnection2(port2, "127.0.0.1");
6036
6037
  socket.setTimeout(timeoutMs);
6037
6038
  socket.once("connect", () => {
6038
6039
  socket.destroy();
6039
- resolve34(true);
6040
+ resolve35(true);
6040
6041
  });
6041
6042
  socket.once("error", () => {
6042
6043
  socket.destroy();
6043
- resolve34(false);
6044
+ resolve35(false);
6044
6045
  });
6045
6046
  socket.once("timeout", () => {
6046
6047
  socket.destroy();
6047
- resolve34(false);
6048
+ resolve35(false);
6048
6049
  });
6049
6050
  });
6050
6051
  }
@@ -7321,8 +7322,8 @@ async function startLogin(opts) {
7321
7322
  await clearAuth(authDir);
7322
7323
  let resolveCode = null;
7323
7324
  let rejectCode = null;
7324
- const codePromise = new Promise((resolve34, reject) => {
7325
- resolveCode = resolve34;
7325
+ const codePromise = new Promise((resolve35, reject) => {
7326
+ resolveCode = resolve35;
7326
7327
  rejectCode = reject;
7327
7328
  });
7328
7329
  const codeTimer = setTimeout(
@@ -7842,17 +7843,30 @@ function projectionFor(requestedAccountId) {
7842
7843
  houseAccountManagers
7843
7844
  });
7844
7845
  }
7845
- function callerScopeDenial(c, requestedAccountId) {
7846
+ function evaluateCallerScope(c, requestedAccountId) {
7846
7847
  const callerAccountId = c.req.header("x-maxy-caller-account")?.trim() || null;
7847
7848
  const houseAdminScope = c.req.header("x-maxy-house-admin-scope")?.trim() || null;
7848
7849
  const decision = authorizeRecallRead({ requestedAccountId, callerAccountId, houseAdminScope });
7850
+ return { decision, callerAccountId, houseAdminScope };
7851
+ }
7852
+ function callerScopeDenial(c, requestedAccountId) {
7853
+ const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, requestedAccountId);
7849
7854
  if (decision.authorized) return null;
7850
7855
  console.error(`[whatsapp-read-tool] op=authz-deny requested=${requestedAccountId} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
7851
7856
  return c.json({ error: decision.reason }, 403);
7852
7857
  }
7858
+ function houseSocketScopeDenial(c, op) {
7859
+ const houseAccountId = resolveAccount()?.accountId ?? "";
7860
+ const { decision, callerAccountId, houseAdminScope } = evaluateCallerScope(c, houseAccountId);
7861
+ if (decision.authorized) return null;
7862
+ console.error(`${TAG21} op=authz-deny route=${op} caller=${callerAccountId ?? "none"} houseAdmin=${houseAdminScope ? "y" : "n"}`);
7863
+ return c.json({ ok: false, error: "Not authorized. The WhatsApp connection and its settings are house-scoped; this session may only act on its own account." }, 403);
7864
+ }
7853
7865
  var app2 = new Hono();
7854
7866
  app2.get("/status", (c) => {
7855
7867
  try {
7868
+ const denial = houseSocketScopeDenial(c, "status");
7869
+ if (denial) return denial;
7856
7870
  const live = getStatus();
7857
7871
  const liveIds = new Set(live.map((a) => a.accountId));
7858
7872
  const activeLoginIds = new Set(listActiveLoginAccountIds());
@@ -7880,6 +7894,8 @@ app2.get("/status", (c) => {
7880
7894
  });
7881
7895
  app2.post("/login/start", async (c) => {
7882
7896
  try {
7897
+ const denial = houseSocketScopeDenial(c, "login/start");
7898
+ if (denial) return denial;
7883
7899
  const body = await c.req.json().catch(() => ({}));
7884
7900
  const accountId = validateAccountId(body.accountId);
7885
7901
  const force = body.force ?? false;
@@ -7899,6 +7915,8 @@ app2.post("/login/start", async (c) => {
7899
7915
  });
7900
7916
  app2.post("/login/wait", async (c) => {
7901
7917
  try {
7918
+ const denial = houseSocketScopeDenial(c, "login/wait");
7919
+ if (denial) return denial;
7902
7920
  const body = await c.req.json().catch(() => ({}));
7903
7921
  const accountId = validateAccountId(body.accountId);
7904
7922
  const timeoutMs = body.timeoutMs ?? 6e4;
@@ -7917,6 +7935,8 @@ app2.post("/login/wait", async (c) => {
7917
7935
  });
7918
7936
  app2.post("/disconnect", async (c) => {
7919
7937
  try {
7938
+ const denial = houseSocketScopeDenial(c, "disconnect");
7939
+ if (denial) return denial;
7920
7940
  const body = await c.req.json().catch(() => ({}));
7921
7941
  const accountId = validateAccountId(body.accountId);
7922
7942
  await stopConnection(accountId);
@@ -7928,6 +7948,8 @@ app2.post("/disconnect", async (c) => {
7928
7948
  });
7929
7949
  app2.post("/reconnect", async (c) => {
7930
7950
  try {
7951
+ const denial = houseSocketScopeDenial(c, "reconnect");
7952
+ if (denial) return denial;
7931
7953
  const body = await c.req.json().catch(() => ({}));
7932
7954
  const accountId = validateAccountId(body.accountId);
7933
7955
  await startConnection(accountId);
@@ -7944,6 +7966,8 @@ app2.post("/config", async (c) => {
7944
7966
  if (!action || typeof action !== "string") {
7945
7967
  return c.json({ ok: false, error: 'Missing required field "action".' }, 400);
7946
7968
  }
7969
+ const denial = houseSocketScopeDenial(c, `config action=${action}`);
7970
+ if (denial) return denial;
7947
7971
  const account = resolveAccount();
7948
7972
  if (!account) {
7949
7973
  return c.json({ ok: false, error: "No account configured." }, 500);
@@ -8983,6 +9007,16 @@ function asString(content) {
8983
9007
  function tsOf(row) {
8984
9008
  return typeof row.timestamp === "string" ? row.timestamp : null;
8985
9009
  }
9010
+ function hasWebchatReply(content) {
9011
+ if (!Array.isArray(content)) return false;
9012
+ for (const block of content) {
9013
+ if (block && typeof block === "object") {
9014
+ const b = block;
9015
+ if (b.type === "tool_use" && b.name === WEBCHAT_REPLY_TOOL) return true;
9016
+ }
9017
+ }
9018
+ return false;
9019
+ }
8986
9020
  function joinTextBlocks(content) {
8987
9021
  if (!Array.isArray(content)) return "";
8988
9022
  const parts = [];
@@ -9075,8 +9109,10 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
9075
9109
  out.push({ kind: "agent-error", code, raw, ts });
9076
9110
  continue;
9077
9111
  }
9112
+ if (hasWebchatReply(msg?.content)) turnCtx.repliedThisTurn = true;
9078
9113
  const isEnd = msg?.stop_reason === "end_turn";
9079
- out.push(...assistantTurns(msg?.content, ts, isEnd && turnCtx.lastChannelSource === "webchat"));
9114
+ const promoteFinal = isEnd && turnCtx.lastChannelSource === "webchat" && !turnCtx.repliedThisTurn;
9115
+ out.push(...assistantTurns(msg?.content, ts, promoteFinal));
9080
9116
  continue;
9081
9117
  }
9082
9118
  if (row.type === "queue-operation" && row.operation === "enqueue") {
@@ -9084,6 +9120,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
9084
9120
  if (content !== null && CHANNEL_WRAPPER2.test(content)) {
9085
9121
  const u = unwrapChannel(content);
9086
9122
  turnCtx.lastChannelSource = u.source;
9123
+ turnCtx.repliedThisTurn = false;
9087
9124
  if (!isScheduleSource(content)) {
9088
9125
  out.push(operatorInboundTurn(u, ts));
9089
9126
  queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
@@ -9097,6 +9134,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
9097
9134
  if (isChannelQueued) {
9098
9135
  const u = unwrapChannel(att.prompt);
9099
9136
  turnCtx.lastChannelSource = u.source;
9137
+ turnCtx.repliedThisTurn = false;
9100
9138
  if (!isScheduleSource(att.prompt)) {
9101
9139
  renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress);
9102
9140
  }
@@ -9126,6 +9164,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
9126
9164
  if (isChannel) {
9127
9165
  const u = unwrapChannel(text);
9128
9166
  turnCtx.lastChannelSource = u.source;
9167
+ turnCtx.repliedThisTurn = false;
9129
9168
  if (!isScheduleSource(text)) {
9130
9169
  renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress);
9131
9170
  }
@@ -9210,6 +9249,24 @@ function splitNewLines(buf, baseOffset) {
9210
9249
  };
9211
9250
  }
9212
9251
 
9252
+ // app/lib/whatsapp-reader/authorize-reply-file-ref.ts
9253
+ 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;
9254
+ function accountPartitionOwner(relative7) {
9255
+ const segs = relative7.split("/").filter(Boolean);
9256
+ if (segs.length < 2 || segs[0] !== "accounts") return null;
9257
+ return ACCOUNT_UUID_RE2.test(segs[1]) ? segs[1] : null;
9258
+ }
9259
+ function authorizeReplyFileRef(input) {
9260
+ const { relative: relative7, sendAccountId, sessionAccountId } = input;
9261
+ const segs = relative7.split("/").filter(Boolean);
9262
+ const inAccounts = segs.length >= 2 && segs[0] === "accounts";
9263
+ if (inAccounts && segs[1] === sendAccountId) return { allow: true, via: "own" };
9264
+ if (inAccounts && sessionAccountId && segs[1] === sessionAccountId) return { allow: true, via: "session" };
9265
+ if (accountPartitionOwner(relative7)) return { allow: false, reason: "cross-account" };
9266
+ if (segs[0] === "public" || inAccounts && segs[1] === "public") return { allow: false, reason: "public" };
9267
+ return { allow: false, reason: "foreign" };
9268
+ }
9269
+
9213
9270
  // server/routes/admin/manager-client.ts
9214
9271
  var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9215
9272
  function isSessionId(value) {
@@ -9244,6 +9301,11 @@ function isMimeAdmitted(mimeType, supportedSet) {
9244
9301
 
9245
9302
  // server/routes/whatsapp-reader.ts
9246
9303
  var app4 = new Hono();
9304
+ var DENY_COPY = {
9305
+ "cross-account": "This file belongs to another account. Open that account to send it.",
9306
+ public: "This file cannot be sent to a WhatsApp contact.",
9307
+ foreign: "This file cannot be sent to a WhatsApp contact."
9308
+ };
9247
9309
  app4.get("/conversations", requireAdminSession, async (c) => {
9248
9310
  const cacheKey = c.var.cacheKey;
9249
9311
  const scopeAccountId = getAccountIdForSession(cacheKey) ?? null;
@@ -9891,7 +9953,9 @@ app4.post("/reply", requireAdminSession, async (c) => {
9891
9953
  return c.json({ error: "invalid accountId" }, 400);
9892
9954
  }
9893
9955
  const validAccount = isValidAccountId(accountId);
9894
- console.log(`${MANUAL_TAG} op=scope sendId=${sendId} accountId=${accountId} validAccount=${validAccount}`);
9956
+ const cacheKey = c.var.cacheKey;
9957
+ const sessionAccountId = getAccountIdForSession(cacheKey) ?? null;
9958
+ console.log(`${MANUAL_TAG} op=scope sendId=${sendId} accountId=${accountId} validAccount=${validAccount} sessionAccount=${sessionAccountId ?? "null"} src=session`);
9895
9959
  if (!validAccount) {
9896
9960
  exit("rejected");
9897
9961
  return c.json({ error: "unknown account" }, 400);
@@ -9929,26 +9993,37 @@ app4.post("/reply", requireAdminSession, async (c) => {
9929
9993
  }
9930
9994
  }
9931
9995
  const resolvedRefs = [];
9996
+ const acct8 = accountId.slice(0, 8);
9997
+ const sess8 = sessionAccountId ? sessionAccountId.slice(0, 8) : "";
9932
9998
  for (const ref of fileRefs) {
9933
9999
  const resolved = resolveDataPath(ref);
9934
- const withinOwn = resolved.ok && !crossesForeignAccountPartition(resolved.relative, accountId) && isWithinOwnAccountPartition(resolved.relative, accountId);
9935
- let absolute = "";
10000
+ if (!resolved.ok) {
10001
+ console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner= sendAccount=${acct8} sessionAccount=${sess8} via=deny reason=unresolved ok=false`);
10002
+ exit("rejected");
10003
+ return c.json({ error: `device file not found: ${ref}`, reason: "file-ref-unresolved" }, 404);
10004
+ }
10005
+ const owner = accountPartitionOwner(resolved.relative);
10006
+ const owner8 = owner ? owner.slice(0, 8) : "";
10007
+ const decision = authorizeReplyFileRef({ relative: resolved.relative, sendAccountId: accountId, sessionAccountId });
10008
+ if (!decision.allow) {
10009
+ console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=deny reason=${decision.reason} ok=false`);
10010
+ exit("rejected");
10011
+ return c.json({ error: DENY_COPY[decision.reason], reason: `file-ref-${decision.reason}` }, 403);
10012
+ }
10013
+ const absolute = resolved.absolute;
9936
10014
  let size = -1;
9937
- if (withinOwn) {
9938
- absolute = resolved.absolute;
9939
- try {
9940
- const st = statSync5(absolute);
9941
- size = st.isFile() ? st.size : -1;
9942
- } catch {
9943
- size = -1;
9944
- }
10015
+ try {
10016
+ const st = statSync5(absolute);
10017
+ size = st.isFile() ? st.size : -1;
10018
+ } catch {
10019
+ size = -1;
9945
10020
  }
9946
- const ok = size >= 0;
9947
- console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} resolved=${absolute} ok=${ok}`);
9948
- if (!ok) {
10021
+ if (size < 0) {
10022
+ console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=${decision.via} reason=missing ok=false`);
9949
10023
  exit("rejected");
9950
10024
  return c.json({ error: `device file not found: ${ref}`, reason: "file-ref-unresolved" }, 404);
9951
10025
  }
10026
+ console.log(`${MANUAL_TAG} op=reply-file-ref sendId=${sendId} path=${ref} owner=${owner8} sendAccount=${acct8} sessionAccount=${sess8} via=${decision.via} reason=none ok=true`);
9952
10027
  if (size > MAX_FILE_BYTES) {
9953
10028
  exit("rejected");
9954
10029
  return c.json({ error: `"${basename4(absolute)}" exceeds the 50 MB limit` }, 400);
@@ -10837,6 +10912,7 @@ function createWebchatRoutes(deps) {
10837
10912
  let text;
10838
10913
  let target;
10839
10914
  let files = [];
10915
+ let clearSignal = false;
10840
10916
  const contentType = c.req.header("content-type") ?? "";
10841
10917
  const isMultipart = contentType.startsWith("multipart/form-data");
10842
10918
  if (isMultipart) {
@@ -10857,6 +10933,7 @@ function createWebchatRoutes(deps) {
10857
10933
  }
10858
10934
  target = rawTarget;
10859
10935
  }
10936
+ clearSignal = formData.get("clearSignal") === "true";
10860
10937
  } else {
10861
10938
  const body = await c.req.json().catch(() => null);
10862
10939
  const typed = body?.text;
@@ -10871,14 +10948,25 @@ function createWebchatRoutes(deps) {
10871
10948
  }
10872
10949
  target = rawTarget;
10873
10950
  }
10951
+ clearSignal = body?.clearSignal === true;
10874
10952
  }
10875
10953
  let deliveryKey = WEBCHAT_ADMIN_KEY;
10876
10954
  let deliverySessionId;
10877
10955
  let deliveryAccountId = accountId;
10878
10956
  const explicitTarget = target !== void 0;
10957
+ let sendIdFromResolve;
10879
10958
  if (target === void 0) {
10880
10959
  const latest = latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccountId, multiAccount);
10881
- if (latest !== null) target = latest;
10960
+ let sendTargetMode = "bootstrap";
10961
+ if (clearSignal) {
10962
+ sendTargetMode = "spawn-new";
10963
+ } else if (latest !== null) {
10964
+ target = latest;
10965
+ sendTargetMode = "resume-latest";
10966
+ }
10967
+ const sendId2 = ++sendSeq;
10968
+ sendIdFromResolve = sendId2;
10969
+ console.error(`[webchat:inbound] op=send-target-resolve seq=${sendId2} mode=${sendTargetMode} hadLatest=${latest !== null} clearSignal=${clearSignal}`);
10882
10970
  }
10883
10971
  if (explicitTarget && target !== void 0) {
10884
10972
  const t = readTargetOwner(target);
@@ -10993,7 +11081,7 @@ ${note}` : note;
10993
11081
  if (deliveredIntId !== null) {
10994
11082
  console.log(`[webchat-interrupt] op=delivered intId=${deliveredIntId} sessionId=${deliverySessionId.slice(0, 8)}`);
10995
11083
  }
10996
- const sendId = ++sendSeq;
11084
+ const sendId = sendIdFromResolve ?? ++sendSeq;
10997
11085
  let turnSessionId = deliverySessionId;
10998
11086
  if (turnSessionId === void 0) {
10999
11087
  let canonAccount;
@@ -11163,7 +11251,7 @@ ${note}` : note;
11163
11251
  }
11164
11252
  }
11165
11253
  const indicators = await fetchComposerIndicators(sessionId);
11166
- return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
11254
+ return c.json({ sessionId, projectDir, source, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
11167
11255
  });
11168
11256
  app62.post("/permission-verdict", requireAdminSession, async (c) => {
11169
11257
  const body = await c.req.json().catch(() => null);
@@ -17099,6 +17187,142 @@ function isHiddenByDefault(label) {
17099
17187
  return HIDDEN_BY_DEFAULT_LABELS.has(label);
17100
17188
  }
17101
17189
 
17190
+ // server/lib/top-level-labels.ts
17191
+ import { readdirSync as readdirSync19, readFileSync as readFileSync30 } from "fs";
17192
+ import { join as join30, resolve as resolve23 } from "path";
17193
+ var STATIC_TOP_LEVEL_LABELS = Object.freeze(
17194
+ /* @__PURE__ */ new Set([
17195
+ // Base-schema infra (schema-base.md has no top-level section).
17196
+ "LocalBusiness",
17197
+ "Service",
17198
+ "PriceSpecification",
17199
+ "OpeningHoursSpecification",
17200
+ "Organization",
17201
+ "Person",
17202
+ "UserProfile",
17203
+ "Preference",
17204
+ "AdminUser",
17205
+ "AccessGrant",
17206
+ "KnowledgeDocument",
17207
+ "DigitalDocument",
17208
+ "CreativeWork",
17209
+ "Question",
17210
+ "FAQPage",
17211
+ "DefinedTerm",
17212
+ "Review",
17213
+ "ImageObject",
17214
+ "Invoice",
17215
+ "Task",
17216
+ "Project",
17217
+ "Event",
17218
+ "Workflow",
17219
+ "Email",
17220
+ "EmailAccount",
17221
+ "Agent",
17222
+ // Knowledge-work vertical: schema-knowledge-work.md has no top-level
17223
+ // section yet.
17224
+ "Objective",
17225
+ "KeyResult",
17226
+ "Decision",
17227
+ "Risk",
17228
+ "Source",
17229
+ "Finding",
17230
+ "Hypothesis"
17231
+ ])
17232
+ );
17233
+ function splitPipeRow(row) {
17234
+ let trimmed = row.trim();
17235
+ if (trimmed.startsWith("|")) trimmed = trimmed.slice(1);
17236
+ if (trimmed.endsWith("|")) trimmed = trimmed.slice(0, -1);
17237
+ const cells = [];
17238
+ let inBacktick = false;
17239
+ let start = 0;
17240
+ for (let i = 0; i < trimmed.length; i++) {
17241
+ const ch = trimmed[i];
17242
+ if (ch === "`") inBacktick = !inBacktick;
17243
+ else if (ch === "|" && !inBacktick) {
17244
+ cells.push(trimmed.slice(start, i).trim());
17245
+ start = i + 1;
17246
+ }
17247
+ }
17248
+ cells.push(trimmed.slice(start).trim());
17249
+ return cells;
17250
+ }
17251
+ var stripBackticks = (s) => s.replace(/`/g, "").trim();
17252
+ function parseTopLevelLabels(content) {
17253
+ const lines = content.split(/\r?\n/);
17254
+ let i = 0;
17255
+ while (i < lines.length) {
17256
+ if (lines[i].toLowerCase().startsWith("## top-level node types")) break;
17257
+ i++;
17258
+ }
17259
+ if (i >= lines.length) return [];
17260
+ i++;
17261
+ for (; i < lines.length - 1; i++) {
17262
+ const line = lines[i];
17263
+ if (line.startsWith("## ")) return [];
17264
+ if (!line.includes("|")) continue;
17265
+ const sep9 = lines[i + 1];
17266
+ if (!/^\s*\|?[\s:|-]+\|?\s*$/.test(sep9) || !sep9.includes("-")) continue;
17267
+ const headers = splitPipeRow(line).map((h) => stripBackticks(h).toLowerCase());
17268
+ const labelCol = headers.findIndex((h) => h === "neo4j label");
17269
+ if (labelCol === -1) return [];
17270
+ const out = [];
17271
+ let j = i + 2;
17272
+ for (; j < lines.length; j++) {
17273
+ const row = lines[j];
17274
+ if (!row.trim() || !row.includes("|")) break;
17275
+ const cells = splitPipeRow(row);
17276
+ const label = stripBackticks(cells[labelCol] ?? "");
17277
+ if (label) out.push(label);
17278
+ }
17279
+ return out;
17280
+ }
17281
+ return [];
17282
+ }
17283
+ function resolveReferencesDir() {
17284
+ if (process.env.MAXY_PLATFORM_ROOT) {
17285
+ return join30(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
17286
+ }
17287
+ return resolve23(import.meta.dirname, "../../../plugins/memory/references");
17288
+ }
17289
+ function parseTableTopLevelLabels(referencesDir) {
17290
+ const labels = /* @__PURE__ */ new Set();
17291
+ const contributingFiles = [];
17292
+ try {
17293
+ const fileNames = readdirSync19(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
17294
+ for (const fileName of fileNames) {
17295
+ const content = readFileSync30(join30(referencesDir, fileName), "utf-8");
17296
+ const parsed = parseTopLevelLabels(content);
17297
+ if (parsed.length > 0) contributingFiles.push(fileName);
17298
+ for (const label of parsed) labels.add(label);
17299
+ }
17300
+ } catch (err) {
17301
+ const message = err instanceof Error ? err.message : String(err);
17302
+ process.stderr.write(
17303
+ `[graph-page] op=top-level-labels source=ontology status=error dir=${referencesDir} reason="${message}"
17304
+ `
17305
+ );
17306
+ throw err;
17307
+ }
17308
+ return { labels, contributingFiles };
17309
+ }
17310
+ var cached = null;
17311
+ function getTopLevelLabelAllowlist(opts = {}) {
17312
+ if (!opts.referencesDir && cached) return cached;
17313
+ const referencesDir = opts.referencesDir ?? resolveReferencesDir();
17314
+ const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
17315
+ const derivedCount = derived.size;
17316
+ for (const label of STATIC_TOP_LEVEL_LABELS) derived.add(label);
17317
+ const result = Object.freeze(derived);
17318
+ process.stderr.write(
17319
+ `[graph-page] op=top-level-labels source=ontology count=${derived.size} files=${contributingFiles.join("|") || "none"} derived=${derivedCount} static=${STATIC_TOP_LEVEL_LABELS.size}
17320
+ `
17321
+ );
17322
+ if (!opts.referencesDir) cached = result;
17323
+ return result;
17324
+ }
17325
+
17102
17326
  // server/routes/admin/graph-subgraph.ts
17103
17327
  var CEILING = 2e3;
17104
17328
  var TOP_LEVEL_LIMIT = 1e3;
@@ -17220,7 +17444,7 @@ async function handleDefault(c, accountId) {
17220
17444
  }
17221
17445
  async function handleDefaultTopLevel(c, accountId, flags) {
17222
17446
  const { includeTrashed, includeAgentActions } = flags;
17223
- const labels = [...FILTER_TOP_LEVEL_LABELS].filter((l) => !HIDDEN_BY_DEFAULT_LABELS.has(l));
17447
+ const labels = [...getTopLevelLabelAllowlist()].filter((l) => !HIDDEN_BY_DEFAULT_LABELS.has(l));
17224
17448
  const agentActionLabels = [...AGENT_ACTION_LABELS];
17225
17449
  const started = Date.now();
17226
17450
  const session = getSession();
@@ -18031,7 +18255,7 @@ app26.get("/", requireAdminSession, async (c) => {
18031
18255
  const started = Date.now();
18032
18256
  const session = getSession();
18033
18257
  try {
18034
- const allowedSet = new Set(FILTER_TOP_LEVEL_LABELS);
18258
+ const allowedSet = new Set(getTopLevelLabelAllowlist());
18035
18259
  if (includeAgentActions) {
18036
18260
  for (const label of AGENT_ACTION_LABELS) allowedSet.add(label);
18037
18261
  }
@@ -18193,12 +18417,12 @@ function validateBody(body) {
18193
18417
  if (typeof lbl !== "string") {
18194
18418
  return { ok: false, code: "shape", reason: "labels must be an array of strings" };
18195
18419
  }
18196
- if (!FILTER_TOP_LEVEL_LABELS.has(lbl)) {
18420
+ if (!getTopLevelLabelAllowlist().has(lbl)) {
18197
18421
  return {
18198
18422
  ok: false,
18199
18423
  code: "not-eligible-chip",
18200
18424
  label: lbl,
18201
- reason: `label "${lbl}" is not eligible for default view \u2014 outside the chip allowlist (FILTER_TOP_LEVEL_LABELS)`
18425
+ reason: `label "${lbl}" is not eligible for default view \u2014 outside the chip allowlist`
18202
18426
  };
18203
18427
  }
18204
18428
  seen.add(lbl);
@@ -18221,7 +18445,7 @@ var graph_default_view_default = app27;
18221
18445
 
18222
18446
  // server/routes/admin/sidebar-artefacts.ts
18223
18447
  import { readdir as readdir4, stat as stat5 } from "fs/promises";
18224
- import { resolve as resolve23, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
18448
+ import { resolve as resolve24, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
18225
18449
  import { existsSync as existsSync27 } from "fs";
18226
18450
  var LIMIT = 50;
18227
18451
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -18241,7 +18465,7 @@ app28.get("/", requireAdminSession, async (c) => {
18241
18465
  if (accountFiles === null) {
18242
18466
  return c.json({ error: "Failed to load artefacts" }, 500);
18243
18467
  }
18244
- const accountDir = resolve23(ACCOUNTS_DIR, accountId);
18468
+ const accountDir = resolve24(ACCOUNTS_DIR, accountId);
18245
18469
  const agents = await fetchAgentTemplateRows(accountDir);
18246
18470
  const artefacts = [...accountFiles, ...agents].sort(
18247
18471
  (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
@@ -18293,8 +18517,8 @@ async function fetchAccountFileArtefacts(accountId) {
18293
18517
  async function fetchAgentTemplateRows(accountDir) {
18294
18518
  const rows = [];
18295
18519
  for (const filename of ADMIN_AGENT_FILES) {
18296
- const overridePath = resolve23(accountDir, "agents", "admin", filename);
18297
- const bundledPath = resolve23(PLATFORM_ROOT, "templates", "agents", "admin", filename);
18520
+ const overridePath = resolve24(accountDir, "agents", "admin", filename);
18521
+ const bundledPath = resolve24(PLATFORM_ROOT, "templates", "agents", "admin", filename);
18298
18522
  const labelStem = filename.replace(/\.md$/, "");
18299
18523
  const row = await readAgentTemplateRow({
18300
18524
  id: `agent-template:admin:${filename}`,
@@ -18307,12 +18531,12 @@ async function fetchAgentTemplateRows(accountDir) {
18307
18531
  });
18308
18532
  if (row) rows.push(row);
18309
18533
  }
18310
- const overrideDir = resolve23(accountDir, "specialists", "agents");
18311
- const bundledDir = resolve23(PLATFORM_ROOT, "templates", "specialists", "agents");
18534
+ const overrideDir = resolve24(accountDir, "specialists", "agents");
18535
+ const bundledDir = resolve24(PLATFORM_ROOT, "templates", "specialists", "agents");
18312
18536
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
18313
18537
  for (const filename of specialistNames) {
18314
- const overridePath = resolve23(overrideDir, filename);
18315
- const bundledPath = resolve23(bundledDir, filename);
18538
+ const overridePath = resolve24(overrideDir, filename);
18539
+ const bundledPath = resolve24(bundledDir, filename);
18316
18540
  const row = await readAgentTemplateRow({
18317
18541
  id: `agent-template:specialist:${filename}`,
18318
18542
  displayName: filename.replace(/\.md$/, ""),
@@ -18594,7 +18818,7 @@ var session_usage_default = app33;
18594
18818
 
18595
18819
  // server/routes/admin/session-rc-spawn.ts
18596
18820
  import { randomUUID as randomUUID10 } from "crypto";
18597
- var ACCOUNT_UUID_RE2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
18821
+ var ACCOUNT_UUID_RE3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
18598
18822
  function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId, authenticatedName, callerAccountId) {
18599
18823
  const operator = isOperatorHost(host, operatorDomains);
18600
18824
  const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
@@ -18605,8 +18829,8 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
18605
18829
  const pickedModel = kind === "new" && typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
18606
18830
  const pickedEffort = kind === "new" && typeof body.effort === "string" && isNewSessionEffortLevel(body.effort) ? body.effort : null;
18607
18831
  const paramsSource = pickedModel !== null && pickedEffort !== null ? "picker" : "default";
18608
- const callerTargetAccountId = typeof callerAccountId === "string" && ACCOUNT_UUID_RE2.test(callerAccountId) ? callerAccountId : void 0;
18609
- const bodyTargetAccountId = typeof body.targetAccountId === "string" && ACCOUNT_UUID_RE2.test(body.targetAccountId) ? body.targetAccountId : void 0;
18832
+ const callerTargetAccountId = typeof callerAccountId === "string" && ACCOUNT_UUID_RE3.test(callerAccountId) ? callerAccountId : void 0;
18833
+ const bodyTargetAccountId = typeof body.targetAccountId === "string" && ACCOUNT_UUID_RE3.test(body.targetAccountId) ? body.targetAccountId : void 0;
18610
18834
  const targetAccountId = kind === "new" ? callerTargetAccountId : bodyTargetAccountId;
18611
18835
  const payload = {};
18612
18836
  let sessionId;
@@ -18957,24 +19181,24 @@ app36.get("/", async (c) => {
18957
19181
  var system_stats_default = app36;
18958
19182
 
18959
19183
  // server/routes/admin/health.ts
18960
- import { existsSync as existsSync28, readFileSync as readFileSync30 } from "fs";
18961
- import { resolve as resolve24, join as join30 } from "path";
18962
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
19184
+ import { existsSync as existsSync28, readFileSync as readFileSync31 } from "fs";
19185
+ import { resolve as resolve25, join as join31 } from "path";
19186
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
18963
19187
  var brandHostname = "maxy";
18964
- var brandJsonPath = join30(PLATFORM_ROOT6, "config", "brand.json");
19188
+ var brandJsonPath = join31(PLATFORM_ROOT6, "config", "brand.json");
18965
19189
  if (existsSync28(brandJsonPath)) {
18966
19190
  try {
18967
- const brand = JSON.parse(readFileSync30(brandJsonPath, "utf-8"));
19191
+ const brand = JSON.parse(readFileSync31(brandJsonPath, "utf-8"));
18968
19192
  if (brand.hostname) brandHostname = brand.hostname;
18969
19193
  } catch {
18970
19194
  }
18971
19195
  }
18972
- var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
19196
+ var VERSION_FILE = resolve25(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
18973
19197
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
18974
19198
  var PROBE_TIMEOUT_MS = 1e3;
18975
19199
  function readVersion() {
18976
19200
  if (!existsSync28(VERSION_FILE)) return "unknown";
18977
- return readFileSync30(VERSION_FILE, "utf-8").trim() || "unknown";
19201
+ return readFileSync31(VERSION_FILE, "utf-8").trim() || "unknown";
18978
19202
  }
18979
19203
  async function probeConversationDb() {
18980
19204
  let session;
@@ -19751,7 +19975,7 @@ var browser_default = app44;
19751
19975
 
19752
19976
  // server/routes/admin/calendar.ts
19753
19977
  import { existsSync as existsSync29 } from "fs";
19754
- import { join as join32 } from "path";
19978
+ import { join as join33 } from "path";
19755
19979
 
19756
19980
  // server/lib/calendar-ics.ts
19757
19981
  var CRLF = "\r\n";
@@ -19850,8 +20074,8 @@ function countVEvents(ics) {
19850
20074
  }
19851
20075
 
19852
20076
  // server/lib/calendar-availability.ts
19853
- import { readFileSync as readFileSync31 } from "fs";
19854
- import { join as join31 } from "path";
20077
+ import { readFileSync as readFileSync32 } from "fs";
20078
+ import { join as join32 } from "path";
19855
20079
  var AVAILABILITY_FILENAME = "calendar-availability.json";
19856
20080
  var REQUIRED_KEYS = [
19857
20081
  "timezone",
@@ -19860,10 +20084,10 @@ var REQUIRED_KEYS = [
19860
20084
  "weekly"
19861
20085
  ];
19862
20086
  function readAvailabilityConfig(accountDir) {
19863
- const path2 = join31(accountDir, AVAILABILITY_FILENAME);
20087
+ const path2 = join32(accountDir, AVAILABILITY_FILENAME);
19864
20088
  let raw;
19865
20089
  try {
19866
- raw = readFileSync31(path2, "utf-8");
20090
+ raw = readFileSync32(path2, "utf-8");
19867
20091
  } catch {
19868
20092
  throw new Error(`availability not configured: ${path2} not found`);
19869
20093
  }
@@ -20222,7 +20446,7 @@ app45.get("/booking-link", requireAdminSession, (c) => {
20222
20446
  console.error('[calendar] op=booking-link-fail err="no account configured"');
20223
20447
  return c.json({ bookingDomain: null });
20224
20448
  }
20225
- if (!existsSync29(join32(account.accountDir, AVAILABILITY_FILENAME))) {
20449
+ if (!existsSync29(join33(account.accountDir, AVAILABILITY_FILENAME))) {
20226
20450
  console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
20227
20451
  return c.json({ bookingDomain: null });
20228
20452
  }
@@ -20696,9 +20920,9 @@ var verify_token_default = app52;
20696
20920
 
20697
20921
  // app/lib/access-email.ts
20698
20922
  import { spawn as spawn2 } from "child_process";
20699
- import { resolve as resolve25 } from "path";
20700
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
20701
- var SEND_SCRIPT = resolve25(
20923
+ import { resolve as resolve26 } from "path";
20924
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
20925
+ var SEND_SCRIPT = resolve26(
20702
20926
  PLATFORM_ROOT7,
20703
20927
  "plugins",
20704
20928
  "email",
@@ -20840,8 +21064,8 @@ app54.route("/request-magic-link", request_magic_link_default);
20840
21064
  var access_default = app54;
20841
21065
 
20842
21066
  // server/routes/sites.ts
20843
- import { existsSync as existsSync30, readFileSync as readFileSync32, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
20844
- import { resolve as resolve26 } from "path";
21067
+ import { existsSync as existsSync30, readFileSync as readFileSync33, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
21068
+ import { resolve as resolve27 } from "path";
20845
21069
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
20846
21070
  var MIME = {
20847
21071
  ".html": "text/html; charset=utf-8",
@@ -20898,8 +21122,8 @@ app55.get("/:rel{.*}", (c) => {
20898
21122
  }
20899
21123
  segments.push(seg);
20900
21124
  }
20901
- const rootDir = resolve26(account.accountDir, "sites");
20902
- let filePath = segments.length === 0 ? rootDir : resolve26(rootDir, ...segments);
21125
+ const rootDir = resolve27(account.accountDir, "sites");
21126
+ let filePath = segments.length === 0 ? rootDir : resolve27(rootDir, ...segments);
20903
21127
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
20904
21128
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
20905
21129
  return c.text("Forbidden", 403);
@@ -20919,7 +21143,7 @@ app55.get("/:rel{.*}", (c) => {
20919
21143
  return c.redirect(target, 301);
20920
21144
  }
20921
21145
  if (stat8?.isDirectory()) {
20922
- filePath = resolve26(filePath, "index.html");
21146
+ filePath = resolve27(filePath, "index.html");
20923
21147
  }
20924
21148
  if (!filePath.startsWith(rootDir + "/")) {
20925
21149
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
@@ -20944,7 +21168,7 @@ app55.get("/:rel{.*}", (c) => {
20944
21168
  }
20945
21169
  let body;
20946
21170
  try {
20947
- body = readFileSync32(realPath);
21171
+ body = readFileSync33(realPath);
20948
21172
  } catch (err) {
20949
21173
  const code = err?.code;
20950
21174
  if (code === "EISDIR") {
@@ -20980,7 +21204,7 @@ var sites_default = app55;
20980
21204
 
20981
21205
  // app/lib/visitor-token.ts
20982
21206
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
20983
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync33, writeFileSync as writeFileSync11 } from "fs";
21207
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync34, writeFileSync as writeFileSync11 } from "fs";
20984
21208
  import { dirname as dirname11 } from "path";
20985
21209
  var TOKEN_PREFIX = "v1.";
20986
21210
  var SECRET_BYTES = 32;
@@ -20989,7 +21213,7 @@ var cachedSecret = null;
20989
21213
  function getSecret() {
20990
21214
  if (cachedSecret) return cachedSecret;
20991
21215
  try {
20992
- const hex2 = readFileSync33(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
21216
+ const hex2 = readFileSync34(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
20993
21217
  if (hex2.length === SECRET_BYTES * 2) {
20994
21218
  cachedSecret = Buffer.from(hex2, "hex");
20995
21219
  return cachedSecret;
@@ -21003,7 +21227,7 @@ function getSecret() {
21003
21227
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
21004
21228
  } catch {
21005
21229
  }
21006
- const hex = readFileSync33(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
21230
+ const hex = readFileSync34(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
21007
21231
  cachedSecret = Buffer.from(hex, "hex");
21008
21232
  return cachedSecret;
21009
21233
  }
@@ -21056,20 +21280,20 @@ var VISITOR_COOKIE_NAME = "mxy_v";
21056
21280
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
21057
21281
 
21058
21282
  // app/lib/brand-config.ts
21059
- import { existsSync as existsSync31, readFileSync as readFileSync34 } from "fs";
21060
- import { join as join33 } from "path";
21061
- var cached = null;
21283
+ import { existsSync as existsSync31, readFileSync as readFileSync35 } from "fs";
21284
+ import { join as join34 } from "path";
21285
+ var cached2 = null;
21062
21286
  var cachedAttempted = false;
21063
21287
  function readBrandConfig() {
21064
- if (cachedAttempted) return cached;
21288
+ if (cachedAttempted) return cached2;
21065
21289
  cachedAttempted = true;
21066
21290
  const platformRoot3 = process.env.MAXY_PLATFORM_ROOT;
21067
21291
  if (!platformRoot3) return null;
21068
- const brandPath = join33(platformRoot3, "config", "brand.json");
21292
+ const brandPath = join34(platformRoot3, "config", "brand.json");
21069
21293
  if (!existsSync31(brandPath)) return null;
21070
21294
  try {
21071
- cached = JSON.parse(readFileSync34(brandPath, "utf-8"));
21072
- return cached;
21295
+ cached2 = JSON.parse(readFileSync35(brandPath, "utf-8"));
21296
+ return cached2;
21073
21297
  } catch {
21074
21298
  return null;
21075
21299
  }
@@ -21556,14 +21780,14 @@ async function writeEvent(opts) {
21556
21780
  var visitor_event_default = app58;
21557
21781
 
21558
21782
  // server/routes/session.ts
21559
- import { resolve as resolve27 } from "path";
21783
+ import { resolve as resolve28 } from "path";
21560
21784
  import { existsSync as existsSync32, writeFileSync as writeFileSync12, mkdirSync as mkdirSync8 } from "fs";
21561
21785
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
21562
21786
  function writeBrandingCache(accountId, agentSlug, branding) {
21563
21787
  try {
21564
- const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
21788
+ const cacheDir = resolve28(MAXY_DIR, "branding-cache", accountId);
21565
21789
  mkdirSync8(cacheDir, { recursive: true });
21566
- writeFileSync12(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
21790
+ writeFileSync12(resolve28(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
21567
21791
  } catch (err) {
21568
21792
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
21569
21793
  }
@@ -21640,8 +21864,8 @@ app59.post("/", async (c) => {
21640
21864
  }
21641
21865
  let agentConfig = null;
21642
21866
  if (account) {
21643
- const agentDir = resolve27(account.accountDir, "agents", agentSlug);
21644
- if (!existsSync32(agentDir) || !existsSync32(resolve27(agentDir, "config.json"))) {
21867
+ const agentDir = resolve28(account.accountDir, "agents", agentSlug);
21868
+ if (!existsSync32(agentDir) || !existsSync32(resolve28(agentDir, "config.json"))) {
21645
21869
  return c.json({ error: "Agent not found" }, 404);
21646
21870
  }
21647
21871
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -22087,8 +22311,8 @@ function startGraphHealthTimer() {
22087
22311
 
22088
22312
  // app/lib/file-watcher.ts
22089
22313
  import * as fsp2 from "fs/promises";
22090
- import { resolve as resolve28, sep as sep8 } from "path";
22091
- var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22314
+ import { resolve as resolve29, sep as sep8 } from "path";
22315
+ var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22092
22316
  var DEFAULT_COALESCE_MS = 500;
22093
22317
  var ROOTS = ["accounts"];
22094
22318
  function _routeEvent(rootName, filename) {
@@ -22096,7 +22320,7 @@ function _routeEvent(rootName, filename) {
22096
22320
  const segs = filename.split(sep8).filter(Boolean);
22097
22321
  if (segs.length < 2) return null;
22098
22322
  const accountId = segs[0];
22099
- if (!ACCOUNT_UUID_RE3.test(accountId)) return null;
22323
+ if (!ACCOUNT_UUID_RE4.test(accountId)) return null;
22100
22324
  return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
22101
22325
  }
22102
22326
  async function startFileWatcher(opts = {}) {
@@ -22106,7 +22330,7 @@ async function startFileWatcher(opts = {}) {
22106
22330
  const dropFn = opts.drop ?? dropFileIndex;
22107
22331
  for (const r of ROOTS) {
22108
22332
  try {
22109
- await fsp2.mkdir(resolve28(dataRoot, r), { recursive: true });
22333
+ await fsp2.mkdir(resolve29(dataRoot, r), { recursive: true });
22110
22334
  } catch (err) {
22111
22335
  console.error(
22112
22336
  `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
@@ -22127,7 +22351,7 @@ async function startFileWatcher(opts = {}) {
22127
22351
  timers.set(relativePath, t);
22128
22352
  }
22129
22353
  async function runHook(relativePath, accountId) {
22130
- const absolute = resolve28(dataRoot, relativePath);
22354
+ const absolute = resolve29(dataRoot, relativePath);
22131
22355
  let exists = false;
22132
22356
  try {
22133
22357
  const st = await fsp2.stat(absolute);
@@ -22151,7 +22375,7 @@ async function startFileWatcher(opts = {}) {
22151
22375
  }
22152
22376
  }
22153
22377
  async function watchRoot(rootName) {
22154
- const absRoot = resolve28(dataRoot, rootName);
22378
+ const absRoot = resolve29(dataRoot, rootName);
22155
22379
  try {
22156
22380
  const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
22157
22381
  for await (const event of iter) {
@@ -22190,8 +22414,8 @@ async function startFileWatcher(opts = {}) {
22190
22414
 
22191
22415
  // app/lib/migrate-uploads.ts
22192
22416
  import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
22193
- import { dirname as dirname12, relative as relative6, resolve as resolve29 } from "path";
22194
- var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22417
+ import { dirname as dirname12, relative as relative6, resolve as resolve30 } from "path";
22418
+ var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
22195
22419
  async function walkFiles(dir) {
22196
22420
  const out = [];
22197
22421
  let entries;
@@ -22201,7 +22425,7 @@ async function walkFiles(dir) {
22201
22425
  return out;
22202
22426
  }
22203
22427
  for (const e of entries) {
22204
- const abs = resolve29(dir, e.name);
22428
+ const abs = resolve30(dir, e.name);
22205
22429
  if (e.isDirectory()) {
22206
22430
  out.push(...await walkFiles(abs));
22207
22431
  } else if (e.isFile()) {
@@ -22221,7 +22445,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
22221
22445
  let moved = 0;
22222
22446
  for (const oldAbs of files) {
22223
22447
  const suffix = relative6(srcDir, oldAbs);
22224
- const newAbs = resolve29(destDir, suffix);
22448
+ const newAbs = resolve30(destDir, suffix);
22225
22449
  await mkdir5(dirname12(newAbs), { recursive: true });
22226
22450
  await rename2(oldAbs, newAbs);
22227
22451
  moved++;
@@ -22248,7 +22472,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
22248
22472
  }
22249
22473
  async function migrateUploads(opts = {}) {
22250
22474
  const dataRoot = opts.dataRoot ?? DATA_ROOT;
22251
- const oldRoot = resolve29(dataRoot, "uploads");
22475
+ const oldRoot = resolve30(dataRoot, "uploads");
22252
22476
  let topEntries;
22253
22477
  try {
22254
22478
  topEntries = await readdir5(oldRoot, { withFileTypes: true });
@@ -22267,10 +22491,10 @@ async function migrateUploads(opts = {}) {
22267
22491
  try {
22268
22492
  for (const entry of topEntries) {
22269
22493
  const name = entry.name;
22270
- if (ACCOUNT_UUID_RE4.test(name)) {
22494
+ if (ACCOUNT_UUID_RE5.test(name)) {
22271
22495
  moved += await relocateTree(
22272
- resolve29(oldRoot, name),
22273
- resolve29(dataRoot, "accounts", name, "uploads"),
22496
+ resolve30(oldRoot, name),
22497
+ resolve30(dataRoot, "accounts", name, "uploads"),
22274
22498
  dataRoot,
22275
22499
  name,
22276
22500
  session
@@ -22282,8 +22506,8 @@ async function migrateUploads(opts = {}) {
22282
22506
  continue;
22283
22507
  }
22284
22508
  moved += await relocateTree(
22285
- resolve29(oldRoot, "public"),
22286
- resolve29(dataRoot, "accounts", installAccountId, "uploads", "public"),
22509
+ resolve30(oldRoot, "public"),
22510
+ resolve30(dataRoot, "accounts", installAccountId, "uploads", "public"),
22287
22511
  dataRoot,
22288
22512
  null,
22289
22513
  // public uploads carry no graph nodes
@@ -22314,7 +22538,7 @@ async function migrateUploads(opts = {}) {
22314
22538
  // app/lib/migrate-admin-webchat-sidecars.ts
22315
22539
  import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
22316
22540
  import { existsSync as existsSync33 } from "fs";
22317
- import { join as join34 } from "path";
22541
+ import { join as join35 } from "path";
22318
22542
  var ADMIN_ROLE2 = "admin";
22319
22543
  var WEBCHAT_CHANNEL2 = "webchat";
22320
22544
  var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
@@ -22359,7 +22583,7 @@ async function collectLiveSidecars(projectsRoot) {
22359
22583
  }
22360
22584
  for (const slug of slugs) {
22361
22585
  if (!slug.isDirectory()) continue;
22362
- const slugDir = join34(projectsRoot, slug.name);
22586
+ const slugDir = join35(projectsRoot, slug.name);
22363
22587
  let entries;
22364
22588
  try {
22365
22589
  entries = await readdir6(slugDir, { withFileTypes: true });
@@ -22368,9 +22592,9 @@ async function collectLiveSidecars(projectsRoot) {
22368
22592
  }
22369
22593
  for (const entry of entries) {
22370
22594
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
22371
- out.push(join34(slugDir, entry.name));
22595
+ out.push(join35(slugDir, entry.name));
22372
22596
  } else if (entry.isDirectory() && entry.name === "subagents") {
22373
- const subDir = join34(slugDir, entry.name);
22597
+ const subDir = join35(slugDir, entry.name);
22374
22598
  let subs;
22375
22599
  try {
22376
22600
  subs = await readdir6(subDir, { withFileTypes: true });
@@ -22378,7 +22602,7 @@ async function collectLiveSidecars(projectsRoot) {
22378
22602
  continue;
22379
22603
  }
22380
22604
  for (const s of subs) {
22381
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join34(subDir, s.name));
22605
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join35(subDir, s.name));
22382
22606
  }
22383
22607
  }
22384
22608
  }
@@ -22390,7 +22614,7 @@ function shortId(path2) {
22390
22614
  return base.slice(0, 8);
22391
22615
  }
22392
22616
  async function migrateAdminWebchatSidecars(opts = {}) {
22393
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join34(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
22617
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join35(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
22394
22618
  const usersFile = opts.usersFile ?? USERS_FILE;
22395
22619
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
22396
22620
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -23300,15 +23524,15 @@ function createWebchatChannelRoutes(deps) {
23300
23524
  const finalBytes = typeof body?.finalBytes === "number" && Number.isFinite(body.finalBytes) ? body.finalBytes : 0;
23301
23525
  const k = key.slice(0, 8);
23302
23526
  const sid = sessionId.slice(0, 8);
23303
- if (interactive && finalBytes > 0) {
23304
- console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} replied=${replied ? "yes" : "no"} delivered=fallback bytes=${finalBytes}`);
23305
- return c.json({ ok: true, delivered: "fallback" });
23306
- }
23307
23527
  if (replied) {
23308
- console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} delivered=reply`);
23528
+ console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} replied=yes delivered=reply bytes=${finalBytes}`);
23309
23529
  return c.json({ ok: true, delivered: "reply" });
23310
23530
  }
23311
- console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} delivered=none`);
23531
+ if (interactive && finalBytes > 0) {
23532
+ console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} replied=no delivered=fallback bytes=${finalBytes}`);
23533
+ return c.json({ ok: true, delivered: "fallback" });
23534
+ }
23535
+ console.error(`[webchat-native] op=turn-end channel=webchat key=${k} sessionId=${sid} replied=no delivered=none`);
23312
23536
  return c.json({ ok: true, delivered: "none" });
23313
23537
  });
23314
23538
  return app62;
@@ -23369,16 +23593,16 @@ var WebchatGateway = class _WebchatGateway {
23369
23593
  * The public /api/chat route awaits this to return the reply on the same SSE
23370
23594
  * response, preserving the pre-756 POST→single-blob browser contract. */
23371
23595
  awaitReply(key, timeoutMs) {
23372
- return new Promise((resolve34) => {
23596
+ return new Promise((resolve35) => {
23373
23597
  const timer2 = setTimeout(() => {
23374
23598
  this.replyAwaiters.delete(key);
23375
- resolve34({ timeout: true });
23599
+ resolve35({ timeout: true });
23376
23600
  }, timeoutMs);
23377
23601
  if (timer2.unref) timer2.unref();
23378
23602
  this.replyAwaiters.set(key, (r) => {
23379
23603
  clearTimeout(timer2);
23380
23604
  this.replyAwaiters.delete(key);
23381
- resolve34(r);
23605
+ resolve35(r);
23382
23606
  });
23383
23607
  });
23384
23608
  }
@@ -23389,11 +23613,11 @@ var WebchatGateway = class _WebchatGateway {
23389
23613
  * terminal dialog stays answerable). */
23390
23614
  awaitPermissionVerdict(p, timeoutMs) {
23391
23615
  const k = _WebchatGateway.promptKey(p.key, p.requestId);
23392
- return new Promise((resolve34) => {
23616
+ return new Promise((resolve35) => {
23393
23617
  this.pendingPrompts.get(k)?.resolve({ timeout: true });
23394
23618
  const timer2 = setTimeout(() => {
23395
23619
  this.pendingPrompts.delete(k);
23396
- resolve34({ timeout: true });
23620
+ resolve35({ timeout: true });
23397
23621
  }, timeoutMs);
23398
23622
  if (timer2.unref) timer2.unref();
23399
23623
  this.pendingPrompts.set(k, {
@@ -23402,7 +23626,7 @@ var WebchatGateway = class _WebchatGateway {
23402
23626
  resolve: (r) => {
23403
23627
  clearTimeout(timer2);
23404
23628
  this.pendingPrompts.delete(k);
23405
- resolve34(r);
23629
+ resolve35(r);
23406
23630
  }
23407
23631
  });
23408
23632
  console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
@@ -24398,7 +24622,7 @@ function buildTelegramSpawnRequest(input) {
24398
24622
  // app/lib/telegram/outbound/send-document.ts
24399
24623
  import { realpathSync as realpathSync7 } from "fs";
24400
24624
  import { readFile as readFile7, stat as stat7 } from "fs/promises";
24401
- import { resolve as resolve30, basename as basename11 } from "path";
24625
+ import { resolve as resolve31, basename as basename11 } from "path";
24402
24626
  var TAG42 = "[telegram:outbound]";
24403
24627
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
24404
24628
  async function sendTelegramDocument(input) {
@@ -24409,7 +24633,7 @@ async function sendTelegramDocument(input) {
24409
24633
  if (!maxyAccountId || !platformRoot3) {
24410
24634
  return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
24411
24635
  }
24412
- const accountDir = resolve30(platformRoot3, "..", "data/accounts", maxyAccountId);
24636
+ const accountDir = resolve31(platformRoot3, "..", "data/accounts", maxyAccountId);
24413
24637
  let resolvedPath;
24414
24638
  try {
24415
24639
  resolvedPath = realpathSync7(filePath);
@@ -24536,12 +24760,12 @@ function startTelegramNativeFileFollower(input) {
24536
24760
  }
24537
24761
 
24538
24762
  // server/telegram-descriptor.ts
24539
- import { resolve as resolve31, join as join35 } from "path";
24763
+ import { resolve as resolve32, join as join36 } from "path";
24540
24764
  function telegramGatewayUrl() {
24541
24765
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
24542
24766
  }
24543
24767
  function telegramServerPath() {
24544
- return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join35(__dirname, ".."), "services/telegram-channel/dist/server.js");
24768
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, ".."), "services/telegram-channel/dist/server.js");
24545
24769
  }
24546
24770
 
24547
24771
  // app/lib/channel-pty-bridge/public-session-end-review.ts
@@ -24803,8 +25027,8 @@ function broadcastAdminShutdown(reason) {
24803
25027
 
24804
25028
  // ../lib/entitlement/src/index.ts
24805
25029
  import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
24806
- import { existsSync as existsSync34, readFileSync as readFileSync35, statSync as statSync13 } from "fs";
24807
- import { resolve as resolve32 } from "path";
25030
+ import { existsSync as existsSync34, readFileSync as readFileSync36, statSync as statSync13 } from "fs";
25031
+ import { resolve as resolve33 } from "path";
24808
25032
 
24809
25033
  // ../lib/entitlement/src/canonicalize.ts
24810
25034
  function canonicalize(value) {
@@ -24839,7 +25063,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
24839
25063
  var GRACE_DAYS = 7;
24840
25064
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
24841
25065
  function pubkeyPath(brand) {
24842
- return resolve32(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
25066
+ return resolve33(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
24843
25067
  }
24844
25068
  var memo = null;
24845
25069
  function memoKey(mtimeMs, account) {
@@ -24851,7 +25075,7 @@ function resolveEntitlement(brand, account) {
24851
25075
  if (brand.commercialMode !== true) {
24852
25076
  return logResolved(implicitTrust(account), null);
24853
25077
  }
24854
- const entitlementPath = resolve32(brand.configDir, "entitlement.json");
25078
+ const entitlementPath = resolve33(brand.configDir, "entitlement.json");
24855
25079
  if (!existsSync34(entitlementPath)) {
24856
25080
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
24857
25081
  }
@@ -24867,7 +25091,7 @@ function resolveEntitlement(brand, account) {
24867
25091
  function verifyAndResolve(brand, entitlementPath, account) {
24868
25092
  let pubkeyPem;
24869
25093
  try {
24870
- pubkeyPem = readFileSync35(pubkeyPath(brand), "utf-8");
25094
+ pubkeyPem = readFileSync36(pubkeyPath(brand), "utf-8");
24871
25095
  } catch (err) {
24872
25096
  return logResolved(anonymousFallback("pubkey-missing"), {
24873
25097
  reason: "pubkey-missing"
@@ -24881,7 +25105,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
24881
25105
  }
24882
25106
  let envelope;
24883
25107
  try {
24884
- envelope = JSON.parse(readFileSync35(entitlementPath, "utf-8"));
25108
+ envelope = JSON.parse(readFileSync36(entitlementPath, "utf-8"));
24885
25109
  } catch {
24886
25110
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
24887
25111
  }
@@ -25042,14 +25266,14 @@ function clientFrom(c) {
25042
25266
  );
25043
25267
  }
25044
25268
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
25045
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join36(PLATFORM_ROOT8, "config", "brand.json") : "";
25269
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join37(PLATFORM_ROOT8, "config", "brand.json") : "";
25046
25270
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
25047
25271
  if (BRAND_JSON_PATH && !existsSync35(BRAND_JSON_PATH)) {
25048
25272
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
25049
25273
  }
25050
25274
  if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
25051
25275
  try {
25052
- const parsed = JSON.parse(readFileSync36(BRAND_JSON_PATH, "utf-8"));
25276
+ const parsed = JSON.parse(readFileSync37(BRAND_JSON_PATH, "utf-8"));
25053
25277
  BRAND = { ...BRAND, ...parsed };
25054
25278
  } catch (err) {
25055
25279
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -25081,11 +25305,11 @@ var brandLoginOpts = {
25081
25305
  appleTouchIconPath: brandAppIcon512Path,
25082
25306
  themeColor: BRAND.defaultColors?.primary
25083
25307
  };
25084
- var ALIAS_DOMAINS_PATH = join36(homedir4(), BRAND.configDir, "alias-domains.json");
25308
+ var ALIAS_DOMAINS_PATH = join37(homedir4(), BRAND.configDir, "alias-domains.json");
25085
25309
  function loadAliasDomains() {
25086
25310
  try {
25087
25311
  if (!existsSync35(ALIAS_DOMAINS_PATH)) return null;
25088
- const parsed = JSON.parse(readFileSync36(ALIAS_DOMAINS_PATH, "utf-8"));
25312
+ const parsed = JSON.parse(readFileSync37(ALIAS_DOMAINS_PATH, "utf-8"));
25089
25313
  if (!Array.isArray(parsed)) {
25090
25314
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
25091
25315
  return null;
@@ -25148,7 +25372,7 @@ async function recordPassiveDispatch(input) {
25148
25372
  var waGateway = new WaGateway({
25149
25373
  fetchStandingRules: fetchAccountStandingRules,
25150
25374
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
25151
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
25375
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
25152
25376
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
25153
25377
  // path-validation scope) is the sender's effective SESSION account, resolved
25154
25378
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -25163,7 +25387,7 @@ var waGateway = new WaGateway({
25163
25387
  caption,
25164
25388
  accountId,
25165
25389
  maxyAccountId,
25166
- platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, ".."))
25390
+ platformRoot: resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, ".."))
25167
25391
  });
25168
25392
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
25169
25393
  },
@@ -25761,8 +25985,8 @@ app61.get("/agent-assets/:slug/:filename", (c) => {
25761
25985
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
25762
25986
  return c.text("Not found", 404);
25763
25987
  }
25764
- const filePath = resolve33(account.accountDir, "agents", slug, "assets", filename);
25765
- const expectedDir = resolve33(account.accountDir, "agents", slug, "assets");
25988
+ const filePath = resolve34(account.accountDir, "agents", slug, "assets", filename);
25989
+ const expectedDir = resolve34(account.accountDir, "agents", slug, "assets");
25766
25990
  if (!filePath.startsWith(expectedDir + "/")) {
25767
25991
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
25768
25992
  return c.text("Forbidden", 403);
@@ -25774,7 +25998,7 @@ app61.get("/agent-assets/:slug/:filename", (c) => {
25774
25998
  const ext = "." + filename.split(".").pop()?.toLowerCase();
25775
25999
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
25776
26000
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
25777
- const body = readFileSync36(filePath);
26001
+ const body = readFileSync37(filePath);
25778
26002
  return c.body(body, 200, {
25779
26003
  "Content-Type": contentType,
25780
26004
  "Cache-Control": "public, max-age=3600"
@@ -25791,8 +26015,8 @@ app61.get("/generated/:filename", (c) => {
25791
26015
  console.error(`[generated] serve file=${filename} status=404`);
25792
26016
  return c.text("Not found", 404);
25793
26017
  }
25794
- const filePath = resolve33(account.accountDir, "generated", filename);
25795
- const expectedDir = resolve33(account.accountDir, "generated");
26018
+ const filePath = resolve34(account.accountDir, "generated", filename);
26019
+ const expectedDir = resolve34(account.accountDir, "generated");
25796
26020
  if (!filePath.startsWith(expectedDir + "/")) {
25797
26021
  console.error(`[generated] serve file=${filename} status=403`);
25798
26022
  return c.text("Forbidden", 403);
@@ -25804,7 +26028,7 @@ app61.get("/generated/:filename", (c) => {
25804
26028
  const ext = "." + filename.split(".").pop()?.toLowerCase();
25805
26029
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
25806
26030
  console.log(`[generated] serve file=${filename} status=200`);
25807
- const body = readFileSync36(filePath);
26031
+ const body = readFileSync37(filePath);
25808
26032
  return c.body(body, 200, {
25809
26033
  "Content-Type": contentType,
25810
26034
  "Cache-Control": "public, max-age=86400"
@@ -25819,7 +26043,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
25819
26043
  var brandIconPath = "/brand/maxy-monochrome.png";
25820
26044
  if (BRAND_JSON_PATH && existsSync35(BRAND_JSON_PATH)) {
25821
26045
  try {
25822
- const fullBrand = JSON.parse(readFileSync36(BRAND_JSON_PATH, "utf-8"));
26046
+ const fullBrand = JSON.parse(readFileSync37(BRAND_JSON_PATH, "utf-8"));
25823
26047
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
25824
26048
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
25825
26049
  } catch {
@@ -25846,11 +26070,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
25846
26070
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
25847
26071
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
25848
26072
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
25849
- (p) => existsSync35(resolve33(process.cwd(), "public", p.replace(/^\//, "")))
26073
+ (p) => existsSync35(resolve34(process.cwd(), "public", p.replace(/^\//, "")))
25850
26074
  );
25851
26075
  var SW_SOURCE = (() => {
25852
26076
  try {
25853
- return readFileSync36(resolve33(process.cwd(), "public", "sw.js"), "utf-8");
26077
+ return readFileSync37(resolve34(process.cwd(), "public", "sw.js"), "utf-8");
25854
26078
  } catch {
25855
26079
  return null;
25856
26080
  }
@@ -25858,9 +26082,9 @@ var SW_SOURCE = (() => {
25858
26082
  function readInstalledVersion() {
25859
26083
  try {
25860
26084
  if (!PLATFORM_ROOT8) return "unknown";
25861
- const versionFile = join36(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
26085
+ const versionFile = join37(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
25862
26086
  if (!existsSync35(versionFile)) return "unknown";
25863
- const content = readFileSync36(versionFile, "utf-8").trim();
26087
+ const content = readFileSync37(versionFile, "utf-8").trim();
25864
26088
  return content || "unknown";
25865
26089
  } catch {
25866
26090
  return "unknown";
@@ -25901,7 +26125,7 @@ var clientErrorReporterScript = `<script>
25901
26125
  function cachedHtml(file) {
25902
26126
  let html = htmlCache.get(file);
25903
26127
  if (!html) {
25904
- html = readFileSync36(resolve33(process.cwd(), "public", file), "utf-8");
26128
+ html = readFileSync37(resolve34(process.cwd(), "public", file), "utf-8");
25905
26129
  const productNameEsc = escapeHtml(BRAND.productName);
25906
26130
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
25907
26131
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -25918,13 +26142,13 @@ ${clientErrorReporterScript}
25918
26142
  return html;
25919
26143
  }
25920
26144
  function loadBrandingCache(agentSlug) {
25921
- const configDir2 = join36(homedir4(), BRAND.configDir);
26145
+ const configDir2 = join37(homedir4(), BRAND.configDir);
25922
26146
  try {
25923
26147
  const accountId = getDefaultAccountId();
25924
26148
  if (!accountId) return null;
25925
- const cachePath = join36(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
26149
+ const cachePath = join37(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
25926
26150
  if (!existsSync35(cachePath)) return null;
25927
- return JSON.parse(readFileSync36(cachePath, "utf-8"));
26151
+ return JSON.parse(readFileSync37(cachePath, "utf-8"));
25928
26152
  } catch {
25929
26153
  return null;
25930
26154
  }
@@ -25941,11 +26165,11 @@ var brandedHtmlCache = /* @__PURE__ */ new Map();
25941
26165
  function brandedPublicHtml(agentSlug) {
25942
26166
  const baseHtml = cachedHtml("public.html");
25943
26167
  if (!agentSlug) return baseHtml;
25944
- const cached2 = brandedHtmlCache.get(agentSlug);
26168
+ const cached3 = brandedHtmlCache.get(agentSlug);
25945
26169
  const branding = loadBrandingCache(agentSlug);
25946
26170
  if (!branding) return baseHtml;
25947
26171
  const brandHash = JSON.stringify(branding).length;
25948
- if (cached2 && cached2.mtime === brandHash) return cached2.html;
26172
+ if (cached3 && cached3.mtime === brandHash) return cached3.html;
25949
26173
  const title = escapeHtml(branding.name);
25950
26174
  const description = branding.tagline ? escapeHtml(branding.tagline) : "";
25951
26175
  const themeColor = branding.primaryColor || "";
@@ -26019,7 +26243,7 @@ app61.use("/vnc-popout.html", logViewerFetch);
26019
26243
  app61.get("/vnc-popout.html", (c) => {
26020
26244
  let html = htmlCache.get("vnc-popout.html");
26021
26245
  if (!html) {
26022
- html = readFileSync36(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
26246
+ html = readFileSync37(resolve34(process.cwd(), "public", "vnc-popout.html"), "utf-8");
26023
26247
  const name = escapeHtml(BRAND.productName);
26024
26248
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
26025
26249
  html = html.replace("</head>", ` ${brandScript}
@@ -26151,8 +26375,8 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
26151
26375
  var httpServer = serve({ fetch: app61.fetch, port, hostname });
26152
26376
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
26153
26377
  {
26154
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
26155
- const reconcileScript = resolve33(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
26378
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
26379
+ const reconcileScript = resolve34(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
26156
26380
  const RECONCILE_INTERVAL_MS = 12e4;
26157
26381
  const runReconcile = () => {
26158
26382
  if (!existsSync35(reconcileScript)) return;
@@ -26173,8 +26397,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
26173
26397
  loop.unref();
26174
26398
  }
26175
26399
  {
26176
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
26177
- const publishScript = resolve33(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
26400
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
26401
+ const publishScript = resolve34(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
26178
26402
  const PUBLISH_INTERVAL_MS = 3e5;
26179
26403
  const currentAccount = () => {
26180
26404
  try {
@@ -26203,21 +26427,21 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
26203
26427
  }
26204
26428
  };
26205
26429
  const auditSnapshotAge = (account) => {
26206
- const availPath = resolve33(account.accountDir, "calendar-availability.json");
26430
+ const availPath = resolve34(account.accountDir, "calendar-availability.json");
26207
26431
  let hasBookingSite = false;
26208
26432
  try {
26209
26433
  if (existsSync35(availPath)) {
26210
- const cfg = JSON.parse(readFileSync36(availPath, "utf-8"));
26434
+ const cfg = JSON.parse(readFileSync37(availPath, "utf-8"));
26211
26435
  hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
26212
26436
  }
26213
26437
  } catch {
26214
26438
  }
26215
26439
  if (!hasBookingSite) return;
26216
- const statePath = resolve33(account.accountDir, "state", "booking-availability", "last-publish.json");
26440
+ const statePath = resolve34(account.accountDir, "state", "booking-availability", "last-publish.json");
26217
26441
  let lastSuccessAt = null;
26218
26442
  if (existsSync35(statePath)) {
26219
26443
  try {
26220
- const rec = JSON.parse(readFileSync36(statePath, "utf-8"));
26444
+ const rec = JSON.parse(readFileSync37(statePath, "utf-8"));
26221
26445
  lastSuccessAt = rec.lastSuccessAt ?? null;
26222
26446
  } catch {
26223
26447
  console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
@@ -26241,8 +26465,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
26241
26465
  }
26242
26466
  startTimeEntryCensus(() => getSession());
26243
26467
  {
26244
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
26245
- const auditScript = resolve33(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
26468
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..");
26469
+ const auditScript = resolve34(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
26246
26470
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
26247
26471
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
26248
26472
  const runConnectorAudit = () => {
@@ -26360,7 +26584,7 @@ async function runAdminUserReconcileTick() {
26360
26584
  console.error("[adminuser-self-heal] skip reason=no-users-file");
26361
26585
  return;
26362
26586
  }
26363
- const usersRaw = readFileSync36(USERS_FILE, "utf-8").trim();
26587
+ const usersRaw = readFileSync37(USERS_FILE, "utf-8").trim();
26364
26588
  if (!usersRaw) {
26365
26589
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
26366
26590
  return;
@@ -26390,7 +26614,7 @@ if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer
26390
26614
  var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
26391
26615
  function countUsersRows() {
26392
26616
  if (!existsSync35(USERS_FILE)) return 0;
26393
- const raw = readFileSync36(USERS_FILE, "utf-8").trim();
26617
+ const raw = readFileSync37(USERS_FILE, "utf-8").trim();
26394
26618
  if (!raw) return 0;
26395
26619
  const users = JSON.parse(raw);
26396
26620
  return users.filter((u) => typeof u.userId === "string").length;
@@ -26510,7 +26734,7 @@ if (bootAccountConfig?.whatsapp) {
26510
26734
  }
26511
26735
  init({
26512
26736
  configDir: configDirForWhatsApp,
26513
- platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..")),
26737
+ platformRoot: resolve34(process.env.MAXY_PLATFORM_ROOT ?? join37(__dirname, "..")),
26514
26738
  accountConfig: bootAccountConfig,
26515
26739
  onMessage: async (msg) => {
26516
26740
  if (msg.isOwnerMirror) {