@rubytech/create-realagent 1.0.852 → 1.0.854

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 (41) hide show
  1. package/dist/__tests__/preflight-port-classifier.test.js +240 -73
  2. package/dist/index.js +59 -11
  3. package/dist/preflight-port-classifier.js +176 -41
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand-registry.json +44 -0
  6. package/payload/platform/lib/persistent-components/dist/index.d.ts +21 -0
  7. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
  8. package/payload/platform/lib/persistent-components/dist/index.js +32 -0
  9. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
  10. package/payload/platform/lib/persistent-components/src/index.ts +28 -0
  11. package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
  12. package/payload/platform/package.json +2 -2
  13. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  14. package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +278 -0
  15. package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +204 -20
  16. package/payload/platform/plugins/admin/mcp/dist/index.js +40 -1
  17. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/docs/references/deployment.md +2 -0
  19. package/payload/platform/plugins/docs/references/getting-started.md +2 -0
  20. package/payload/platform/plugins/docs/references/platform.md +1 -1
  21. package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
  22. package/payload/platform/scripts/admin-persist-audit.ts +191 -0
  23. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +214 -0
  24. package/payload/platform/scripts/installer-device-verify.sh +249 -0
  25. package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
  26. package/payload/server/chunk-CFNSKDGA.js +667 -0
  27. package/payload/server/chunk-DC6DWYZJ.js +1603 -0
  28. package/payload/server/chunk-LTB5SSQW.js +10889 -0
  29. package/payload/server/chunk-MN2LGNUB.js +2143 -0
  30. package/payload/server/client-pool-AMT2W3II.js +34 -0
  31. package/payload/server/cloudflare-task-tracker-LJ4SMK2D.js +20 -0
  32. package/payload/server/maxy-edge.js +3 -3
  33. package/payload/server/public/assets/admin-DZ8Ke7t3.js +352 -0
  34. package/payload/server/public/assets/public-DApUXgoq.js +5 -0
  35. package/payload/server/public/assets/useVoiceRecorder-CI8GpxfU.js +36 -0
  36. package/payload/server/public/index.html +2 -2
  37. package/payload/server/public/public.html +2 -2
  38. package/payload/server/server.js +535 -351
  39. package/payload/server/public/assets/admin-Dyl8uNxX.js +0 -352
  40. package/payload/server/public/assets/public-B_PNZUph.js +0 -5
  41. 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 };
