@rubytech/create-maxy 1.0.764 → 1.0.766

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 (26) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/docs/references/platform.md +1 -1
  3. package/payload/server/chunk-IO2WQEY4.js +9562 -0
  4. package/payload/server/chunk-TKYZ7AEB.js +3142 -0
  5. package/payload/server/client-pool-CX2MFW75.js +28 -0
  6. package/payload/server/maxy-edge.js +2 -2
  7. package/payload/server/public/assets/{Checkbox-BRLBdX7n.js → Checkbox-D4ru6Rnc.js} +1 -1
  8. package/payload/server/public/assets/admin-RgtF1AAZ.js +352 -0
  9. package/payload/server/public/assets/data-5fPP3RXM.js +1 -0
  10. package/payload/server/public/assets/graph-BLaHRtJ3.js +1 -0
  11. package/payload/server/public/assets/{jsx-runtime-BRkYVd7p.css → jsx-runtime-Rr9ViFRF.css} +1 -1
  12. package/payload/server/public/assets/page-DAKUQ1yb.js +50 -0
  13. package/payload/server/public/assets/{page-v5z5MBB6.js → page-Dw31Y-B8.js} +1 -1
  14. package/payload/server/public/assets/{public-CQ_WMUng.js → public-Xx3SnSxV.js} +1 -1
  15. package/payload/server/public/assets/{share-2-Cc99o2of.js → share-2-D8-hi3T3.js} +1 -1
  16. package/payload/server/public/assets/{useVoiceRecorder-C2CyyNiy.js → useVoiceRecorder-CXxtW1ks.js} +1 -1
  17. package/payload/server/public/data.html +5 -5
  18. package/payload/server/public/graph.html +6 -6
  19. package/payload/server/public/index.html +8 -8
  20. package/payload/server/public/public.html +5 -5
  21. package/payload/server/server.js +440 -163
  22. package/payload/server/public/assets/admin-V6NDkEoR.js +0 -352
  23. package/payload/server/public/assets/data-DVeGdjv2.js +0 -1
  24. package/payload/server/public/assets/graph-BHcUKzXh.js +0 -1
  25. package/payload/server/public/assets/page-DxH_Opxt.js +0 -50
  26. /package/payload/server/public/assets/{jsx-runtime-B4QFltsm.js → jsx-runtime-C96Yp1GB.js} +0 -0
@@ -47,7 +47,7 @@ import {
47
47
  vncLog,
48
48
  waitForExit,
49
49
  writeChromiumWrapper
50
- } from "./chunk-EIQT6QDH.js";
50
+ } from "./chunk-IO2WQEY4.js";
51
51
  import {
52
52
  ACCOUNTS_DIR,
53
53
  GREETING_DIRECTIVE,
@@ -107,7 +107,7 @@ import {
107
107
  validateSession,
108
108
  verifyAndGetConversationUpdatedAt,
109
109
  verifyConversationOwnership
110
- } from "./chunk-S3M2NZMA.js";
110
+ } from "./chunk-TKYZ7AEB.js";
111
111
 
112
112
  // ../lib/graph-trash/dist/index.js
