@rubytech/create-realagent 1.0.853 → 1.0.855

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 (42) hide show
  1. package/dist/index.js +9 -3
  2. package/package.json +1 -1
  3. package/payload/platform/lib/persistent-components/dist/index.d.ts +21 -0
  4. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
  5. package/payload/platform/lib/persistent-components/dist/index.js +32 -0
  6. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
  7. package/payload/platform/lib/persistent-components/src/index.ts +28 -0
  8. package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
  9. package/payload/platform/package.json +2 -2
  10. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  11. package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +278 -0
  12. package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +204 -20
  13. package/payload/platform/plugins/admin/mcp/dist/index.js +40 -1
  14. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  15. package/payload/platform/plugins/cloudflare/references/manual-setup.md +2 -0
  16. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.sh +39 -10
  17. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +112 -20
  18. package/payload/platform/plugins/docs/references/cloudflare.md +1 -0
  19. package/payload/platform/plugins/docs/references/deployment.md +2 -0
  20. package/payload/platform/plugins/docs/references/getting-started.md +2 -0
  21. package/payload/platform/plugins/docs/references/platform.md +1 -1
  22. package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
  23. package/payload/platform/scripts/admin-persist-audit.ts +191 -0
  24. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +214 -0
  25. package/payload/platform/scripts/installer-device-verify.sh +17 -4
  26. package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
  27. package/payload/server/chunk-CFNSKDGA.js +667 -0
  28. package/payload/server/chunk-DC6DWYZJ.js +1603 -0
  29. package/payload/server/chunk-LTB5SSQW.js +10889 -0
  30. package/payload/server/chunk-MN2LGNUB.js +2143 -0
  31. package/payload/server/client-pool-AMT2W3II.js +34 -0
  32. package/payload/server/cloudflare-task-tracker-LJ4SMK2D.js +20 -0
  33. package/payload/server/maxy-edge.js +3 -3
  34. package/payload/server/public/assets/admin-Cpk5cT4I.js +352 -0
  35. package/payload/server/public/assets/public-DApUXgoq.js +5 -0
  36. package/payload/server/public/assets/useVoiceRecorder-CI8GpxfU.js +36 -0
  37. package/payload/server/public/index.html +2 -2
  38. package/payload/server/public/public.html +2 -2
  39. package/payload/server/server.js +543 -354
  40. package/payload/server/public/assets/admin-Dyl8uNxX.js +0 -352
  41. package/payload/server/public/assets/public-B_PNZUph.js +0 -5
  42. package/payload/server/public/assets/useVoiceRecorder-fD0IWzJj.js +0 -36
