@rubytech/create-realagent 1.0.825 → 1.0.828

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 (102) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/task-secrets/dist/index.d.ts +40 -0
  3. package/payload/platform/lib/task-secrets/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/task-secrets/dist/index.js +44 -0
  5. package/payload/platform/lib/task-secrets/dist/index.js.map +1 -0
  6. package/payload/platform/lib/task-secrets/src/__tests__/redact-secrets.test.ts +127 -0
  7. package/payload/platform/lib/task-secrets/src/index.ts +77 -0
  8. package/payload/platform/lib/task-secrets/tsconfig.json +9 -0
  9. package/payload/platform/lib/task-secrets/vitest.config.ts +9 -0
  10. package/payload/platform/neo4j/schema.cypher +34 -2
  11. package/payload/platform/package.json +2 -2
  12. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +19 -13
  13. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +2 -2
  14. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +13 -12
  15. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +4 -4
  16. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +2 -2
  17. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +6 -6
  18. package/payload/platform/plugins/admin/skills/unzip-attachment/references/safety.md +1 -1
  19. package/payload/platform/plugins/cloudflare/references/manual-setup.md +3 -3
  20. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +4 -4
  21. package/payload/platform/plugins/docs/references/cloudflare.md +2 -2
  22. package/payload/platform/plugins/docs/references/internals.md +2 -2
  23. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  24. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -1
  25. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +2 -2
  26. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +1 -1
  27. package/payload/platform/plugins/memory/PLUGIN.md +1 -1
  28. package/payload/platform/plugins/memory/mcp/dist/index.js +6 -41
  29. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  30. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +51 -0
  31. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
  32. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +19 -4
  33. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
  34. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +139 -56
  35. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts +2 -0
  37. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts.map +1 -0
  38. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +61 -0
  39. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -0
  40. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +34 -0
  41. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  42. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +241 -0
  43. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  44. package/payload/platform/plugins/memory/references/graph-primitives.md +5 -5
  45. package/payload/platform/plugins/memory/references/schema-base.md +6 -3
  46. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +6 -6
  47. package/payload/platform/plugins/tasks/PLUGIN.md +1 -1
  48. package/payload/platform/plugins/tasks/mcp/dist/index.js +11 -2
  49. package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
  50. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts +19 -2
  51. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts.map +1 -1
  52. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js +17 -1
  53. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js.map +1 -1
  54. package/payload/platform/plugins/whatsapp-import/PLUGIN.md +17 -15
  55. package/payload/platform/plugins/whatsapp-import/bin/ingest.mjs +313 -366
  56. package/payload/platform/plugins/whatsapp-import/bin/whatsapp-ingest.sh +27 -60
  57. package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.d.ts +18 -0
  58. package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.d.ts.map +1 -0
  59. package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.js +31 -0
  60. package/payload/platform/plugins/whatsapp-import/lib/dist/delta-cursor.js.map +1 -0
  61. package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.d.ts +27 -12
  62. package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.d.ts.map +1 -1
  63. package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.js +40 -20
  64. package/payload/platform/plugins/whatsapp-import/lib/dist/derive-keys.js.map +1 -1
  65. package/payload/platform/plugins/whatsapp-import/lib/dist/index.d.ts +7 -4
  66. package/payload/platform/plugins/whatsapp-import/lib/dist/index.d.ts.map +1 -1
  67. package/payload/platform/plugins/whatsapp-import/lib/dist/index.js +9 -6
  68. package/payload/platform/plugins/whatsapp-import/lib/dist/index.js.map +1 -1
  69. package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.d.ts +25 -0
  70. package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.d.ts.map +1 -0
  71. package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.js +48 -0
  72. package/payload/platform/plugins/whatsapp-import/lib/dist/sessionize.js.map +1 -0
  73. package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.d.ts +3 -0
  74. package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.d.ts.map +1 -0
  75. package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.js +47 -0
  76. package/payload/platform/plugins/whatsapp-import/lib/dist/to-classifier-input.js.map +1 -0
  77. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/delta-append.test.ts +163 -0
  78. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/sessionize.test.ts +91 -0
  79. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/to-classifier-input.test.ts +59 -0
  80. package/payload/platform/plugins/whatsapp-import/lib/src/delta-cursor.ts +54 -0
  81. package/payload/platform/plugins/whatsapp-import/lib/src/derive-keys.ts +55 -32
  82. package/payload/platform/plugins/whatsapp-import/lib/src/index.ts +9 -6
  83. package/payload/platform/plugins/whatsapp-import/lib/src/sessionize.ts +81 -0
  84. package/payload/platform/plugins/whatsapp-import/lib/src/to-classifier-input.ts +48 -0
  85. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/SKILL.md +66 -73
  86. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/conversation-archive-shape.md +143 -0
  87. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/export-parse.md +2 -2
  88. package/payload/platform/templates/specialists/agents/database-operator.md +17 -18
  89. package/payload/server/chunk-T2OPNP3L.js +654 -0
  90. package/payload/server/chunk-ZTBTX3IO.js +642 -0
  91. package/payload/server/cloudflare-task-tracker-BAMJY4MH.js +17 -0
  92. package/payload/server/cloudflare-task-tracker-CR6TL4VL.js +19 -0
  93. package/payload/server/public/assets/{admin-DOkUspG1.js → admin-BNwPsMhJ.js} +2 -2
  94. package/payload/server/public/assets/{graph-LLMJa4Ch.js → graph-N_Bw-8oT.js} +1 -1
  95. package/payload/server/public/assets/{page-DoaF3DB0.js → page-BKLGP-th.js} +1 -1
  96. package/payload/server/public/graph.html +2 -2
  97. package/payload/server/public/index.html +2 -2
  98. package/payload/server/server.js +291 -172
  99. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/filter-gate.test.ts +0 -172
  100. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/ingest-idempotence.test.ts +0 -141
  101. package/payload/platform/plugins/whatsapp-import/lib/src/filter.ts +0 -136
  102. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import-enrich/SKILL.md +0 -333