@@ -9045,7 +9229,7 @@ app21.get("/domains", requireAdminSession, async (c) => {
9045
9229
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
9046
9230
  log(`phase=stream-log-resolved path=${streamLogPath}`);
9047
9231
  const brand = loadBrandInfo();
9048
- const scriptPath = resolve14(homedir(), "list-cf-domains.sh");
9232
+ const scriptPath = resolve13(homedir2(), "list-cf-domains.sh");
9049
9233
  const result = await runFormSpawn({
9050
9234
  scriptPath,
9051
9235
  args: [brand.hostname],
@@ -9135,9 +9319,9 @@ app21.get("/tunnels", requireAdminSession, async (c) => {
9135
9319
  if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
9136
9320
  if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
9137
9321
  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)) {
9322
+ const certPath = resolve13(homedir2(), brand.configDir, "cloudflared", "cert.pem");
9323
+ const { existsSync: existsSync25 } = await import("fs");
9324
+ if (!existsSync25(certPath)) {
9141
9325
  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
9326
  }
9143
9327
  const result = await runFormSpawn({
@@ -9425,22 +9609,22 @@ var cloudflare_default = app21;
9425
9609
 
9426
9610
  // server/routes/admin/files.ts
9427
9611
  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";
9612
+ import { readdir as readdir2, readFile as readFile3, stat as stat3, mkdir as mkdir2, writeFile as writeFile3, unlink as unlink2 } from "fs/promises";
9613
+ import { realpathSync as realpathSync3 } from "fs";
9614
+ import { basename as basename3, dirname as dirname6, join as join10, resolve as resolve15, sep as sep2 } from "path";
9431
9615
  import { Readable as Readable2 } from "stream";
9432
9616
 
9433
9617
  // 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");
9618
+ import { realpathSync as realpathSync2 } from "fs";
9619
+ import { resolve as resolve14, normalize, sep, relative } from "path";
9620
+ var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "../platform");
9621
+ var DATA_ROOT = resolve14(PLATFORM_ROOT5, "..", "data");
9438
9622
  function resolveDataPath(raw) {
9439
9623
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
9440
- const absolute = resolve15(DATA_ROOT, cleaned);
9624
+ const absolute = resolve14(DATA_ROOT, cleaned);
9441
9625
  let dataRootReal;
9442
9626
  try {
9443
- dataRootReal = realpathSync3(DATA_ROOT);
9627
+ dataRootReal = realpathSync2(DATA_ROOT);
9444
9628
  } catch (err) {
9445
9629
  return {
9446
9630
  ok: false,
@@ -9450,7 +9634,7 @@ function resolveDataPath(raw) {
9450
9634
  }
9451
9635
  let resolvedReal;
9452
9636
  try {
9453
- resolvedReal = realpathSync3(absolute);
9637
+ resolvedReal = realpathSync2(absolute);
9454
9638
  } catch (err) {
9455
9639
  const code = err.code;
9456
9640
  if (code === "ENOENT") {
@@ -9785,7 +9969,7 @@ async function cascadeDeleteDocument(params) {
9785
9969
  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
9970
  async function readMeta(absDir, baseName) {
9787
9971
  try {
9788
- const raw = await readFile4(join10(absDir, `${baseName}.meta.json`), "utf8");
9972
+ const raw = await readFile3(join10(absDir, `${baseName}.meta.json`), "utf8");
9789
9973
  const parsed = JSON.parse(raw);
9790
9974
  if (typeof parsed?.filename === "string") {
9791
9975
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -9796,7 +9980,7 @@ async function readMeta(absDir, baseName) {
9796
9980
  }
9797
9981
  async function readAccountNames() {
9798
9982
  const map = /* @__PURE__ */ new Map();
9799
- const accountsDir = resolve16(DATA_ROOT, "accounts");
9983
+ const accountsDir = resolve15(DATA_ROOT, "accounts");
9800
9984
  let names;
9801
9985
  try {
9802
9986
  names = await readdir2(accountsDir);
@@ -9805,9 +9989,9 @@ async function readAccountNames() {
9805
9989
  }
9806
9990
  for (const name of names) {
9807
9991
  if (!UUID_RE4.test(name)) continue;
9808
- const configPath2 = resolve16(accountsDir, name, "account.json");
9992
+ const configPath2 = resolve15(accountsDir, name, "account.json");
9809
9993
  try {
9810
- const raw = await readFile4(configPath2, "utf8");
9994
+ const raw = await readFile3(configPath2, "utf8");
9811
9995
  const parsed = JSON.parse(raw);
9812
9996
  if (typeof parsed?.name === "string" && parsed.name.length > 0) {
9813
9997
  map.set(name, parsed.name);
@@ -9871,7 +10055,7 @@ app22.get("/", requireAdminSession, async (c) => {
9871
10055
  }
9872
10056
  const { absolute, relative: relPath2 } = resolution;
9873
10057
  try {
9874
- const info = await stat4(absolute);
10058
+ const info = await stat3(absolute);
9875
10059
  if (!info.isDirectory()) {
9876
10060
  return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
9877
10061
  }
@@ -9883,7 +10067,7 @@ app22.get("/", requireAdminSession, async (c) => {
9883
10067
  }
9884
10068
  try {
9885
10069
  const entryPath = join10(absolute, name);
9886
- const s = await stat4(entryPath);
10070
+ const s = await stat3(entryPath);
9887
10071
  entries.push({
9888
10072
  name,
9889
10073
  kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
@@ -9933,11 +10117,11 @@ app22.get("/download", requireAdminSession, async (c) => {
9933
10117
  }
9934
10118
  const { absolute, relative: relPath2 } = resolution;
9935
10119
  try {
9936
- const info = await stat4(absolute);
10120
+ const info = await stat3(absolute);
9937
10121
  if (!info.isFile()) {
9938
10122
  return c.json({ error: "Path is not a file" }, 400);
9939
10123
  }
9940
- const filename = basename4(absolute);
10124
+ const filename = basename3(absolute);
9941
10125
  const mimeType = detectMimeType(absolute);
9942
10126
  const nodeStream = createReadStream3(absolute);
9943
10127
  const webStream = Readable2.toWeb(nodeStream);
@@ -9994,20 +10178,20 @@ app22.post("/upload", requireAdminSession, async (c) => {
9994
10178
  error: `Unsupported file type: "${file.type}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
9995
10179
  }, 422);
9996
10180
  }
9997
- const safeName = basename4(file.name).replace(/[\0/\\]/g, "_");
10181
+ const safeName = basename3(file.name).replace(/[\0/\\]/g, "_");
9998
10182
  const finalName = `${Date.now()}-${safeName}`;
9999
- const destDir = resolve16(DATA_ROOT, "uploads", accountId);
10000
- const destPath = resolve16(destDir, finalName);
10183
+ const destDir = resolve15(DATA_ROOT, "uploads", accountId);
10184
+ const destPath = resolve15(destDir, finalName);
10001
10185
  try {
10002
- await mkdir3(destDir, { recursive: true });
10003
- const dataRootReal = realpathSync4(DATA_ROOT);
10004
- const destDirReal = realpathSync4(destDir);
10186
+ await mkdir2(destDir, { recursive: true });
10187
+ const dataRootReal = realpathSync3(DATA_ROOT);
10188
+ const destDirReal = realpathSync3(destDir);
10005
10189
  if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep2)) {
10006
10190
  console.error(`[data] path-traversal-blocked requested="uploads/${accountId}" resolved="${destDirReal}"`);
10007
10191
  return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
10008
10192
  }
10009
10193
  const buffer = Buffer.from(await file.arrayBuffer());
10010
- await writeFile4(destPath, buffer);
10194
+ await writeFile3(destPath, buffer);
10011
10195
  } catch (err) {
10012
10196
  const message = err instanceof Error ? err.message : String(err);
10013
10197
  console.error(`[data] file-upload error filename="${safeName}" err="${message}"`);
@@ -10039,14 +10223,14 @@ app22.delete("/", requireAdminSession, async (c) => {
10039
10223
  return c.json({ error: resolution.error }, resolution.status);
10040
10224
  }
10041
10225
  const { absolute, relative: relPath2 } = resolution;
10042
- const base = basename4(absolute);
10226
+ const base = basename3(absolute);
10043
10227
  const segments = relPath2.split("/").filter(Boolean);
10044
10228
  if (base === "account.json" || segments.includes(".git")) {
10045
10229
  console.error(`[data] file-delete blocked path="${relPath2}" reason="protected"`);
10046
10230
  return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
10047
10231
  }
10048
10232
  try {
10049
- const info = await stat4(absolute);
10233
+ const info = await stat3(absolute);
10050
10234
  if (info.isDirectory()) {
10051
10235
  return c.json({ error: "Directory deletion not supported" }, 400);
10052
10236
  }
@@ -11675,9 +11859,9 @@ var adherence_default = app30;
11675
11859
 
11676
11860
  // server/routes/admin/sidebar-artefacts.ts
11677
11861
  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";
11862
+ import { readFile as readFile4, readdir as readdir3, stat as stat4 } from "fs/promises";
11863
+ import { resolve as resolve16, relative as relative2, isAbsolute } from "path";
11864
+ import { existsSync as existsSync19 } from "fs";
11681
11865
  var LIMIT = 50;
11682
11866
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11683
11867
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -11693,7 +11877,7 @@ app31.get("/", requireAdminSession, async (c) => {
11693
11877
  if (docs === null) {
11694
11878
  return c.json({ error: "Failed to load artefacts" }, 500);
11695
11879
  }
11696
- const accountDir = resolve17(ACCOUNTS_DIR, accountId);
11880
+ const accountDir = resolve16(ACCOUNTS_DIR, accountId);
11697
11881
  const agents = await fetchAgentTemplateRows(accountDir);
11698
11882
  const artefacts = [...docs, ...agents].sort(
11699
11883
  (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
@@ -11756,8 +11940,8 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
11756
11940
  logSkip(displayName, "non-text-mime", mimeType);
11757
11941
  return { content: "", skipReason: "non-text-mime" };
11758
11942
  }
11759
- const accountDir = resolve17(ATTACHMENTS_ROOT, accountId);
11760
- const dir = resolve17(accountDir, attachmentId);
11943
+ const accountDir = resolve16(ATTACHMENTS_ROOT, accountId);
11944
+ const dir = resolve16(accountDir, attachmentId);
11761
11945
  try {
11762
11946
  validateFilePathInAccount(dir, accountDir);
11763
11947
  } catch {
@@ -11771,7 +11955,7 @@ async function readArtefactContent(accountId, attachmentId, mimeType, displayNam
11771
11955
  logSkip(displayName, "missing-on-disk", mimeType);
11772
11956
  return { content: "", skipReason: "missing-on-disk" };
11773
11957
  }
11774
- return { content: await readFile5(resolve17(dir, dataFile), "utf-8"), skipReason: null };
11958
+ return { content: await readFile4(resolve16(dir, dataFile), "utf-8"), skipReason: null };
11775
11959
  } catch (err) {
11776
11960
  const message = err instanceof Error ? err.message : String(err);
11777
11961
  console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
@@ -11787,8 +11971,8 @@ function logSkip(name, reason, mimeType) {
11787
11971
  async function fetchAgentTemplateRows(accountDir) {
11788
11972
  const rows = [];
11789
11973
  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);
11974
+ const overridePath = resolve16(accountDir, "agents", "admin", filename);
11975
+ const bundledPath = resolve16(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11792
11976
  const labelStem = filename.replace(/\.md$/, "");
11793
11977
  const row = await readAgentTemplateRow({
11794
11978
  id: `agent-template:admin:${filename}`,
@@ -11802,12 +11986,12 @@ async function fetchAgentTemplateRows(accountDir) {
11802
11986
  });
11803
11987
  if (row) rows.push(row);
11804
11988
  }
11805
- const overrideDir = resolve17(accountDir, "specialists", "agents");
11806
- const bundledDir = resolve17(PLATFORM_ROOT, "templates", "specialists", "agents");
11989
+ const overrideDir = resolve16(accountDir, "specialists", "agents");
11990
+ const bundledDir = resolve16(PLATFORM_ROOT, "templates", "specialists", "agents");
11807
11991
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
11808
11992
  for (const filename of specialistNames) {
11809
- const overridePath = resolve17(overrideDir, filename);
11810
- const bundledPath = resolve17(bundledDir, filename);
11993
+ const overridePath = resolve16(overrideDir, filename);
11994
+ const bundledPath = resolve16(bundledDir, filename);
11811
11995
  const row = await readAgentTemplateRow({
11812
11996
  id: `agent-template:specialist:${filename}`,
11813
11997
  displayName: filename.replace(/\.md$/, ""),
@@ -11825,7 +12009,7 @@ async function fetchAgentTemplateRows(accountDir) {
11825
12009
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
11826
12010
  const names = /* @__PURE__ */ new Set();
11827
12011
  for (const dir of [overrideDir, bundledDir]) {
11828
- if (!existsSync18(dir)) continue;
12012
+ if (!existsSync19(dir)) continue;
11829
12013
  try {
11830
12014
  const entries = await readdir3(dir);
11831
12015
  for (const entry of entries) {
@@ -11840,7 +12024,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
11840
12024
  }
11841
12025
  async function readAgentTemplateRow(inp) {
11842
12026
  let chosenPath = null;
11843
- if (existsSync18(inp.overridePath)) {
12027
+ if (existsSync19(inp.overridePath)) {
11844
12028
  try {
11845
12029
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
11846
12030
  chosenPath = inp.overridePath;
@@ -11851,7 +12035,7 @@ async function readAgentTemplateRow(inp) {
11851
12035
  );
11852
12036
  return null;
11853
12037
  }
11854
- } else if (existsSync18(inp.bundledPath)) {
12038
+ } else if (existsSync19(inp.bundledPath)) {
11855
12039
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
11856
12040
  console.error(
11857
12041
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -11863,8 +12047,8 @@ async function readAgentTemplateRow(inp) {
11863
12047
  if (!chosenPath) return null;
11864
12048
  try {
11865
12049
  const [content, st] = await Promise.all([
11866
- readFile5(chosenPath, "utf-8"),
11867
- stat5(chosenPath)
12050
+ readFile4(chosenPath, "utf-8"),
12051
+ stat4(chosenPath)
11868
12052
  ]);
11869
12053
  return {
11870
12054
  id: inp.id,
@@ -11891,9 +12075,9 @@ function isWithin(target, root) {
11891
12075
  var sidebar_artefacts_default = app31;
11892
12076
 
11893
12077
  // 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";
12078
+ import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
12079
+ import { resolve as resolve17 } from "path";
12080
+ import { existsSync as existsSync20 } from "fs";
11897
12081
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
11898
12082
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11899
12083
  var app32 = new Hono();
@@ -11905,7 +12089,7 @@ app32.post("/", requireAdminSession, async (c) => {
11905
12089
  if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
11906
12090
  return c.json({ error: "id and content required" }, 400);
11907
12091
  }
11908
- const accountDir = resolve18(ACCOUNTS_DIR, accountId);
12092
+ const accountDir = resolve17(ACCOUNTS_DIR, accountId);
11909
12093
  const resolved = await resolveSavePath(body.id, accountId, accountDir);
11910
12094
  if (resolved.kind === "reject") {
11911
12095
  console.error(
@@ -11915,7 +12099,7 @@ app32.post("/", requireAdminSession, async (c) => {
11915
12099
  }
11916
12100
  const start = Date.now();
11917
12101
  try {
11918
- await writeFile5(resolved.path, body.content, "utf-8");
12102
+ await writeFile4(resolved.path, body.content, "utf-8");
11919
12103
  } catch (err) {
11920
12104
  const message = err instanceof Error ? err.message : String(err);
11921
12105
  console.error(
@@ -11925,7 +12109,7 @@ app32.post("/", requireAdminSession, async (c) => {
11925
12109
  }
11926
12110
  let updatedAt = (/* @__PURE__ */ new Date()).toISOString();
11927
12111
  try {
11928
- const st = await stat6(resolved.path);
12112
+ const st = await stat5(resolved.path);
11929
12113
  updatedAt = st.mtime.toISOString();
11930
12114
  } catch {
11931
12115
  }
@@ -11946,22 +12130,22 @@ async function resolveSavePath(id, accountId, accountDir) {
11946
12130
  if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
11947
12131
  return { kind: "reject", status: 400, reason: "invalid-id" };
11948
12132
  }
11949
- const parent = resolve18(accountDir, "agents", "admin");
11950
- await mkdir4(parent, { recursive: true });
12133
+ const parent = resolve17(accountDir, "agents", "admin");
12134
+ await mkdir3(parent, { recursive: true });
11951
12135
  try {
11952
12136
  validateFilePathInAccount(parent, accountDir);
11953
12137
  } catch {
11954
12138
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11955
12139
  }
11956
- return { kind: "admin-template", path: resolve18(parent, filename) };
12140
+ return { kind: "admin-template", path: resolve17(parent, filename) };
11957
12141
  }
11958
12142
  if (UUID_RE5.test(id)) {
11959
- const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
11960
- if (!existsSync19(dir)) {
12143
+ const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
12144
+ if (!existsSync20(dir)) {
11961
12145
  return { kind: "reject", status: 400, reason: "not-found" };
11962
12146
  }
11963
12147
  try {
11964
- validateFilePathInAccount(dir, resolve18(ATTACHMENTS_ROOT, accountId));
12148
+ validateFilePathInAccount(dir, resolve17(ATTACHMENTS_ROOT, accountId));
11965
12149
  } catch {
11966
12150
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11967
12151
  }
@@ -11970,7 +12154,7 @@ async function resolveSavePath(id, accountId, accountDir) {
11970
12154
  if (!dataFile) {
11971
12155
  return { kind: "reject", status: 400, reason: "not-found" };
11972
12156
  }
11973
- return { kind: "knowledge-doc", path: resolve18(dir, dataFile) };
12157
+ return { kind: "knowledge-doc", path: resolve17(dir, dataFile) };
11974
12158
  }
11975
12159
  return { kind: "reject", status: 400, reason: "invalid-id" };
11976
12160
  }
@@ -11980,9 +12164,9 @@ function relPath(absPath, root) {
11980
12164
  var sidebar_artefact_save_default = app32;
11981
12165
 
11982
12166
  // 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";
12167
+ import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
12168
+ import { existsSync as existsSync21 } from "fs";
12169
+ import { resolve as resolve18 } from "path";
11986
12170
  var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11987
12171
  var app33 = new Hono();
11988
12172
  app33.get("/", requireAdminSession, async (c) => {
@@ -11994,14 +12178,14 @@ app33.get("/", requireAdminSession, async (c) => {
11994
12178
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11995
12179
  return new Response("Not found", { status: 404 });
11996
12180
  }
11997
- const dir = resolve19(ATTACHMENTS_ROOT, accountId, id);
11998
- if (!existsSync20(dir)) {
12181
+ const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
12182
+ if (!existsSync21(dir)) {
11999
12183
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12000
12184
  return new Response("Not found", { status: 404 });
12001
12185
  }
12002
12186
  let meta;
12003
12187
  try {
12004
- meta = JSON.parse(await readFile6(resolve19(dir, `${id}.meta.json`), "utf-8"));
12188
+ meta = JSON.parse(await readFile5(resolve18(dir, `${id}.meta.json`), "utf-8"));
12005
12189
  } catch {
12006
12190
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12007
12191
  return new Response("Not found", { status: 404 });
@@ -12013,7 +12197,7 @@ app33.get("/", requireAdminSession, async (c) => {
12013
12197
  return new Response("Not found", { status: 404 });
12014
12198
  }
12015
12199
  const start = Date.now();
12016
- const buffer = await readFile6(resolve19(dir, dataFile));
12200
+ const buffer = await readFile5(resolve18(dir, dataFile));
12017
12201
  const ms = Date.now() - start;
12018
12202
  console.log(
12019
12203
  `[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
@@ -12029,24 +12213,24 @@ app33.get("/", requireAdminSession, async (c) => {
12029
12213
  var sidebar_artefact_content_default = app33;
12030
12214
 
12031
12215
  // 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(), "..");
12216
+ import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
12217
+ import { resolve as resolve19, join as join11 } from "path";
12218
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
12035
12219
  var brandHostname = "maxy";
12036
- var brandJsonPath = join11(PLATFORM_ROOT7, "config", "brand.json");
12037
- if (existsSync21(brandJsonPath)) {
12220
+ var brandJsonPath = join11(PLATFORM_ROOT6, "config", "brand.json");
12221
+ if (existsSync22(brandJsonPath)) {
12038
12222
  try {
12039
- const brand = JSON.parse(readFileSync15(brandJsonPath, "utf-8"));
12223
+ const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
12040
12224
  if (brand.hostname) brandHostname = brand.hostname;
12041
12225
  } catch {
12042
12226
  }
12043
12227
  }
12044
- var VERSION_FILE = resolve20(PLATFORM_ROOT7, `config/.${brandHostname}-version`);
12228
+ var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
12045
12229
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
12046
12230
  var PROBE_TIMEOUT_MS = 1e3;
12047
12231
  function readVersion() {
12048
- if (!existsSync21(VERSION_FILE)) return "unknown";
12049
- return readFileSync15(VERSION_FILE, "utf-8").trim() || "unknown";
12232
+ if (!existsSync22(VERSION_FILE)) return "unknown";
12233
+ return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
12050
12234
  }
12051
12235
  async function probeConversationDb() {
12052
12236
  let session;
@@ -12126,8 +12310,8 @@ app35.route("/health-brand", health_default2);
12126
12310
  var admin_default = app35;
12127
12311
 
12128
12312
  // 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";
12313
+ import { existsSync as existsSync23, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
12314
+ import { resolve as resolve20 } from "path";
12131
12315
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12132
12316
  var MIME = {
12133
12317
  ".html": "text/html; charset=utf-8",
@@ -12184,19 +12368,19 @@ app36.get("/:rel{.*}", (c) => {
12184
12368
  }
12185
12369
  segments.push(seg);
12186
12370
  }
12187
- const rootDir = resolve21(account.accountDir, "sites");
12188
- let filePath = segments.length === 0 ? rootDir : resolve21(rootDir, ...segments);
12371
+ const rootDir = resolve20(account.accountDir, "sites");
12372
+ let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
12189
12373
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
12190
12374
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
12191
12375
  return c.text("Forbidden", 403);
12192
12376
  }
12193
- let stat7;
12377
+ let stat6;
12194
12378
  try {
12195
- stat7 = existsSync22(filePath) ? statSync7(filePath) : null;
12379
+ stat6 = existsSync23(filePath) ? statSync7(filePath) : null;
12196
12380
  } catch {
12197
- stat7 = null;
12381
+ stat6 = null;
12198
12382
  }
12199
- if (stat7?.isDirectory() && !reqPath.endsWith("/")) {
12383
+ if (stat6?.isDirectory() && !reqPath.endsWith("/")) {
12200
12384
  const search = new URL(c.req.url).search;
12201
12385
  const target = `${reqPath}/${search}`;
12202
12386
  console.log(
@@ -12204,22 +12388,22 @@ app36.get("/:rel{.*}", (c) => {
12204
12388
  );
12205
12389
  return c.redirect(target, 301);
12206
12390
  }
12207
- if (stat7?.isDirectory()) {
12208
- filePath = resolve21(filePath, "index.html");
12391
+ if (stat6?.isDirectory()) {
12392
+ filePath = resolve20(filePath, "index.html");
12209
12393
  }
12210
12394
  if (!filePath.startsWith(rootDir + "/")) {
12211
12395
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
12212
12396
  return c.text("Forbidden", 403);
12213
12397
  }
12214
- if (!existsSync22(filePath)) {
12398
+ if (!existsSync23(filePath)) {
12215
12399
  console.error(`[sites] not-found path=${reqPath} status=404`);
12216
12400
  return c.text("Not found", 404);
12217
12401
  }
12218
12402
  let realPath;
12219
12403
  let realRoot;
12220
12404
  try {
12221
- realPath = realpathSync5(filePath);
12222
- realRoot = realpathSync5(rootDir);
12405
+ realPath = realpathSync4(filePath);
12406
+ realRoot = realpathSync4(rootDir);
12223
12407
  } catch {
12224
12408
  console.error(`[sites] not-found path=${reqPath} status=404`);
12225
12409
  return c.text("Not found", 404);
@@ -12230,7 +12414,7 @@ app36.get("/:rel{.*}", (c) => {
12230
12414
  }
12231
12415
  let body;
12232
12416
  try {
12233
- body = readFileSync16(realPath);
12417
+ body = readFileSync17(realPath);
12234
12418
  } catch (err) {
12235
12419
  const code = err?.code;
12236
12420
  if (code === "EISDIR") {
@@ -12361,15 +12545,15 @@ function clientFrom(c) {
12361
12545
  c.req.header("x-forwarded-for")
12362
12546
  );
12363
12547
  }
12364
- var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
12365
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join12(PLATFORM_ROOT8, "config", "brand.json") : "";
12548
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
12549
+ var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join12(PLATFORM_ROOT7, "config", "brand.json") : "";
12366
12550
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12367
- if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
12551
+ if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
12368
12552
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
12369
12553
  }
12370
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
12554
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
12371
12555
  try {
12372
- const parsed = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
12556
+ const parsed = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
12373
12557
  BRAND = { ...BRAND, ...parsed };
12374
12558
  } catch (err) {
12375
12559
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -12388,11 +12572,11 @@ var brandLoginOpts = {
12388
12572
  bodyFont: BRAND.defaultFonts?.body,
12389
12573
  logoContainsName: !!BRAND.logoContainsName
12390
12574
  };
12391
- var ALIAS_DOMAINS_PATH2 = join12(homedir2(), BRAND.configDir, "alias-domains.json");
12575
+ var ALIAS_DOMAINS_PATH2 = join12(homedir3(), BRAND.configDir, "alias-domains.json");
12392
12576
  function loadAliasDomains() {
12393
12577
  try {
12394
- if (!existsSync23(ALIAS_DOMAINS_PATH2)) return null;
12395
- const parsed = JSON.parse(readFileSync17(ALIAS_DOMAINS_PATH2, "utf-8"));
12578
+ if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
12579
+ const parsed = JSON.parse(readFileSync18(ALIAS_DOMAINS_PATH2, "utf-8"));
12396
12580
  if (!Array.isArray(parsed)) {
12397
12581
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
12398
12582
  return null;
@@ -12732,20 +12916,20 @@ app37.get("/agent-assets/:slug/:filename", (c) => {
12732
12916
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
12733
12917
  return c.text("Not found", 404);
12734
12918
  }
12735
- const filePath = resolve22(account.accountDir, "agents", slug, "assets", filename);
12736
- const expectedDir = resolve22(account.accountDir, "agents", slug, "assets");
12919
+ const filePath = resolve21(account.accountDir, "agents", slug, "assets", filename);
12920
+ const expectedDir = resolve21(account.accountDir, "agents", slug, "assets");
12737
12921
  if (!filePath.startsWith(expectedDir + "/")) {
12738
12922
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
12739
12923
  return c.text("Forbidden", 403);
12740
12924
  }
12741
- if (!existsSync23(filePath)) {
12925
+ if (!existsSync24(filePath)) {
12742
12926
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
12743
12927
  return c.text("Not found", 404);
12744
12928
  }
12745
12929
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12746
12930
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12747
12931
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
12748
- const body = readFileSync17(filePath);
12932
+ const body = readFileSync18(filePath);
12749
12933
  return c.body(body, 200, {
12750
12934
  "Content-Type": contentType,
12751
12935
  "Cache-Control": "public, max-age=3600"
@@ -12762,20 +12946,20 @@ app37.get("/generated/:filename", (c) => {
12762
12946
  console.error(`[generated] serve file=${filename} status=404`);
12763
12947
  return c.text("Not found", 404);
12764
12948
  }
12765
- const filePath = resolve22(account.accountDir, "generated", filename);
12766
- const expectedDir = resolve22(account.accountDir, "generated");
12949
+ const filePath = resolve21(account.accountDir, "generated", filename);
12950
+ const expectedDir = resolve21(account.accountDir, "generated");
12767
12951
  if (!filePath.startsWith(expectedDir + "/")) {
12768
12952
  console.error(`[generated] serve file=${filename} status=403`);
12769
12953
  return c.text("Forbidden", 403);
12770
12954
  }
12771
- if (!existsSync23(filePath)) {
12955
+ if (!existsSync24(filePath)) {
12772
12956
  console.error(`[generated] serve file=${filename} status=404`);
12773
12957
  return c.text("Not found", 404);
12774
12958
  }
12775
12959
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12776
12960
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12777
12961
  console.log(`[generated] serve file=${filename} status=200`);
12778
- const body = readFileSync17(filePath);
12962
+ const body = readFileSync18(filePath);
12779
12963
  return c.body(body, 200, {
12780
12964
  "Content-Type": contentType,
12781
12965
  "Cache-Control": "public, max-age=86400"
@@ -12785,9 +12969,9 @@ app37.route("/sites", sites_default);
12785
12969
  var htmlCache = /* @__PURE__ */ new Map();
12786
12970
  var brandLogoPath = "/brand/maxy-monochrome.png";
12787
12971
  var brandIconPath = "/brand/maxy-monochrome.png";
12788
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
12972
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
12789
12973
  try {
12790
- const fullBrand = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
12974
+ const fullBrand = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
12791
12975
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
12792
12976
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
12793
12977
  } catch {
@@ -12803,10 +12987,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
12803
12987
  })}</script>`;
12804
12988
  function readInstalledVersion() {
12805
12989
  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();
12990
+ if (!PLATFORM_ROOT7) return "unknown";
12991
+ const versionFile = join12(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
12992
+ if (!existsSync24(versionFile)) return "unknown";
12993
+ const content = readFileSync18(versionFile, "utf-8").trim();
12810
12994
  return content || "unknown";
12811
12995
  } catch {
12812
12996
  return "unknown";
@@ -12847,7 +13031,7 @@ var clientErrorReporterScript = `<script>
12847
13031
  function cachedHtml(file) {
12848
13032
  let html = htmlCache.get(file);
12849
13033
  if (!html) {
12850
- html = readFileSync17(resolve22(process.cwd(), "public", file), "utf-8");
13034
+ html = readFileSync18(resolve21(process.cwd(), "public", file), "utf-8");
12851
13035
  const productNameEsc = escapeHtml(BRAND.productName);
12852
13036
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
12853
13037
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -12863,26 +13047,26 @@ ${clientErrorReporterScript}
12863
13047
  }
12864
13048
  var brandedHtmlCache = /* @__PURE__ */ new Map();
12865
13049
  function loadBrandingCache(agentSlug) {
12866
- const configDir2 = join12(homedir2(), BRAND.configDir);
13050
+ const configDir2 = join12(homedir3(), BRAND.configDir);
12867
13051
  try {
12868
13052
  const accountJsonPath = join12(configDir2, "account.json");
12869
- if (!existsSync23(accountJsonPath)) return null;
12870
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13053
+ if (!existsSync24(accountJsonPath)) return null;
13054
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
12871
13055
  const accountId = account.accountId;
12872
13056
  if (!accountId) return null;
12873
13057
  const cachePath = join12(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12874
- if (!existsSync23(cachePath)) return null;
12875
- return JSON.parse(readFileSync17(cachePath, "utf-8"));
13058
+ if (!existsSync24(cachePath)) return null;
13059
+ return JSON.parse(readFileSync18(cachePath, "utf-8"));
12876
13060
  } catch {
12877
13061
  return null;
12878
13062
  }
12879
13063
  }
12880
13064
  function resolveDefaultSlug() {
12881
13065
  try {
12882
- const configDir2 = join12(homedir2(), BRAND.configDir);
13066
+ const configDir2 = join12(homedir3(), BRAND.configDir);
12883
13067
  const accountJsonPath = join12(configDir2, "account.json");
12884
- if (!existsSync23(accountJsonPath)) return null;
12885
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13068
+ if (!existsSync24(accountJsonPath)) return null;
13069
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
12886
13070
  return account.defaultAgent || null;
12887
13071
  } catch {
12888
13072
  return null;
@@ -12955,7 +13139,7 @@ app37.use("/vnc-popout.html", logViewerFetch);
12955
13139
  app37.get("/vnc-popout.html", (c) => {
12956
13140
  let html = htmlCache.get("vnc-popout.html");
12957
13141
  if (!html) {
12958
- html = readFileSync17(resolve22(process.cwd(), "public", "vnc-popout.html"), "utf-8");
13142
+ html = readFileSync18(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12959
13143
  const name = escapeHtml(BRAND.productName);
12960
13144
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
12961
13145
  html = html.replace("</head>", ` ${brandScript}
@@ -13061,8 +13245,8 @@ try {
13061
13245
  (async () => {
13062
13246
  try {
13063
13247
  let userId = "";
13064
- if (existsSync23(USERS_FILE)) {
13065
- const users = JSON.parse(readFileSync17(USERS_FILE, "utf-8").trim() || "[]");
13248
+ if (existsSync24(USERS_FILE)) {
13249
+ const users = JSON.parse(readFileSync18(USERS_FILE, "utf-8").trim() || "[]");
13066
13250
  userId = users[0]?.userId ?? "";
13067
13251
  }
13068
13252
  await backfillNullUserIdConversations(userId);
@@ -13072,8 +13256,8 @@ try {
13072
13256
  })();
13073
13257
  (async () => {
13074
13258
  try {
13075
- if (!existsSync23(USERS_FILE)) return;
13076
- const usersRaw = readFileSync17(USERS_FILE, "utf-8").trim();
13259
+ if (!existsSync24(USERS_FILE)) return;
13260
+ const usersRaw = readFileSync18(USERS_FILE, "utf-8").trim();
13077
13261
  if (!usersRaw) return;
13078
13262
  const users = JSON.parse(usersRaw);
13079
13263
  const userId = users[0]?.userId;
@@ -13095,7 +13279,7 @@ try {
13095
13279
  } catch (err) {
13096
13280
  console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
13097
13281
  }
13098
- var configDirForWhatsApp = basename5(MAXY_DIR) || ".maxy";
13282
+ var configDirForWhatsApp = basename4(MAXY_DIR) || ".maxy";
13099
13283
  var bootAccount = resolveAccount();
13100
13284
  var bootAccountConfig = bootAccount?.config;
13101
13285
  var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
@@ -13112,7 +13296,7 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
13112
13296
  (async () => {
13113
13297
  if (!bootAccount) return;
13114
13298
  try {
13115
- const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-NQK7A2EQ.js");
13299
+ const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-LJ4SMK2D.js");
13116
13300
  const result = await recoverRunningCloudflareTasks(
13117
13301
  bootAccount.accountId,
13118
13302
  configDirForWhatsApp,
@@ -13162,7 +13346,7 @@ if (bootAccountConfig?.whatsapp) {
13162
13346
  }
13163
13347
  init({
13164
13348
  configDir: configDirForWhatsApp,
13165
- platformRoot: resolve22(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
13349
+ platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
13166
13350
  accountConfig: bootAccountConfig,
13167
13351
  onMessage: async (msg) => {
13168
13352
  try {