@@ -1,5 +1,10 @@
1
1
  import {
2
+ ATTACHMENTS_ROOT,
2
3
  Hono,
4
+ MAX_FILES_PER_MESSAGE,
5
+ MAX_FILE_SIZE_BYTES,
6
+ SUPPORTED_MIME_TYPES,
7
+ assertSupportedMime,
3
8
  autoDeliverPremiumPlugins,
4
9
  buildX11Env,
5
10
  callOauthLlm,
@@ -10,6 +15,10 @@ import {
10
15
  compactSession,
11
16
  computeConstraints,
12
17
  createRemoteSession,
18
+ deriveComponentAttachmentId,
19
+ deriveComponentMimeType,
20
+ deriveComponentTitle,
21
+ detectMimeType,
13
22
  ensureAuth,
14
23
  ensureCdp,
15
24
  ensureLogDir,
@@ -19,11 +28,13 @@ import {
19
28
  invokeAgent,
20
29
  isActionActive,
21
30
  isPasswordValid,
31
+ isPersistentComponent,
22
32
  isRemoteAuthConfigured,
23
33
  keyFilePath,
24
34
  launchAction,
25
35
  load,
26
36
  logPath,
37
+ pickComponentBytes,
27
38
  recordFailedAttempt,
28
39
  render,
29
40
  renderLoginPage,
@@ -36,9 +47,14 @@ import {
36
47
  serve,
37
48
  setRemotePassword,
38
49
  sleep,
50
+ storeAttachment,
51
+ storeComponentArtefact,
52
+ storeGeneratedFile,
53
+ storePublicAttachment,
39
54
  streamLogPathFor,
40
55
  stripAttachmentMetaSuffix,
41
56
  tryCookieBridgeForConversation,
57
+ validateFilePathInAccount,
42
58
  validateKey,
43
59
  validatePasswordStrength,
44
60
  verifyPassword,
@@ -46,7 +62,7 @@ import {
46
62
  vncLog,
47
63
  waitForExit,
48
64
  writeChromiumWrapper
49
- } from "./chunk-X3LVMXI5.js";
65
+ } from "./chunk-LTB5SSQW.js";
50
66
  import {
51
67
  ACCOUNTS_DIR,
52
68
  CDP_PORT,
@@ -91,7 +107,7 @@ import {
91
107
  unregisterSession,
92
108
  validateAgentSlug,
93
109
  validateSession
94
- } from "./chunk-DIRNBH7F.js";
110
+ } from "./chunk-DC6DWYZJ.js";
95
111
  import {
96
112
  CLOUDFLARE_TASK_DIAGNOSTICS,
97
113
  appendCloudflareSteps,
@@ -99,7 +115,7 @@ import {
99
115
  openCloudflareTask,
100
116
  readTunnelState,
101
117
  resolveUnitGoneVerdict
102
- } from "./chunk-DTWW35TK.js";
118
+ } from "./chunk-CFNSKDGA.js";
103
119
  import {
104
120
  GREETING_DIRECTIVE,
105
121
  HAIKU_MODEL,
@@ -123,13 +139,14 @@ import {
123
139
  listAdminSessions,
124
140
  loadAdminUserName,
125
141
  loadOnboardingStep,
142
+ persistMessage,
126
143
  projectAgent,
127
144
  renameConversation,
128
145
  runAdminUserSelfHeal,
129
146
  verifyAndGetConversationUpdatedAt,
130
147
  verifyConversationOwnership,
131
148
  writeAdminUserAndPerson
132
- } from "./chunk-CJWFM3WX.js";
149
+ } from "./chunk-MN2LGNUB.js";
133
150
  import {
134
151
  __commonJS,
135
152
  __toESM
@@ -632,9 +649,9 @@ var serveStatic = (options = { root: "" }) => {
632
649
  };
633
650
 
634
651
  // server/index.ts
635
- import { readFileSync as readFileSync17, existsSync as existsSync23, watchFile } from "fs";
636
- import { resolve as resolve22, join as join12, basename as basename5 } from "path";
637
- import { homedir as homedir2 } from "os";
652
+ import { readFileSync as readFileSync18, existsSync as existsSync24, watchFile } from "fs";
653
+ import { resolve as resolve21, join as join12, basename as basename4 } from "path";
654
+ import { homedir as homedir3 } from "os";
638
655
 
639
656
  // app/lib/agent-slug-pattern.ts
640
657
  var AGENT_SLUG_PATTERN = /^\/([a-z][a-z0-9-]{2,49})$/;
@@ -1277,7 +1294,7 @@ var credsSaveQueue = Promise.resolve();
1277
1294
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
1278
1295
  console.error(`${TAG3} draining credential save queue\u2026`);
1279
1296
  const timer2 = new Promise(
1280
- (resolve23) => setTimeout(() => resolve23("timeout"), timeoutMs)
1297
+ (resolve22) => setTimeout(() => resolve22("timeout"), timeoutMs)
1281
1298
  );
1282
1299
  const result = await Promise.race([
1283
1300
  credsSaveQueue.then(() => "drained"),
@@ -1405,11 +1422,11 @@ async function createWaSocket(opts) {
1405
1422
  return sock;
1406
1423
  }
1407
1424
  async function waitForConnection(sock) {
1408
- return new Promise((resolve23, reject) => {
1425
+ return new Promise((resolve22, reject) => {
1409
1426
  const handler = (update) => {
1410
1427
  if (update.connection === "open") {
1411
1428
  sock.ev.off("connection.update", handler);
1412
- resolve23();
1429
+ resolve22();
1413
1430
  }
1414
1431
  if (update.connection === "close") {
1415
1432
  sock.ev.off("connection.update", handler);
@@ -1523,14 +1540,14 @@ ${inspected}`;
1523
1540
  return inspect2(err, INSPECT_OPTS2);
1524
1541
  }
1525
1542
  function withTimeout(label, promise, timeoutMs) {
1526
- return new Promise((resolve23, reject) => {
1543
+ return new Promise((resolve22, reject) => {
1527
1544
  const timer2 = setTimeout(() => {
1528
1545
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
1529
1546
  }, timeoutMs);
1530
1547
  promise.then(
1531
1548
  (value) => {
1532
1549
  clearTimeout(timer2);
1533
- resolve23(value);
1550
+ resolve22(value);
1534
1551
  },
1535
1552
  (err) => {
1536
1553
  clearTimeout(timer2);
@@ -2065,8 +2082,8 @@ async function persistWhatsAppMessage(input) {
2065
2082
  const { givenName, familyName } = splitName(input.pushName);
2066
2083
  const prev = sessionWriteLocks.get(input.sessionKey);
2067
2084
  let release;
2068
- const mine = new Promise((resolve23) => {
2069
- release = resolve23;
2085
+ const mine = new Promise((resolve22) => {
2086
+ release = resolve22;
2070
2087
  });
2071
2088
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2072
2089
  sessionWriteLocks.set(input.sessionKey, chained);
@@ -3091,11 +3108,11 @@ async function connectWithReconnect(conn) {
3091
3108
  console.error(
3092
3109
  `${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3093
3110
  );
3094
- await new Promise((resolve23) => {
3095
- const timer2 = setTimeout(resolve23, delay);
3111
+ await new Promise((resolve22) => {
3112
+ const timer2 = setTimeout(resolve22, delay);
3096
3113
  conn.abortController.signal.addEventListener("abort", () => {
3097
3114
  clearTimeout(timer2);
3098
- resolve23();
3115
+ resolve22();
3099
3116
  }, { once: true });
3100
3117
  });
3101
3118
  }
@@ -3103,16 +3120,16 @@ async function connectWithReconnect(conn) {
3103
3120
  }
3104
3121
  }
3105
3122
  function waitForDisconnectEvent(conn) {
3106
- return new Promise((resolve23) => {
3123
+ return new Promise((resolve22) => {
3107
3124
  if (!conn.sock) {
3108
- resolve23();
3125
+ resolve22();
3109
3126
  return;
3110
3127
  }
3111
3128
  const sock = conn.sock;
3112
3129
  const handler = (update) => {
3113
3130
  if (update.connection === "close") {
3114
3131
  sock.ev.off("connection.update", handler);
3115
- resolve23();
3132
+ resolve22();
3116
3133
  }
3117
3134
  };
3118
3135
  sock.ev.on("connection.update", handler);
@@ -3373,8 +3390,8 @@ async function handleInboundMessage(conn, msg) {
3373
3390
  const conversationKey = isGroup ? remoteJid : senderPhone;
3374
3391
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
3375
3392
  let resolvePending;
3376
- const sttPending = new Promise((resolve23) => {
3377
- resolvePending = resolve23;
3393
+ const sttPending = new Promise((resolve22) => {
3394
+ resolvePending = resolve22;
3378
3395
  });
3379
3396
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
3380
3397
  try {
@@ -3495,20 +3512,20 @@ async function probeApiKey() {
3495
3512
  return result.status;
3496
3513
  }
3497
3514
  function checkPort(port2, timeoutMs = 500) {
3498
- return new Promise((resolve23) => {
3515
+ return new Promise((resolve22) => {
3499
3516
  const socket = createConnection(port2, "127.0.0.1");
3500
3517
  socket.setTimeout(timeoutMs);
3501
3518
  socket.once("connect", () => {
3502
3519
  socket.destroy();
3503
- resolve23(true);
3520
+ resolve22(true);
3504
3521
  });
3505
3522
  socket.once("error", () => {
3506
3523
  socket.destroy();
3507
- resolve23(false);
3524
+ resolve22(false);
3508
3525
  });
3509
3526
  socket.once("timeout", () => {
3510
3527
  socket.destroy();
3511
- resolve23(false);
3528
+ resolve22(false);
3512
3529
  });
3513
3530
  });
3514
3531
  }
@@ -3921,142 +3938,31 @@ ${raw}`;
3921
3938
  return base;
3922
3939
  }
3923
3940
 
3924
- // app/lib/attachments.ts
3925
- import { randomUUID as randomUUID3 } from "crypto";
3926
- import { mkdir as mkdir2, readFile, stat as stat2, writeFile as writeFile2 } from "fs/promises";
3927
- import { realpathSync } from "fs";
3928
- import { resolve as resolve4, extname, basename } from "path";
3929
- var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "../platform");
3930
- var ATTACHMENTS_ROOT = resolve4(PLATFORM_ROOT2, "..", "data/uploads");
3931
- var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
3932
- "image/jpeg",
3933
- "image/png",
3934
- "image/gif",
3935
- "image/webp",
3936
- "application/pdf",
3937
- "text/plain",
3938
- "text/markdown",
3939
- "text/csv",
3940
- "text/html",
3941
- "text/calendar",
3942
- "application/zip",
3943
- "application/x-zip-compressed"
3944
- ]);
3945
- var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
3946
- var MAX_FILES_PER_MESSAGE = 5;
3947
- var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
3948
- function assertSupportedMime(mimeType) {
3949
- if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
3950
- throw new Error(
3951
- `Unsupported file type: "${mimeType}". Supported types: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
3952
- );
3953
- }
3954
- }
3955
- async function writeAttachment(scope, filename, mimeType, sizeBytes, buffer) {
3956
- const attachmentId = randomUUID3();
3957
- const dir = resolve4(ATTACHMENTS_ROOT, scope, attachmentId);
3958
- await mkdir2(dir, { recursive: true });
3959
- const ext = extname(filename) || "";
3960
- const storagePath = resolve4(dir, `${attachmentId}${ext}`);
3961
- const metaPath = resolve4(dir, `${attachmentId}.meta.json`);
3962
- const meta = {
3963
- attachmentId,
3964
- scope,
3965
- filename,
3966
- mimeType,
3967
- sizeBytes,
3968
- storedAt: (/* @__PURE__ */ new Date()).toISOString()
3969
- };
3970
- await writeFile2(storagePath, buffer);
3971
- await writeFile2(metaPath, JSON.stringify(meta, null, 2));
3972
- return { attachmentId, filename, storagePath, metaPath, mimeType, sizeBytes };
3973
- }
3974
- async function storeAttachment(accountId, file) {
3975
- assertSupportedMime(file.type);
3976
- if (file.size > MAX_FILE_SIZE_BYTES) {
3977
- throw new Error(
3978
- `File "${file.name}" exceeds the 50 MB limit (${(file.size / 1024 / 1024).toFixed(1)} MB).`
3979
- );
3980
- }
3981
- const buffer = Buffer.from(await file.arrayBuffer());
3982
- return writeAttachment(accountId, file.name, file.type, file.size, buffer);
3983
- }
3984
- async function storePublicAttachment(sessionId, file, buffer) {
3985
- assertSupportedMime(file.type);
3986
- if (file.size > MAX_FILE_SIZE_BYTES) {
3987
- throw new Error(
3988
- `File "${file.name}" exceeds the 50 MB limit (${(file.size / 1024 / 1024).toFixed(1)} MB).`
3989
- );
3990
- }
3991
- return writeAttachment(`public/${sessionId}`, file.name, file.type, file.size, buffer);
3992
- }
3993
- var MIME_BY_EXT = {
3994
- ".pdf": "application/pdf",
3995
- ".png": "image/png",
3996
- ".jpg": "image/jpeg",
3997
- ".jpeg": "image/jpeg",
3998
- ".gif": "image/gif",
3999
- ".webp": "image/webp",
4000
- ".svg": "image/svg+xml",
4001
- ".html": "text/html",
4002
- ".htm": "text/html",
4003
- ".css": "text/css",
4004
- ".js": "application/javascript",
4005
- ".json": "application/json",
4006
- ".csv": "text/csv",
4007
- ".txt": "text/plain",
4008
- ".md": "text/markdown",
4009
- ".xml": "text/xml",
4010
- ".zip": "application/zip",
4011
- ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
4012
- ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
4013
- ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
4014
- ".ics": "text/calendar"
4015
- };
4016
- function detectMimeType(filePath) {
4017
- const ext = extname(filePath).toLowerCase();
4018
- return MIME_BY_EXT[ext] ?? "application/octet-stream";
4019
- }
4020
- function validateFilePathInAccount(filePath, accountDir) {
4021
- const resolved = realpathSync(filePath);
4022
- const accountResolved = realpathSync(accountDir);
4023
- if (!resolved.startsWith(accountResolved + "/")) {
4024
- throw new Error(`File path is outside the account directory`);
4025
- }
4026
- return resolved;
4027
- }
4028
- async function storeGeneratedFile(accountId, filePath) {
4029
- const fileStat = await stat2(filePath);
4030
- if (fileStat.size > MAX_FILE_SIZE_BYTES) {
4031
- throw new Error(
4032
- `File exceeds the 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB).`
4033
- );
4034
- }
4035
- const filename = basename(filePath);
4036
- const mimeType = detectMimeType(filePath);
4037
- const buffer = await readFile(filePath);
4038
- return writeAttachment(accountId, filename, mimeType, fileStat.size, buffer);
4039
- }
4040
-
4041
3941
  // app/lib/stt/voice-note.ts
4042
- import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
3942
+ import { writeFile as writeFile2, mkdtemp, rm } from "fs/promises";
4043
3943
  import { tmpdir } from "os";
4044
3944
  import { join as join4 } from "path";
4045
3945
  var TAG14 = "[voice]";
4046
3946
  var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
4047
3947
  "audio/ogg",
3948
+ "audio/opus",
4048
3949
  "audio/webm",
4049
3950
  "audio/mp4",
4050
3951
  "audio/mpeg",
4051
3952
  "audio/wav"
4052
3953
  ]);
3954
+ function normalizeMime(mimeType) {
3955
+ return mimeType.split(";")[0].trim().toLowerCase();
3956
+ }
4053
3957
  function isAudioMime(mimeType) {
4054
- return AUDIO_MIME_TYPES.has(mimeType);
3958
+ return AUDIO_MIME_TYPES.has(normalizeMime(mimeType));
4055
3959
  }
4056
3960
  function audioExtension(mimeType) {
4057
- switch (mimeType) {
3961
+ switch (normalizeMime(mimeType)) {
4058
3962
  case "audio/ogg":
4059
3963
  return ".ogg";
3964
+ case "audio/opus":
3965
+ return ".opus";
4060
3966
  case "audio/webm":
4061
3967
  return ".webm";
4062
3968
  case "audio/mp4":
@@ -4083,7 +3989,7 @@ async function transcribeVoiceNote(file, source) {
4083
3989
  const ext = audioExtension(mimeType);
4084
3990
  tempPath = join4(tempDir, `recording${ext}`);
4085
3991
  const buffer = Buffer.from(await file.arrayBuffer());
4086
- await writeFile3(tempPath, buffer);
3992
+ await writeFile2(tempPath, buffer);
4087
3993
  } catch (err) {
4088
3994
  const reason = err instanceof Error ? err.message : String(err);
4089
3995
  console.error(`${TAG14} failed source=${source} error=temp-file-write: ${reason}`);
@@ -4637,13 +4543,13 @@ var group_default = app4;
4637
4543
  // app/lib/access-gate.ts
4638
4544
  import neo4j from "neo4j-driver";
4639
4545
  import { readFileSync as readFileSync4 } from "fs";
4640
- import { resolve as resolve5 } from "path";
4641
- import { randomUUID as randomUUID4, randomInt } from "crypto";
4642
- var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
4546
+ import { resolve as resolve4 } from "path";
4547
+ import { randomUUID as randomUUID3, randomInt } from "crypto";
4548
+ var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "..");
4643
4549
  var driver = null;
4644
4550
  function readPassword() {
4645
4551
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
4646
- const passwordFile = resolve5(PLATFORM_ROOT3, "config/.neo4j-password");
4552
+ const passwordFile = resolve4(PLATFORM_ROOT2, "config/.neo4j-password");
4647
4553
  try {
4648
4554
  return readFileSync4(passwordFile, "utf-8").trim();
4649
4555
  } catch {
@@ -4894,7 +4800,7 @@ async function setGrantPassword(grantId, passwordHash) {
4894
4800
  }
4895
4801
  }
4896
4802
  async function generateNewMagicToken(grantId) {
4897
- const token = randomUUID4();
4803
+ const token = randomUUID3();
4898
4804
  const session = getSession2();
4899
4805
  try {
4900
4806
  await session.run(
@@ -4958,15 +4864,15 @@ async function findActiveGrantByContact(contactValue, agentSlug, accountId) {
4958
4864
  // app/lib/brevo-sms.ts
4959
4865
  import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync5, chmodSync } from "fs";
4960
4866
  import { dirname } from "path";
4961
- import { resolve as resolve6 } from "path";
4962
- var BREVO_API_KEY_FILE = resolve6(MAXY_DIR, ".brevo-api-key");
4867
+ import { resolve as resolve5 } from "path";
4868
+ var BREVO_API_KEY_FILE = resolve5(MAXY_DIR, ".brevo-api-key");
4963
4869
  var BREVO_API_URL = "https://api.brevo.com/v3/transactionalSMS/sms";
4964
4870
  var BREVO_TIMEOUT_MS = 1e4;
4965
4871
  var BREVO_SENDER = "Maxy";
4966
4872
  var platformRoot = process.env.MAXY_PLATFORM_ROOT;
4967
4873
  if (platformRoot) {
4968
4874
  try {
4969
- const brandPath = resolve6(platformRoot, "config", "brand.json");
4875
+ const brandPath = resolve5(platformRoot, "config", "brand.json");
4970
4876
  if (existsSync5(brandPath)) {
4971
4877
  const brand = JSON.parse(readFileSync5(brandPath, "utf-8"));
4972
4878
  if (brand.productName) BREVO_SENDER = brand.productName;
@@ -5603,12 +5509,12 @@ app6.post("/webhook", async (c) => {
5603
5509
  var telegram_default = app6;
5604
5510
 
5605
5511
  // server/routes/whatsapp.ts
5606
- import { join as join5, resolve as resolve7, basename as basename2 } from "path";
5607
- import { readFile as readFile2, stat as stat3 } from "fs/promises";
5608
- import { realpathSync as realpathSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
5512
+ import { join as join5, resolve as resolve6, basename } from "path";
5513
+ import { readFile, stat as stat2 } from "fs/promises";
5514
+ import { realpathSync, readdirSync as readdirSync2, readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
5609
5515
 
5610
5516
  // app/lib/whatsapp/login.ts
5611
- import { randomUUID as randomUUID5 } from "crypto";
5517
+ import { randomUUID as randomUUID4 } from "crypto";
5612
5518
  var TAG17 = "[whatsapp:login]";
5613
5519
  var ACTIVE_LOGIN_TTL_MS = 3 * 6e4;
5614
5520
  var activeLogins = /* @__PURE__ */ new Map();
@@ -5711,8 +5617,8 @@ async function startLogin(opts) {
5711
5617
  resetActiveLogin(accountId);
5712
5618
  let resolveQr = null;
5713
5619
  let rejectQr = null;
5714
- const qrPromise = new Promise((resolve23, reject) => {
5715
- resolveQr = resolve23;
5620
+ const qrPromise = new Promise((resolve22, reject) => {
5621
+ resolveQr = resolve22;
5716
5622
  rejectQr = reject;
5717
5623
  });
5718
5624
  const qrTimer = setTimeout(
@@ -5747,7 +5653,7 @@ async function startLogin(opts) {
5747
5653
  const login = {
5748
5654
  accountId,
5749
5655
  authDir,
5750
- id: randomUUID5(),
5656
+ id: randomUUID4(),
5751
5657
  sock,
5752
5658
  startedAt: Date.now(),
5753
5659
  connected: false
@@ -5928,7 +5834,7 @@ function serializeWhatsAppSchema() {
5928
5834
 
5929
5835
  // server/routes/whatsapp.ts
5930
5836
  var TAG18 = "[whatsapp:api]";
5931
- var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT || "";
5837
+ var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT || "";
5932
5838
  var app7 = new Hono();
5933
5839
  app7.get("/status", (c) => {
5934
5840
  try {
@@ -6106,14 +6012,14 @@ app7.post("/config", async (c) => {
6106
6012
  return c.json(result, result.ok ? 200 : 400);
6107
6013
  }
6108
6014
  case "list-public-agents": {
6109
- const agentsDir = resolve7(account.accountDir, "agents");
6015
+ const agentsDir = resolve6(account.accountDir, "agents");
6110
6016
  const agents = [];
6111
6017
  if (existsSync7(agentsDir)) {
6112
6018
  try {
6113
6019
  const entries = readdirSync2(agentsDir, { withFileTypes: true });
6114
6020
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
6115
6021
  if (!entry.isDirectory() || entry.name === "admin") continue;
6116
- const configPath2 = resolve7(agentsDir, entry.name, "config.json");
6022
+ const configPath2 = resolve6(agentsDir, entry.name, "config.json");
6117
6023
  if (!existsSync7(configPath2)) continue;
6118
6024
  try {
6119
6025
  const config = JSON.parse(readFileSync7(configPath2, "utf-8"));
@@ -6188,14 +6094,14 @@ app7.post("/send-document", async (c) => {
6188
6094
  if (!to || !filePath) {
6189
6095
  return c.json({ error: "Missing required fields: to, filePath" }, 400);
6190
6096
  }
6191
- if (!maxyAccountId || !PLATFORM_ROOT4) {
6097
+ if (!maxyAccountId || !PLATFORM_ROOT3) {
6192
6098
  return c.json({ error: "Cannot validate file path: missing account or platform context" }, 400);
6193
6099
  }
6194
- const accountDir = resolve7(PLATFORM_ROOT4, "..", "data/accounts", maxyAccountId);
6100
+ const accountDir = resolve6(PLATFORM_ROOT3, "..", "data/accounts", maxyAccountId);
6195
6101
  let resolvedPath;
6196
6102
  try {
6197
- resolvedPath = realpathSync2(filePath);
6198
- const accountResolved = realpathSync2(accountDir);
6103
+ resolvedPath = realpathSync(filePath);
6104
+ const accountResolved = realpathSync(accountDir);
6199
6105
  if (!resolvedPath.startsWith(accountResolved + "/")) {
6200
6106
  const sanitised = filePath.replace(accountDir, "<account>/");
6201
6107
  console.error(`${TAG18} send-document REJECTED path=${sanitised} reason=outside_account_directory`);
@@ -6210,12 +6116,12 @@ app7.post("/send-document", async (c) => {
6210
6116
  console.error(`${TAG18} send-document path error: ${String(err)}`);
6211
6117
  return c.json({ error: String(err) }, 500);
6212
6118
  }
6213
- const fileStat = await stat3(resolvedPath);
6119
+ const fileStat = await stat2(resolvedPath);
6214
6120
  if (fileStat.size > MAX_FILE_SIZE_BYTES) {
6215
6121
  return c.json({ error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)` }, 400);
6216
6122
  }
6217
- const buffer = Buffer.from(await readFile2(resolvedPath));
6218
- const filename = basename2(resolvedPath);
6123
+ const buffer = Buffer.from(await readFile(resolvedPath));
6124
+ const filename = basename(resolvedPath);
6219
6125
  const mimetype = detectMimeType(resolvedPath);
6220
6126
  const sock = getSocket(accountId);
6221
6127
  if (!sock) {
@@ -6416,8 +6322,8 @@ var whatsapp_default = app7;
6416
6322
  // server/routes/onboarding.ts
6417
6323
  import { spawn, execFileSync } from "child_process";
6418
6324
  import { openSync, closeSync, writeFileSync as writeFileSync5, writeSync, existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync9, unlinkSync } from "fs";
6419
- import { resolve as resolve8, dirname as dirname3 } from "path";
6420
- import { createHash, randomUUID as randomUUID6 } from "crypto";
6325
+ import { resolve as resolve7, dirname as dirname3 } from "path";
6326
+ import { createHash, randomUUID as randomUUID5 } from "crypto";
6421
6327
 
6422
6328
  // ../lib/admins-write/src/index.ts
6423
6329
  import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync4, renameSync, mkdirSync as mkdirSync3, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
@@ -6566,7 +6472,7 @@ function checkAdminAuthInvariant(input) {
6566
6472
  }
6567
6473
 
6568
6474
  // server/routes/onboarding.ts
6569
- var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT || "";
6475
+ var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT || "";
6570
6476
  function hashPin(pin) {
6571
6477
  return createHash("sha256").update(pin).digest("hex");
6572
6478
  }
@@ -6693,7 +6599,7 @@ app8.post("/set-pin", async (c) => {
6693
6599
  const hash = hashPin(body.pin);
6694
6600
  const account = resolveAccount();
6695
6601
  const existingOwnerUserId = account?.config.admins?.find((a) => a.role === "owner")?.userId;
6696
- const userId = existingOwnerUserId ?? randomUUID6();
6602
+ const userId = existingOwnerUserId ?? randomUUID5();
6697
6603
  if (existingOwnerUserId) {
6698
6604
  console.log(`[set-pin] reusing existing owner userId=${userId.slice(0, 8)}\u2026 (change-PIN preserves identity)`);
6699
6605
  } else {
@@ -6785,7 +6691,7 @@ app8.post("/skip", async (c) => {
6785
6691
  }
6786
6692
  const { accountId, accountDir } = account;
6787
6693
  let agentName = "Maxy";
6788
- const brandPath = PLATFORM_ROOT5 ? resolve8(PLATFORM_ROOT5, "config", "brand.json") : "";
6694
+ const brandPath = PLATFORM_ROOT4 ? resolve7(PLATFORM_ROOT4, "config", "brand.json") : "";
6789
6695
  if (brandPath && existsSync9(brandPath)) {
6790
6696
  try {
6791
6697
  const brand = JSON.parse(readFileSync9(brandPath, "utf-8"));
@@ -6794,7 +6700,7 @@ app8.post("/skip", async (c) => {
6794
6700
  console.error(`[onboarding-skip] brand.json read failed: ${err instanceof Error ? err.message : String(err)}`);
6795
6701
  }
6796
6702
  }
6797
- const soulPath = resolve8(accountDir, "agents", "admin", "SOUL.md");
6703
+ const soulPath = resolve7(accountDir, "agents", "admin", "SOUL.md");
6798
6704
  try {
6799
6705
  mkdirSync4(dirname3(soulPath), { recursive: true });
6800
6706
  writeFileSync5(soulPath, `You are ${agentName}, an AI operations manager.
@@ -7225,7 +7131,7 @@ app10.post("/", async (c) => {
7225
7131
  var session_default2 = app10;
7226
7132
 
7227
7133
  // server/routes/admin/chat.ts
7228
- import { resolve as resolve9 } from "path";
7134
+ import { resolve as resolve8 } from "path";
7229
7135
  import { appendFileSync as appendFileSync3 } from "fs";
7230
7136
 
7231
7137
  // app/lib/script-stream-tailer.ts
@@ -7516,7 +7422,7 @@ var app11 = new Hono();
7516
7422
  app11.post("/cancel", requireAdminSession, async (c) => {
7517
7423
  const session_key = c.var.sessionKey;
7518
7424
  try {
7519
- const { interruptClient: interruptClient2 } = await import("./client-pool-7Z6YRUQT.js");
7425
+ const { interruptClient: interruptClient2 } = await import("./client-pool-AMT2W3II.js");
7520
7426
  await interruptClient2(session_key);
7521
7427
  return c.json({ ok: true });
7522
7428
  } catch (err) {
@@ -7680,7 +7586,7 @@ app11.post("/", requireAdminSession, async (c) => {
7680
7586
  function resolveTeeStreamLogPath() {
7681
7587
  const liveConvId = getConversationIdForSession(session_key);
7682
7588
  const key = liveConvId ?? preflushStreamLogKey(session_key);
7683
- return resolve9(account.accountDir, "logs", `claude-agent-stream-${key}.log`);
7589
+ return resolve8(account.accountDir, "logs", `claude-agent-stream-${key}.log`);
7684
7590
  }
7685
7591
  try {
7686
7592
  appendFileSync3(resolveTeeStreamLogPath(), `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task606-tee-path-resolve] sessionKey=${session_key.slice(0, 12)}\u2026
@@ -7782,7 +7688,7 @@ app11.post("/", requireAdminSession, async (c) => {
7782
7688
  try {
7783
7689
  registerAdminSSE(sseEntry);
7784
7690
  if (sseConvId) {
7785
- const streamLogPath = resolve9(account.accountDir, "logs", `claude-agent-stream-${sseConvId}.log`);
7691
+ const streamLogPath = resolve8(account.accountDir, "logs", `claude-agent-stream-${sseConvId}.log`);
7786
7692
  tailer = startScriptStreamTailer({
7787
7693
  path: streamLogPath,
7788
7694
  onEvent: (event) => {
@@ -7912,7 +7818,7 @@ var compact_default = app12;
7912
7818
 
7913
7819
  // server/routes/admin/logs.ts
7914
7820
  import { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
7915
- import { resolve as resolve10, basename as basename3 } from "path";
7821
+ import { resolve as resolve9, basename as basename2 } from "path";
7916
7822
 
7917
7823
  // app/lib/logs-read-resolve.ts
7918
7824
  import { existsSync as existsSync12 } from "fs";
@@ -7956,15 +7862,15 @@ app13.get("/", async (c) => {
7956
7862
  const sessionKeyParam = c.req.query("sessionKey");
7957
7863
  const download = c.req.query("download") === "1";
7958
7864
  const account = resolveAccount();
7959
- const accountLogDir = account ? resolve10(account.accountDir, "logs") : null;
7865
+ const accountLogDir = account ? resolve9(account.accountDir, "logs") : null;
7960
7866
  const logDirs = [];
7961
7867
  if (accountLogDir) logDirs.push(accountLogDir);
7962
7868
  logDirs.push(LOG_DIR);
7963
7869
  if (fileParam) {
7964
- const safe = basename3(fileParam);
7870
+ const safe = basename2(fileParam);
7965
7871
  const searched = [];
7966
7872
  for (const dir of logDirs) {
7967
- const filePath = resolve10(dir, safe);
7873
+ const filePath = resolve9(dir, safe);
7968
7874
  searched.push(filePath);
7969
7875
  try {
7970
7876
  const buffer = readFileSync11(filePath);
@@ -8051,7 +7957,7 @@ app13.get("/", async (c) => {
8051
7957
  const hit = hits[0];
8052
7958
  console.info(`[admin/logs] resolved sessionKey=${sessionKeySlice} conversationId=${conversationIdSlice} shape=${hit.shape} stalePreflushCount=${stalePreflushCount}`);
8053
7959
  try {
8054
- const filename = basename3(hit.path);
7960
+ const filename = basename2(hit.path);
8055
7961
  if (stalePreflushCount > 0 && !download) {
8056
7962
  const content = readFileSync11(hit.path, "utf-8");
8057
7963
  return c.json({
@@ -8104,10 +8010,10 @@ app13.get("/", async (c) => {
8104
8010
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
8105
8011
  continue;
8106
8012
  }
8107
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync6(resolve10(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
8013
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync6(resolve9(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
8108
8014
  seen.add(name);
8109
8015
  try {
8110
- const content = readFileSync11(resolve10(dir, name));
8016
+ const content = readFileSync11(resolve9(dir, name));
8111
8017
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
8112
8018
  logs[name] = tail.trim() || "(empty)";
8113
8019
  } catch (err) {
@@ -8145,9 +8051,9 @@ app14.get("/", (c) => {
8145
8051
  var claude_info_default = app14;
8146
8052
 
8147
8053
  // server/routes/admin/attachment.ts
8148
- import { readFile as readFile3, readdir } from "fs/promises";
8054
+ import { readFile as readFile2, readdir } from "fs/promises";
8149
8055
  import { existsSync as existsSync14 } from "fs";
8150
- import { resolve as resolve11 } from "path";
8056
+ import { resolve as resolve10 } from "path";
8151
8057
  var app15 = new Hono();
8152
8058
  app15.get("/:attachmentId", requireAdminSession, async (c) => {
8153
8059
  const attachmentId = c.req.param("attachmentId");
@@ -8159,17 +8065,17 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
8159
8065
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
8160
8066
  return new Response("Not found", { status: 404 });
8161
8067
  }
8162
- const dir = resolve11(ATTACHMENTS_ROOT, accountId, attachmentId);
8068
+ const dir = resolve10(ATTACHMENTS_ROOT, accountId, attachmentId);
8163
8069
  if (!existsSync14(dir)) {
8164
8070
  return new Response("Not found", { status: 404 });
8165
8071
  }
8166
- const metaPath = resolve11(dir, `${attachmentId}.meta.json`);
8072
+ const metaPath = resolve10(dir, `${attachmentId}.meta.json`);
8167
8073
  if (!existsSync14(metaPath)) {
8168
8074
  return new Response("Not found", { status: 404 });
8169
8075
  }
8170
8076
  let meta;
8171
8077
  try {
8172
- meta = JSON.parse(await readFile3(metaPath, "utf-8"));
8078
+ meta = JSON.parse(await readFile2(metaPath, "utf-8"));
8173
8079
  } catch {
8174
8080
  return new Response("Not found", { status: 404 });
8175
8081
  }
@@ -8178,8 +8084,8 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
8178
8084
  if (!dataFile) {
8179
8085
  return new Response("Not found", { status: 404 });
8180
8086
  }
8181
- const filePath = resolve11(dir, dataFile);
8182
- const buffer = await readFile3(filePath);
8087
+ const filePath = resolve10(dir, dataFile);
8088
+ const buffer = await readFile2(filePath);
8183
8089
  return new Response(new Uint8Array(buffer), {
8184
8090
  headers: {
8185
8091
  "Content-Type": meta.mimeType,
@@ -8191,13 +8097,13 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
8191
8097
  var attachment_default = app15;
8192
8098
 
8193
8099
  // server/routes/admin/agents.ts
8194
- import { resolve as resolve12 } from "path";
8100
+ import { resolve as resolve11 } from "path";
8195
8101
  import { readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as existsSync15, rmSync } from "fs";
8196
8102
  var app16 = new Hono();
8197
8103
  app16.get("/", (c) => {
8198
8104
  const account = resolveAccount();
8199
8105
  if (!account) return c.json({ agents: [] });
8200
- const agentsDir = resolve12(account.accountDir, "agents");
8106
+ const agentsDir = resolve11(account.accountDir, "agents");
8201
8107
  if (!existsSync15(agentsDir)) return c.json({ agents: [] });
8202
8108
  const agents = [];
8203
8109
  try {
@@ -8205,7 +8111,7 @@ app16.get("/", (c) => {
8205
8111
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
8206
8112
  if (!entry.isDirectory()) continue;
8207
8113
  if (entry.name === "admin") continue;
8208
- const configPath2 = resolve12(agentsDir, entry.name, "config.json");
8114
+ const configPath2 = resolve11(agentsDir, entry.name, "config.json");
8209
8115
  if (!existsSync15(configPath2)) continue;
8210
8116
  try {
8211
8117
  const config = JSON.parse(readFileSync12(configPath2, "utf-8"));
@@ -8234,7 +8140,7 @@ app16.delete("/:slug", async (c) => {
8234
8140
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
8235
8141
  return c.json({ error: "Invalid agent slug" }, 400);
8236
8142
  }
8237
- const agentDir = resolve12(account.accountDir, "agents", slug);
8143
+ const agentDir = resolve11(account.accountDir, "agents", slug);
8238
8144
  if (!existsSync15(agentDir)) {
8239
8145
  return c.json({ error: "Agent not found" }, 404);
8240
8146
  }
@@ -8264,7 +8170,7 @@ app16.post("/:slug/project", async (c) => {
8264
8170
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
8265
8171
  return c.json({ error: "Invalid agent slug" }, 400);
8266
8172
  }
8267
- const agentDir = resolve12(account.accountDir, "agents", slug);
8173
+ const agentDir = resolve11(account.accountDir, "agents", slug);
8268
8174
  if (!existsSync15(agentDir)) {
8269
8175
  return c.json({ error: "Agent not found on disk" }, 404);
8270
8176
  }
@@ -8281,7 +8187,7 @@ var agents_default = app16;
8281
8187
  // server/routes/admin/sessions.ts
8282
8188
  import crypto2 from "crypto";
8283
8189
  import { resolve as resolvePath } from "path";
8284
- import { appendFileSync as appendFileSync4, existsSync as existsSync16 } from "fs";
8190
+ import { appendFileSync as appendFileSync4, existsSync as existsSync17 } from "fs";
8285
8191
 
8286
8192
  // app/lib/synthetic-marker.ts
8287
8193
  var CLOUDFLARE_MARKER_PREFIX = "Cloudflare setup completed (actionId: ";
@@ -8292,7 +8198,135 @@ function isSyntheticUserMarker(content) {
8292
8198
  return content.startsWith(COMPONENT_DONE_PREFIX) || content.startsWith(LIFECYCLE_PREFIX) || content.startsWith(CLOUDFLARE_MARKER_PREFIX);
8293
8199
  }
8294
8200
 
8201
+ // app/lib/claude-agent/jsonl-replay.ts
8202
+ import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
8203
+ function replayJsonl(jsonlPath) {
8204
+ if (!existsSync16(jsonlPath)) {
8205
+ return { messages: [], jsonlMissing: true, malformedLines: 0 };
8206
+ }
8207
+ let raw;
8208
+ try {
8209
+ raw = readFileSync13(jsonlPath, "utf8");
8210
+ } catch {
8211
+ return { messages: [], jsonlMissing: true, malformedLines: 0 };
8212
+ }
8213
+ const lines = raw.split("\n");
8214
+ const messages = [];
8215
+ let malformedLines = 0;
8216
+ let pendingText = "";
8217
+ let pendingComponents = [];
8218
+ let pendingMessageId;
8219
+ let pendingCreatedAt;
8220
+ const flushAssistant = () => {
8221
+ if (!pendingMessageId) return;
8222
+ if (pendingText.length === 0 && pendingComponents.length === 0) {
8223
+ pendingMessageId = void 0;
8224
+ pendingCreatedAt = void 0;
8225
+ return;
8226
+ }
8227
+ messages.push({
8228
+ messageId: pendingMessageId,
8229
+ role: "assistant",
8230
+ content: pendingText,
8231
+ createdAt: pendingCreatedAt ?? (/* @__PURE__ */ new Date(0)).toISOString(),
8232
+ components: pendingComponents,
8233
+ attachments: []
8234
+ });
8235
+ pendingText = "";
8236
+ pendingComponents = [];
8237
+ pendingMessageId = void 0;
8238
+ pendingCreatedAt = void 0;
8239
+ };
8240
+ for (const line of lines) {
8241
+ if (!line.trim()) continue;
8242
+ let entry;
8243
+ try {
8244
+ entry = JSON.parse(line);
8245
+ } catch {
8246
+ malformedLines += 1;
8247
+ continue;
8248
+ }
8249
+ if (entry.type === "user") {
8250
+ const content = entry.message?.content;
8251
+ if (typeof content === "string" && content.length > 0) {
8252
+ flushAssistant();
8253
+ messages.push({
8254
+ messageId: entry.uuid ?? `jsonl-user-${messages.length}`,
8255
+ role: "user",
8256
+ content,
8257
+ createdAt: entry.timestamp ?? (/* @__PURE__ */ new Date(0)).toISOString(),
8258
+ components: [],
8259
+ attachments: []
8260
+ });
8261
+ }
8262
+ continue;
8263
+ }
8264
+ if (entry.type === "assistant" && Array.isArray(entry.message?.content)) {
8265
+ if (!pendingMessageId) {
8266
+ pendingMessageId = entry.uuid ?? `jsonl-asst-${messages.length}`;
8267
+ pendingCreatedAt = entry.timestamp;
8268
+ }
8269
+ for (const block of entry.message.content) {
8270
+ if (block.type === "text" && typeof block.text === "string" && block.text.length > 0) {
8271
+ pendingText = pendingText.length > 0 ? `${pendingText}
8272
+
8273
+ ${block.text}` : block.text;
8274
+ } else if (block.type === "tool_use" && block.name === "mcp__admin__render-component") {
8275
+ const rawInput = block.input ?? {};
8276
+ const rawName = rawInput.name;
8277
+ const rawData = rawInput.data;
8278
+ const componentName = typeof rawName === "string" && rawName.length > 0 ? rawName : "unknown";
8279
+ let dataObj = {};
8280
+ if (rawData !== null && typeof rawData === "object" && !Array.isArray(rawData)) {
8281
+ dataObj = rawData;
8282
+ } else if (typeof rawData === "string") {
8283
+ try {
8284
+ dataObj = JSON.parse(rawData);
8285
+ } catch {
8286
+ }
8287
+ }
8288
+ let healArtefactAttachmentId;
8289
+ let healArtefactMimeType;
8290
+ let healArtefactTitle;
8291
+ if (isPersistentComponent(componentName) && block.id) {
8292
+ const mimeType = deriveComponentMimeType(dataObj);
8293
+ if (mimeType) {
8294
+ healArtefactAttachmentId = deriveComponentAttachmentId(block.id);
8295
+ healArtefactMimeType = mimeType;
8296
+ healArtefactTitle = deriveComponentTitle(componentName, dataObj);
8297
+ }
8298
+ }
8299
+ pendingComponents.push({
8300
+ componentId: block.id ?? `jsonl-comp-${pendingComponents.length}`,
8301
+ name: componentName,
8302
+ data: JSON.stringify(dataObj),
8303
+ ordinal: pendingComponents.length,
8304
+ textOffset: pendingText.length,
8305
+ // Submitted state is a Neo4j projection — JSONL has no notion of
8306
+ // it. The resume route supplements `submitted: true` from the
8307
+ // matching :Component row when present.
8308
+ submitted: false,
8309
+ ...healArtefactAttachmentId ? {
8310
+ artefactAttachmentId: healArtefactAttachmentId,
8311
+ artefactMimeType: healArtefactMimeType,
8312
+ artefactTitle: healArtefactTitle
8313
+ } : {}
8314
+ });
8315
+ }
8316
+ }
8317
+ continue;
8318
+ }
8319
+ }
8320
+ flushAssistant();
8321
+ return { messages, jsonlMissing: false, malformedLines };
8322
+ }
8323
+ function resolveJsonlPath(homeDir, accountDir, agentSessionId) {
8324
+ const projectKey = "-" + accountDir.split("/").filter(Boolean).join("-");
8325
+ return `${homeDir}/.claude/projects/${projectKey}/${agentSessionId}.jsonl`;
8326
+ }
8327
+
8295
8328
  // server/routes/admin/sessions.ts
8329
+ import { homedir } from "os";
8296
8330
  function validateAndShapeAttachments(raws, conversationAccountId, conversationId, messageId, streamLogPath) {
8297
8331
  const chips = [];
8298
8332
  let valid = 0;
@@ -8301,7 +8335,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, conversationId
8301
8335
  let reason = null;
8302
8336
  if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
8303
8337
  else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
8304
- else if (!existsSync16(a.storagePath)) reason = "missing-file";
8338
+ else if (!existsSync17(a.storagePath)) reason = "missing-file";
8305
8339
  if (reason) {
8306
8340
  invalid++;
8307
8341
  try {
@@ -8550,15 +8584,150 @@ app17.post("/:id/resume", async (c) => {
8550
8584
  if (persistedAgentSessionId) {
8551
8585
  setAgentSessionId(sessionKey, persistedAgentSessionId);
8552
8586
  }
8587
+ const streamLogPath = resolvePath(ACCOUNTS_DIR, accountId, "logs", `claude-agent-stream-${conversationId}.log`);
8588
+ const tag = persistedAgentSessionId ? `agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026` : "agentSessionId=missing";
8553
8589
  let messages = [];
8590
+ let neo4jMessages = [];
8591
+ let jsonlReplayMessages = [];
8592
+ let jsonlMissing = false;
8593
+ let jsonlMalformedLines = 0;
8594
+ let jsonlHealMissing = 0;
8595
+ let jsonlHealOk = 0;
8596
+ let jsonlHealFail = 0;
8554
8597
  try {
8555
- messages = await getRecentMessages(conversationId);
8598
+ neo4jMessages = await getRecentMessages(conversationId);
8556
8599
  } catch (err) {
8557
8600
  console.error(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} getRecentMessages failed: conversationId=${conversationId.slice(0, 8)}\u2026 error=${err instanceof Error ? err.message : String(err)}`);
8558
8601
  return c.json({ error: "Failed to load conversation messages" }, 500);
8559
8602
  }
8560
- const streamLogPath = resolvePath(ACCOUNTS_DIR, accountId, "logs", `claude-agent-stream-${conversationId}.log`);
8561
- const tag = persistedAgentSessionId ? `agentSessionId=${persistedAgentSessionId.slice(0, 8)}\u2026` : "agentSessionId=missing";
8603
+ if (persistedAgentSessionId) {
8604
+ const jsonlPath = resolveJsonlPath(homedir(), resolvePath(ACCOUNTS_DIR, accountId), persistedAgentSessionId);
8605
+ const replay = replayJsonl(jsonlPath);
8606
+ jsonlMissing = replay.jsonlMissing;
8607
+ jsonlMalformedLines = replay.malformedLines;
8608
+ jsonlReplayMessages = replay.messages;
8609
+ } else {
8610
+ jsonlMissing = true;
8611
+ }
8612
+ if (jsonlMissing || jsonlReplayMessages.length === 0) {
8613
+ messages = neo4jMessages;
8614
+ } else {
8615
+ const neo4jByKey = /* @__PURE__ */ new Map();
8616
+ for (const n of neo4jMessages) {
8617
+ neo4jByKey.set(`${n.role}${n.content}`, n);
8618
+ }
8619
+ const healQueue = [];
8620
+ messages = jsonlReplayMessages.map((j) => {
8621
+ const match = neo4jByKey.get(`${j.role}${j.content}`);
8622
+ if (match) {
8623
+ const mergedComponents = j.components.map((c2, i) => {
8624
+ const neoComp = match.components?.[i];
8625
+ return {
8626
+ componentId: neoComp?.componentId ?? c2.componentId,
8627
+ name: c2.name,
8628
+ data: c2.data,
8629
+ ordinal: c2.ordinal,
8630
+ textOffset: c2.textOffset,
8631
+ submitted: neoComp?.submitted ?? false
8632
+ };
8633
+ });
8634
+ return {
8635
+ messageId: match.messageId,
8636
+ role: match.role,
8637
+ content: match.content,
8638
+ createdAt: match.createdAt,
8639
+ components: mergedComponents,
8640
+ attachments: match.attachments ?? []
8641
+ };
8642
+ }
8643
+ healQueue.push({ role: j.role, content: j.content, createdAt: j.createdAt, components: j.components });
8644
+ return {
8645
+ messageId: j.messageId,
8646
+ role: j.role,
8647
+ content: j.content,
8648
+ createdAt: j.createdAt,
8649
+ components: j.components.map((c2) => ({
8650
+ componentId: c2.componentId,
8651
+ name: c2.name,
8652
+ data: c2.data,
8653
+ ordinal: c2.ordinal,
8654
+ textOffset: c2.textOffset,
8655
+ submitted: false
8656
+ })),
8657
+ attachments: []
8658
+ };
8659
+ });
8660
+ jsonlHealMissing = healQueue.length;
8661
+ if (healQueue.length > 0) {
8662
+ void (async () => {
8663
+ for (let i = 0; i < healQueue.length; i++) {
8664
+ const q = healQueue[i];
8665
+ try {
8666
+ const healComponents = await Promise.all(q.components.map(async (c2) => {
8667
+ const base = {
8668
+ componentId: c2.componentId,
8669
+ name: c2.name,
8670
+ data: c2.data,
8671
+ ordinal: c2.ordinal,
8672
+ textOffset: c2.textOffset
8673
+ };
8674
+ if (!c2.artefactAttachmentId || !c2.artefactMimeType || !c2.artefactTitle) return base;
8675
+ try {
8676
+ const dataObj = JSON.parse(c2.data);
8677
+ const bytesPick = pickComponentBytes(dataObj);
8678
+ if (!bytesPick) return base;
8679
+ const filename = bytesPick.mimeType === "text/html" ? `${c2.artefactTitle}.html` : `${c2.artefactTitle}.md`;
8680
+ await storeComponentArtefact(accountId, c2.artefactAttachmentId, bytesPick.mimeType, bytesPick.content, filename);
8681
+ appendFileSync4(
8682
+ streamLogPath,
8683
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [render-component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} outcome=ok
8684
+ `
8685
+ );
8686
+ return {
8687
+ ...base,
8688
+ artefactAttachmentId: c2.artefactAttachmentId,
8689
+ artefactMimeType: c2.artefactMimeType,
8690
+ artefactTitle: c2.artefactTitle
8691
+ };
8692
+ } catch (writeErr) {
8693
+ const reason2 = writeErr instanceof Error ? writeErr.message : String(writeErr);
8694
+ appendFileSync4(
8695
+ streamLogPath,
8696
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [render-component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} outcome=disk-fail reason=${JSON.stringify(reason2.slice(0, 200))}
8697
+ `
8698
+ );
8699
+ return base;
8700
+ }
8701
+ }));
8702
+ const messageId = await persistMessage(
8703
+ conversationId,
8704
+ q.role,
8705
+ q.content,
8706
+ accountId,
8707
+ void 0,
8708
+ q.createdAt,
8709
+ void 0,
8710
+ healComponents,
8711
+ void 0
8712
+ );
8713
+ jsonlHealOk += 1;
8714
+ try {
8715
+ appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-persist-heal] convId=${conversationId.slice(0, 8)} turnIndex=${i} role=${q.role} outcome=ok messageId=${(messageId ?? "").slice(0, 8)}
8716
+ `);
8717
+ } catch {
8718
+ }
8719
+ } catch (err) {
8720
+ jsonlHealFail += 1;
8721
+ try {
8722
+ appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-persist-heal] convId=${conversationId.slice(0, 8)} turnIndex=${i} role=${q.role} outcome=fail reason=${JSON.stringify((err instanceof Error ? err.message : String(err)).slice(0, 200))}
8723
+ `);
8724
+ } catch {
8725
+ }
8726
+ }
8727
+ }
8728
+ })();
8729
+ }
8730
+ }
8562
8731
  let totalValid = 0;
8563
8732
  let totalInvalid = 0;
8564
8733
  let totalComponents = 0;
@@ -8600,7 +8769,8 @@ app17.post("/:id/resume", async (c) => {
8600
8769
  const userMessageCount = rehydrated.filter((m) => m.role !== "assistant").length;
8601
8770
  const reason = bridged ? "post-restart" : "page-refresh";
8602
8771
  try {
8603
- appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} sessionKey=${sessionKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} componentCount=${totalComponents} userAttachmentCount=${totalAttachments} syntheticHidden=${syntheticHidden}
8772
+ const source = jsonlMissing ? persistedAgentSessionId ? "jsonl-missing" : "neo4j-only" : "jsonl";
8773
+ appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} source=${source} sessionKey=${sessionKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} jsonlReplayMessages=${jsonlReplayMessages.length} neo4jMessages=${neo4jMessages.length} jsonlMalformed=${jsonlMalformedLines} componentCount=${totalComponents} userAttachmentCount=${totalAttachments} syntheticHidden=${syntheticHidden}
8604
8774
  `);
8605
8775
  if (totalComponents > 0) {
8606
8776
  appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
@@ -8608,13 +8778,27 @@ app17.post("/:id/resume", async (c) => {
8608
8778
  }
8609
8779
  if (totalAttachments > 0 || totalAttachmentInvalid > 0) {
8610
8780
  appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [attachment-rehydrate] conversationId=${conversationId.slice(0, 8)} userMessages=${userMessageCount} attachments=${totalAttachments} invalid=${totalAttachmentInvalid}
8781
+ `);
8782
+ }
8783
+ if (jsonlHealMissing > 0) {
8784
+ appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume-heal] conversationId=${conversationId.slice(0, 8)} missingTurns=${jsonlHealMissing} healOk=${jsonlHealOk} healFail=${jsonlHealFail} note=async-writes-may-still-be-in-flight
8611
8785
  `);
8612
8786
  }
8613
8787
  } catch {
8614
8788
  }
8615
8789
  const age = formatAge(updatedAt);
8616
- console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} syntheticHidden=${syntheticHidden} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
8617
- return c.json({ conversationId, messages: rehydrated });
8790
+ console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} syntheticHidden=${syntheticHidden} jsonlMissing=${jsonlMissing} healMissing=${jsonlHealMissing} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
8791
+ return c.json({
8792
+ conversationId,
8793
+ messages: rehydrated,
8794
+ resumeHeal: {
8795
+ missingTurns: jsonlHealMissing,
8796
+ healed: jsonlHealOk,
8797
+ failed: jsonlHealFail,
8798
+ jsonlMissing,
8799
+ jsonlMalformedLines
8800
+ }
8801
+ });
8618
8802
  });
8619
8803
  app17.post("/:id/label", requireAdminSession, async (c) => {
8620
8804
  const conversationId = c.req.param("id");
@@ -8870,9 +9054,9 @@ app20.post("/", async (c) => {
8870
9054
  var events_default = app20;
8871
9055
 
8872
9056
  // server/routes/admin/cloudflare.ts
8873
- import { homedir } from "os";
8874
- import { resolve as resolve14 } from "path";
8875
- import { readFileSync as readFileSync14 } from "fs";
9057
+ import { homedir as homedir2 } from "os";
9058
+ import { resolve as resolve13 } from "path";
9059
+ import { readFileSync as readFileSync15 } from "fs";
8876
9060
 
8877
9061
  // app/lib/dns-label.ts
8878
9062
  var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
@@ -8888,14 +9072,14 @@ function isValidDomain(value) {
8888
9072
  }
8889
9073
 
8890
9074
  // app/lib/alias-domains.ts
8891
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
9075
+ import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
8892
9076
  import { dirname as dirname5 } from "path";
8893
- import { resolve as resolve13 } from "path";
8894
- var ALIAS_DOMAINS_PATH = resolve13(MAXY_DIR, "alias-domains.json");
9077
+ import { resolve as resolve12 } from "path";
9078
+ var ALIAS_DOMAINS_PATH = resolve12(MAXY_DIR, "alias-domains.json");
8895
9079
  function readExisting() {
8896
- if (!existsSync17(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
9080
+ if (!existsSync18(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
8897
9081
  try {
8898
- const parsed = JSON.parse(readFileSync13(ALIAS_DOMAINS_PATH, "utf-8"));
9082
+ const parsed = JSON.parse(readFileSync14(ALIAS_DOMAINS_PATH, "utf-8"));
8899
9083
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
8900
9084
  return new Set(parsed.filter((h) => typeof h === "string"));
8901
9085
  } catch {
@@ -8919,10 +9103,10 @@ var CLOUDFLARE_SETUP_FORM_SCHEMA = {
8919
9103
  var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
8920
9104
  var DOMAINS_TIMEOUT_MS = 40 * 1e3;
8921
9105
  function loadBrandInfo() {
8922
- const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
8923
- const brandPath = resolve14(platformRoot2, "config", "brand.json");
9106
+ const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve13(process.cwd(), "..");
9107
+ const brandPath = resolve13(platformRoot2, "config", "brand.json");
8924
9108
  try {
8925
- const parsed = JSON.parse(readFileSync14(brandPath, "utf-8"));
9109
+ const parsed = JSON.parse(readFileSync15(brandPath, "utf-8"));
8926
9110
  const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
8927
9111
  const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
8928
9112
  return { hostname: hostname2, configDir: configDir2 };
@@ -8990,6 +9174,10 @@ function fieldFromReason(reason) {
8990
9174
  switch (reason) {
8991
9175
  case "not-signed-in":
8992
9176
  return "dashboard";
9177
+ case "brand-arg-missing":
9178
+ case "brand-config-missing":
9179
+ case "cdp-port-unresolved":
9180
+ return "config";
8993
9181
  case "cdp-unreachable":
8994
9182
  case "target-create-failed":
8995
9183
  case "ws-connect-failed":
@@ -9018,7 +9206,7 @@ app21.get("/domains", requireAdminSession, async (c) => {
9018
9206
  function logErr(line) {
9019
9207
  console.error(`[cloudflare-domains] ${line}${tag()}`);
9020
9208
  }
9021
- function err(field, message, output) {
9209
+ function err(field, message, output, brand2) {
9022
9210
  logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
9023
9211
  if (streamLogPath) {
9024
9212
  writeRouteMilestone(
@@ -9033,7 +9221,8 @@ app21.get("/domains", requireAdminSession, async (c) => {
9033
9221
  message,
9034
9222
  output,
9035
9223
  correlationId,
9036
- streamLogPath
9224
+ streamLogPath,
9225
+ brand: brand2
9037
9226
  };
9038
9227
  return c.json(body, 200);
9039
9228
  }
@@ -9045,7 +9234,7 @@ app21.get("/domains", requireAdminSession, async (c) => {
9045
9234
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
9046
9235
  log(`phase=stream-log-resolved path=${streamLogPath}`);
9047
9236
  const brand = loadBrandInfo();
9048
- const scriptPath = resolve14(homedir(), "list-cf-domains.sh");
9237
+ const scriptPath = resolve13(homedir2(), "list-cf-domains.sh");
9049
9238
  const result = await runFormSpawn({
9050
9239
  scriptPath,
9051
9240
  args: [brand.hostname],
@@ -9064,7 +9253,7 @@ ${result.stderr}` : ""}`;
9064
9253
  const reason = reasonMatch ? reasonMatch[1] : void 0;
9065
9254
  const field = fieldFromReason(reason);
9066
9255
  const message = reason ? `Domain discovery failed: ${reason}` : result.timedOut ? `Domain discovery timed out after ${DOMAINS_TIMEOUT_MS / 1e3}s` : `Domain discovery exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
9067
- return err(field, message, combined);
9256
+ return err(field, message, combined, field === "config" ? brand.hostname : void 0);
9068
9257
  }
9069
9258
  let domains;
9070
9259
  try {
@@ -9135,9 +9324,9 @@ app21.get("/tunnels", requireAdminSession, async (c) => {
9135
9324
  if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
9136
9325
  if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
9137
9326
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
9138
- const certPath = resolve14(homedir(), brand.configDir, "cloudflared", "cert.pem");
9139
- const { existsSync: existsSync24 } = await import("fs");
9140
- if (!existsSync24(certPath)) {
9327
+ const certPath = resolve13(homedir2(), brand.configDir, "cloudflared", "cert.pem");
9328
+ const { existsSync: existsSync25 } = await import("fs");
9329
+ if (!existsSync25(certPath)) {
9141
9330
  return err("cert", `Cloudflare origin certificate is not on disk yet (${certPath}). Complete the Cloudflare login first by submitting the form once \u2014 the OAuth flow writes cert.pem.`);
9142
9331
  }
9143
9332
  const result = await runFormSpawn({
@@ -9425,22 +9614,22 @@ var cloudflare_default = app21;
9425
9614
 
9426
9615
  // server/routes/admin/files.ts
9427
9616
  import { createReadStream as createReadStream3 } from "fs";
9428
- import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
9429
- import { realpathSync as realpathSync4 } from "fs";
9430
- import { basename as basename4, dirname as dirname6, join as join10, resolve as resolve16, sep as sep2 } from "path";
9617
+ import { readdir as readdir2, readFile as readFile3, stat as stat3, mkdir as mkdir2, writeFile as writeFile3, unlink as unlink2 } from "fs/promises";
9618
+ import { realpathSync as realpathSync3 } from "fs";
9619
+ import { basename as basename3, dirname as dirname6, join as join10, resolve as resolve15, sep as sep2 } from "path";
9431
9620
  import { Readable as Readable2 } from "stream";
9432
9621
 
9433
9622
  // app/lib/data-path.ts
9434
- import { realpathSync as realpathSync3 } from "fs";
9435
- import { resolve as resolve15, normalize, sep, relative } from "path";
9436
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "../platform");
9437
- var DATA_ROOT = resolve15(PLATFORM_ROOT6, "..", "data");
9623
+ import { realpathSync as realpathSync2 } from "fs";
9624
+ import { resolve as resolve14, normalize, sep, relative } from "path";
9625
+ var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "../platform");
9626
+ var DATA_ROOT = resolve14(PLATFORM_ROOT5, "..", "data");
9438
9627
  function resolveDataPath(raw) {
9439
9628
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
9440
- const absolute = resolve15(DATA_ROOT, cleaned);
9629
+ const absolute = resolve14(DATA_ROOT, cleaned);
9441
9630
  let dataRootReal;
9442
9631
  try {
9443
- dataRootReal = realpathSync3(DATA_ROOT);
9632
+ dataRootReal = realpathSync2(DATA_ROOT);
9444
9633
  } catch (err) {
9445
9634
  return {
9446
9635
  ok: false,
@@ -9450,7 +9639,7 @@ function resolveDataPath(raw) {
9450
9639
  }
9451
9640
  let resolvedReal;
9452
9641
  try {
9453
- resolvedReal = realpathSync3(absolute);
9642
+ resolvedReal = realpathSync2(absolute);
9454
9643
  } catch (err) {
9455
9644
  const code = err.code;
9456
9645
  if (code === "ENOENT") {
@@ -9785,7 +9974,7 @@ async function cascadeDeleteDocument(params) {
9785
9974
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9786
9975
  async function readMeta(absDir, baseName) {
9787
9976
  try {
9788
- const raw = await readFile4(join10(absDir, `${baseName}.meta.json`), "utf8");
9977
+ const raw = await readFile3(join10(absDir, `${baseName}.meta.json`), "utf8");
9789
9978
  const parsed = JSON.parse(raw);
9790
9979
  if (typeof parsed?.filename === "string") {
9791
9980
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -9796,7 +9985,7 @@ async function readMeta(absDir, baseName) {
9796
9985
  }
9797
9986
  async function readAccountNames() {
9798
9987
  const map = /* @__PURE__ */ new Map();
9799
- const accountsDir = resolve16(DATA_ROOT, "accounts");
9988
+ const accountsDir = resolve15(DATA_ROOT, "accounts");
9800
9989
  let names;
9801
9990
  try {
9802
9991
  names = await readdir2(accountsDir);
@@ -9805,9 +9994,9 @@ async function readAccountNames() {
9805
9994
  }
9806
9995
  for (const name of names) {
9807
9996
  if (!UUID_RE4.test(name)) continue;
9808
- const configPath2 = resolve16(accountsDir, name, "account.json");
9997
+ const configPath2 = resolve15(accountsDir, name, "account.json");
9809
9998
  try {
9810
- const raw = await readFile4(configPath2, "utf8");
9999
+ const raw = await readFile3(configPath2, "utf8");
9811
10000
  const parsed = JSON.parse(raw);
9812
10001
  if (typeof parsed?.name === "string" && parsed.name.length > 0) {
9813
10002
  map.set(name, parsed.name);
@@ -9871,7 +10060,7 @@ app22.get("/", requireAdminSession, async (c) => {
9871
10060
  }
9872
10061
  const { absolute, relative: relPath2 } = resolution;
9873
10062
  try {
9874
- const info = await stat4(absolute);
10063
+ const info = await stat3(absolute);
9875
10064
  if (!info.isDirectory()) {
9876
10065
  return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
9877
10066
  }
@@ -9883,7 +10072,7 @@ app22.get("/", requireAdminSession, async (c) => {
9883
10072
  }
9884
10073
  try {
9885
10074
  const entryPath = join10(absolute, name);
9886
- const s = await stat4(entryPath);
10075
+ const s = await stat3(entryPath);
9887
10076
  entries.push({
9888
10077
  name,
9889
10078
  kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
@@ -9933,11 +10122,11 @@ app22.get("/download", requireAdminSession, async (c) => {
9933
10122
  }
9934
10123
  const { absolute, relative: relPath2 } = resolution;
9935
10124
  try {
9936
- const info = await stat4(absolute);
10125
+ const info = await stat3(absolute);
9937
10126
  if (!info.isFile()) {
9938
10127
  return c.json({ error: "Path is not a file" }, 400);
9939
10128
  }
9940
- const filename = basename4(absolute);
10129
+ const filename = basename3(absolute);
9941
10130
  const mimeType = detectMimeType(absolute);
9942
10131
  const nodeStream = createReadStream3(absolute);
9943
10132
  const webStream = Readable2.toWeb(nodeStream);
@@ -9994,20 +10183,20 @@ app22.post("/upload", requireAdminSession, async (c) => {
9994
10183
  error: `Unsupported file type: "${file.type}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
9995
10184
  }, 422);
9996
10185
  }
9997
- const safeName = basename4(file.name).replace(/[\0/\\]/g, "_");
10186
+ const safeName = basename3(file.name).replace(/[\0/\\]/g, "_");
9998
10187
  const finalName = `${Date.now()}-${safeName}`;
9999
- const destDir = resolve16(DATA_ROOT, "uploads", accountId);
10000
- const destPath = resolve16(destDir, finalName);
10188
+ const destDir = resolve15(DATA_ROOT, "uploads", accountId);
10189
+ const destPath = resolve15(destDir, finalName);
10001
10190
  try {
10002
- await mkdir3(destDir, { recursive: true });
10003
- const dataRootReal = realpathSync4(DATA_ROOT);
10004
- const destDirReal = realpathSync4(destDir);
10191
+ await mkdir2(destDir, { recursive: true });
10192
+ const dataRootReal = realpathSync3(DATA_ROOT);
10193
+ const destDirReal = realpathSync3(destDir);
10005
10194
  if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep2)) {
10006
10195
  console.error(`[data] path-traversal-blocked requested="uploads/${accountId}" resolved="${destDirReal}"`);
10007
10196
  return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
10008
10197
  }
10009
10198
  const buffer = Buffer.from(await file.arrayBuffer());
10010
- await writeFile4(destPath, buffer);
10199
+ await writeFile3(destPath, buffer);
10011
10200
  } catch (err) {
10012
10201
  const message = err instanceof Error ? err.message : String(err);
10013
10202
  console.error(`[data] file-upload error filename="${safeName}" err="${message}"`);
@@ -10039,14 +10228,14 @@ app22.delete("/", requireAdminSession, async (c) => {
10039
10228
  return c.json({ error: resolution.error }, resolution.status);
10040
10229
  }
10041
10230
  const { absolute, relative: relPath2 } = resolution;
10042
- const base = basename4(absolute);
10231
+ const base = basename3(absolute);
10043
10232
  const segments = relPath2.split("/").filter(Boolean);
10044
10233
  if (base === "account.json" || segments.includes(".git")) {
10045
10234
  console.error(`[data] file-delete blocked path="${relPath2}" reason="protected"`);
10046
10235
  return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
10047
10236
  }
10048
10237
  try {
10049
- const info = await stat4(absolute);
10238
+ const info = await stat3(absolute);
10050
10239
  if (info.isDirectory()) {
10051
10240
  return c.json({ error: "Directory deletion not supported" }, 400);
10052
10241
  }
@@ -11675,9 +11864,9 @@ var adherence_default = app30;
11675
11864
 
11676
11865
  // server/routes/admin/sidebar-artefacts.ts
11677
11866
  import neo4j3 from "neo4j-driver";
11678
- import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
11679
- import { resolve as resolve17, relative as relative2, isAbsolute } from "path";
11680
- import { existsSync as existsSync18 } from "fs";
11867
+ import { readFile as readFile4, readdir as readdir3, stat as stat4 } from "fs/promises";
11868
+ import { resolve as resolve16, relative as relative2, isAbsolute } from "path";
11869
+ import { existsSync as existsSync19 } from "fs";
11681
11870
  var LIMIT = 50;
11682
11871
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11683
11872
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -11693,7 +11882,7 @@ app31.get("/", requireAdminSession, async (c) => {
11693
11882
  if (docs === null) {
11694
11883
  return c.json({ error: "Failed to load artefacts" }, 500);
11695
11884
  }
11696
- const accountDir = resolve17(ACCOUNTS_DIR, accountId);
11885
+ const accountDir = resolve16(ACCOUNTS_DIR, accountId);
11697
11886
  const agents = await fetchAgentTemplateRows(accountDir);
11698
11887
  const artefacts = [...docs, ...agents].sort(
11699
11888
  (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
@@ -11756,8 +11945,8 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
11756
11945
  logSkip(displayName, "non-text-mime", mimeType);
11757
11946
  return { content: "", skipReason: "non-text-mime" };
11758
11947
  }
11759
- const accountDir = resolve17(ATTACHMENTS_ROOT, accountId);
11760
- const dir = resolve17(accountDir, attachmentId);
11948
+ const accountDir = resolve16(ATTACHMENTS_ROOT, accountId);
11949
+ const dir = resolve16(accountDir, attachmentId);
11761
11950
  try {
11762
11951
  validateFilePathInAccount(dir, accountDir);
11763
11952
  } catch {
@@ -11771,7 +11960,7 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
11771
11960
  logSkip(displayName, "missing-on-disk", mimeType);
11772
11961
  return { content: "", skipReason: "missing-on-disk" };
11773
11962
  }
11774
- return { content: await readFile5(resolve17(dir, dataFile), "utf-8"), skipReason: null };
11963
+ return { content: await readFile4(resolve16(dir, dataFile), "utf-8"), skipReason: null };
11775
11964
  } catch (err) {
11776
11965
  const message = err instanceof Error ? err.message : String(err);
11777
11966
  console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
@@ -11787,8 +11976,8 @@ function logSkip(name, reason, mimeType) {
11787
11976
  async function fetchAgentTemplateRows(accountDir) {
11788
11977
  const rows = [];
11789
11978
  for (const filename of ADMIN_AGENT_FILES) {
11790
- const overridePath = resolve17(accountDir, "agents", "admin", filename);
11791
- const bundledPath = resolve17(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11979
+ const overridePath = resolve16(accountDir, "agents", "admin", filename);
11980
+ const bundledPath = resolve16(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11792
11981
  const labelStem = filename.replace(/\.md$/, "");
11793
11982
  const row = await readAgentTemplateRow({
11794
11983
  id: `agent-template:admin:${filename}`,
@@ -11802,12 +11991,12 @@ async function fetchAgentTemplateRows(accountDir) {
11802
11991
  });
11803
11992
  if (row) rows.push(row);
11804
11993
  }
11805
- const overrideDir = resolve17(accountDir, "specialists", "agents");
11806
- const bundledDir = resolve17(PLATFORM_ROOT, "templates", "specialists", "agents");
11994
+ const overrideDir = resolve16(accountDir, "specialists", "agents");
11995
+ const bundledDir = resolve16(PLATFORM_ROOT, "templates", "specialists", "agents");
11807
11996
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
11808
11997
  for (const filename of specialistNames) {
11809
- const overridePath = resolve17(overrideDir, filename);
11810
- const bundledPath = resolve17(bundledDir, filename);
11998
+ const overridePath = resolve16(overrideDir, filename);
11999
+ const bundledPath = resolve16(bundledDir, filename);
11811
12000
  const row = await readAgentTemplateRow({
11812
12001
  id: `agent-template:specialist:${filename}`,
11813
12002
  displayName: filename.replace(/\.md$/, ""),
@@ -11825,7 +12014,7 @@ async function fetchAgentTemplateRows(accountDir) {
11825
12014
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
11826
12015
  const names = /* @__PURE__ */ new Set();
11827
12016
  for (const dir of [overrideDir, bundledDir]) {
11828
- if (!existsSync18(dir)) continue;
12017
+ if (!existsSync19(dir)) continue;
11829
12018
  try {
11830
12019
  const entries = await readdir3(dir);
11831
12020
  for (const entry of entries) {
@@ -11840,7 +12029,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
11840
12029
  }
11841
12030
  async function readAgentTemplateRow(inp) {
11842
12031
  let chosenPath = null;
11843
- if (existsSync18(inp.overridePath)) {
12032
+ if (existsSync19(inp.overridePath)) {
11844
12033
  try {
11845
12034
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
11846
12035
  chosenPath = inp.overridePath;
@@ -11851,7 +12040,7 @@ async function readAgentTemplateRow(inp) {
11851
12040
  );
11852
12041
  return null;
11853
12042
  }
11854
- } else if (existsSync18(inp.bundledPath)) {
12043
+ } else if (existsSync19(inp.bundledPath)) {
11855
12044
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
11856
12045
  console.error(
11857
12046
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -11863,8 +12052,8 @@ async function readAgentTemplateRow(inp) {
11863
12052
  if (!chosenPath) return null;
11864
12053
  try {
11865
12054
  const [content, st] = await Promise.all([
11866
- readFile5(chosenPath, "utf-8"),
11867
- stat5(chosenPath)
12055
+ readFile4(chosenPath, "utf-8"),
12056
+ stat4(chosenPath)
11868
12057
  ]);
11869
12058
  return {
11870
12059
  id: inp.id,
@@ -11891,9 +12080,9 @@ function isWithin(target, root) {
11891
12080
  var sidebar_artefacts_default = app31;
11892
12081
 
11893
12082
  // server/routes/admin/sidebar-artefact-save.ts
11894
- import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
11895
- import { resolve as resolve18 } from "path";
11896
- import { existsSync as existsSync19 } from "fs";
12083
+ import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
12084
+ import { resolve as resolve17 } from "path";
12085
+ import { existsSync as existsSync20 } from "fs";
11897
12086
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
11898
12087
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11899
12088
  var app32 = new Hono();
@@ -11905,7 +12094,7 @@ app32.post("/", requireAdminSession, async (c) => {
11905
12094
  if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
11906
12095
  return c.json({ error: "id and content required" }, 400);
11907
12096
  }
11908
- const accountDir = resolve18(ACCOUNTS_DIR, accountId);
12097
+ const accountDir = resolve17(ACCOUNTS_DIR, accountId);
11909
12098
  const resolved = await resolveSavePath(body.id, accountId, accountDir);
11910
12099
  if (resolved.kind === "reject") {
11911
12100
  console.error(
@@ -11915,7 +12104,7 @@ app32.post("/", requireAdminSession, async (c) => {
11915
12104
  }
11916
12105
  const start = Date.now();
11917
12106
  try {
11918
- await writeFile5(resolved.path, body.content, "utf-8");
12107
+ await writeFile4(resolved.path, body.content, "utf-8");
11919
12108
  } catch (err) {
11920
12109
  const message = err instanceof Error ? err.message : String(err);
11921
12110
  console.error(
@@ -11925,7 +12114,7 @@ app32.post("/", requireAdminSession, async (c) => {
11925
12114
  }
11926
12115
  let updatedAt = (/* @__PURE__ */ new Date()).toISOString();
11927
12116
  try {
11928
- const st = await stat6(resolved.path);
12117
+ const st = await stat5(resolved.path);
11929
12118
  updatedAt = st.mtime.toISOString();
11930
12119
  } catch {
11931
12120
  }
@@ -11946,22 +12135,22 @@ async function resolveSavePath(id, accountId, accountDir) {
11946
12135
  if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
11947
12136
  return { kind: "reject", status: 400, reason: "invalid-id" };
11948
12137
  }
11949
- const parent = resolve18(accountDir, "agents", "admin");
11950
- await mkdir4(parent, { recursive: true });
12138
+ const parent = resolve17(accountDir, "agents", "admin");
12139
+ await mkdir3(parent, { recursive: true });
11951
12140
  try {
11952
12141
  validateFilePathInAccount(parent, accountDir);
11953
12142
  } catch {
11954
12143
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11955
12144
  }
11956
- return { kind: "admin-template", path: resolve18(parent, filename) };
12145
+ return { kind: "admin-template", path: resolve17(parent, filename) };
11957
12146
  }
11958
12147
  if (UUID_RE5.test(id)) {
11959
- const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
11960
- if (!existsSync19(dir)) {
12148
+ const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
12149
+ if (!existsSync20(dir)) {
11961
12150
  return { kind: "reject", status: 400, reason: "not-found" };
11962
12151
  }
11963
12152
  try {
11964
- validateFilePathInAccount(dir, resolve18(ATTACHMENTS_ROOT, accountId));
12153
+ validateFilePathInAccount(dir, resolve17(ATTACHMENTS_ROOT, accountId));
11965
12154
  } catch {
11966
12155
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11967
12156
  }
@@ -11970,7 +12159,7 @@ async function resolveSavePath(id, accountId, accountDir) {
11970
12159
  if (!dataFile) {
11971
12160
  return { kind: "reject", status: 400, reason: "not-found" };
11972
12161
  }
11973
- return { kind: "knowledge-doc", path: resolve18(dir, dataFile) };
12162
+ return { kind: "knowledge-doc", path: resolve17(dir, dataFile) };
11974
12163
  }
11975
12164
  return { kind: "reject", status: 400, reason: "invalid-id" };
11976
12165
  }
@@ -11980,9 +12169,9 @@ function relPath(absPath, root) {
11980
12169
  var sidebar_artefact_save_default = app32;
11981
12170
 
11982
12171
  // server/routes/admin/sidebar-artefact-content.ts
11983
- import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
11984
- import { existsSync as existsSync20 } from "fs";
11985
- import { resolve as resolve19 } from "path";
12172
+ import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
12173
+ import { existsSync as existsSync21 } from "fs";
12174
+ import { resolve as resolve18 } from "path";
11986
12175
  var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11987
12176
  var app33 = new Hono();
11988
12177
  app33.get("/", requireAdminSession, async (c) => {
@@ -11994,14 +12183,14 @@ app33.get("/", requireAdminSession, async (c) => {
11994
12183
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11995
12184
  return new Response("Not found", { status: 404 });
11996
12185
  }
11997
- const dir = resolve19(ATTACHMENTS_ROOT, accountId, id);
11998
- if (!existsSync20(dir)) {
12186
+ const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
12187
+ if (!existsSync21(dir)) {
11999
12188
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12000
12189
  return new Response("Not found", { status: 404 });
12001
12190
  }
12002
12191
  let meta;
12003
12192
  try {
12004
- meta = JSON.parse(await readFile6(resolve19(dir, `${id}.meta.json`), "utf-8"));
12193
+ meta = JSON.parse(await readFile5(resolve18(dir, `${id}.meta.json`), "utf-8"));
12005
12194
  } catch {
12006
12195
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12007
12196
  return new Response("Not found", { status: 404 });
@@ -12013,7 +12202,7 @@ app33.get("/", requireAdminSession, async (c) => {
12013
12202
  return new Response("Not found", { status: 404 });
12014
12203
  }
12015
12204
  const start = Date.now();
12016
- const buffer = await readFile6(resolve19(dir, dataFile));
12205
+ const buffer = await readFile5(resolve18(dir, dataFile));
12017
12206
  const ms = Date.now() - start;
12018
12207
  console.log(
12019
12208
  `[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
@@ -12029,24 +12218,24 @@ app33.get("/", requireAdminSession, async (c) => {
12029
12218
  var sidebar_artefact_content_default = app33;
12030
12219
 
12031
12220
  // server/routes/admin/health.ts
12032
- import { existsSync as existsSync21, readFileSync as readFileSync15 } from "fs";
12033
- import { resolve as resolve20, join as join11 } from "path";
12034
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
12221
+ import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
12222
+ import { resolve as resolve19, join as join11 } from "path";
12223
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
12035
12224
  var brandHostname = "maxy";
12036
- var brandJsonPath = join11(PLATFORM_ROOT7, "config", "brand.json");
12037
- if (existsSync21(brandJsonPath)) {
12225
+ var brandJsonPath = join11(PLATFORM_ROOT6, "config", "brand.json");
12226
+ if (existsSync22(brandJsonPath)) {
12038
12227
  try {
12039
- const brand = JSON.parse(readFileSync15(brandJsonPath, "utf-8"));
12228
+ const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
12040
12229
  if (brand.hostname) brandHostname = brand.hostname;
12041
12230
  } catch {
12042
12231
  }
12043
12232
  }
12044
- var VERSION_FILE = resolve20(PLATFORM_ROOT7, `config/.${brandHostname}-version`);
12233
+ var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
12045
12234
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
12046
12235
  var PROBE_TIMEOUT_MS = 1e3;
12047
12236
  function readVersion() {
12048
- if (!existsSync21(VERSION_FILE)) return "unknown";
12049
- return readFileSync15(VERSION_FILE, "utf-8").trim() || "unknown";
12237
+ if (!existsSync22(VERSION_FILE)) return "unknown";
12238
+ return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
12050
12239
  }
12051
12240
  async function probeConversationDb() {
12052
12241
  let session;
@@ -12126,8 +12315,8 @@ app35.route("/health-brand", health_default2);
12126
12315
  var admin_default = app35;
12127
12316
 
12128
12317
  // server/routes/sites.ts
12129
- import { existsSync as existsSync22, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
12130
- import { resolve as resolve21 } from "path";
12318
+ import { existsSync as existsSync23, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
12319
+ import { resolve as resolve20 } from "path";
12131
12320
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12132
12321
  var MIME = {
12133
12322
  ".html": "text/html; charset=utf-8",
@@ -12184,19 +12373,19 @@ app36.get("/:rel{.*}", (c) => {
12184
12373
  }
12185
12374
  segments.push(seg);
12186
12375
  }
12187
- const rootDir = resolve21(account.accountDir, "sites");
12188
- let filePath = segments.length === 0 ? rootDir : resolve21(rootDir, ...segments);
12376
+ const rootDir = resolve20(account.accountDir, "sites");
12377
+ let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
12189
12378
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
12190
12379
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
12191
12380
  return c.text("Forbidden", 403);
12192
12381
  }
12193
- let stat7;
12382
+ let stat6;
12194
12383
  try {
12195
- stat7 = existsSync22(filePath) ? statSync7(filePath) : null;
12384
+ stat6 = existsSync23(filePath) ? statSync7(filePath) : null;
12196
12385
  } catch {
12197
- stat7 = null;
12386
+ stat6 = null;
12198
12387
  }
12199
- if (stat7?.isDirectory() && !reqPath.endsWith("/")) {
12388
+ if (stat6?.isDirectory() && !reqPath.endsWith("/")) {
12200
12389
  const search = new URL(c.req.url).search;
12201
12390
  const target = `${reqPath}/${search}`;
12202
12391
  console.log(
@@ -12204,22 +12393,22 @@ app36.get("/:rel{.*}", (c) => {
12204
12393
  );
12205
12394
  return c.redirect(target, 301);
12206
12395
  }
12207
- if (stat7?.isDirectory()) {
12208
- filePath = resolve21(filePath, "index.html");
12396
+ if (stat6?.isDirectory()) {
12397
+ filePath = resolve20(filePath, "index.html");
12209
12398
  }
12210
12399
  if (!filePath.startsWith(rootDir + "/")) {
12211
12400
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
12212
12401
  return c.text("Forbidden", 403);
12213
12402
  }
12214
- if (!existsSync22(filePath)) {
12403
+ if (!existsSync23(filePath)) {
12215
12404
  console.error(`[sites] not-found path=${reqPath} status=404`);
12216
12405
  return c.text("Not found", 404);
12217
12406
  }
12218
12407
  let realPath;
12219
12408
  let realRoot;
12220
12409
  try {
12221
- realPath = realpathSync5(filePath);
12222
- realRoot = realpathSync5(rootDir);
12410
+ realPath = realpathSync4(filePath);
12411
+ realRoot = realpathSync4(rootDir);
12223
12412
  } catch {
12224
12413
  console.error(`[sites] not-found path=${reqPath} status=404`);
12225
12414
  return c.text("Not found", 404);
@@ -12230,7 +12419,7 @@ app36.get("/:rel{.*}", (c) => {
12230
12419
  }
12231
12420
  let body;
12232
12421
  try {
12233
- body = readFileSync16(realPath);
12422
+ body = readFileSync17(realPath);
12234
12423
  } catch (err) {
12235
12424
  const code = err?.code;
12236
12425
  if (code === "EISDIR") {
@@ -12361,15 +12550,15 @@ function clientFrom(c) {
12361
12550
  c.req.header("x-forwarded-for")
12362
12551
  );
12363
12552
  }
12364
- var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
12365
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join12(PLATFORM_ROOT8, "config", "brand.json") : "";
12553
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
12554
+ var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join12(PLATFORM_ROOT7, "config", "brand.json") : "";
12366
12555
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12367
- if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
12556
+ if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
12368
12557
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
12369
12558
  }
12370
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
12559
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
12371
12560
  try {
12372
- const parsed = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
12561
+ const parsed = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
12373
12562
  BRAND = { ...BRAND, ...parsed };
12374
12563
  } catch (err) {
12375
12564
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -12388,11 +12577,11 @@ var brandLoginOpts = {
12388
12577
  bodyFont: BRAND.defaultFonts?.body,
12389
12578
  logoContainsName: !!BRAND.logoContainsName
12390
12579
  };
12391
- var ALIAS_DOMAINS_PATH2 = join12(homedir2(), BRAND.configDir, "alias-domains.json");
12580
+ var ALIAS_DOMAINS_PATH2 = join12(homedir3(), BRAND.configDir, "alias-domains.json");
12392
12581
  function loadAliasDomains() {
12393
12582
  try {
12394
- if (!existsSync23(ALIAS_DOMAINS_PATH2)) return null;
12395
- const parsed = JSON.parse(readFileSync17(ALIAS_DOMAINS_PATH2, "utf-8"));
12583
+ if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
12584
+ const parsed = JSON.parse(readFileSync18(ALIAS_DOMAINS_PATH2, "utf-8"));
12396
12585
  if (!Array.isArray(parsed)) {
12397
12586
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
12398
12587
  return null;
@@ -12732,20 +12921,20 @@ app37.get("/agent-assets/:slug/:filename", (c) => {
12732
12921
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
12733
12922
  return c.text("Not found", 404);
12734
12923
  }
12735
- const filePath = resolve22(account.accountDir, "agents", slug, "assets", filename);
12736
- const expectedDir = resolve22(account.accountDir, "agents", slug, "assets");
12924
+ const filePath = resolve21(account.accountDir, "agents", slug, "assets", filename);
12925
+ const expectedDir = resolve21(account.accountDir, "agents", slug, "assets");
12737
12926
  if (!filePath.startsWith(expectedDir + "/")) {
12738
12927
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
12739
12928
  return c.text("Forbidden", 403);
12740
12929
  }
12741
- if (!existsSync23(filePath)) {
12930
+ if (!existsSync24(filePath)) {
12742
12931
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
12743
12932
  return c.text("Not found", 404);
12744
12933
  }
12745
12934
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12746
12935
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12747
12936
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
12748
- const body = readFileSync17(filePath);
12937
+ const body = readFileSync18(filePath);
12749
12938
  return c.body(body, 200, {
12750
12939
  "Content-Type": contentType,
12751
12940
  "Cache-Control": "public, max-age=3600"
@@ -12762,20 +12951,20 @@ app37.get("/generated/:filename", (c) => {
12762
12951
  console.error(`[generated] serve file=${filename} status=404`);
12763
12952
  return c.text("Not found", 404);
12764
12953
  }
12765
- const filePath = resolve22(account.accountDir, "generated", filename);
12766
- const expectedDir = resolve22(account.accountDir, "generated");
12954
+ const filePath = resolve21(account.accountDir, "generated", filename);
12955
+ const expectedDir = resolve21(account.accountDir, "generated");
12767
12956
  if (!filePath.startsWith(expectedDir + "/")) {
12768
12957
  console.error(`[generated] serve file=${filename} status=403`);
12769
12958
  return c.text("Forbidden", 403);
12770
12959
  }
12771
- if (!existsSync23(filePath)) {
12960
+ if (!existsSync24(filePath)) {
12772
12961
  console.error(`[generated] serve file=${filename} status=404`);
12773
12962
  return c.text("Not found", 404);
12774
12963
  }
12775
12964
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12776
12965
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12777
12966
  console.log(`[generated] serve file=${filename} status=200`);
12778
- const body = readFileSync17(filePath);
12967
+ const body = readFileSync18(filePath);
12779
12968
  return c.body(body, 200, {
12780
12969
  "Content-Type": contentType,
12781
12970
  "Cache-Control": "public, max-age=86400"
@@ -12785,9 +12974,9 @@ app37.route("/sites", sites_default);
12785
12974
  var htmlCache = /* @__PURE__ */ new Map();
12786
12975
  var brandLogoPath = "/brand/maxy-monochrome.png";
12787
12976
  var brandIconPath = "/brand/maxy-monochrome.png";
12788
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
12977
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
12789
12978
  try {
12790
- const fullBrand = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
12979
+ const fullBrand = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
12791
12980
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
12792
12981
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
12793
12982
  } catch {
@@ -12803,10 +12992,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
12803
12992
  })}</script>`;
12804
12993
  function readInstalledVersion() {
12805
12994
  try {
12806
- if (!PLATFORM_ROOT8) return "unknown";
12807
- const versionFile = join12(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
12808
- if (!existsSync23(versionFile)) return "unknown";
12809
- const content = readFileSync17(versionFile, "utf-8").trim();
12995
+ if (!PLATFORM_ROOT7) return "unknown";
12996
+ const versionFile = join12(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
12997
+ if (!existsSync24(versionFile)) return "unknown";
12998
+ const content = readFileSync18(versionFile, "utf-8").trim();
12810
12999
  return content || "unknown";
12811
13000
  } catch {
12812
13001
  return "unknown";
@@ -12847,7 +13036,7 @@ var clientErrorReporterScript = `<script>
12847
13036
  function cachedHtml(file) {
12848
13037
  let html = htmlCache.get(file);
12849
13038
  if (!html) {
12850
- html = readFileSync17(resolve22(process.cwd(), "public", file), "utf-8");
13039
+ html = readFileSync18(resolve21(process.cwd(), "public", file), "utf-8");
12851
13040
  const productNameEsc = escapeHtml(BRAND.productName);
12852
13041
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
12853
13042
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -12863,26 +13052,26 @@ ${clientErrorReporterScript}
12863
13052
  }
12864
13053
  var brandedHtmlCache = /* @__PURE__ */ new Map();
12865
13054
  function loadBrandingCache(agentSlug) {
12866
- const configDir2 = join12(homedir2(), BRAND.configDir);
13055
+ const configDir2 = join12(homedir3(), BRAND.configDir);
12867
13056
  try {
12868
13057
  const accountJsonPath = join12(configDir2, "account.json");
12869
- if (!existsSync23(accountJsonPath)) return null;
12870
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13058
+ if (!existsSync24(accountJsonPath)) return null;
13059
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
12871
13060
  const accountId = account.accountId;
12872
13061
  if (!accountId) return null;
12873
13062
  const cachePath = join12(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12874
- if (!existsSync23(cachePath)) return null;
12875
- return JSON.parse(readFileSync17(cachePath, "utf-8"));
13063
+ if (!existsSync24(cachePath)) return null;
13064
+ return JSON.parse(readFileSync18(cachePath, "utf-8"));
12876
13065
  } catch {
12877
13066
  return null;
12878
13067
  }
12879
13068
  }
12880
13069
  function resolveDefaultSlug() {
12881
13070
  try {
12882
- const configDir2 = join12(homedir2(), BRAND.configDir);
13071
+ const configDir2 = join12(homedir3(), BRAND.configDir);
12883
13072
  const accountJsonPath = join12(configDir2, "account.json");
12884
- if (!existsSync23(accountJsonPath)) return null;
12885
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13073
+ if (!existsSync24(accountJsonPath)) return null;
13074
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
12886
13075
  return account.defaultAgent || null;
12887
13076
  } catch {
12888
13077
  return null;
@@ -12955,7 +13144,7 @@ app37.use("/vnc-popout.html", logViewerFetch);
12955
13144
  app37.get("/vnc-popout.html", (c) => {
12956
13145
  let html = htmlCache.get("vnc-popout.html");
12957
13146
  if (!html) {
12958
- html = readFileSync17(resolve22(process.cwd(), "public", "vnc-popout.html"), "utf-8");
13147
+ html = readFileSync18(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12959
13148
  const name = escapeHtml(BRAND.productName);
12960
13149
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
12961
13150
  html = html.replace("</head>", ` ${brandScript}
@@ -13061,8 +13250,8 @@ try {
13061
13250
  (async () => {
13062
13251
  try {
13063
13252
  let userId = "";
13064
- if (existsSync23(USERS_FILE)) {
13065
- const users = JSON.parse(readFileSync17(USERS_FILE, "utf-8").trim() || "[]");
13253
+ if (existsSync24(USERS_FILE)) {
13254
+ const users = JSON.parse(readFileSync18(USERS_FILE, "utf-8").trim() || "[]");
13066
13255
  userId = users[0]?.userId ?? "";
13067
13256
  }
13068
13257
  await backfillNullUserIdConversations(userId);
@@ -13072,8 +13261,8 @@ try {
13072
13261
  })();
13073
13262
  (async () => {
13074
13263
  try {
13075
- if (!existsSync23(USERS_FILE)) return;
13076
- const usersRaw = readFileSync17(USERS_FILE, "utf-8").trim();
13264
+ if (!existsSync24(USERS_FILE)) return;
13265
+ const usersRaw = readFileSync18(USERS_FILE, "utf-8").trim();
13077
13266
  if (!usersRaw) return;
13078
13267
  const users = JSON.parse(usersRaw);
13079
13268
  const userId = users[0]?.userId;
@@ -13095,7 +13284,7 @@ try {
13095
13284
  } catch (err) {
13096
13285
  console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
13097
13286
  }
13098
- var configDirForWhatsApp = basename5(MAXY_DIR) || ".maxy";
13287
+ var configDirForWhatsApp = basename4(MAXY_DIR) || ".maxy";
13099
13288
  var bootAccount = resolveAccount();
13100
13289
  var bootAccountConfig = bootAccount?.config;
13101
13290
  var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
@@ -13112,7 +13301,7 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
13112
13301
  (async () => {
13113
13302
  if (!bootAccount) return;
13114
13303
  try {
13115
- const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-NQK7A2EQ.js");
13304
+ const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-LJ4SMK2D.js");
13116
13305
  const result = await recoverRunningCloudflareTasks(
13117
13306
  bootAccount.accountId,
13118
13307
  configDirForWhatsApp,
@@ -13162,7 +13351,7 @@ if (bootAccountConfig?.whatsapp) {
13162
13351
  }
13163
13352
  init({
13164
13353
  configDir: configDirForWhatsApp,
13165
- platformRoot: resolve22(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
13354
+ platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
13166
13355
  accountConfig: bootAccountConfig,
13167
13356
  onMessage: async (msg) => {
13168
13357
  try {