@@ -95,8 +95,9 @@ import {
95
95
  appendCloudflareSteps,
96
96
  completeCloudflareTask,
97
97
  openCloudflareTask,
98
- readTunnelState
99
- } from "./chunk-TDTQEKNP.js";
98
+ readTunnelState,
99
+ resolveUnitGoneVerdict
100
+ } from "./chunk-T2OPNP3L.js";
100
101
  import {
101
102
  GREETING_DIRECTIVE,
102
103
  HAIKU_MODEL,
@@ -627,8 +628,8 @@ var serveStatic = (options = { root: "" }) => {
627
628
  };
628
629
 
629
630
  // server/index.ts
630
- import { readFileSync as readFileSync15, existsSync as existsSync21, watchFile } from "fs";
631
- import { resolve as resolve21, join as join9, basename as basename5 } from "path";
631
+ import { readFileSync as readFileSync16, existsSync as existsSync22, watchFile } from "fs";
632
+ import { resolve as resolve22, join as join10, basename as basename5 } from "path";
632
633
  import { homedir as homedir2 } from "os";
633
634
 
634
635
  // app/lib/agent-slug-pattern.ts
@@ -1272,7 +1273,7 @@ var credsSaveQueue = Promise.resolve();
1272
1273
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
1273
1274
  console.error(`${TAG3} draining credential save queue\u2026`);
1274
1275
  const timer2 = new Promise(
1275
- (resolve22) => setTimeout(() => resolve22("timeout"), timeoutMs)
1276
+ (resolve23) => setTimeout(() => resolve23("timeout"), timeoutMs)
1276
1277
  );
1277
1278
  const result = await Promise.race([
1278
1279
  credsSaveQueue.then(() => "drained"),
@@ -1400,11 +1401,11 @@ async function createWaSocket(opts) {
1400
1401
  return sock;
1401
1402
  }
1402
1403
  async function waitForConnection(sock) {
1403
- return new Promise((resolve22, reject) => {
1404
+ return new Promise((resolve23, reject) => {
1404
1405
  const handler = (update) => {
1405
1406
  if (update.connection === "open") {
1406
1407
  sock.ev.off("connection.update", handler);
1407
- resolve22();
1408
+ resolve23();
1408
1409
  }
1409
1410
  if (update.connection === "close") {
1410
1411
  sock.ev.off("connection.update", handler);
@@ -1518,14 +1519,14 @@ ${inspected}`;
1518
1519
  return inspect2(err, INSPECT_OPTS2);
1519
1520
  }
1520
1521
  function withTimeout(label, promise, timeoutMs) {
1521
- return new Promise((resolve22, reject) => {
1522
+ return new Promise((resolve23, reject) => {
1522
1523
  const timer2 = setTimeout(() => {
1523
1524
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
1524
1525
  }, timeoutMs);
1525
1526
  promise.then(
1526
1527
  (value) => {
1527
1528
  clearTimeout(timer2);
1528
- resolve22(value);
1529
+ resolve23(value);
1529
1530
  },
1530
1531
  (err) => {
1531
1532
  clearTimeout(timer2);
@@ -2060,8 +2061,8 @@ async function persistWhatsAppMessage(input) {
2060
2061
  const { givenName, familyName } = splitName(input.pushName);
2061
2062
  const prev = sessionWriteLocks.get(input.sessionKey);
2062
2063
  let release;
2063
- const mine = new Promise((resolve22) => {
2064
- release = resolve22;
2064
+ const mine = new Promise((resolve23) => {
2065
+ release = resolve23;
2065
2066
  });
2066
2067
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2067
2068
  sessionWriteLocks.set(input.sessionKey, chained);
@@ -3068,11 +3069,11 @@ async function connectWithReconnect(conn) {
3068
3069
  console.error(
3069
3070
  `${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3070
3071
  );
3071
- await new Promise((resolve22) => {
3072
- const timer2 = setTimeout(resolve22, delay);
3072
+ await new Promise((resolve23) => {
3073
+ const timer2 = setTimeout(resolve23, delay);
3073
3074
  conn.abortController.signal.addEventListener("abort", () => {
3074
3075
  clearTimeout(timer2);
3075
- resolve22();
3076
+ resolve23();
3076
3077
  }, { once: true });
3077
3078
  });
3078
3079
  }
@@ -3080,16 +3081,16 @@ async function connectWithReconnect(conn) {
3080
3081
  }
3081
3082
  }
3082
3083
  function waitForDisconnectEvent(conn) {
3083
- return new Promise((resolve22) => {
3084
+ return new Promise((resolve23) => {
3084
3085
  if (!conn.sock) {
3085
- resolve22();
3086
+ resolve23();
3086
3087
  return;
3087
3088
  }
3088
3089
  const sock = conn.sock;
3089
3090
  const handler = (update) => {
3090
3091
  if (update.connection === "close") {
3091
3092
  sock.ev.off("connection.update", handler);
3092
- resolve22();
3093
+ resolve23();
3093
3094
  }
3094
3095
  };
3095
3096
  sock.ev.on("connection.update", handler);
@@ -3350,8 +3351,8 @@ async function handleInboundMessage(conn, msg) {
3350
3351
  const conversationKey = isGroup ? remoteJid : senderPhone;
3351
3352
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
3352
3353
  let resolvePending;
3353
- const sttPending = new Promise((resolve22) => {
3354
- resolvePending = resolve22;
3354
+ const sttPending = new Promise((resolve23) => {
3355
+ resolvePending = resolve23;
3355
3356
  });
3356
3357
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
3357
3358
  try {
@@ -3472,20 +3473,20 @@ async function probeApiKey() {
3472
3473
  return result.status;
3473
3474
  }
3474
3475
  function checkPort(port2, timeoutMs = 500) {
3475
- return new Promise((resolve22) => {
3476
+ return new Promise((resolve23) => {
3476
3477
  const socket = createConnection(port2, "127.0.0.1");
3477
3478
  socket.setTimeout(timeoutMs);
3478
3479
  socket.once("connect", () => {
3479
3480
  socket.destroy();
3480
- resolve22(true);
3481
+ resolve23(true);
3481
3482
  });
3482
3483
  socket.once("error", () => {
3483
3484
  socket.destroy();
3484
- resolve22(false);
3485
+ resolve23(false);
3485
3486
  });
3486
3487
  socket.once("timeout", () => {
3487
3488
  socket.destroy();
3488
- resolve22(false);
3489
+ resolve23(false);
3489
3490
  });
3490
3491
  });
3491
3492
  }
@@ -5686,8 +5687,8 @@ async function startLogin(opts) {
5686
5687
  resetActiveLogin(accountId);
5687
5688
  let resolveQr = null;
5688
5689
  let rejectQr = null;
5689
- const qrPromise = new Promise((resolve22, reject) => {
5690
- resolveQr = resolve22;
5690
+ const qrPromise = new Promise((resolve23, reject) => {
5691
+ resolveQr = resolve23;
5691
5692
  rejectQr = reject;
5692
5693
  });
5693
5694
  const qrTimer = setTimeout(
@@ -8039,6 +8040,17 @@ var agents_default = app16;
8039
8040
  import crypto2 from "crypto";
8040
8041
  import { resolve as resolvePath } from "path";
8041
8042
  import { appendFileSync as appendFileSync4, existsSync as existsSync15 } from "fs";
8043
+
8044
+ // app/lib/synthetic-marker.ts
8045
+ var CLOUDFLARE_MARKER_PREFIX = "Cloudflare setup completed (actionId: ";
8046
+ var COMPONENT_DONE_PREFIX = '{"_componentDone"';
8047
+ var LIFECYCLE_PREFIX = '{"_lifecycle"';
8048
+ function isSyntheticUserMarker(content) {
8049
+ if (typeof content !== "string" || content.length === 0) return false;
8050
+ return content.startsWith(COMPONENT_DONE_PREFIX) || content.startsWith(LIFECYCLE_PREFIX) || content.startsWith(CLOUDFLARE_MARKER_PREFIX);
8051
+ }
8052
+
8053
+ // server/routes/admin/sessions.ts
8042
8054
  function validateAndShapeAttachments(raws, conversationAccountId, conversationId, messageId, streamLogPath) {
8043
8055
  const chips = [];
8044
8056
  let valid = 0;
@@ -8310,6 +8322,7 @@ app17.post("/:id/resume", async (c) => {
8310
8322
  let totalComponents = 0;
8311
8323
  let totalAttachments = 0;
8312
8324
  let totalAttachmentInvalid = 0;
8325
+ let syntheticHidden = 0;
8313
8326
  const rehydrated = messages.map((m) => {
8314
8327
  const components = m.components ?? [];
8315
8328
  const rawAttachments = m.attachments ?? [];
@@ -8318,6 +8331,7 @@ app17.post("/:id/resume", async (c) => {
8318
8331
  totalAttachments += valid2;
8319
8332
  totalAttachmentInvalid += invalid2;
8320
8333
  const cleanedContent = chips.length > 0 ? stripAttachmentMetaSuffix(m.content) : m.content;
8334
+ if (m.role === "user" && isSyntheticUserMarker(cleanedContent)) syntheticHidden += 1;
8321
8335
  return {
8322
8336
  messageId: m.messageId,
8323
8337
  role: m.role,
@@ -8344,7 +8358,7 @@ app17.post("/:id/resume", async (c) => {
8344
8358
  const userMessageCount = rehydrated.filter((m) => m.role !== "assistant").length;
8345
8359
  const reason = bridged ? "post-restart" : "page-refresh";
8346
8360
  try {
8347
- 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}
8361
+ 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}
8348
8362
  `);
8349
8363
  if (totalComponents > 0) {
8350
8364
  appendFileSync4(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
@@ -8357,7 +8371,7 @@ app17.post("/:id/resume", async (c) => {
8357
8371
  } catch {
8358
8372
  }
8359
8373
  const age = formatAge(updatedAt);
8360
- 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} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
8374
+ 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`);
8361
8375
  return c.json({ conversationId, messages: rehydrated });
8362
8376
  });
8363
8377
  app17.post("/:id/label", requireAdminSession, async (c) => {
@@ -8654,6 +8668,11 @@ function addAliasDomain(hostname2) {
8654
8668
  writeFileSync6(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
8655
8669
  }
8656
8670
 
8671
+ // app/lib/cloudflare-setup-types.ts
8672
+ var CLOUDFLARE_SETUP_FORM_SCHEMA = {
8673
+ secretFields: ["password", "session_key", "messageId"]
8674
+ };
8675
+
8657
8676
  // server/routes/admin/cloudflare.ts
8658
8677
  var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
8659
8678
  var DOMAINS_TIMEOUT_MS = 40 * 1e3;
@@ -8875,8 +8894,8 @@ app21.get("/tunnels", requireAdminSession, async (c) => {
8875
8894
  if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
8876
8895
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
8877
8896
  const certPath = resolve14(homedir(), brand.configDir, "cloudflared", "cert.pem");
8878
- const { existsSync: existsSync22 } = await import("fs");
8879
- if (!existsSync22(certPath)) {
8897
+ const { existsSync: existsSync23 } = await import("fs");
8898
+ if (!existsSync23(certPath)) {
8880
8899
  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.`);
8881
8900
  }
8882
8901
  const result = await runFormSpawn({
@@ -9012,19 +9031,20 @@ app21.post("/setup", requireAdminSession, async (c) => {
9012
9031
  if (await isActionActive("cloudflare-setup")) {
9013
9032
  return err("request", "Another Cloudflare setup is already running. Wait for it to finish before starting a new one.");
9014
9033
  }
9034
+ const taskInputs = {};
9035
+ for (const [key, value] of Object.entries(body)) {
9036
+ if (value !== void 0 && value !== null && value !== "") {
9037
+ taskInputs[key] = value;
9038
+ }
9039
+ }
9015
9040
  let cloudflareTask;
9016
9041
  try {
9017
9042
  cloudflareTask = await openCloudflareTask({
9018
9043
  accountId,
9019
9044
  conversationKey: sessionKey,
9020
- inputsProvided: ["adminLabel", "adminDomain", publicFqdn ? "publicLabel" : null, apex ? "apex" : null, "password"].filter((s) => typeof s === "string"),
9021
- inputs: {
9022
- adminLabel: body.adminLabel,
9023
- adminDomain: body.adminDomain,
9024
- publicLabel: body.publicLabel,
9025
- publicDomain: body.publicDomain,
9026
- apex: body.apex
9027
- },
9045
+ inputsProvided: Object.keys(taskInputs),
9046
+ inputs: taskInputs,
9047
+ inputSchema: CLOUDFLARE_SETUP_FORM_SCHEMA,
9028
9048
  messageId: typeof body.messageId === "string" && body.messageId.length > 0 ? body.messageId : void 0
9029
9049
  });
9030
9050
  log(`phase=task-opened taskId=${cloudflareTask.taskId}`);
@@ -9055,38 +9075,63 @@ app21.post("/setup", requireAdminSession, async (c) => {
9055
9075
  } catch (e) {
9056
9076
  logErr(`phase=task-steps-append-failed reason="${e instanceof Error ? e.message : String(e)}"`);
9057
9077
  }
9058
- if (!status || status.execMainStatus !== 0) {
9059
- logErr(`phase=post-exit-skipped reason=${status ? `exit=${status.execMainStatus}` : "unit-gone"} id=${actionId}`);
9078
+ let unitGoneWithDiskProof = false;
9079
+ if (status === null) {
9080
+ const verdict = resolveUnitGoneVerdict({
9081
+ tunnelState: readTunnelState(brand.configDir),
9082
+ expected: { tunnelName: body.tunnelName, tunnelId: body.tunnelId }
9083
+ });
9084
+ const resolution = verdict.kind === "close-completed" ? "close-completed" : "close-failed-diagnostic";
9085
+ log(`phase=post-exit-disk-check tunnel-state-found=${verdict.tunnelStateFound} identity-match=${verdict.identityMatch} resolution=${resolution}`);
9086
+ if (verdict.kind === "close-failed") {
9087
+ try {
9088
+ await completeCloudflareTask({
9089
+ taskId: cloudflareTask.taskId,
9090
+ taskElementId: cloudflareTask.taskElementId,
9091
+ accountId,
9092
+ conversationKey: sessionKey,
9093
+ status: "failed",
9094
+ errorMessage: CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile
9095
+ });
9096
+ } catch (e) {
9097
+ logErr(`phase=task-close-failed status=failed reason="${e instanceof Error ? e.message : String(e)}"`);
9098
+ }
9099
+ return;
9100
+ }
9101
+ unitGoneWithDiskProof = true;
9102
+ } else if (status.execMainStatus !== 0) {
9103
+ logErr(`phase=post-exit-skipped reason=exit=${status.execMainStatus} id=${actionId}`);
9060
9104
  try {
9061
- const diagnostic = status ? `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}` : CLOUDFLARE_TASK_DIAGNOSTICS.endpointDiedPreReconcile;
9062
9105
  await completeCloudflareTask({
9063
9106
  taskId: cloudflareTask.taskId,
9064
9107
  taskElementId: cloudflareTask.taskElementId,
9065
9108
  accountId,
9066
9109
  conversationKey: sessionKey,
9067
9110
  status: "failed",
9068
- errorMessage: diagnostic
9111
+ errorMessage: `${CLOUDFLARE_TASK_DIAGNOSTICS.scriptExitedNonzero} exit=${status.execMainStatus}`
9069
9112
  });
9070
9113
  } catch (e) {
9071
9114
  logErr(`phase=task-close-failed status=failed reason="${e instanceof Error ? e.message : String(e)}"`);
9072
9115
  }
9073
9116
  return;
9074
9117
  }
9075
- const candidates = [publicFqdn, apex].filter((h) => typeof h === "string" && h.length > 0);
9076
- for (const host of candidates) {
9077
- if (host === adminFqdn) {
9078
- log(`phase=alias-domain-write host=${host} result=skipped-admin`);
9079
- continue;
9080
- }
9081
- if (host.startsWith("public.")) {
9082
- log(`phase=alias-domain-write host=${host} result=skipped-public-prefix`);
9083
- continue;
9084
- }
9085
- try {
9086
- addAliasDomain(host);
9087
- log(`phase=alias-domain-write host=${host} result=written`);
9088
- } catch (e) {
9089
- logErr(`phase=alias-domain-write host=${host} result=error reason="${e instanceof Error ? e.message : String(e)}"`);
9118
+ if (!unitGoneWithDiskProof) {
9119
+ const candidates = [publicFqdn, apex].filter((h) => typeof h === "string" && h.length > 0);
9120
+ for (const host of candidates) {
9121
+ if (host === adminFqdn) {
9122
+ log(`phase=alias-domain-write host=${host} result=skipped-admin`);
9123
+ continue;
9124
+ }
9125
+ if (host.startsWith("public.")) {
9126
+ log(`phase=alias-domain-write host=${host} result=skipped-public-prefix`);
9127
+ continue;
9128
+ }
9129
+ try {
9130
+ addAliasDomain(host);
9131
+ log(`phase=alias-domain-write host=${host} result=written`);
9132
+ } catch (e) {
9133
+ logErr(`phase=alias-domain-write host=${host} result=error reason="${e instanceof Error ? e.message : String(e)}"`);
9134
+ }
9090
9135
  }
9091
9136
  }
9092
9137
  try {
@@ -10270,6 +10315,11 @@ var GRAPH_LABEL_COLOURS = {
10270
10315
  AccessGrant: "#66381F",
10271
10316
  // Knowledge — moss family (organic)
10272
10317
  KnowledgeDocument: "#6E8A5A",
10318
+ // Task 891 — chunked WhatsApp/messaging archive parent. Sits in the
10319
+ // knowledge moss family because it's structurally a document parent
10320
+ // (HAS_SECTION → :Section:Conversation chunks); the conversational
10321
+ // plum family is reserved for the live Conversation/Message labels.
10322
+ ConversationArchive: "#82A06A",
10273
10323
  Section: "#8AA876",
10274
10324
  Chunk: "#A6C194",
10275
10325
  DigitalDocument: "#5A7548",
@@ -11736,37 +11786,106 @@ app33.get("/", requireAdminSession, async (c) => {
11736
11786
  });
11737
11787
  var sidebar_artefact_content_default = app33;
11738
11788
 
11739
- // server/routes/admin/index.ts
11789
+ // server/routes/admin/health.ts
11790
+ import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
11791
+ import { resolve as resolve20, join as join9 } from "path";
11792
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
11793
+ var brandHostname = "maxy";
11794
+ var brandJsonPath = join9(PLATFORM_ROOT7, "config", "brand.json");
11795
+ if (existsSync20(brandJsonPath)) {
11796
+ try {
11797
+ const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
11798
+ if (brand.hostname) brandHostname = brand.hostname;
11799
+ } catch {
11800
+ }
11801
+ }
11802
+ var VERSION_FILE = resolve20(PLATFORM_ROOT7, `config/.${brandHostname}-version`);
11803
+ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
11804
+ var PROBE_TIMEOUT_MS = 1e3;
11805
+ function readVersion() {
11806
+ if (!existsSync20(VERSION_FILE)) return "unknown";
11807
+ return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
11808
+ }
11809
+ async function probeConversationDb() {
11810
+ let session;
11811
+ try {
11812
+ session = getSession();
11813
+ } catch (err) {
11814
+ return { state: "error", reason: err instanceof Error ? err.message : String(err) };
11815
+ }
11816
+ let timer2;
11817
+ try {
11818
+ const probe = session.run("RETURN 1");
11819
+ const timeout = new Promise((_, reject) => {
11820
+ timer2 = setTimeout(() => reject(new Error("timeout")), PROBE_TIMEOUT_MS);
11821
+ });
11822
+ await Promise.race([probe, timeout]);
11823
+ return { state: "ok" };
11824
+ } catch (err) {
11825
+ return { state: "error", reason: err instanceof Error ? err.message : String(err) };
11826
+ } finally {
11827
+ if (timer2) clearTimeout(timer2);
11828
+ session.close().catch(() => {
11829
+ });
11830
+ }
11831
+ }
11740
11832
  var app34 = new Hono();
11741
- app34.route("/session", session_default2);
11742
- app34.route("/chat", chat_default2);
11743
- app34.route("/compact", compact_default);
11744
- app34.route("/logs", logs_default);
11745
- app34.route("/claude-info", claude_info_default);
11746
- app34.route("/attachment", attachment_default);
11747
- app34.route("/agents", agents_default);
11748
- app34.route("/sessions", sessions_default);
11749
- app34.route("/browser", browser_default);
11750
- app34.route("/device-browser", device_browser_default);
11751
- app34.route("/events", events_default);
11752
- app34.route("/cloudflare", cloudflare_default);
11753
- app34.route("/files", files_default);
11754
- app34.route("/graph-search", graph_search_default);
11755
- app34.route("/graph-subgraph", graph_subgraph_default);
11756
- app34.route("/graph-delete", graph_delete_default);
11757
- app34.route("/graph-restore", graph_restore_default);
11758
- app34.route("/graph-labels-in-graph", graph_labels_in_graph_default);
11759
- app34.route("/graph-default-view", graph_default_view_default);
11760
- app34.route("/file-attach", file_attach_default);
11761
- app34.route("/adherence", adherence_default);
11762
- app34.route("/sidebar-artefacts", sidebar_artefacts_default);
11763
- app34.route("/sidebar-artefact-save", sidebar_artefact_save_default);
11764
- app34.route("/sidebar-artefact-content", sidebar_artefact_content_default);
11765
- var admin_default = app34;
11833
+ app34.get("/", async (c) => {
11834
+ const version = readVersion();
11835
+ const probe = await probeConversationDb();
11836
+ const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
11837
+ if (probe.state === "error") {
11838
+ const reason = (probe.reason ?? "").replace(/\s+/g, " ").trim() || "unknown";
11839
+ console.log(
11840
+ `[admin/health-brand] processStartedAt=${PROCESS_STARTED_AT} uptimeMs=${uptimeMs} version=${version} conversationDb=error errorReason=${reason}`
11841
+ );
11842
+ } else {
11843
+ console.log(
11844
+ `[admin/health-brand] processStartedAt=${PROCESS_STARTED_AT} uptimeMs=${uptimeMs} version=${version} conversationDb=ok`
11845
+ );
11846
+ }
11847
+ return c.json({
11848
+ ok: true,
11849
+ processStartedAt: PROCESS_STARTED_AT,
11850
+ version,
11851
+ conversationDb: probe.state,
11852
+ uptimeMs
11853
+ });
11854
+ });
11855
+ var health_default2 = app34;
11856
+
11857
+ // server/routes/admin/index.ts
11858
+ var app35 = new Hono();
11859
+ app35.route("/session", session_default2);
11860
+ app35.route("/chat", chat_default2);
11861
+ app35.route("/compact", compact_default);
11862
+ app35.route("/logs", logs_default);
11863
+ app35.route("/claude-info", claude_info_default);
11864
+ app35.route("/attachment", attachment_default);
11865
+ app35.route("/agents", agents_default);
11866
+ app35.route("/sessions", sessions_default);
11867
+ app35.route("/browser", browser_default);
11868
+ app35.route("/device-browser", device_browser_default);
11869
+ app35.route("/events", events_default);
11870
+ app35.route("/cloudflare", cloudflare_default);
11871
+ app35.route("/files", files_default);
11872
+ app35.route("/graph-search", graph_search_default);
11873
+ app35.route("/graph-subgraph", graph_subgraph_default);
11874
+ app35.route("/graph-delete", graph_delete_default);
11875
+ app35.route("/graph-restore", graph_restore_default);
11876
+ app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
11877
+ app35.route("/graph-default-view", graph_default_view_default);
11878
+ app35.route("/file-attach", file_attach_default);
11879
+ app35.route("/adherence", adherence_default);
11880
+ app35.route("/sidebar-artefacts", sidebar_artefacts_default);
11881
+ app35.route("/sidebar-artefact-save", sidebar_artefact_save_default);
11882
+ app35.route("/sidebar-artefact-content", sidebar_artefact_content_default);
11883
+ app35.route("/health-brand", health_default2);
11884
+ var admin_default = app35;
11766
11885
 
11767
11886
  // server/routes/sites.ts
11768
- import { existsSync as existsSync20, readFileSync as readFileSync14, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
11769
- import { resolve as resolve20 } from "path";
11887
+ import { existsSync as existsSync21, readFileSync as readFileSync15, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
11888
+ import { resolve as resolve21 } from "path";
11770
11889
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
11771
11890
  var MIME = {
11772
11891
  ".html": "text/html; charset=utf-8",
@@ -11797,8 +11916,8 @@ function getExt(p) {
11797
11916
  if (idx < p.lastIndexOf("/")) return "";
11798
11917
  return p.slice(idx).toLowerCase();
11799
11918
  }
11800
- var app35 = new Hono();
11801
- app35.get("/:rel{.*}", (c) => {
11919
+ var app36 = new Hono();
11920
+ app36.get("/:rel{.*}", (c) => {
11802
11921
  const reqPath = c.req.path;
11803
11922
  const rawRel = c.req.param("rel") ?? "";
11804
11923
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -11824,28 +11943,28 @@ app35.get("/:rel{.*}", (c) => {
11824
11943
  }
11825
11944
  segments.push(seg);
11826
11945
  }
11827
- const rootDir = resolve20(account.accountDir, "sites");
11828
- let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
11946
+ const rootDir = resolve21(account.accountDir, "sites");
11947
+ let filePath = segments.length === 0 ? rootDir : resolve21(rootDir, ...segments);
11829
11948
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
11830
11949
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
11831
11950
  return c.text("Forbidden", 403);
11832
11951
  }
11833
11952
  let stat7;
11834
11953
  try {
11835
- stat7 = existsSync20(filePath) ? statSync5(filePath) : null;
11954
+ stat7 = existsSync21(filePath) ? statSync5(filePath) : null;
11836
11955
  } catch {
11837
11956
  stat7 = null;
11838
11957
  }
11839
11958
  if (stat7?.isDirectory()) {
11840
- filePath = resolve20(filePath, "index.html");
11959
+ filePath = resolve21(filePath, "index.html");
11841
11960
  } else if (stat7 === null && isDirRequest) {
11842
- filePath = resolve20(filePath, "index.html");
11961
+ filePath = resolve21(filePath, "index.html");
11843
11962
  }
11844
11963
  if (!filePath.startsWith(rootDir + "/")) {
11845
11964
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
11846
11965
  return c.text("Forbidden", 403);
11847
11966
  }
11848
- if (!existsSync20(filePath)) {
11967
+ if (!existsSync21(filePath)) {
11849
11968
  console.error(`[sites] not-found path=${reqPath} status=404`);
11850
11969
  return c.text("Not found", 404);
11851
11970
  }
@@ -11864,7 +11983,7 @@ app35.get("/:rel{.*}", (c) => {
11864
11983
  }
11865
11984
  let body;
11866
11985
  try {
11867
- body = readFileSync14(realPath);
11986
+ body = readFileSync15(realPath);
11868
11987
  } catch (err) {
11869
11988
  const code = err?.code;
11870
11989
  if (code === "EISDIR") {
@@ -11896,7 +12015,7 @@ app35.get("/:rel{.*}", (c) => {
11896
12015
  "X-Content-Type-Options": "nosniff"
11897
12016
  });
11898
12017
  });
11899
- var sites_default = app35;
12018
+ var sites_default = app36;
11900
12019
 
11901
12020
  // app/lib/graph-health.ts
11902
12021
  var HOUR_MS = 60 * 60 * 1e3;
@@ -11995,15 +12114,15 @@ function clientFrom(c) {
11995
12114
  c.req.header("x-forwarded-for")
11996
12115
  );
11997
12116
  }
11998
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
11999
- var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join9(PLATFORM_ROOT7, "config", "brand.json") : "";
12117
+ var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
12118
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join10(PLATFORM_ROOT8, "config", "brand.json") : "";
12000
12119
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12001
- if (BRAND_JSON_PATH && !existsSync21(BRAND_JSON_PATH)) {
12120
+ if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
12002
12121
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
12003
12122
  }
12004
- if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
12123
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
12005
12124
  try {
12006
- const parsed = JSON.parse(readFileSync15(BRAND_JSON_PATH, "utf-8"));
12125
+ const parsed = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
12007
12126
  BRAND = { ...BRAND, ...parsed };
12008
12127
  } catch (err) {
12009
12128
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -12022,11 +12141,11 @@ var brandLoginOpts = {
12022
12141
  bodyFont: BRAND.defaultFonts?.body,
12023
12142
  logoContainsName: !!BRAND.logoContainsName
12024
12143
  };
12025
- var ALIAS_DOMAINS_PATH2 = join9(homedir2(), BRAND.configDir, "alias-domains.json");
12144
+ var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.json");
12026
12145
  function loadAliasDomains() {
12027
12146
  try {
12028
- if (!existsSync21(ALIAS_DOMAINS_PATH2)) return null;
12029
- const parsed = JSON.parse(readFileSync15(ALIAS_DOMAINS_PATH2, "utf-8"));
12147
+ if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
12148
+ const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH2, "utf-8"));
12030
12149
  if (!Array.isArray(parsed)) {
12031
12150
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
12032
12151
  return null;
@@ -12050,9 +12169,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
12050
12169
  function isPublicHost(host) {
12051
12170
  return host.startsWith("public.") || aliasDomains.has(host);
12052
12171
  }
12053
- var app36 = new Hono();
12054
- app36.use("*", clientIpMiddleware);
12055
- app36.use("*", async (c, next) => {
12172
+ var app37 = new Hono();
12173
+ app37.use("*", clientIpMiddleware);
12174
+ app37.use("*", async (c, next) => {
12056
12175
  await next();
12057
12176
  c.header("X-Content-Type-Options", "nosniff");
12058
12177
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -12076,7 +12195,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
12076
12195
  "/sites/"
12077
12196
  ];
12078
12197
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
12079
- app36.use("*", async (c, next) => {
12198
+ app37.use("*", async (c, next) => {
12080
12199
  const host = (c.req.header("host") ?? "").split(":")[0];
12081
12200
  if (!isPublicHost(host)) {
12082
12201
  await next();
@@ -12116,7 +12235,7 @@ function resolveRemoteAuthOpts() {
12116
12235
  return brandLoginOpts;
12117
12236
  }
12118
12237
  var MAX_LOGIN_BODY = 8 * 1024;
12119
- app36.post("/__remote-auth/login", async (c) => {
12238
+ app37.post("/__remote-auth/login", async (c) => {
12120
12239
  const client = clientFrom(c);
12121
12240
  const clientIp = client.ip || "unknown";
12122
12241
  if (!requestIsTlsTerminated(c)) {
@@ -12160,7 +12279,7 @@ app36.post("/__remote-auth/login", async (c) => {
12160
12279
  }
12161
12280
  });
12162
12281
  });
12163
- app36.get("/__remote-auth/logout", (c) => {
12282
+ app37.get("/__remote-auth/logout", (c) => {
12164
12283
  return new Response(null, {
12165
12284
  status: 302,
12166
12285
  headers: {
@@ -12170,7 +12289,7 @@ app36.get("/__remote-auth/logout", (c) => {
12170
12289
  }
12171
12290
  });
12172
12291
  });
12173
- app36.post("/__remote-auth/change-password", async (c) => {
12292
+ app37.post("/__remote-auth/change-password", async (c) => {
12174
12293
  const client = clientFrom(c);
12175
12294
  const clientIp = client.ip || "unknown";
12176
12295
  const rateLimited = checkRateLimit(client);
@@ -12220,13 +12339,13 @@ app36.post("/__remote-auth/change-password", async (c) => {
12220
12339
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
12221
12340
  }
12222
12341
  });
12223
- app36.get("/__remote-auth/setup", (c) => {
12342
+ app37.get("/__remote-auth/setup", (c) => {
12224
12343
  if (isRemoteAuthConfigured()) {
12225
12344
  return c.redirect("/");
12226
12345
  }
12227
12346
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
12228
12347
  });
12229
- app36.post("/__remote-auth/set-initial-password", async (c) => {
12348
+ app37.post("/__remote-auth/set-initial-password", async (c) => {
12230
12349
  if (isRemoteAuthConfigured()) {
12231
12350
  return c.redirect("/");
12232
12351
  }
@@ -12262,10 +12381,10 @@ app36.post("/__remote-auth/set-initial-password", async (c) => {
12262
12381
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
12263
12382
  }
12264
12383
  });
12265
- app36.get("/api/remote-auth/status", (c) => {
12384
+ app37.get("/api/remote-auth/status", (c) => {
12266
12385
  return c.json({ configured: isRemoteAuthConfigured() });
12267
12386
  });
12268
- app36.post("/api/remote-auth/set-password", async (c) => {
12387
+ app37.post("/api/remote-auth/set-password", async (c) => {
12269
12388
  let body;
12270
12389
  try {
12271
12390
  body = await c.req.json();
@@ -12295,9 +12414,9 @@ app36.post("/api/remote-auth/set-password", async (c) => {
12295
12414
  return c.json({ error: "Failed to save password" }, 500);
12296
12415
  }
12297
12416
  });
12298
- app36.route("/api/_client-error", client_error_default);
12417
+ app37.route("/api/_client-error", client_error_default);
12299
12418
  console.log("[client-error-route] mounted");
12300
- app36.use("*", async (c, next) => {
12419
+ app37.use("*", async (c, next) => {
12301
12420
  const host = (c.req.header("host") ?? "").split(":")[0];
12302
12421
  const path2 = c.req.path;
12303
12422
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -12330,15 +12449,15 @@ app36.use("*", async (c, next) => {
12330
12449
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
12331
12450
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
12332
12451
  });
12333
- app36.route("/api/health", health_default);
12334
- app36.route("/api/session", session_default);
12335
- app36.route("/api/chat", chat_default);
12336
- app36.route("/api/group", group_default);
12337
- app36.route("/api/access", access_default);
12338
- app36.route("/api/telegram", telegram_default);
12339
- app36.route("/api/whatsapp", whatsapp_default);
12340
- app36.route("/api/onboarding", onboarding_default);
12341
- app36.route("/api/admin", admin_default);
12452
+ app37.route("/api/health", health_default);
12453
+ app37.route("/api/session", session_default);
12454
+ app37.route("/api/chat", chat_default);
12455
+ app37.route("/api/group", group_default);
12456
+ app37.route("/api/access", access_default);
12457
+ app37.route("/api/telegram", telegram_default);
12458
+ app37.route("/api/whatsapp", whatsapp_default);
12459
+ app37.route("/api/onboarding", onboarding_default);
12460
+ app37.route("/api/admin", admin_default);
12342
12461
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
12343
12462
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12344
12463
  var IMAGE_MIME = {
@@ -12350,7 +12469,7 @@ var IMAGE_MIME = {
12350
12469
  ".svg": "image/svg+xml",
12351
12470
  ".ico": "image/x-icon"
12352
12471
  };
12353
- app36.get("/agent-assets/:slug/:filename", (c) => {
12472
+ app37.get("/agent-assets/:slug/:filename", (c) => {
12354
12473
  const slug = c.req.param("slug");
12355
12474
  const filename = c.req.param("filename");
12356
12475
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -12366,26 +12485,26 @@ app36.get("/agent-assets/:slug/:filename", (c) => {
12366
12485
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
12367
12486
  return c.text("Not found", 404);
12368
12487
  }
12369
- const filePath = resolve21(account.accountDir, "agents", slug, "assets", filename);
12370
- const expectedDir = resolve21(account.accountDir, "agents", slug, "assets");
12488
+ const filePath = resolve22(account.accountDir, "agents", slug, "assets", filename);
12489
+ const expectedDir = resolve22(account.accountDir, "agents", slug, "assets");
12371
12490
  if (!filePath.startsWith(expectedDir + "/")) {
12372
12491
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
12373
12492
  return c.text("Forbidden", 403);
12374
12493
  }
12375
- if (!existsSync21(filePath)) {
12494
+ if (!existsSync22(filePath)) {
12376
12495
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
12377
12496
  return c.text("Not found", 404);
12378
12497
  }
12379
12498
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12380
12499
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12381
12500
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
12382
- const body = readFileSync15(filePath);
12501
+ const body = readFileSync16(filePath);
12383
12502
  return c.body(body, 200, {
12384
12503
  "Content-Type": contentType,
12385
12504
  "Cache-Control": "public, max-age=3600"
12386
12505
  });
12387
12506
  });
12388
- app36.get("/generated/:filename", (c) => {
12507
+ app37.get("/generated/:filename", (c) => {
12389
12508
  const filename = c.req.param("filename");
12390
12509
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
12391
12510
  console.error(`[generated] serve file=${filename} status=403`);
@@ -12396,32 +12515,32 @@ app36.get("/generated/:filename", (c) => {
12396
12515
  console.error(`[generated] serve file=${filename} status=404`);
12397
12516
  return c.text("Not found", 404);
12398
12517
  }
12399
- const filePath = resolve21(account.accountDir, "generated", filename);
12400
- const expectedDir = resolve21(account.accountDir, "generated");
12518
+ const filePath = resolve22(account.accountDir, "generated", filename);
12519
+ const expectedDir = resolve22(account.accountDir, "generated");
12401
12520
  if (!filePath.startsWith(expectedDir + "/")) {
12402
12521
  console.error(`[generated] serve file=${filename} status=403`);
12403
12522
  return c.text("Forbidden", 403);
12404
12523
  }
12405
- if (!existsSync21(filePath)) {
12524
+ if (!existsSync22(filePath)) {
12406
12525
  console.error(`[generated] serve file=${filename} status=404`);
12407
12526
  return c.text("Not found", 404);
12408
12527
  }
12409
12528
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12410
12529
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12411
12530
  console.log(`[generated] serve file=${filename} status=200`);
12412
- const body = readFileSync15(filePath);
12531
+ const body = readFileSync16(filePath);
12413
12532
  return c.body(body, 200, {
12414
12533
  "Content-Type": contentType,
12415
12534
  "Cache-Control": "public, max-age=86400"
12416
12535
  });
12417
12536
  });
12418
- app36.route("/sites", sites_default);
12537
+ app37.route("/sites", sites_default);
12419
12538
  var htmlCache = /* @__PURE__ */ new Map();
12420
12539
  var brandLogoPath = "/brand/maxy-monochrome.png";
12421
12540
  var brandIconPath = "/brand/maxy-monochrome.png";
12422
- if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
12541
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
12423
12542
  try {
12424
- const fullBrand = JSON.parse(readFileSync15(BRAND_JSON_PATH, "utf-8"));
12543
+ const fullBrand = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
12425
12544
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
12426
12545
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
12427
12546
  } catch {
@@ -12437,10 +12556,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
12437
12556
  })}</script>`;
12438
12557
  function readInstalledVersion() {
12439
12558
  try {
12440
- if (!PLATFORM_ROOT7) return "unknown";
12441
- const versionFile = join9(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
12442
- if (!existsSync21(versionFile)) return "unknown";
12443
- const content = readFileSync15(versionFile, "utf-8").trim();
12559
+ if (!PLATFORM_ROOT8) return "unknown";
12560
+ const versionFile = join10(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
12561
+ if (!existsSync22(versionFile)) return "unknown";
12562
+ const content = readFileSync16(versionFile, "utf-8").trim();
12444
12563
  return content || "unknown";
12445
12564
  } catch {
12446
12565
  return "unknown";
@@ -12481,7 +12600,7 @@ var clientErrorReporterScript = `<script>
12481
12600
  function cachedHtml(file) {
12482
12601
  let html = htmlCache.get(file);
12483
12602
  if (!html) {
12484
- html = readFileSync15(resolve21(process.cwd(), "public", file), "utf-8");
12603
+ html = readFileSync16(resolve22(process.cwd(), "public", file), "utf-8");
12485
12604
  const productNameEsc = escapeHtml(BRAND.productName);
12486
12605
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
12487
12606
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -12497,26 +12616,26 @@ ${clientErrorReporterScript}
12497
12616
  }
12498
12617
  var brandedHtmlCache = /* @__PURE__ */ new Map();
12499
12618
  function loadBrandingCache(agentSlug) {
12500
- const configDir2 = join9(homedir2(), BRAND.configDir);
12619
+ const configDir2 = join10(homedir2(), BRAND.configDir);
12501
12620
  try {
12502
- const accountJsonPath = join9(configDir2, "account.json");
12503
- if (!existsSync21(accountJsonPath)) return null;
12504
- const account = JSON.parse(readFileSync15(accountJsonPath, "utf-8"));
12621
+ const accountJsonPath = join10(configDir2, "account.json");
12622
+ if (!existsSync22(accountJsonPath)) return null;
12623
+ const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12505
12624
  const accountId = account.accountId;
12506
12625
  if (!accountId) return null;
12507
- const cachePath = join9(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12508
- if (!existsSync21(cachePath)) return null;
12509
- return JSON.parse(readFileSync15(cachePath, "utf-8"));
12626
+ const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12627
+ if (!existsSync22(cachePath)) return null;
12628
+ return JSON.parse(readFileSync16(cachePath, "utf-8"));
12510
12629
  } catch {
12511
12630
  return null;
12512
12631
  }
12513
12632
  }
12514
12633
  function resolveDefaultSlug() {
12515
12634
  try {
12516
- const configDir2 = join9(homedir2(), BRAND.configDir);
12517
- const accountJsonPath = join9(configDir2, "account.json");
12518
- if (!existsSync21(accountJsonPath)) return null;
12519
- const account = JSON.parse(readFileSync15(accountJsonPath, "utf-8"));
12635
+ const configDir2 = join10(homedir2(), BRAND.configDir);
12636
+ const accountJsonPath = join10(configDir2, "account.json");
12637
+ if (!existsSync22(accountJsonPath)) return null;
12638
+ const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12520
12639
  return account.defaultAgent || null;
12521
12640
  } catch {
12522
12641
  return null;
@@ -12552,7 +12671,7 @@ function brandedPublicHtml(agentSlug) {
12552
12671
  function escapeHtml(s) {
12553
12672
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12554
12673
  }
12555
- app36.get("/", (c) => {
12674
+ app37.get("/", (c) => {
12556
12675
  const host = (c.req.header("host") ?? "").split(":")[0];
12557
12676
  if (isPublicHost(host)) {
12558
12677
  const defaultSlug = resolveDefaultSlug();
@@ -12560,12 +12679,12 @@ app36.get("/", (c) => {
12560
12679
  }
12561
12680
  return c.html(cachedHtml("index.html"));
12562
12681
  });
12563
- app36.get("/public", (c) => {
12682
+ app37.get("/public", (c) => {
12564
12683
  const host = (c.req.header("host") ?? "").split(":")[0];
12565
12684
  if (isPublicHost(host)) return c.text("Not found", 404);
12566
12685
  return c.html(cachedHtml("public.html"));
12567
12686
  });
12568
- app36.get("/chat", (c) => {
12687
+ app37.get("/chat", (c) => {
12569
12688
  const host = (c.req.header("host") ?? "").split(":")[0];
12570
12689
  if (isPublicHost(host)) return c.text("Not found", 404);
12571
12690
  return c.html(cachedHtml("public.html"));
@@ -12584,12 +12703,12 @@ async function logViewerFetch(c, next) {
12584
12703
  duration_ms: Date.now() - start
12585
12704
  });
12586
12705
  }
12587
- app36.use("/vnc-viewer.html", logViewerFetch);
12588
- app36.use("/vnc-popout.html", logViewerFetch);
12589
- app36.get("/vnc-popout.html", (c) => {
12706
+ app37.use("/vnc-viewer.html", logViewerFetch);
12707
+ app37.use("/vnc-popout.html", logViewerFetch);
12708
+ app37.get("/vnc-popout.html", (c) => {
12590
12709
  let html = htmlCache.get("vnc-popout.html");
12591
12710
  if (!html) {
12592
- html = readFileSync15(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12711
+ html = readFileSync16(resolve22(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12593
12712
  const name = escapeHtml(BRAND.productName);
12594
12713
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
12595
12714
  html = html.replace("</head>", ` ${brandScript}
@@ -12599,7 +12718,7 @@ app36.get("/vnc-popout.html", (c) => {
12599
12718
  }
12600
12719
  return c.html(html);
12601
12720
  });
12602
- app36.post("/api/vnc/client-event", async (c) => {
12721
+ app37.post("/api/vnc/client-event", async (c) => {
12603
12722
  let body;
12604
12723
  try {
12605
12724
  body = await c.req.json();
@@ -12620,20 +12739,20 @@ app36.post("/api/vnc/client-event", async (c) => {
12620
12739
  });
12621
12740
  return c.json({ ok: true });
12622
12741
  });
12623
- app36.get("/g/:slug", (c) => {
12742
+ app37.get("/g/:slug", (c) => {
12624
12743
  return c.html(brandedPublicHtml());
12625
12744
  });
12626
- app36.get("/graph", (c) => {
12745
+ app37.get("/graph", (c) => {
12627
12746
  const host = (c.req.header("host") ?? "").split(":")[0];
12628
12747
  if (isPublicHost(host)) return c.text("Not found", 404);
12629
12748
  return c.html(cachedHtml("graph.html"));
12630
12749
  });
12631
- app36.get("/data", (c) => {
12750
+ app37.get("/data", (c) => {
12632
12751
  const host = (c.req.header("host") ?? "").split(":")[0];
12633
12752
  if (isPublicHost(host)) return c.text("Not found", 404);
12634
12753
  return c.html(cachedHtml("data.html"));
12635
12754
  });
12636
- app36.get("/:slug", async (c, next) => {
12755
+ app37.get("/:slug", async (c, next) => {
12637
12756
  const slug = c.req.param("slug");
12638
12757
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
12639
12758
  const branding = loadBrandingCache(slug);
@@ -12642,10 +12761,10 @@ app36.get("/:slug", async (c, next) => {
12642
12761
  }
12643
12762
  await next();
12644
12763
  });
12645
- app36.use("/*", serveStatic({ root: "./public" }));
12764
+ app37.use("/*", serveStatic({ root: "./public" }));
12646
12765
  var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
12647
12766
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
12648
- var httpServer = serve({ fetch: app36.fetch, port, hostname });
12767
+ var httpServer = serve({ fetch: app37.fetch, port, hostname });
12649
12768
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
12650
12769
  var SUBAPP_MANIFEST = [
12651
12770
  { prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
@@ -12665,7 +12784,7 @@ for (const m of SUBAPP_MANIFEST) {
12665
12784
  }
12666
12785
  try {
12667
12786
  const registered = [];
12668
- for (const r of app36.routes ?? []) {
12787
+ for (const r of app37.routes ?? []) {
12669
12788
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
12670
12789
  if (AGENT_SLUG_PATTERN.test(r.path)) {
12671
12790
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -12679,8 +12798,8 @@ try {
12679
12798
  (async () => {
12680
12799
  try {
12681
12800
  let userId = "";
12682
- if (existsSync21(USERS_FILE)) {
12683
- const users = JSON.parse(readFileSync15(USERS_FILE, "utf-8").trim() || "[]");
12801
+ if (existsSync22(USERS_FILE)) {
12802
+ const users = JSON.parse(readFileSync16(USERS_FILE, "utf-8").trim() || "[]");
12684
12803
  userId = users[0]?.userId ?? "";
12685
12804
  }
12686
12805
  await backfillNullUserIdConversations(userId);
@@ -12713,7 +12832,7 @@ autoDeliverPremiumPlugins(bootEntitlement?.purchasedPlugins ?? void 0);
12713
12832
  (async () => {
12714
12833
  if (!bootAccount) return;
12715
12834
  try {
12716
- const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-3WV7DZKQ.js");
12835
+ const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-CR6TL4VL.js");
12717
12836
  const result = await recoverRunningCloudflareTasks(
12718
12837
  bootAccount.accountId,
12719
12838
  configDirForWhatsApp,
@@ -12763,7 +12882,7 @@ if (bootAccountConfig?.whatsapp) {
12763
12882
  }
12764
12883
  init({
12765
12884
  configDir: configDirForWhatsApp,
12766
- platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join9(__dirname, "..")),
12885
+ platformRoot: resolve22(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
12767
12886
  accountConfig: bootAccountConfig,
12768
12887
  onMessage: async (msg) => {
12769
12888
  try {