113
113
  var require_dist = __commonJS({
@@ -606,8 +606,8 @@ var serveStatic = (options = { root: "" }) => {
606
606
  };
607
607
 
608
608
  // server/index.ts
609
- import { readFileSync as readFileSync16, existsSync as existsSync19, watchFile } from "fs";
610
- import { resolve as resolve21, join as join10, basename as basename7 } from "path";
609
+ import { readFileSync as readFileSync16, existsSync as existsSync22, watchFile } from "fs";
610
+ import { resolve as resolve23, join as join10, basename as basename7 } from "path";
611
611
  import { homedir as homedir2 } from "os";
612
612
 
613
613
  // app/lib/agent-slug-pattern.ts
@@ -1351,9 +1351,9 @@ function discoverAllSources(configDir2, accountLogDir2) {
1351
1351
  }
1352
1352
  function readNewLines(filepath, prev) {
1353
1353
  if (!existsSync3(filepath)) return null;
1354
- const stat5 = statSync3(filepath);
1355
- const size = stat5.size;
1356
- const inode = stat5.ino;
1354
+ const stat7 = statSync3(filepath);
1355
+ const size = stat7.size;
1356
+ const inode = stat7.ino;
1357
1357
  let startOffset = 0;
1358
1358
  let rotated = false;
1359
1359
  let truncated = false;
@@ -2692,7 +2692,7 @@ var credsSaveQueue = Promise.resolve();
2692
2692
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
2693
2693
  console.error(`${TAG3} draining credential save queue\u2026`);
2694
2694
  const timer2 = new Promise(
2695
- (resolve22) => setTimeout(() => resolve22("timeout"), timeoutMs)
2695
+ (resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
2696
2696
  );
2697
2697
  const result = await Promise.race([
2698
2698
  credsSaveQueue.then(() => "drained"),
@@ -2820,11 +2820,11 @@ async function createWaSocket(opts) {
2820
2820
  return sock;
2821
2821
  }
2822
2822
  async function waitForConnection(sock) {
2823
- return new Promise((resolve22, reject) => {
2823
+ return new Promise((resolve24, reject) => {
2824
2824
  const handler = (update) => {
2825
2825
  if (update.connection === "open") {
2826
2826
  sock.ev.off("connection.update", handler);
2827
- resolve22();
2827
+ resolve24();
2828
2828
  }
2829
2829
  if (update.connection === "close") {
2830
2830
  sock.ev.off("connection.update", handler);
@@ -2938,14 +2938,14 @@ ${inspected}`;
2938
2938
  return inspect2(err, INSPECT_OPTS2);
2939
2939
  }
2940
2940
  function withTimeout(label, promise, timeoutMs) {
2941
- return new Promise((resolve22, reject) => {
2941
+ return new Promise((resolve24, reject) => {
2942
2942
  const timer2 = setTimeout(() => {
2943
2943
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
2944
2944
  }, timeoutMs);
2945
2945
  promise.then(
2946
2946
  (value) => {
2947
2947
  clearTimeout(timer2);
2948
- resolve22(value);
2948
+ resolve24(value);
2949
2949
  },
2950
2950
  (err) => {
2951
2951
  clearTimeout(timer2);
@@ -4159,11 +4159,11 @@ async function connectWithReconnect(conn) {
4159
4159
  console.error(
4160
4160
  `${TAG11} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
4161
4161
  );
4162
- await new Promise((resolve22) => {
4163
- const timer2 = setTimeout(resolve22, delay);
4162
+ await new Promise((resolve24) => {
4163
+ const timer2 = setTimeout(resolve24, delay);
4164
4164
  conn.abortController.signal.addEventListener("abort", () => {
4165
4165
  clearTimeout(timer2);
4166
- resolve22();
4166
+ resolve24();
4167
4167
  }, { once: true });
4168
4168
  });
4169
4169
  }
@@ -4171,16 +4171,16 @@ async function connectWithReconnect(conn) {
4171
4171
  }
4172
4172
  }
4173
4173
  function waitForDisconnectEvent(conn) {
4174
- return new Promise((resolve22) => {
4174
+ return new Promise((resolve24) => {
4175
4175
  if (!conn.sock) {
4176
- resolve22();
4176
+ resolve24();
4177
4177
  return;
4178
4178
  }
4179
4179
  const sock = conn.sock;
4180
4180
  const handler = (update) => {
4181
4181
  if (update.connection === "close") {
4182
4182
  sock.ev.off("connection.update", handler);
4183
- resolve22();
4183
+ resolve24();
4184
4184
  }
4185
4185
  };
4186
4186
  sock.ev.on("connection.update", handler);
@@ -4397,8 +4397,8 @@ async function handleInboundMessage(conn, msg) {
4397
4397
  const conversationKey = isGroup ? remoteJid : senderPhone;
4398
4398
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
4399
4399
  let resolvePending;
4400
- const sttPending = new Promise((resolve22) => {
4401
- resolvePending = resolve22;
4400
+ const sttPending = new Promise((resolve24) => {
4401
+ resolvePending = resolve24;
4402
4402
  });
4403
4403
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
4404
4404
  try {
@@ -4511,20 +4511,20 @@ async function probeApiKey() {
4511
4511
  return result.status;
4512
4512
  }
4513
4513
  function checkPort(port2, timeoutMs = 500) {
4514
- return new Promise((resolve22) => {
4514
+ return new Promise((resolve24) => {
4515
4515
  const socket = createConnection(port2, "127.0.0.1");
4516
4516
  socket.setTimeout(timeoutMs);
4517
4517
  socket.once("connect", () => {
4518
4518
  socket.destroy();
4519
- resolve22(true);
4519
+ resolve24(true);
4520
4520
  });
4521
4521
  socket.once("error", () => {
4522
4522
  socket.destroy();
4523
- resolve22(false);
4523
+ resolve24(false);
4524
4524
  });
4525
4525
  socket.once("timeout", () => {
4526
4526
  socket.destroy();
4527
- resolve22(false);
4527
+ resolve24(false);
4528
4528
  });
4529
4529
  });
4530
4530
  }
@@ -6734,8 +6734,8 @@ async function startLogin(opts) {
6734
6734
  resetActiveLogin(accountId);
6735
6735
  let resolveQr = null;
6736
6736
  let rejectQr = null;
6737
- const qrPromise = new Promise((resolve22, reject) => {
6738
- resolveQr = resolve22;
6737
+ const qrPromise = new Promise((resolve24, reject) => {
6738
+ resolveQr = resolve24;
6739
6739
  rejectQr = reject;
6740
6740
  });
6741
6741
  const qrTimer = setTimeout(
@@ -8132,7 +8132,7 @@ var app11 = new Hono();
8132
8132
  app11.post("/cancel", requireAdminSession, async (c) => {
8133
8133
  const session_key = c.var.sessionKey;
8134
8134
  try {
8135
- const { interruptClient: interruptClient2 } = await import("./client-pool-5V5GX3UT.js");
8135
+ const { interruptClient: interruptClient2 } = await import("./client-pool-CX2MFW75.js");
8136
8136
  await interruptClient2(session_key);
8137
8137
  return c.json({ ok: true });
8138
8138
  } catch (err) {
@@ -8843,12 +8843,6 @@ var agents_default = app16;
8843
8843
  import crypto2 from "crypto";
8844
8844
  import { resolve as resolvePath } from "path";
8845
8845
  import { appendFileSync as appendFileSync5 } from "fs";
8846
- var PERSISTENT_COMPONENT_NAMES = /* @__PURE__ */ new Set([
8847
- "action-list",
8848
- "document-editor",
8849
- "rich-content-editor",
8850
- "grid-editor"
8851
- ]);
8852
8846
  function reconstructAssistantEvents(content, components, conversationId, messageId, streamLogPath) {
8853
8847
  if (components.length === 0) {
8854
8848
  return {
@@ -8904,7 +8898,7 @@ function reconstructAssistantEvents(content, components, conversationId, message
8904
8898
  valid += 1;
8905
8899
  const eventIndex = events.length;
8906
8900
  events.push({ type: "component", name: c.name, data: parsedData });
8907
- if (c.submitted === true && !PERSISTENT_COMPONENT_NAMES.has(c.name)) {
8901
+ if (c.submitted === true) {
8908
8902
  submittedEventIndices.push(eventIndex);
8909
8903
  }
8910
8904
  }
@@ -9049,8 +9043,7 @@ app17.post("/:id/resume", requireAdminSession, async (c) => {
9049
9043
  events,
9050
9044
  createdAt: m.createdAt,
9051
9045
  // Submitted-event indices for client `submittedComponents` seed —
9052
- // empty array when no PERSISTENT_COMPONENT was approved live, omitted
9053
- // from the wire payload to keep the response slim.
9046
+ // omitted from the wire payload when empty to keep the response slim.
9054
9047
  ...submittedEventIndices.length > 0 ? { submittedEventIndices } : {}
9055
9048
  };
9056
9049
  });
@@ -9704,8 +9697,8 @@ function resolveDataPath(raw) {
9704
9697
  if (resolvedReal !== dataRootReal && !resolvedReal.startsWith(dataRootReal + sep)) {
9705
9698
  return { ok: false, status: 403, error: "Path escapes DATA_ROOT", resolved: resolvedReal };
9706
9699
  }
9707
- const relPath = relative(dataRootReal, resolvedReal) || ".";
9708
- return { ok: true, absolute: resolvedReal, dataRootReal, relative: relPath };
9700
+ const relPath2 = relative(dataRootReal, resolvedReal) || ".";
9701
+ return { ok: true, absolute: resolvedReal, dataRootReal, relative: relPath2 };
9709
9702
  }
9710
9703
 
9711
9704
  // ../lib/graph-trash/src/index.ts
@@ -9939,8 +9932,8 @@ async function restoreNode(params) {
9939
9932
 
9940
9933
  // app/lib/file-delete-cascade.ts
9941
9934
  var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9942
- function parseAttachmentPath(relPath) {
9943
- const segments = relPath.split("/").filter(Boolean);
9935
+ function parseAttachmentPath(relPath2) {
9936
+ const segments = relPath2.split("/").filter(Boolean);
9944
9937
  if (segments.length !== 4) return null;
9945
9938
  if (segments[0] !== "uploads") return null;
9946
9939
  const accountId = segments[1];
@@ -10083,9 +10076,9 @@ async function enrich(absolute, entry, accountNames) {
10083
10076
  }
10084
10077
  }
10085
10078
  }
10086
- function buildDisplayPath(relPath, accountNames) {
10087
- if (relPath === "." || relPath === "") return [];
10088
- return relPath.split("/").filter(Boolean).map((seg) => {
10079
+ function buildDisplayPath(relPath2, accountNames) {
10080
+ if (relPath2 === "." || relPath2 === "") return [];
10081
+ return relPath2.split("/").filter(Boolean).map((seg) => {
10089
10082
  const dn = UUID_RE3.test(seg) ? accountNames.get(seg) : void 0;
10090
10083
  return dn ? { name: seg, displayName: dn } : { name: seg };
10091
10084
  });
@@ -10105,7 +10098,7 @@ app22.get("/", requireAdminSession, async (c) => {
10105
10098
  }
10106
10099
  return c.json({ error: resolution.error }, resolution.status);
10107
10100
  }
10108
- const { absolute, relative: relPath } = resolution;
10101
+ const { absolute, relative: relPath2 } = resolution;
10109
10102
  try {
10110
10103
  const info = await stat4(absolute);
10111
10104
  if (!info.isDirectory()) {
@@ -10138,17 +10131,17 @@ app22.get("/", requireAdminSession, async (c) => {
10138
10131
  const bKey = b.displayName ?? b.name;
10139
10132
  return aKey.localeCompare(bKey);
10140
10133
  });
10141
- const displayPath = buildDisplayPath(relPath, accountNames);
10142
- console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
10143
- return c.json({ path: relPath, displayPath, entries });
10134
+ const displayPath = buildDisplayPath(relPath2, accountNames);
10135
+ console.error(`[data] file-list path="${relPath2}" entries=${entries.length}`);
10136
+ return c.json({ path: relPath2, displayPath, entries });
10144
10137
  } catch (err) {
10145
10138
  const code = err.code;
10146
10139
  if (code === "ENOENT") {
10147
- console.error(`[data] file-list not-found path="${relPath}"`);
10140
+ console.error(`[data] file-list not-found path="${relPath2}"`);
10148
10141
  return c.json({ error: "Not found" }, 404);
10149
10142
  }
10150
10143
  const message = err instanceof Error ? err.message : String(err);
10151
- console.error(`[data] file-list error path="${relPath}" err="${message}"`);
10144
+ console.error(`[data] file-list error path="${relPath2}" err="${message}"`);
10152
10145
  return c.json({ error: message }, 500);
10153
10146
  }
10154
10147
  });
@@ -10167,7 +10160,7 @@ app22.get("/download", requireAdminSession, async (c) => {
10167
10160
  }
10168
10161
  return c.json({ error: resolution.error }, resolution.status);
10169
10162
  }
10170
- const { absolute, relative: relPath } = resolution;
10163
+ const { absolute, relative: relPath2 } = resolution;
10171
10164
  try {
10172
10165
  const info = await stat4(absolute);
10173
10166
  if (!info.isFile()) {
@@ -10177,7 +10170,7 @@ app22.get("/download", requireAdminSession, async (c) => {
10177
10170
  const mimeType = detectMimeType(absolute);
10178
10171
  const nodeStream = createReadStream3(absolute);
10179
10172
  const webStream = Readable2.toWeb(nodeStream);
10180
- console.error(`[data] file-download path="${relPath}" size=${info.size}`);
10173
+ console.error(`[data] file-download path="${relPath2}" size=${info.size}`);
10181
10174
  const safeQuotedName = filename.replace(/[\r\n"\\]/g, "_");
10182
10175
  const encodedName = encodeURIComponent(filename);
10183
10176
  return new Response(webStream, {
@@ -10192,11 +10185,11 @@ app22.get("/download", requireAdminSession, async (c) => {
10192
10185
  } catch (err) {
10193
10186
  const code = err.code;
10194
10187
  if (code === "ENOENT") {
10195
- console.error(`[data] file-download not-found path="${relPath}"`);
10188
+ console.error(`[data] file-download not-found path="${relPath2}"`);
10196
10189
  return c.json({ error: "Not found" }, 404);
10197
10190
  }
10198
10191
  const message = err instanceof Error ? err.message : String(err);
10199
- console.error(`[data] file-download error path="${relPath}" err="${message}"`);
10192
+ console.error(`[data] file-download error path="${relPath2}" err="${message}"`);
10200
10193
  return c.json({ error: message }, 500);
10201
10194
  }
10202
10195
  });
@@ -10274,11 +10267,11 @@ app22.delete("/", requireAdminSession, async (c) => {
10274
10267
  }
10275
10268
  return c.json({ error: resolution.error }, resolution.status);
10276
10269
  }
10277
- const { absolute, relative: relPath } = resolution;
10270
+ const { absolute, relative: relPath2 } = resolution;
10278
10271
  const base = basename6(absolute);
10279
- const segments = relPath.split("/").filter(Boolean);
10272
+ const segments = relPath2.split("/").filter(Boolean);
10280
10273
  if (base === "account.json" || segments.includes(".git")) {
10281
- console.error(`[data] file-delete blocked path="${relPath}" reason="protected"`);
10274
+ console.error(`[data] file-delete blocked path="${relPath2}" reason="protected"`);
10282
10275
  return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
10283
10276
  }
10284
10277
  try {
@@ -10299,29 +10292,29 @@ app22.delete("/", requireAdminSession, async (c) => {
10299
10292
  } catch {
10300
10293
  }
10301
10294
  }
10302
- console.error(`[data] file-delete path="${relPath}" bytes=${info.size}`);
10303
- const parsed = parseAttachmentPath(relPath);
10295
+ console.error(`[data] file-delete path="${relPath2}" bytes=${info.size}`);
10296
+ const parsed = parseAttachmentPath(relPath2);
10304
10297
  if (parsed) {
10305
10298
  try {
10306
10299
  const { nodes } = await cascadeDeleteDocument({
10307
10300
  accountId,
10308
10301
  attachmentId: parsed.attachmentId
10309
10302
  });
10310
- console.error(`[data] file-delete graph-cascade path="${relPath}" nodes=${nodes}`);
10303
+ console.error(`[data] file-delete graph-cascade path="${relPath2}" nodes=${nodes}`);
10311
10304
  } catch (err) {
10312
10305
  const message = err instanceof Error ? err.message : String(err);
10313
- console.error(`[data] file-delete graph-cascade-failed path="${relPath}" err="${message}"`);
10306
+ console.error(`[data] file-delete graph-cascade-failed path="${relPath2}" err="${message}"`);
10314
10307
  }
10315
10308
  }
10316
10309
  return c.json({ ok: true });
10317
10310
  } catch (err) {
10318
10311
  const code = err.code;
10319
10312
  if (code === "ENOENT") {
10320
- console.error(`[data] file-delete not-found path="${relPath}"`);
10313
+ console.error(`[data] file-delete not-found path="${relPath2}"`);
10321
10314
  return c.json({ error: "Not found" }, 404);
10322
10315
  }
10323
10316
  const message = err instanceof Error ? err.message : String(err);
10324
- console.error(`[data] file-delete error path="${relPath}" err="${message}"`);
10317
+ console.error(`[data] file-delete error path="${relPath2}" err="${message}"`);
10325
10318
  return c.json({ error: message }, 500);
10326
10319
  }
10327
10320
  });
@@ -11691,13 +11684,14 @@ app31.get("/", requireAdminSession, async (c) => {
11691
11684
  const result = await session.run(
11692
11685
  `MATCH (p:Project { accountId: $accountId })
11693
11686
  WHERE NOT p:Trashed
11694
- RETURN p.taskId AS id, p.name AS name, p.updatedAt AS updatedAt
11687
+ RETURN p.taskId AS id, elementId(p) AS elementId, p.name AS name, p.updatedAt AS updatedAt
11695
11688
  ORDER BY p.updatedAt DESC
11696
11689
  LIMIT $limit`,
11697
11690
  { accountId, limit: neo4j3.int(LIMIT) }
11698
11691
  );
11699
11692
  const projects = result.records.map((r) => ({
11700
11693
  id: r.get("id"),
11694
+ elementId: r.get("elementId"),
11701
11695
  name: r.get("name") ?? "",
11702
11696
  updatedAt: r.get("updatedAt") ?? ""
11703
11697
  }));
@@ -11717,10 +11711,12 @@ var sidebar_projects_default = app31;
11717
11711
 
11718
11712
  // server/routes/admin/sidebar-artefacts.ts
11719
11713
  import neo4j4 from "neo4j-driver";
11720
- import { readFile as readFile5, readdir as readdir3 } from "fs/promises";
11721
- import { resolve as resolve20 } from "path";
11714
+ import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
11715
+ import { resolve as resolve20, relative as relative2, isAbsolute } from "path";
11716
+ import { existsSync as existsSync19 } from "fs";
11722
11717
  var LIMIT2 = 50;
11723
11718
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11719
+ var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
11724
11720
  var app32 = new Hono();
11725
11721
  app32.get("/", requireAdminSession, async (c) => {
11726
11722
  const sessionKey = c.var.sessionKey;
@@ -11729,6 +11725,22 @@ app32.get("/", requireAdminSession, async (c) => {
11729
11725
  return c.json({ error: "Account not found for session" }, 401);
11730
11726
  }
11731
11727
  const start = Date.now();
11728
+ const docs = await fetchKnowledgeDocs(accountId);
11729
+ if (docs === null) {
11730
+ return c.json({ error: "Failed to load artefacts" }, 500);
11731
+ }
11732
+ const accountDir = resolve20(ACCOUNTS_DIR, accountId);
11733
+ const agents = await fetchAgentTemplateRows(accountDir);
11734
+ const artefacts = [...docs, ...agents].sort(
11735
+ (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
11736
+ ).slice(0, LIMIT2);
11737
+ const ms = Date.now() - start;
11738
+ console.log(
11739
+ `[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} docs=${docs.length} agents=${agents.length} ms=${ms}`
11740
+ );
11741
+ return c.json({ artefacts });
11742
+ });
11743
+ async function fetchKnowledgeDocs(accountId) {
11732
11744
  const session = getSession();
11733
11745
  let metas = [];
11734
11746
  try {
@@ -11749,72 +11761,337 @@ app32.get("/", requireAdminSession, async (c) => {
11749
11761
  mimeType: r.get("mimeType") ?? ""
11750
11762
  }));
11751
11763
  } catch (err) {
11752
- const ms2 = Date.now() - start;
11753
11764
  const message = err instanceof Error ? err.message : String(err);
11754
- console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}" ms=${ms2}`);
11765
+ console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
11755
11766
  await session.close();
11756
- return c.json({ error: "Failed to load artefacts" }, 500);
11767
+ return null;
11757
11768
  } finally {
11758
11769
  await session.close();
11759
11770
  }
11760
- const artefacts = await Promise.all(metas.map(async (m) => {
11761
- const content = await readArtefactContent(accountId, m.attachmentId, m.mimeType);
11762
- return { id: m.id, name: m.name, updatedAt: m.updatedAt, content };
11771
+ return Promise.all(metas.map(async (m) => {
11772
+ const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
11773
+ return {
11774
+ id: m.id,
11775
+ name: m.name,
11776
+ kind: "knowledge-doc",
11777
+ updatedAt: m.updatedAt,
11778
+ content,
11779
+ editable: skipReason === null,
11780
+ mimeType: m.mimeType,
11781
+ skipReason
11782
+ };
11763
11783
  }));
11764
- const ms = Date.now() - start;
11765
- console.log(`[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} ms=${ms}`);
11766
- return c.json({ artefacts });
11767
- });
11768
- async function readArtefactContent(accountId, attachmentId, mimeType) {
11769
- if (!attachmentId) return "";
11784
+ }
11785
+ async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
11786
+ if (!attachmentId) {
11787
+ logSkip(displayName, "null-attachmentId", mimeType);
11788
+ return { content: "", skipReason: "null-attachmentId" };
11789
+ }
11770
11790
  const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
11771
- if (!isText) return "";
11791
+ if (!isText) {
11792
+ logSkip(displayName, "non-text-mime", mimeType);
11793
+ return { content: "", skipReason: "non-text-mime" };
11794
+ }
11772
11795
  const accountDir = resolve20(ATTACHMENTS_ROOT, accountId);
11773
11796
  const dir = resolve20(accountDir, attachmentId);
11774
11797
  try {
11775
11798
  validateFilePathInAccount(dir, accountDir);
11776
11799
  } catch {
11777
- return "";
11800
+ logSkip(displayName, "containment-rejected", mimeType);
11801
+ return { content: "", skipReason: "containment-rejected" };
11778
11802
  }
11779
11803
  try {
11780
11804
  const entries = await readdir3(dir);
11781
11805
  const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
11782
- if (!dataFile) return "";
11783
- return await readFile5(resolve20(dir, dataFile), "utf-8");
11806
+ if (!dataFile) {
11807
+ logSkip(displayName, "missing-on-disk", mimeType);
11808
+ return { content: "", skipReason: "missing-on-disk" };
11809
+ }
11810
+ return { content: await readFile5(resolve20(dir, dataFile), "utf-8"), skipReason: null };
11784
11811
  } catch (err) {
11785
11812
  const message = err instanceof Error ? err.message : String(err);
11786
11813
  console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
11787
- return "";
11814
+ logSkip(displayName, "missing-on-disk", mimeType);
11815
+ return { content: "", skipReason: "missing-on-disk" };
11816
+ }
11817
+ }
11818
+ function logSkip(name, reason, mimeType) {
11819
+ console.log(
11820
+ `[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
11821
+ );
11822
+ }
11823
+ async function fetchAgentTemplateRows(accountDir) {
11824
+ const rows = [];
11825
+ for (const filename of ADMIN_AGENT_FILES) {
11826
+ const overridePath = resolve20(accountDir, "agents", "admin", filename);
11827
+ const bundledPath = resolve20(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11828
+ const labelStem = filename.replace(/\.md$/, "");
11829
+ const row = await readAgentTemplateRow({
11830
+ id: `agent-template:admin:${filename}`,
11831
+ displayName: `Admin \xB7 ${labelStem}`,
11832
+ logName: `admin/${filename}`,
11833
+ overridePath,
11834
+ overrideRoot: accountDir,
11835
+ bundledPath,
11836
+ bundledRoot: PLATFORM_ROOT,
11837
+ editable: true
11838
+ });
11839
+ if (row) rows.push(row);
11840
+ }
11841
+ const overrideDir = resolve20(accountDir, "specialists", "agents");
11842
+ const bundledDir = resolve20(PLATFORM_ROOT, "templates", "specialists", "agents");
11843
+ const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
11844
+ for (const filename of specialistNames) {
11845
+ const overridePath = resolve20(overrideDir, filename);
11846
+ const bundledPath = resolve20(bundledDir, filename);
11847
+ const row = await readAgentTemplateRow({
11848
+ id: `agent-template:specialist:${filename}`,
11849
+ displayName: filename.replace(/\.md$/, ""),
11850
+ logName: `specialist/${filename}`,
11851
+ overridePath,
11852
+ overrideRoot: accountDir,
11853
+ bundledPath,
11854
+ bundledRoot: PLATFORM_ROOT,
11855
+ editable: false
11856
+ });
11857
+ if (row) rows.push(row);
11858
+ }
11859
+ return rows;
11860
+ }
11861
+ async function unionSpecialistFilenames(overrideDir, bundledDir) {
11862
+ const names = /* @__PURE__ */ new Set();
11863
+ for (const dir of [overrideDir, bundledDir]) {
11864
+ if (!existsSync19(dir)) continue;
11865
+ try {
11866
+ const entries = await readdir3(dir);
11867
+ for (const entry of entries) {
11868
+ if (entry.endsWith(".md")) names.add(entry);
11869
+ }
11870
+ } catch (err) {
11871
+ const message = err instanceof Error ? err.message : String(err);
11872
+ console.error(`[admin/sidebar-artefacts] specialists-read-failed dir=${dir} error="${message}"`);
11873
+ }
11788
11874
  }
11875
+ return [...names].sort();
11876
+ }
11877
+ async function readAgentTemplateRow(inp) {
11878
+ let chosenPath = null;
11879
+ if (existsSync19(inp.overridePath)) {
11880
+ try {
11881
+ validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
11882
+ chosenPath = inp.overridePath;
11883
+ } catch (err) {
11884
+ const message = err instanceof Error ? err.message : String(err);
11885
+ console.error(
11886
+ `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
11887
+ );
11888
+ return null;
11889
+ }
11890
+ } else if (existsSync19(inp.bundledPath)) {
11891
+ if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
11892
+ console.error(
11893
+ `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
11894
+ );
11895
+ return null;
11896
+ }
11897
+ chosenPath = inp.bundledPath;
11898
+ }
11899
+ if (!chosenPath) return null;
11900
+ try {
11901
+ const [content, st] = await Promise.all([
11902
+ readFile5(chosenPath, "utf-8"),
11903
+ stat5(chosenPath)
11904
+ ]);
11905
+ return {
11906
+ id: inp.id,
11907
+ name: inp.displayName,
11908
+ kind: "agent-template",
11909
+ updatedAt: st.mtime.toISOString(),
11910
+ content,
11911
+ editable: inp.editable,
11912
+ mimeType: "text/markdown",
11913
+ skipReason: null
11914
+ };
11915
+ } catch (err) {
11916
+ const message = err instanceof Error ? err.message : String(err);
11917
+ console.error(
11918
+ `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="${message}"`
11919
+ );
11920
+ return null;
11921
+ }
11922
+ }
11923
+ function isWithin(target, root) {
11924
+ const rel = relative2(root, target);
11925
+ return !rel.startsWith("..") && !isAbsolute(rel);
11789
11926
  }
11790
11927
  var sidebar_artefacts_default = app32;
11791
11928
 
11792
- // server/routes/admin/index.ts
11929
+ // server/routes/admin/sidebar-artefact-save.ts
11930
+ import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
11931
+ import { resolve as resolve21 } from "path";
11932
+ import { existsSync as existsSync20 } from "fs";
11933
+ var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
11934
+ var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11793
11935
  var app33 = new Hono();
11794
- app33.route("/session", session_default2);
11795
- app33.route("/chat", chat_default2);
11796
- app33.route("/compact", compact_default);
11797
- app33.route("/logs", logs_default);
11798
- app33.route("/claude-info", claude_info_default);
11799
- app33.route("/attachment", attachment_default);
11800
- app33.route("/agents", agents_default);
11801
- app33.route("/sessions", sessions_default);
11802
- app33.route("/browser", browser_default);
11803
- app33.route("/device-browser", device_browser_default);
11804
- app33.route("/events", events_default);
11805
- app33.route("/cloudflare", cloudflare_default);
11806
- app33.route("/files", files_default);
11807
- app33.route("/graph-search", graph_search_default);
11808
- app33.route("/graph-subgraph", graph_subgraph_default);
11809
- app33.route("/graph-delete", graph_delete_default);
11810
- app33.route("/graph-restore", graph_restore_default);
11811
- app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
11812
- app33.route("/graph-default-view", graph_default_view_default);
11813
- app33.route("/file-attach", file_attach_default);
11814
- app33.route("/adherence", adherence_default);
11815
- app33.route("/sidebar-projects", sidebar_projects_default);
11816
- app33.route("/sidebar-artefacts", sidebar_artefacts_default);
11817
- var admin_default = app33;
11936
+ app33.post("/", requireAdminSession, async (c) => {
11937
+ const sessionKey = c.var.sessionKey;
11938
+ const accountId = getAccountIdForSession(sessionKey);
11939
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
11940
+ const body = await safeJson(c);
11941
+ if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
11942
+ return c.json({ error: "id and content required" }, 400);
11943
+ }
11944
+ const accountDir = resolve21(ACCOUNTS_DIR, accountId);
11945
+ const resolved = await resolveSavePath(body.id, accountId, accountDir);
11946
+ if (resolved.kind === "reject") {
11947
+ console.error(
11948
+ `[admin/sidebar-artefact-save] auth-rejected reason=${resolved.reason} path=${body.id}`
11949
+ );
11950
+ return c.json({ error: resolved.reason }, resolved.status);
11951
+ }
11952
+ const start = Date.now();
11953
+ try {
11954
+ await writeFile5(resolved.path, body.content, "utf-8");
11955
+ } catch (err) {
11956
+ const message = err instanceof Error ? err.message : String(err);
11957
+ console.error(
11958
+ `[admin/sidebar-artefact-save] write-failed path=${relPath(resolved.path, accountDir)} error="${message}"`
11959
+ );
11960
+ return c.json({ error: "Write failed" }, 500);
11961
+ }
11962
+ let updatedAt = (/* @__PURE__ */ new Date()).toISOString();
11963
+ try {
11964
+ const st = await stat6(resolved.path);
11965
+ updatedAt = st.mtime.toISOString();
11966
+ } catch {
11967
+ }
11968
+ const ms = Date.now() - start;
11969
+ console.log(
11970
+ `[admin/sidebar-artefact-save] account=${accountId} path=${relPath(resolved.path, accountDir)} bytes=${body.content.length} ms=${ms}`
11971
+ );
11972
+ return c.json({ updatedAt });
11973
+ });
11974
+ async function resolveSavePath(id, accountId, accountDir) {
11975
+ if (id.startsWith("agent-template:")) {
11976
+ const parts = id.split(":");
11977
+ if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
11978
+ const [, role, filename] = parts;
11979
+ if (role === "specialist") {
11980
+ return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
11981
+ }
11982
+ if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
11983
+ return { kind: "reject", status: 400, reason: "invalid-id" };
11984
+ }
11985
+ const parent = resolve21(accountDir, "agents", "admin");
11986
+ await mkdir4(parent, { recursive: true });
11987
+ try {
11988
+ validateFilePathInAccount(parent, accountDir);
11989
+ } catch {
11990
+ return { kind: "reject", status: 400, reason: "containment-rejected" };
11991
+ }
11992
+ return { kind: "admin-template", path: resolve21(parent, filename) };
11993
+ }
11994
+ if (UUID_RE4.test(id)) {
11995
+ const dir = resolve21(ATTACHMENTS_ROOT, accountId, id);
11996
+ if (!existsSync20(dir)) {
11997
+ return { kind: "reject", status: 400, reason: "not-found" };
11998
+ }
11999
+ try {
12000
+ validateFilePathInAccount(dir, resolve21(ATTACHMENTS_ROOT, accountId));
12001
+ } catch {
12002
+ return { kind: "reject", status: 400, reason: "containment-rejected" };
12003
+ }
12004
+ const entries = await readdir4(dir);
12005
+ const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
12006
+ if (!dataFile) {
12007
+ return { kind: "reject", status: 400, reason: "not-found" };
12008
+ }
12009
+ return { kind: "knowledge-doc", path: resolve21(dir, dataFile) };
12010
+ }
12011
+ return { kind: "reject", status: 400, reason: "invalid-id" };
12012
+ }
12013
+ function relPath(absPath, root) {
12014
+ return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
12015
+ }
12016
+ var sidebar_artefact_save_default = app33;
12017
+
12018
+ // server/routes/admin/sidebar-artefact-content.ts
12019
+ import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
12020
+ import { existsSync as existsSync21 } from "fs";
12021
+ import { resolve as resolve22 } from "path";
12022
+ var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12023
+ var app34 = new Hono();
12024
+ app34.get("/", requireAdminSession, async (c) => {
12025
+ const sessionKey = c.var.sessionKey;
12026
+ const accountId = getAccountIdForSession(sessionKey);
12027
+ if (!accountId) return new Response("Unauthorized", { status: 401 });
12028
+ const id = c.req.query("id") ?? "";
12029
+ if (!UUID_RE5.test(id)) {
12030
+ console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12031
+ return new Response("Not found", { status: 404 });
12032
+ }
12033
+ const dir = resolve22(ATTACHMENTS_ROOT, accountId, id);
12034
+ if (!existsSync21(dir)) {
12035
+ console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12036
+ return new Response("Not found", { status: 404 });
12037
+ }
12038
+ let meta;
12039
+ try {
12040
+ meta = JSON.parse(await readFile6(resolve22(dir, `${id}.meta.json`), "utf-8"));
12041
+ } catch {
12042
+ console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12043
+ return new Response("Not found", { status: 404 });
12044
+ }
12045
+ const entries = await readdir5(dir);
12046
+ const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
12047
+ if (!dataFile) {
12048
+ console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12049
+ return new Response("Not found", { status: 404 });
12050
+ }
12051
+ const start = Date.now();
12052
+ const buffer = await readFile6(resolve22(dir, dataFile));
12053
+ const ms = Date.now() - start;
12054
+ console.log(
12055
+ `[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
12056
+ );
12057
+ return new Response(new Uint8Array(buffer), {
12058
+ headers: {
12059
+ "Content-Type": meta.mimeType,
12060
+ "Content-Disposition": `inline; filename="${meta.filename}"`,
12061
+ "Cache-Control": "private, max-age=3600"
12062
+ }
12063
+ });
12064
+ });
12065
+ var sidebar_artefact_content_default = app34;
12066
+
12067
+ // server/routes/admin/index.ts
12068
+ var app35 = new Hono();
12069
+ app35.route("/session", session_default2);
12070
+ app35.route("/chat", chat_default2);
12071
+ app35.route("/compact", compact_default);
12072
+ app35.route("/logs", logs_default);
12073
+ app35.route("/claude-info", claude_info_default);
12074
+ app35.route("/attachment", attachment_default);
12075
+ app35.route("/agents", agents_default);
12076
+ app35.route("/sessions", sessions_default);
12077
+ app35.route("/browser", browser_default);
12078
+ app35.route("/device-browser", device_browser_default);
12079
+ app35.route("/events", events_default);
12080
+ app35.route("/cloudflare", cloudflare_default);
12081
+ app35.route("/files", files_default);
12082
+ app35.route("/graph-search", graph_search_default);
12083
+ app35.route("/graph-subgraph", graph_subgraph_default);
12084
+ app35.route("/graph-delete", graph_delete_default);
12085
+ app35.route("/graph-restore", graph_restore_default);
12086
+ app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12087
+ app35.route("/graph-default-view", graph_default_view_default);
12088
+ app35.route("/file-attach", file_attach_default);
12089
+ app35.route("/adherence", adherence_default);
12090
+ app35.route("/sidebar-projects", sidebar_projects_default);
12091
+ app35.route("/sidebar-artefacts", sidebar_artefacts_default);
12092
+ app35.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12093
+ app35.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12094
+ var admin_default = app35;
11818
12095
 
11819
12096
  // app/lib/graph-health.ts
11820
12097
  var HOUR_MS = 60 * 60 * 1e3;
@@ -11916,10 +12193,10 @@ function clientFrom(c) {
11916
12193
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
11917
12194
  var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join10(PLATFORM_ROOT7, "config", "brand.json") : "";
11918
12195
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
11919
- if (BRAND_JSON_PATH && !existsSync19(BRAND_JSON_PATH)) {
12196
+ if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
11920
12197
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
11921
12198
  }
11922
- if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
12199
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
11923
12200
  try {
11924
12201
  const parsed = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
11925
12202
  BRAND = { ...BRAND, ...parsed };
@@ -11943,7 +12220,7 @@ var brandLoginOpts = {
11943
12220
  var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.json");
11944
12221
  function loadAliasDomains() {
11945
12222
  try {
11946
- if (!existsSync19(ALIAS_DOMAINS_PATH2)) return null;
12223
+ if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
11947
12224
  const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH2, "utf-8"));
11948
12225
  if (!Array.isArray(parsed)) {
11949
12226
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
@@ -11968,9 +12245,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
11968
12245
  function isPublicHost(host) {
11969
12246
  return host.startsWith("public.") || aliasDomains.has(host);
11970
12247
  }
11971
- var app34 = new Hono();
11972
- app34.use("*", clientIpMiddleware);
11973
- app34.use("*", async (c, next) => {
12248
+ var app36 = new Hono();
12249
+ app36.use("*", clientIpMiddleware);
12250
+ app36.use("*", async (c, next) => {
11974
12251
  await next();
11975
12252
  c.header("X-Content-Type-Options", "nosniff");
11976
12253
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -11993,7 +12270,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
11993
12270
  "/g/"
11994
12271
  ];
11995
12272
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
11996
- app34.use("*", async (c, next) => {
12273
+ app36.use("*", async (c, next) => {
11997
12274
  const host = (c.req.header("host") ?? "").split(":")[0];
11998
12275
  if (!isPublicHost(host)) {
11999
12276
  await next();
@@ -12033,7 +12310,7 @@ function resolveRemoteAuthOpts() {
12033
12310
  return brandLoginOpts;
12034
12311
  }
12035
12312
  var MAX_LOGIN_BODY = 8 * 1024;
12036
- app34.post("/__remote-auth/login", async (c) => {
12313
+ app36.post("/__remote-auth/login", async (c) => {
12037
12314
  const client = clientFrom(c);
12038
12315
  const clientIp = client.ip || "unknown";
12039
12316
  if (!requestIsTlsTerminated(c)) {
@@ -12077,7 +12354,7 @@ app34.post("/__remote-auth/login", async (c) => {
12077
12354
  }
12078
12355
  });
12079
12356
  });
12080
- app34.get("/__remote-auth/logout", (c) => {
12357
+ app36.get("/__remote-auth/logout", (c) => {
12081
12358
  return new Response(null, {
12082
12359
  status: 302,
12083
12360
  headers: {
@@ -12087,7 +12364,7 @@ app34.get("/__remote-auth/logout", (c) => {
12087
12364
  }
12088
12365
  });
12089
12366
  });
12090
- app34.post("/__remote-auth/change-password", async (c) => {
12367
+ app36.post("/__remote-auth/change-password", async (c) => {
12091
12368
  const client = clientFrom(c);
12092
12369
  const clientIp = client.ip || "unknown";
12093
12370
  const rateLimited = checkRateLimit(client);
@@ -12137,13 +12414,13 @@ app34.post("/__remote-auth/change-password", async (c) => {
12137
12414
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
12138
12415
  }
12139
12416
  });
12140
- app34.get("/__remote-auth/setup", (c) => {
12417
+ app36.get("/__remote-auth/setup", (c) => {
12141
12418
  if (isRemoteAuthConfigured()) {
12142
12419
  return c.redirect("/");
12143
12420
  }
12144
12421
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
12145
12422
  });
12146
- app34.post("/__remote-auth/set-initial-password", async (c) => {
12423
+ app36.post("/__remote-auth/set-initial-password", async (c) => {
12147
12424
  if (isRemoteAuthConfigured()) {
12148
12425
  return c.redirect("/");
12149
12426
  }
@@ -12179,10 +12456,10 @@ app34.post("/__remote-auth/set-initial-password", async (c) => {
12179
12456
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
12180
12457
  }
12181
12458
  });
12182
- app34.get("/api/remote-auth/status", (c) => {
12459
+ app36.get("/api/remote-auth/status", (c) => {
12183
12460
  return c.json({ configured: isRemoteAuthConfigured() });
12184
12461
  });
12185
- app34.post("/api/remote-auth/set-password", async (c) => {
12462
+ app36.post("/api/remote-auth/set-password", async (c) => {
12186
12463
  let body;
12187
12464
  try {
12188
12465
  body = await c.req.json();
@@ -12212,9 +12489,9 @@ app34.post("/api/remote-auth/set-password", async (c) => {
12212
12489
  return c.json({ error: "Failed to save password" }, 500);
12213
12490
  }
12214
12491
  });
12215
- app34.route("/api/_client-error", client_error_default);
12492
+ app36.route("/api/_client-error", client_error_default);
12216
12493
  console.log("[client-error-route] mounted");
12217
- app34.use("*", async (c, next) => {
12494
+ app36.use("*", async (c, next) => {
12218
12495
  const host = (c.req.header("host") ?? "").split(":")[0];
12219
12496
  const path2 = c.req.path;
12220
12497
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -12247,15 +12524,15 @@ app34.use("*", async (c, next) => {
12247
12524
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
12248
12525
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
12249
12526
  });
12250
- app34.route("/api/health", health_default);
12251
- app34.route("/api/session", session_default);
12252
- app34.route("/api/chat", chat_default);
12253
- app34.route("/api/group", group_default);
12254
- app34.route("/api/access", access_default);
12255
- app34.route("/api/telegram", telegram_default);
12256
- app34.route("/api/whatsapp", whatsapp_default);
12257
- app34.route("/api/onboarding", onboarding_default);
12258
- app34.route("/api/admin", admin_default);
12527
+ app36.route("/api/health", health_default);
12528
+ app36.route("/api/session", session_default);
12529
+ app36.route("/api/chat", chat_default);
12530
+ app36.route("/api/group", group_default);
12531
+ app36.route("/api/access", access_default);
12532
+ app36.route("/api/telegram", telegram_default);
12533
+ app36.route("/api/whatsapp", whatsapp_default);
12534
+ app36.route("/api/onboarding", onboarding_default);
12535
+ app36.route("/api/admin", admin_default);
12259
12536
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
12260
12537
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12261
12538
  var IMAGE_MIME = {
@@ -12267,7 +12544,7 @@ var IMAGE_MIME = {
12267
12544
  ".svg": "image/svg+xml",
12268
12545
  ".ico": "image/x-icon"
12269
12546
  };
12270
- app34.get("/agent-assets/:slug/:filename", (c) => {
12547
+ app36.get("/agent-assets/:slug/:filename", (c) => {
12271
12548
  const slug = c.req.param("slug");
12272
12549
  const filename = c.req.param("filename");
12273
12550
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -12283,13 +12560,13 @@ app34.get("/agent-assets/:slug/:filename", (c) => {
12283
12560
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
12284
12561
  return c.text("Not found", 404);
12285
12562
  }
12286
- const filePath = resolve21(account.accountDir, "agents", slug, "assets", filename);
12287
- const expectedDir = resolve21(account.accountDir, "agents", slug, "assets");
12563
+ const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
12564
+ const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
12288
12565
  if (!filePath.startsWith(expectedDir + "/")) {
12289
12566
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
12290
12567
  return c.text("Forbidden", 403);
12291
12568
  }
12292
- if (!existsSync19(filePath)) {
12569
+ if (!existsSync22(filePath)) {
12293
12570
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
12294
12571
  return c.text("Not found", 404);
12295
12572
  }
@@ -12302,7 +12579,7 @@ app34.get("/agent-assets/:slug/:filename", (c) => {
12302
12579
  "Cache-Control": "public, max-age=3600"
12303
12580
  });
12304
12581
  });
12305
- app34.get("/generated/:filename", (c) => {
12582
+ app36.get("/generated/:filename", (c) => {
12306
12583
  const filename = c.req.param("filename");
12307
12584
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
12308
12585
  console.error(`[generated] serve file=${filename} status=403`);
@@ -12313,13 +12590,13 @@ app34.get("/generated/:filename", (c) => {
12313
12590
  console.error(`[generated] serve file=${filename} status=404`);
12314
12591
  return c.text("Not found", 404);
12315
12592
  }
12316
- const filePath = resolve21(account.accountDir, "generated", filename);
12317
- const expectedDir = resolve21(account.accountDir, "generated");
12593
+ const filePath = resolve23(account.accountDir, "generated", filename);
12594
+ const expectedDir = resolve23(account.accountDir, "generated");
12318
12595
  if (!filePath.startsWith(expectedDir + "/")) {
12319
12596
  console.error(`[generated] serve file=${filename} status=403`);
12320
12597
  return c.text("Forbidden", 403);
12321
12598
  }
12322
- if (!existsSync19(filePath)) {
12599
+ if (!existsSync22(filePath)) {
12323
12600
  console.error(`[generated] serve file=${filename} status=404`);
12324
12601
  return c.text("Not found", 404);
12325
12602
  }
@@ -12335,7 +12612,7 @@ app34.get("/generated/:filename", (c) => {
12335
12612
  var htmlCache = /* @__PURE__ */ new Map();
12336
12613
  var brandLogoPath = "/brand/maxy-monochrome.png";
12337
12614
  var brandIconPath = "/brand/maxy-monochrome.png";
12338
- if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
12615
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
12339
12616
  try {
12340
12617
  const fullBrand = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
12341
12618
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
@@ -12355,7 +12632,7 @@ function readInstalledVersion() {
12355
12632
  try {
12356
12633
  if (!PLATFORM_ROOT7) return "unknown";
12357
12634
  const versionFile = join10(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
12358
- if (!existsSync19(versionFile)) return "unknown";
12635
+ if (!existsSync22(versionFile)) return "unknown";
12359
12636
  const content = readFileSync16(versionFile, "utf-8").trim();
12360
12637
  return content || "unknown";
12361
12638
  } catch {
@@ -12397,7 +12674,7 @@ var clientErrorReporterScript = `<script>
12397
12674
  function cachedHtml(file) {
12398
12675
  let html = htmlCache.get(file);
12399
12676
  if (!html) {
12400
- html = readFileSync16(resolve21(process.cwd(), "public", file), "utf-8");
12677
+ html = readFileSync16(resolve23(process.cwd(), "public", file), "utf-8");
12401
12678
  const productNameEsc = escapeHtml(BRAND.productName);
12402
12679
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
12403
12680
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -12416,12 +12693,12 @@ function loadBrandingCache(agentSlug) {
12416
12693
  const configDir2 = join10(homedir2(), BRAND.configDir);
12417
12694
  try {
12418
12695
  const accountJsonPath = join10(configDir2, "account.json");
12419
- if (!existsSync19(accountJsonPath)) return null;
12696
+ if (!existsSync22(accountJsonPath)) return null;
12420
12697
  const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12421
12698
  const accountId = account.accountId;
12422
12699
  if (!accountId) return null;
12423
12700
  const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12424
- if (!existsSync19(cachePath)) return null;
12701
+ if (!existsSync22(cachePath)) return null;
12425
12702
  return JSON.parse(readFileSync16(cachePath, "utf-8"));
12426
12703
  } catch {
12427
12704
  return null;
@@ -12431,7 +12708,7 @@ function resolveDefaultSlug() {
12431
12708
  try {
12432
12709
  const configDir2 = join10(homedir2(), BRAND.configDir);
12433
12710
  const accountJsonPath = join10(configDir2, "account.json");
12434
- if (!existsSync19(accountJsonPath)) return null;
12711
+ if (!existsSync22(accountJsonPath)) return null;
12435
12712
  const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12436
12713
  return account.defaultAgent || null;
12437
12714
  } catch {
@@ -12468,7 +12745,7 @@ function brandedPublicHtml(agentSlug) {
12468
12745
  function escapeHtml(s) {
12469
12746
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12470
12747
  }
12471
- app34.get("/", (c) => {
12748
+ app36.get("/", (c) => {
12472
12749
  const host = (c.req.header("host") ?? "").split(":")[0];
12473
12750
  if (isPublicHost(host)) {
12474
12751
  const defaultSlug = resolveDefaultSlug();
@@ -12476,12 +12753,12 @@ app34.get("/", (c) => {
12476
12753
  }
12477
12754
  return c.html(cachedHtml("index.html"));
12478
12755
  });
12479
- app34.get("/public", (c) => {
12756
+ app36.get("/public", (c) => {
12480
12757
  const host = (c.req.header("host") ?? "").split(":")[0];
12481
12758
  if (isPublicHost(host)) return c.text("Not found", 404);
12482
12759
  return c.html(cachedHtml("public.html"));
12483
12760
  });
12484
- app34.get("/chat", (c) => {
12761
+ app36.get("/chat", (c) => {
12485
12762
  const host = (c.req.header("host") ?? "").split(":")[0];
12486
12763
  if (isPublicHost(host)) return c.text("Not found", 404);
12487
12764
  return c.html(cachedHtml("public.html"));
@@ -12500,12 +12777,12 @@ async function logViewerFetch(c, next) {
12500
12777
  duration_ms: Date.now() - start
12501
12778
  });
12502
12779
  }
12503
- app34.use("/vnc-viewer.html", logViewerFetch);
12504
- app34.use("/vnc-popout.html", logViewerFetch);
12505
- app34.get("/vnc-popout.html", (c) => {
12780
+ app36.use("/vnc-viewer.html", logViewerFetch);
12781
+ app36.use("/vnc-popout.html", logViewerFetch);
12782
+ app36.get("/vnc-popout.html", (c) => {
12506
12783
  let html = htmlCache.get("vnc-popout.html");
12507
12784
  if (!html) {
12508
- html = readFileSync16(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12785
+ html = readFileSync16(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12509
12786
  const name = escapeHtml(BRAND.productName);
12510
12787
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
12511
12788
  html = html.replace("</head>", ` ${brandScript}
@@ -12515,7 +12792,7 @@ app34.get("/vnc-popout.html", (c) => {
12515
12792
  }
12516
12793
  return c.html(html);
12517
12794
  });
12518
- app34.post("/api/vnc/client-event", async (c) => {
12795
+ app36.post("/api/vnc/client-event", async (c) => {
12519
12796
  let body;
12520
12797
  try {
12521
12798
  body = await c.req.json();
@@ -12536,20 +12813,20 @@ app34.post("/api/vnc/client-event", async (c) => {
12536
12813
  });
12537
12814
  return c.json({ ok: true });
12538
12815
  });
12539
- app34.get("/g/:slug", (c) => {
12816
+ app36.get("/g/:slug", (c) => {
12540
12817
  return c.html(brandedPublicHtml());
12541
12818
  });
12542
- app34.get("/graph", (c) => {
12819
+ app36.get("/graph", (c) => {
12543
12820
  const host = (c.req.header("host") ?? "").split(":")[0];
12544
12821
  if (isPublicHost(host)) return c.text("Not found", 404);
12545
12822
  return c.html(cachedHtml("graph.html"));
12546
12823
  });
12547
- app34.get("/data", (c) => {
12824
+ app36.get("/data", (c) => {
12548
12825
  const host = (c.req.header("host") ?? "").split(":")[0];
12549
12826
  if (isPublicHost(host)) return c.text("Not found", 404);
12550
12827
  return c.html(cachedHtml("data.html"));
12551
12828
  });
12552
- app34.get("/:slug", async (c, next) => {
12829
+ app36.get("/:slug", async (c, next) => {
12553
12830
  const slug = c.req.param("slug");
12554
12831
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
12555
12832
  const branding = loadBrandingCache(slug);
@@ -12558,10 +12835,10 @@ app34.get("/:slug", async (c, next) => {
12558
12835
  }
12559
12836
  await next();
12560
12837
  });
12561
- app34.use("/*", serveStatic({ root: "./public" }));
12838
+ app36.use("/*", serveStatic({ root: "./public" }));
12562
12839
  var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
12563
12840
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
12564
- var httpServer = serve({ fetch: app34.fetch, port, hostname });
12841
+ var httpServer = serve({ fetch: app36.fetch, port, hostname });
12565
12842
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
12566
12843
  var SUBAPP_MANIFEST = [
12567
12844
  { prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
@@ -12581,7 +12858,7 @@ for (const m of SUBAPP_MANIFEST) {
12581
12858
  }
12582
12859
  try {
12583
12860
  const registered = [];
12584
- for (const r of app34.routes ?? []) {
12861
+ for (const r of app36.routes ?? []) {
12585
12862
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
12586
12863
  if (AGENT_SLUG_PATTERN.test(r.path)) {
12587
12864
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -12595,7 +12872,7 @@ try {
12595
12872
  (async () => {
12596
12873
  try {
12597
12874
  let userId = "";
12598
- if (existsSync19(USERS_FILE)) {
12875
+ if (existsSync22(USERS_FILE)) {
12599
12876
  const users = JSON.parse(readFileSync16(USERS_FILE, "utf-8").trim() || "[]");
12600
12877
  userId = users[0]?.userId ?? "";
12601
12878
  }
@@ -12648,7 +12925,7 @@ if (bootAccountConfig?.whatsapp) {
12648
12925
  }
12649
12926
  init({
12650
12927
  configDir: configDirForWhatsApp,
12651
- platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
12928
+ platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
12652
12929
  accountConfig: bootAccountConfig,
12653
12930
  onMessage: async (msg) => {
12654
12931
  try {