@rubytech/create-realagent 1.0.663 → 1.0.665

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 (53) hide show
  1. package/dist/index.js +5 -1
  2. package/package.json +1 -1
  3. package/payload/platform/neo4j/schema.cypher +34 -1
  4. package/payload/platform/plugins/docs/references/memory-guide.md +2 -2
  5. package/payload/platform/plugins/docs/references/platform.md +1 -1
  6. package/payload/platform/plugins/docs/references/troubleshooting.md +24 -6
  7. package/payload/platform/scripts/vnc.sh +174 -2
  8. package/payload/server/public/assets/{admin-C9qoVb2l.js → admin-Brug36E-.js} +5 -5
  9. package/payload/server/public/assets/data-woLf2Tmp.js +1 -0
  10. package/payload/server/public/assets/{file-lmzx24EO.js → file-rN5uuyaV.js} +1 -1
  11. package/payload/server/public/assets/{graph-DkjvCb8B.js → graph-BYaOEZUg.js} +16 -16
  12. package/payload/server/public/assets/{house-ClhI06TA.js → house-DnFgpCt2.js} +1 -1
  13. package/payload/server/public/assets/jsx-runtime-CSCPZpLN.css +1 -0
  14. package/payload/server/public/assets/{public-Dz33-dIE.js → public-BRrqpeVH.js} +1 -1
  15. package/payload/server/public/assets/{share-2-MZ4MqbjS.js → share-2-DLjRUEiG.js} +1 -1
  16. package/payload/server/public/assets/{useVoiceRecorder-Cm0G51D_.js → useVoiceRecorder-D_efR3Nx.js} +1 -1
  17. package/payload/server/public/assets/{x-CLhtM_Mh.js → x-L6KPMfIN.js} +1 -1
  18. package/payload/server/public/data.html +6 -6
  19. package/payload/server/public/graph.html +6 -6
  20. package/payload/server/public/index.html +7 -7
  21. package/payload/server/public/public.html +4 -4
  22. package/payload/server/server.js +360 -126
  23. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.test.d.ts +0 -2
  24. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.test.d.ts.map +0 -1
  25. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.test.js +0 -224
  26. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.test.js.map +0 -1
  27. package/payload/platform/plugins/documents/mcp/dist/index.d.ts +0 -2
  28. package/payload/platform/plugins/documents/mcp/dist/index.d.ts.map +0 -1
  29. package/payload/platform/plugins/documents/mcp/dist/index.js +0 -98
  30. package/payload/platform/plugins/documents/mcp/dist/index.js.map +0 -1
  31. package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.test.d.ts +0 -2
  32. package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.test.d.ts.map +0 -1
  33. package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.test.js +0 -233
  34. package/payload/platform/plugins/memory/mcp/dist/lib/semantic-chunker.test.js.map +0 -1
  35. package/payload/platform/plugins/memory/mcp/dist/scripts/graph-prune.d.ts +0 -18
  36. package/payload/platform/plugins/memory/mcp/dist/scripts/graph-prune.d.ts.map +0 -1
  37. package/payload/platform/plugins/memory/mcp/dist/scripts/graph-prune.js +0 -80
  38. package/payload/platform/plugins/memory/mcp/dist/scripts/graph-prune.js.map +0 -1
  39. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-run.d.ts +0 -7
  40. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-run.d.ts.map +0 -1
  41. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-run.js +0 -10
  42. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-run.js.map +0 -1
  43. package/payload/platform/plugins/waitlist/mcp/dist/lib/anthropic.d.ts +0 -23
  44. package/payload/platform/plugins/waitlist/mcp/dist/lib/anthropic.d.ts.map +0 -1
  45. package/payload/platform/plugins/waitlist/mcp/dist/lib/anthropic.js +0 -115
  46. package/payload/platform/plugins/waitlist/mcp/dist/lib/anthropic.js.map +0 -1
  47. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts +0 -12
  48. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.d.ts.map +0 -1
  49. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js +0 -197
  50. package/payload/platform/plugins/waitlist/mcp/dist/tools/waitlist-extract.js.map +0 -1
  51. package/payload/server/public/assets/data-C-WE3FGr.js +0 -1
  52. package/payload/server/public/assets/jsx-runtime-CLCFnMYD.css +0 -1
  53. /package/payload/server/public/assets/{jsx-runtime-ImbU973I.js → jsx-runtime-XWiDQoTG.js} +0 -0
@@ -1201,14 +1201,14 @@ var Hono = class _Hono {
1201
1201
  * app.route("/api", app2) // GET /api/user
1202
1202
  * ```
1203
1203
  */
1204
- route(path2, app35) {
1204
+ route(path2, app36) {
1205
1205
  const subApp = this.basePath(path2);
1206
- app35.routes.map((r) => {
1206
+ app36.routes.map((r) => {
1207
1207
  let handler;
1208
- if (app35.errorHandler === errorHandler) {
1208
+ if (app36.errorHandler === errorHandler) {
1209
1209
  handler = r.handler;
1210
1210
  } else {
1211
- handler = async (c, next) => (await compose([], app35.errorHandler)(c, () => r.handler(c, next))).res;
1211
+ handler = async (c, next) => (await compose([], app36.errorHandler)(c, () => r.handler(c, next))).res;
1212
1212
  handler[COMPOSED_HANDLER] = r.handler;
1213
1213
  }
1214
1214
  subApp.#addRoute(r.method, r.path, handler);
@@ -4501,6 +4501,7 @@ function resolveBrowserTransport(req, remoteAddress) {
4501
4501
  return transport;
4502
4502
  }
4503
4503
  var currentCdpDisplay = null;
4504
+ var currentTerminalDisplay = null;
4504
4505
  function discoverNativeDisplay() {
4505
4506
  const fallback = { sessionType: "x11", display: ":0", waylandDisplay: "" };
4506
4507
  try {
@@ -4671,6 +4672,73 @@ async function ensureCdp(transport = "vnc") {
4671
4672
  function killChromium() {
4672
4673
  spawnSync("pkill", ["-f", "chromium"], { stdio: "pipe" });
4673
4674
  }
4675
+ function terminalAlive() {
4676
+ const result = spawnSync("bash", [VNC_SCRIPT, "status-terminal"], {
4677
+ stdio: "pipe",
4678
+ timeout: 2e3
4679
+ });
4680
+ return result.status === 0;
4681
+ }
4682
+ async function ensureTerminal(transport = "vnc") {
4683
+ const targetSentinel = transport === "native" ? "native" : ":99";
4684
+ if (terminalAlive()) {
4685
+ if (currentTerminalDisplay !== null && currentTerminalDisplay !== targetSentinel) {
4686
+ console.error(`[ensureTerminal] Display switch: ${currentTerminalDisplay} \u2192 ${targetSentinel}`);
4687
+ vncLog("ensure-terminal", {
4688
+ action: "display-switch",
4689
+ transport,
4690
+ from_display: currentTerminalDisplay,
4691
+ to_display: targetSentinel
4692
+ });
4693
+ killTerminal();
4694
+ await sleep(500);
4695
+ } else {
4696
+ if (currentTerminalDisplay === null) {
4697
+ currentTerminalDisplay = targetSentinel;
4698
+ }
4699
+ vncLog("ensure-terminal", { action: "already-running", transport });
4700
+ return true;
4701
+ }
4702
+ }
4703
+ const vncCommand = transport === "native" ? "start-terminal-native" : "start-terminal";
4704
+ if (transport === "vnc") {
4705
+ const xAlive = await waitForPort(5900, 1e3);
4706
+ if (!xAlive) {
4707
+ console.error("[ensureTerminal] X server down on :5900 \u2014 escalating to full VNC restart");
4708
+ vncLog("ensure-terminal", { action: "escalate-vnc-restart", reason: "x-down", transport });
4709
+ const vncOk = await ensureVnc();
4710
+ if (!vncOk) {
4711
+ console.error("[ensureTerminal] Full VNC restart failed \u2014 terminal degraded");
4712
+ vncLog("ensure-terminal", { action: "degraded", reason: "vnc-restart-failed", transport });
4713
+ return false;
4714
+ }
4715
+ }
4716
+ }
4717
+ if (transport === "native") {
4718
+ const nativeInfo = discoverNativeDisplay();
4719
+ vncLog("ensure-terminal", {
4720
+ action: "native-display-resolved",
4721
+ transport,
4722
+ session_type: nativeInfo.sessionType,
4723
+ display: nativeInfo.display
4724
+ });
4725
+ }
4726
+ console.error(`[ensureTerminal] Launching terminal (${vncCommand}) for transport=${transport}`);
4727
+ vncLog("ensure-terminal", { action: `launch-${vncCommand}`, transport });
4728
+ try {
4729
+ execFileSync("bash", [VNC_SCRIPT, vncCommand], { timeout: 1e4 });
4730
+ } catch (err) {
4731
+ vncLog("ensure-terminal", { action: "launch-failed", transport, err: err.message });
4732
+ return false;
4733
+ }
4734
+ currentTerminalDisplay = targetSentinel;
4735
+ vncLog("ensure-terminal", { action: "launch-complete", transport, sentinel: targetSentinel });
4736
+ return true;
4737
+ }
4738
+ function killTerminal() {
4739
+ spawnSync("bash", [VNC_SCRIPT, "kill-terminal"], { stdio: "pipe", timeout: 5e3 });
4740
+ currentTerminalDisplay = null;
4741
+ }
4674
4742
  function writeChromiumWrapper() {
4675
4743
  mkdirSync4(BIN_DIR, { recursive: true });
4676
4744
  const wrapperPath = resolve5(BIN_DIR, "chromium");
@@ -5212,9 +5280,11 @@ async function persistToolCall(record) {
5212
5280
  await session.close();
5213
5281
  }
5214
5282
  }
5283
+ var SUMMARY_MAX_LEN = 200;
5215
5284
  async function persistMessage(conversationId, role, content, accountId, tokens, createdAt, sender) {
5216
5285
  if (!content) return null;
5217
5286
  const messageId = randomUUID();
5287
+ const summary = role === "user" ? content.slice(0, SUMMARY_MAX_LEN).trim() : "";
5218
5288
  let embedding = null;
5219
5289
  try {
5220
5290
  embedding = await embed(content);
@@ -5223,8 +5293,17 @@ async function persistMessage(conversationId, role, content, accountId, tokens,
5223
5293
  }
5224
5294
  const session = getSession();
5225
5295
  try {
5226
- await session.run(
5227
- `CREATE (m:Message {
5296
+ const result = await session.run(
5297
+ `MATCH (c:Conversation {conversationId: $conversationId})
5298
+ OPTIONAL MATCH (tail:Message)-[:PART_OF]->(c)
5299
+ WHERE NOT (tail)-[:NEXT]->(:Message)
5300
+ // Capture whether THIS write's guard will fire. Read c.summary
5301
+ // before the SET so the boolean reflects the pre-state, not the
5302
+ // post-state \u2014 a false positive otherwise when a new user message
5303
+ // happens to equal an already-set summary (verbatim retry, short
5304
+ // catchphrase) and fooled a post-state equality check.
5305
+ WITH c, tail, (c.summary IS NULL AND $role = 'user' AND $summary <> '') AS summarySetThisWrite
5306
+ CREATE (m:Message {
5228
5307
  messageId: $messageId,
5229
5308
  conversationId: $conversationId,
5230
5309
  accountId: $accountId,
@@ -5238,16 +5317,24 @@ async function persistMessage(conversationId, role, content, accountId, tokens,
5238
5317
  ${tokens?.cacheReadTokens != null ? ", cacheReadTokens: $cacheReadTokens" : ""}
5239
5318
  ${tokens?.cacheCreationTokens != null ? ", cacheCreationTokens: $cacheCreationTokens" : ""}
5240
5319
  })
5241
- WITH m
5242
- MATCH (c:Conversation {conversationId: $conversationId})
5243
5320
  SET c.updatedAt = datetime()
5244
- CREATE (m)-[:PART_OF]->(c)`,
5321
+ CREATE (m)-[:PART_OF]->(c)
5322
+ FOREACH (prev IN CASE WHEN tail IS NULL THEN [] ELSE [tail] END |
5323
+ CREATE (prev)-[:NEXT]->(m)
5324
+ )
5325
+ FOREACH (_ IN CASE WHEN summarySetThisWrite THEN [1] ELSE [] END |
5326
+ SET c.summary = $summary
5327
+ )
5328
+ RETURN tail.messageId AS prevMessageId,
5329
+ summarySetThisWrite,
5330
+ size([(m2:Message)-[:PART_OF]->(c) | m2]) AS chainLen`,
5245
5331
  {
5246
5332
  messageId,
5247
5333
  conversationId,
5248
5334
  accountId,
5249
5335
  role,
5250
5336
  content,
5337
+ summary,
5251
5338
  ...createdAt ? { createdAt } : {},
5252
5339
  ...embedding ? { embedding } : {},
5253
5340
  ...sender ? { senderVisitorId: sender.visitorId, senderName: sender.displayName } : {},
@@ -5257,6 +5344,19 @@ async function persistMessage(conversationId, role, content, accountId, tokens,
5257
5344
  ...tokens?.cacheCreationTokens != null ? { cacheCreationTokens: neo4j.int(tokens.cacheCreationTokens) } : {}
5258
5345
  }
5259
5346
  );
5347
+ if (result.records.length === 0) {
5348
+ console.error(`[persist] Neo4j write skipped \u2014 conversation not found: ${conversationId.slice(0, 8)}\u2026`);
5349
+ return null;
5350
+ }
5351
+ const record = result.records[0];
5352
+ const prevMessageId = record.get("prevMessageId") ?? null;
5353
+ const summarySetThisWrite = record.get("summarySetThisWrite") === true;
5354
+ const chainLenRaw = record.get("chainLen");
5355
+ const chainLen = typeof chainLenRaw === "bigint" ? Number(chainLenRaw) : typeof chainLenRaw?.toNumber === "function" ? chainLenRaw.toNumber() : Number(chainLenRaw ?? 0);
5356
+ console.error(`[neo4j-store] append-message conversationId=${conversationId.slice(0, 8)}\u2026 messageId=${messageId.slice(0, 8)}\u2026 prev=${prevMessageId ? prevMessageId.slice(0, 8) + "\u2026" : "null"} chainLen=${chainLen}`);
5357
+ if (summarySetThisWrite) {
5358
+ console.error(`[neo4j-store] conversation-summary-set conversationId=${conversationId.slice(0, 8)}\u2026 len=${summary.length}`);
5359
+ }
5260
5360
  console.error(`[persist] ${(/* @__PURE__ */ new Date()).toISOString()} conversationId=${conversationId.slice(0, 8)}\u2026 role=${role} len=${content.length}${sender ? ` sender=${sender.displayName}` : ""}`);
5261
5361
  return messageId;
5262
5362
  } catch (err) {
@@ -18461,7 +18561,16 @@ app9.post("/", async (c) => {
18461
18561
  return c.text("Invalid JSON", 400);
18462
18562
  }
18463
18563
  const kindRaw = typeof body.kind === "string" ? body.kind : "unknown";
18464
- const allowedKinds = /* @__PURE__ */ new Set(["uncaught", "unhandled-rejection", "subresource", "test", "unknown"]);
18564
+ const allowedKinds = /* @__PURE__ */ new Set([
18565
+ "uncaught",
18566
+ "unhandled-rejection",
18567
+ "subresource",
18568
+ "test",
18569
+ "unknown",
18570
+ "graph-labels-in-graph",
18571
+ "graph-default-view",
18572
+ "graph-neighbourhood-pivot"
18573
+ ]);
18465
18574
  const kind = allowedKinds.has(kindRaw) ? kindRaw : "unknown";
18466
18575
  const msg = truncate2(body.msg, MAX_MSG_LEN);
18467
18576
  const url = truncate2(body.url, MAX_URL_LEN);
@@ -18550,6 +18659,41 @@ async function createAdminSession(accountId, thinkingView, userId, userName) {
18550
18659
  };
18551
18660
  }
18552
18661
  var app10 = new Hono2();
18662
+ app10.get("/", async (c) => {
18663
+ const sessionKey = c.req.query("session_key");
18664
+ if (!sessionKey || !validateSession(sessionKey, "admin")) {
18665
+ return c.json({ error: "Invalid or expired admin session" }, 401);
18666
+ }
18667
+ const accountId = getAccountIdForSession(sessionKey);
18668
+ if (!accountId) {
18669
+ return c.json({ error: "Session has no account binding" }, 401);
18670
+ }
18671
+ const account = resolveAccount();
18672
+ const thinkingView = account?.config.thinkingView ?? "default";
18673
+ let onboardingComplete = true;
18674
+ try {
18675
+ const step = await loadOnboardingStep(accountId);
18676
+ onboardingComplete = step === null || step >= 8;
18677
+ } catch (err) {
18678
+ console.error(`[session] restore onboarding query failed: ${err instanceof Error ? err.message : String(err)}`);
18679
+ }
18680
+ let businessName;
18681
+ try {
18682
+ const branding = await fetchBranding(accountId);
18683
+ businessName = branding?.name || void 0;
18684
+ } catch {
18685
+ }
18686
+ return c.json({
18687
+ session_key: sessionKey,
18688
+ agent_id: "admin",
18689
+ userId: getUserIdForSession(sessionKey),
18690
+ userName: getUserNameForSession(sessionKey),
18691
+ thinkingView,
18692
+ onboardingComplete,
18693
+ businessName,
18694
+ conversationId: getConversationIdForSession(sessionKey) ?? null
18695
+ });
18696
+ });
18553
18697
  app10.post("/", async (c) => {
18554
18698
  let body;
18555
18699
  try {
@@ -19721,6 +19865,44 @@ app20.post("/launch", async (c) => {
19721
19865
  });
19722
19866
  var browser_default = app20;
19723
19867
 
19868
+ // server/routes/admin/terminal.ts
19869
+ var app21 = new Hono2();
19870
+ app21.post("/launch", async (c) => {
19871
+ try {
19872
+ const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
19873
+ if (transport === "vnc") {
19874
+ const vncOk = await ensureVnc();
19875
+ if (!vncOk) {
19876
+ return c.json({ ok: false, error: "VNC failed to start" }, 502);
19877
+ }
19878
+ }
19879
+ const terminalOk = await ensureTerminal(transport);
19880
+ if (!terminalOk) {
19881
+ return c.json({ ok: false, error: "Terminal failed to start" }, 502);
19882
+ }
19883
+ return c.json({ ok: true, transport });
19884
+ } catch (err) {
19885
+ console.error("[admin/terminal/launch] Failed to start terminal:", err);
19886
+ return c.json(
19887
+ { ok: false, error: err instanceof Error ? err.message : "Unknown error" },
19888
+ 500
19889
+ );
19890
+ }
19891
+ });
19892
+ app21.post("/close", (c) => {
19893
+ try {
19894
+ killTerminal();
19895
+ return c.json({ ok: true });
19896
+ } catch (err) {
19897
+ console.error("[admin/terminal/close] kill failed:", err);
19898
+ return c.json(
19899
+ { ok: false, error: err instanceof Error ? err.message : "Unknown error" },
19900
+ 500
19901
+ );
19902
+ }
19903
+ });
19904
+ var terminal_default = app21;
19905
+
19724
19906
  // app/lib/cdp-client.ts
19725
19907
  var CDP_HOST = "127.0.0.1";
19726
19908
  var CDP_PORT = 9222;
@@ -19762,8 +19944,8 @@ async function cdpNavigateNewTab(url, opts = {}) {
19762
19944
  }
19763
19945
 
19764
19946
  // server/routes/admin/device-browser.ts
19765
- var app21 = new Hono2();
19766
- app21.post("/navigate", async (c) => {
19947
+ var app22 = new Hono2();
19948
+ app22.post("/navigate", async (c) => {
19767
19949
  const TAG19 = "[device-url:click]";
19768
19950
  let body;
19769
19951
  try {
@@ -19850,7 +20032,7 @@ app21.post("/navigate", async (c) => {
19850
20032
  targetId: outcome.targetId
19851
20033
  });
19852
20034
  });
19853
- var device_browser_default = app21;
20035
+ var device_browser_default = app22;
19854
20036
 
19855
20037
  // server/routes/admin/events.ts
19856
20038
  var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
@@ -19859,8 +20041,8 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
19859
20041
  "device-url:vnc-surface-shown",
19860
20042
  "device-url:malformed"
19861
20043
  ]);
19862
- var app22 = new Hono2();
19863
- app22.post("/", async (c) => {
20044
+ var app23 = new Hono2();
20045
+ app23.post("/", async (c) => {
19864
20046
  const TAG19 = "[admin:events]";
19865
20047
  let body;
19866
20048
  try {
@@ -19891,7 +20073,7 @@ app22.post("/", async (c) => {
19891
20073
  console.error(`[${event}] ${formatted}`);
19892
20074
  return c.json({ ok: true });
19893
20075
  });
19894
- var events_default = app22;
20076
+ var events_default = app23;
19895
20077
 
19896
20078
  // server/routes/admin/cloudflare.ts
19897
20079
  import { homedir as homedir4 } from "os";
@@ -19984,7 +20166,7 @@ function validateBody(body) {
19984
20166
  }
19985
20167
  return null;
19986
20168
  }
19987
- var app23 = new Hono2();
20169
+ var app24 = new Hono2();
19988
20170
  function fieldFromReason(reason) {
19989
20171
  switch (reason) {
19990
20172
  case "not-signed-in":
@@ -20001,7 +20183,7 @@ function fieldFromReason(reason) {
20001
20183
  return "script";
20002
20184
  }
20003
20185
  }
20004
- app23.get("/domains", requireAdminSession, async (c) => {
20186
+ app24.get("/domains", requireAdminSession, async (c) => {
20005
20187
  const started = Date.now();
20006
20188
  const sessionKey = c.var.sessionKey;
20007
20189
  let correlationId;
@@ -20094,7 +20276,7 @@ ${result.stderr}` : ""}`;
20094
20276
  );
20095
20277
  return c.json(success, 200);
20096
20278
  });
20097
- app23.post("/setup", requireAdminSession, async (c) => {
20279
+ app24.post("/setup", requireAdminSession, async (c) => {
20098
20280
  const started = Date.now();
20099
20281
  const sessionKey = c.var.sessionKey;
20100
20282
  let correlationId;
@@ -20232,7 +20414,7 @@ ${result.stderr}` : ""}`;
20232
20414
  log2(`phase=response-sent`);
20233
20415
  return resp;
20234
20416
  });
20235
- var cloudflare_default = app23;
20417
+ var cloudflare_default = app24;
20236
20418
 
20237
20419
  // server/routes/admin/files.ts
20238
20420
  import { createReadStream as createReadStream3 } from "fs";
@@ -20584,8 +20766,8 @@ function buildDisplayPath(relPath, accountNames) {
20584
20766
  return dn ? { name: seg, displayName: dn } : { name: seg };
20585
20767
  });
20586
20768
  }
20587
- var app24 = new Hono2();
20588
- app24.get("/", requireAdminSession, async (c) => {
20769
+ var app25 = new Hono2();
20770
+ app25.get("/", requireAdminSession, async (c) => {
20589
20771
  const sessionKey = c.var.sessionKey;
20590
20772
  if (!getAccountIdForSession(sessionKey)) {
20591
20773
  console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
@@ -20646,7 +20828,7 @@ app24.get("/", requireAdminSession, async (c) => {
20646
20828
  return c.json({ error: message }, 500);
20647
20829
  }
20648
20830
  });
20649
- app24.get("/download", requireAdminSession, async (c) => {
20831
+ app25.get("/download", requireAdminSession, async (c) => {
20650
20832
  const sessionKey = c.var.sessionKey;
20651
20833
  if (!getAccountIdForSession(sessionKey)) {
20652
20834
  console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
@@ -20694,7 +20876,7 @@ app24.get("/download", requireAdminSession, async (c) => {
20694
20876
  return c.json({ error: message }, 500);
20695
20877
  }
20696
20878
  });
20697
- app24.post("/upload", requireAdminSession, async (c) => {
20879
+ app25.post("/upload", requireAdminSession, async (c) => {
20698
20880
  const sessionKey = c.var.sessionKey;
20699
20881
  const accountId = getAccountIdForSession(sessionKey);
20700
20882
  if (!accountId) {
@@ -20752,7 +20934,7 @@ app24.post("/upload", requireAdminSession, async (c) => {
20752
20934
  mimeType: file.type
20753
20935
  });
20754
20936
  });
20755
- app24.delete("/", requireAdminSession, async (c) => {
20937
+ app25.delete("/", requireAdminSession, async (c) => {
20756
20938
  const sessionKey = c.var.sessionKey;
20757
20939
  const accountId = getAccountIdForSession(sessionKey);
20758
20940
  if (!accountId) {
@@ -20819,13 +21001,13 @@ app24.delete("/", requireAdminSession, async (c) => {
20819
21001
  return c.json({ error: message }, 500);
20820
21002
  }
20821
21003
  });
20822
- var files_default = app24;
21004
+ var files_default = app25;
20823
21005
 
20824
21006
  // server/routes/admin/graph-search.ts
20825
21007
  var DEFAULT_LIMIT = 20;
20826
21008
  var MAX_LIMIT = 100;
20827
- var app25 = new Hono2();
20828
- app25.get("/", requireAdminSession, async (c) => {
21009
+ var app26 = new Hono2();
21010
+ app26.get("/", requireAdminSession, async (c) => {
20829
21011
  const sessionKey = c.var.sessionKey;
20830
21012
  const q = (c.req.query("q") ?? "").trim();
20831
21013
  const rawLimit = c.req.query("limit");
@@ -20850,7 +21032,10 @@ app25.get("/", requireAdminSession, async (c) => {
20850
21032
  return c.json({ error: `Graph search unavailable: ${message}` }, 503);
20851
21033
  }
20852
21034
  });
20853
- var graph_search_default = app25;
21035
+ var graph_search_default = app26;
21036
+
21037
+ // server/routes/admin/graph-subgraph.ts
21038
+ import neo4j3 from "neo4j-driver";
20854
21039
 
20855
21040
  // app/lib/graph-labels.ts
20856
21041
  var GRAPH_LABEL_COLOURS = {
@@ -20893,7 +21078,13 @@ var GRAPH_LABEL_COLOURS = {
20893
21078
  OnboardingState: "#8B5CF6",
20894
21079
  // Email
20895
21080
  Email: "#65A30D",
20896
- EmailAccount: "#84CC16"
21081
+ EmailAccount: "#84CC16",
21082
+ // Review signals (Task 626 — previously written by review-detector but
21083
+ // unregistered here, producing an `unknown label` 400 whenever the
21084
+ // filter popover advertised the label. Registry reconciled so every
21085
+ // label written anywhere in the codebase has a colour + a 200 from
21086
+ // graph-subgraph default mode).
21087
+ ReviewAlert: "#DC2626"
20897
21088
  };
20898
21089
  var ALL_GRAPH_LABELS = Object.freeze(
20899
21090
  Object.keys(GRAPH_LABEL_COLOURS)
@@ -20901,6 +21092,9 @@ var ALL_GRAPH_LABELS = Object.freeze(
20901
21092
  var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
20902
21093
  /* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
20903
21094
  );
21095
+ var FILTER_EXCLUDED_LABELS = Object.freeze(
21096
+ /* @__PURE__ */ new Set(["ToolCall", "WorkflowRun", "WorkflowStep", "ReviewAlert"])
21097
+ );
20904
21098
  function isKnownLabel(label) {
20905
21099
  return Object.prototype.hasOwnProperty.call(GRAPH_LABEL_COLOURS, label);
20906
21100
  }
@@ -20917,8 +21111,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
20917
21111
  "otpCode",
20918
21112
  "sessionKey"
20919
21113
  ]);
20920
- var app26 = new Hono2();
20921
- app26.get("/", requireAdminSession, async (c) => {
21114
+ var app27 = new Hono2();
21115
+ app27.get("/", requireAdminSession, async (c) => {
20922
21116
  const sessionKey = c.var.sessionKey;
20923
21117
  const accountId = getAccountIdForSession(sessionKey);
20924
21118
  if (!accountId) {
@@ -21143,22 +21337,31 @@ var NEIGHBOURHOOD_CYPHER = `
21143
21337
  [x IN windowNodes | {id: elementId(x), labels: labels(x), properties: properties(x)}] AS nodes,
21144
21338
  [e IN rawEdges WHERE e IS NOT NULL] AS edges
21145
21339
  `;
21340
+ function convertNeo4jValue(value) {
21341
+ if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
21342
+ return value.toString();
21343
+ }
21344
+ if (neo4j3.isInt(value)) {
21345
+ return value.inSafeRange() ? value.toNumber() : value.toString();
21346
+ }
21347
+ return value;
21348
+ }
21146
21349
  function pruneNode(node) {
21147
21350
  const properties = {};
21148
21351
  for (const [key, value] of Object.entries(node.properties ?? {})) {
21149
21352
  if (STRIPPED_PROPERTIES.has(key)) continue;
21150
- properties[key] = value;
21353
+ properties[key] = convertNeo4jValue(value);
21151
21354
  }
21152
21355
  const trashed = (node.labels ?? []).includes("Trashed");
21153
21356
  const labels = (node.labels ?? []).filter((l) => l !== "Trashed");
21154
21357
  return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
21155
21358
  }
21156
- var graph_subgraph_default = app26;
21359
+ var graph_subgraph_default = app27;
21157
21360
 
21158
21361
  // server/routes/admin/graph-delete.ts
21159
21362
  var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
21160
- var app27 = new Hono2();
21161
- app27.post("/", requireAdminSession, async (c) => {
21363
+ var app28 = new Hono2();
21364
+ app28.post("/", requireAdminSession, async (c) => {
21162
21365
  const sessionKey = c.var.sessionKey;
21163
21366
  const accountId = getAccountIdForSession(sessionKey);
21164
21367
  if (!accountId) {
@@ -21229,11 +21432,11 @@ app27.post("/", requireAdminSession, async (c) => {
21229
21432
  }
21230
21433
  }
21231
21434
  });
21232
- var graph_delete_default = app27;
21435
+ var graph_delete_default = app28;
21233
21436
 
21234
21437
  // server/routes/admin/graph-restore.ts
21235
- var app28 = new Hono2();
21236
- app28.post("/", requireAdminSession, async (c) => {
21438
+ var app29 = new Hono2();
21439
+ app29.post("/", requireAdminSession, async (c) => {
21237
21440
  const sessionKey = c.var.sessionKey;
21238
21441
  const accountId = getAccountIdForSession(sessionKey);
21239
21442
  if (!accountId) {
@@ -21297,11 +21500,11 @@ app28.post("/", requireAdminSession, async (c) => {
21297
21500
  }
21298
21501
  }
21299
21502
  });
21300
- var graph_restore_default = app28;
21503
+ var graph_restore_default = app29;
21301
21504
 
21302
21505
  // server/routes/admin/graph-labels-in-graph.ts
21303
- var app29 = new Hono2();
21304
- app29.get("/", requireAdminSession, async (c) => {
21506
+ var app30 = new Hono2();
21507
+ app30.get("/", requireAdminSession, async (c) => {
21305
21508
  const sessionKey = c.var.sessionKey;
21306
21509
  const accountId = getAccountIdForSession(sessionKey);
21307
21510
  if (!accountId) {
@@ -21311,16 +21514,23 @@ app29.get("/", requireAdminSession, async (c) => {
21311
21514
  const started = Date.now();
21312
21515
  const session = getSession();
21313
21516
  try {
21314
- const hidden = [...HIDDEN_BY_DEFAULT_LABELS];
21517
+ const excluded = [...HIDDEN_BY_DEFAULT_LABELS, ...FILTER_EXCLUDED_LABELS];
21315
21518
  const result = await session.executeRead(async (tx) => {
21316
- return await tx.run(LABELS_IN_GRAPH_CYPHER, { accountId, hidden });
21519
+ return await tx.run(LABELS_IN_GRAPH_CYPHER, { accountId, excluded });
21520
+ });
21521
+ const labels = result.records.map((r) => ({
21522
+ label: String(r.get("label")),
21523
+ nodeCount: toNumber(r.get("nodeCount")),
21524
+ relDegree: toNumber(r.get("relDegree")),
21525
+ childOnly: toBool(r.get("childOnly"))
21526
+ })).filter((row) => row.nodeCount > 0).sort((a, b) => {
21527
+ if (b.relDegree !== a.relDegree) return b.relDegree - a.relDegree;
21528
+ return a.label.localeCompare(b.label);
21317
21529
  });
21318
- const record = result.records[0];
21319
- const rawLabels = record?.get("labels") ?? [];
21320
- const labels = [...new Set(rawLabels)].sort();
21321
21530
  const elapsed = Date.now() - started;
21531
+ const summary = labels.map((l) => `${l.label}:${l.nodeCount}:${l.relDegree}:${l.childOnly ? 1 : 0}`).join(",");
21322
21532
  console.error(
21323
- `[graph-page] labels-in-graph account=${accountId} labels=${labels.join(",")} ms=${elapsed}`
21533
+ `[graph-page] labels-in-graph account=${accountId} labels=${summary} ms=${elapsed}`
21324
21534
  );
21325
21535
  return c.json({ labels });
21326
21536
  } catch (err) {
@@ -21337,21 +21547,44 @@ app29.get("/", requireAdminSession, async (c) => {
21337
21547
  }
21338
21548
  }
21339
21549
  });
21550
+ function toNumber(v) {
21551
+ if (typeof v === "bigint") return Number(v);
21552
+ if (typeof v === "number") return v;
21553
+ return Number(v ?? 0);
21554
+ }
21555
+ function toBool(v) {
21556
+ return v === true;
21557
+ }
21340
21558
  var LABELS_IN_GRAPH_CYPHER = `
21341
21559
  MATCH (n)
21342
21560
  WHERE n.accountId = $accountId
21343
21561
  AND NOT n:Trashed
21344
21562
  AND n.deletedAt IS NULL
21345
- UNWIND labels(n) AS lbl
21346
- WITH DISTINCT lbl
21347
- WHERE NOT lbl IN $hidden
21348
- RETURN collect(lbl) AS labels
21563
+ WITH n,
21564
+ [l IN labels(n) WHERE NOT l IN $excluded] AS keptLabels,
21565
+ size([(n)--() | 1]) AS halfEdges
21566
+ UNWIND keptLabels AS label
21567
+ WITH label, n, halfEdges,
21568
+ EXISTS {
21569
+ MATCH (other)-[]->(n)
21570
+ WHERE NOT other:Trashed
21571
+ AND other.deletedAt IS NULL
21572
+ AND NONE(ol IN labels(other) WHERE ol = label)
21573
+ } AS hasNonSelfInbound
21574
+ WITH label,
21575
+ count(DISTINCT n) AS nodeCount,
21576
+ sum(halfEdges) AS relDegree,
21577
+ count(DISTINCT CASE WHEN hasNonSelfInbound THEN n END) AS qualifyingCount
21578
+ RETURN label,
21579
+ nodeCount,
21580
+ relDegree,
21581
+ (nodeCount > 0 AND qualifyingCount = nodeCount) AS childOnly
21349
21582
  `;
21350
- var graph_labels_in_graph_default = app29;
21583
+ var graph_labels_in_graph_default = app30;
21351
21584
 
21352
21585
  // server/routes/admin/graph-default-view.ts
21353
- var app30 = new Hono2();
21354
- app30.get("/", requireAdminSession, async (c) => {
21586
+ var app31 = new Hono2();
21587
+ app31.get("/", requireAdminSession, async (c) => {
21355
21588
  const sessionKey = c.var.sessionKey;
21356
21589
  const accountId = getAccountIdForSession(sessionKey);
21357
21590
  const userId = getUserIdForSession(sessionKey);
@@ -21389,7 +21622,7 @@ app30.get("/", requireAdminSession, async (c) => {
21389
21622
  }
21390
21623
  }
21391
21624
  });
21392
- app30.put("/", requireAdminSession, async (c) => {
21625
+ app31.put("/", requireAdminSession, async (c) => {
21393
21626
  const sessionKey = c.var.sessionKey;
21394
21627
  const accountId = getAccountIdForSession(sessionKey);
21395
21628
  const userId = getUserIdForSession(sessionKey);
@@ -21471,11 +21704,11 @@ var WRITE_CYPHER = `
21471
21704
  p.updatedAt = $updatedAt
21472
21705
  RETURN p.labels AS labels
21473
21706
  `;
21474
- var graph_default_view_default = app30;
21707
+ var graph_default_view_default = app31;
21475
21708
 
21476
21709
  // server/routes/admin/file-attach.ts
21477
- var app31 = new Hono2();
21478
- app31.post("/", async (c) => {
21710
+ var app32 = new Hono2();
21711
+ app32.post("/", async (c) => {
21479
21712
  try {
21480
21713
  const body = await c.req.json();
21481
21714
  const { filePath, accountId } = body;
@@ -21498,11 +21731,11 @@ app31.post("/", async (c) => {
21498
21731
  return c.json({ error: message }, 500);
21499
21732
  }
21500
21733
  });
21501
- var file_attach_default = app31;
21734
+ var file_attach_default = app32;
21502
21735
 
21503
21736
  // server/routes/admin/adherence.ts
21504
- var app32 = new Hono2();
21505
- app32.get("/", requireAdminSession, async (c) => {
21737
+ var app33 = new Hono2();
21738
+ app33.get("/", requireAdminSession, async (c) => {
21506
21739
  const agent = c.req.query("agent") ?? "admin";
21507
21740
  const includeBlock = c.req.query("block") === "1";
21508
21741
  const account = resolveAccount();
@@ -21523,34 +21756,35 @@ app32.get("/", requireAdminSession, async (c) => {
21523
21756
  return c.json({ error: "Failed to read adherence ledger", agent }, 500);
21524
21757
  }
21525
21758
  });
21526
- var adherence_default = app32;
21759
+ var adherence_default = app33;
21527
21760
 
21528
21761
  // server/routes/admin/index.ts
21529
- var app33 = new Hono2();
21530
- app33.route("/session", session_default2);
21531
- app33.route("/chat", chat_default2);
21532
- app33.route("/compact", compact_default);
21533
- app33.route("/logs", logs_default);
21534
- app33.route("/claude-info", claude_info_default);
21535
- app33.route("/attachment", attachment_default);
21536
- app33.route("/account", account_default);
21537
- app33.route("/agents", agents_default);
21538
- app33.route("/version", version_default);
21539
- app33.route("/sessions", sessions_default);
21540
- app33.route("/browser", browser_default);
21541
- app33.route("/device-browser", device_browser_default);
21542
- app33.route("/events", events_default);
21543
- app33.route("/cloudflare", cloudflare_default);
21544
- app33.route("/files", files_default);
21545
- app33.route("/graph-search", graph_search_default);
21546
- app33.route("/graph-subgraph", graph_subgraph_default);
21547
- app33.route("/graph-delete", graph_delete_default);
21548
- app33.route("/graph-restore", graph_restore_default);
21549
- app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
21550
- app33.route("/graph-default-view", graph_default_view_default);
21551
- app33.route("/file-attach", file_attach_default);
21552
- app33.route("/adherence", adherence_default);
21553
- var admin_default = app33;
21762
+ var app34 = new Hono2();
21763
+ app34.route("/session", session_default2);
21764
+ app34.route("/chat", chat_default2);
21765
+ app34.route("/compact", compact_default);
21766
+ app34.route("/logs", logs_default);
21767
+ app34.route("/claude-info", claude_info_default);
21768
+ app34.route("/attachment", attachment_default);
21769
+ app34.route("/account", account_default);
21770
+ app34.route("/agents", agents_default);
21771
+ app34.route("/version", version_default);
21772
+ app34.route("/sessions", sessions_default);
21773
+ app34.route("/browser", browser_default);
21774
+ app34.route("/terminal", terminal_default);
21775
+ app34.route("/device-browser", device_browser_default);
21776
+ app34.route("/events", events_default);
21777
+ app34.route("/cloudflare", cloudflare_default);
21778
+ app34.route("/files", files_default);
21779
+ app34.route("/graph-search", graph_search_default);
21780
+ app34.route("/graph-subgraph", graph_subgraph_default);
21781
+ app34.route("/graph-delete", graph_delete_default);
21782
+ app34.route("/graph-restore", graph_restore_default);
21783
+ app34.route("/graph-labels-in-graph", graph_labels_in_graph_default);
21784
+ app34.route("/graph-default-view", graph_default_view_default);
21785
+ app34.route("/file-attach", file_attach_default);
21786
+ app34.route("/adherence", adherence_default);
21787
+ var admin_default = app34;
21554
21788
 
21555
21789
  // server/index.ts
21556
21790
  var PLATFORM_ROOT11 = process.env.MAXY_PLATFORM_ROOT || "";
@@ -21608,9 +21842,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
21608
21842
  function isPublicHost(host) {
21609
21843
  return host.startsWith("public.") || aliasDomains.has(host);
21610
21844
  }
21611
- var app34 = new Hono2();
21612
- app34.use("*", clientIpMiddleware);
21613
- app34.use("*", async (c, next) => {
21845
+ var app35 = new Hono2();
21846
+ app35.use("*", clientIpMiddleware);
21847
+ app35.use("*", async (c, next) => {
21614
21848
  await next();
21615
21849
  c.header("X-Content-Type-Options", "nosniff");
21616
21850
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -21633,7 +21867,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
21633
21867
  "/g/"
21634
21868
  ];
21635
21869
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
21636
- app34.use("*", async (c, next) => {
21870
+ app35.use("*", async (c, next) => {
21637
21871
  const host = (c.req.header("host") ?? "").split(":")[0];
21638
21872
  if (!isPublicHost(host)) {
21639
21873
  await next();
@@ -21673,7 +21907,7 @@ function resolveRemoteAuthOpts() {
21673
21907
  return brandLoginOpts;
21674
21908
  }
21675
21909
  var MAX_LOGIN_BODY = 8 * 1024;
21676
- app34.post("/__remote-auth/login", async (c) => {
21910
+ app35.post("/__remote-auth/login", async (c) => {
21677
21911
  const clientIp = c.var.clientIp || "unknown";
21678
21912
  const rateLimited = checkRateLimit(clientIp);
21679
21913
  if (rateLimited) {
@@ -21709,7 +21943,7 @@ app34.post("/__remote-auth/login", async (c) => {
21709
21943
  }
21710
21944
  });
21711
21945
  });
21712
- app34.get("/__remote-auth/logout", (c) => {
21946
+ app35.get("/__remote-auth/logout", (c) => {
21713
21947
  const cookieHeader = c.req.header("cookie");
21714
21948
  const token = parseCookie(cookieHeader, "__remote_session");
21715
21949
  if (token) invalidateRemoteSession(token);
@@ -21722,7 +21956,7 @@ app34.get("/__remote-auth/logout", (c) => {
21722
21956
  }
21723
21957
  });
21724
21958
  });
21725
- app34.post("/__remote-auth/change-password", async (c) => {
21959
+ app35.post("/__remote-auth/change-password", async (c) => {
21726
21960
  const clientIp = c.var.clientIp || "unknown";
21727
21961
  const rateLimited = checkRateLimit(clientIp);
21728
21962
  if (rateLimited) {
@@ -21771,13 +22005,13 @@ app34.post("/__remote-auth/change-password", async (c) => {
21771
22005
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
21772
22006
  }
21773
22007
  });
21774
- app34.get("/__remote-auth/setup", (c) => {
22008
+ app35.get("/__remote-auth/setup", (c) => {
21775
22009
  if (isRemoteAuthConfigured()) {
21776
22010
  return c.redirect("/");
21777
22011
  }
21778
22012
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
21779
22013
  });
21780
- app34.post("/__remote-auth/set-initial-password", async (c) => {
22014
+ app35.post("/__remote-auth/set-initial-password", async (c) => {
21781
22015
  if (isRemoteAuthConfigured()) {
21782
22016
  return c.redirect("/");
21783
22017
  }
@@ -21813,10 +22047,10 @@ app34.post("/__remote-auth/set-initial-password", async (c) => {
21813
22047
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
21814
22048
  }
21815
22049
  });
21816
- app34.get("/api/remote-auth/status", (c) => {
22050
+ app35.get("/api/remote-auth/status", (c) => {
21817
22051
  return c.json({ configured: isRemoteAuthConfigured() });
21818
22052
  });
21819
- app34.post("/api/remote-auth/set-password", async (c) => {
22053
+ app35.post("/api/remote-auth/set-password", async (c) => {
21820
22054
  let body;
21821
22055
  try {
21822
22056
  body = await c.req.json();
@@ -21846,9 +22080,9 @@ app34.post("/api/remote-auth/set-password", async (c) => {
21846
22080
  return c.json({ error: "Failed to save password" }, 500);
21847
22081
  }
21848
22082
  });
21849
- app34.route("/api/_client-error", client_error_default);
22083
+ app35.route("/api/_client-error", client_error_default);
21850
22084
  console.log("[client-error-route] mounted");
21851
- app34.use("*", async (c, next) => {
22085
+ app35.use("*", async (c, next) => {
21852
22086
  const host = (c.req.header("host") ?? "").split(":")[0];
21853
22087
  const path2 = c.req.path;
21854
22088
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -21888,15 +22122,15 @@ function parseCookie(cookieHeader, name) {
21888
22122
  return null;
21889
22123
  }
21890
22124
  }
21891
- app34.route("/api/health", health_default);
21892
- app34.route("/api/session", session_default);
21893
- app34.route("/api/chat", chat_default);
21894
- app34.route("/api/group", group_default);
21895
- app34.route("/api/access", access_default);
21896
- app34.route("/api/telegram", telegram_default);
21897
- app34.route("/api/whatsapp", whatsapp_default);
21898
- app34.route("/api/onboarding", onboarding_default);
21899
- app34.route("/api/admin", admin_default);
22125
+ app35.route("/api/health", health_default);
22126
+ app35.route("/api/session", session_default);
22127
+ app35.route("/api/chat", chat_default);
22128
+ app35.route("/api/group", group_default);
22129
+ app35.route("/api/access", access_default);
22130
+ app35.route("/api/telegram", telegram_default);
22131
+ app35.route("/api/whatsapp", whatsapp_default);
22132
+ app35.route("/api/onboarding", onboarding_default);
22133
+ app35.route("/api/admin", admin_default);
21900
22134
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
21901
22135
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
21902
22136
  var IMAGE_MIME = {
@@ -21908,7 +22142,7 @@ var IMAGE_MIME = {
21908
22142
  ".svg": "image/svg+xml",
21909
22143
  ".ico": "image/x-icon"
21910
22144
  };
21911
- app34.get("/agent-assets/:slug/:filename", (c) => {
22145
+ app35.get("/agent-assets/:slug/:filename", (c) => {
21912
22146
  const slug = c.req.param("slug");
21913
22147
  const filename = c.req.param("filename");
21914
22148
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -21943,7 +22177,7 @@ app34.get("/agent-assets/:slug/:filename", (c) => {
21943
22177
  "Cache-Control": "public, max-age=3600"
21944
22178
  });
21945
22179
  });
21946
- app34.get("/generated/:filename", (c) => {
22180
+ app35.get("/generated/:filename", (c) => {
21947
22181
  const filename = c.req.param("filename");
21948
22182
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
21949
22183
  console.error(`[generated] serve file=${filename} status=403`);
@@ -22108,7 +22342,7 @@ function brandedPublicHtml(agentSlug) {
22108
22342
  function escapeHtml2(s) {
22109
22343
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
22110
22344
  }
22111
- app34.get("/", (c) => {
22345
+ app35.get("/", (c) => {
22112
22346
  const host = (c.req.header("host") ?? "").split(":")[0];
22113
22347
  if (isPublicHost(host)) {
22114
22348
  const defaultSlug = resolveDefaultSlug();
@@ -22116,12 +22350,12 @@ app34.get("/", (c) => {
22116
22350
  }
22117
22351
  return c.html(cachedHtml("index.html"));
22118
22352
  });
22119
- app34.get("/public", (c) => {
22353
+ app35.get("/public", (c) => {
22120
22354
  const host = (c.req.header("host") ?? "").split(":")[0];
22121
22355
  if (isPublicHost(host)) return c.text("Not found", 404);
22122
22356
  return c.html(cachedHtml("public.html"));
22123
22357
  });
22124
- app34.get("/chat", (c) => {
22358
+ app35.get("/chat", (c) => {
22125
22359
  const host = (c.req.header("host") ?? "").split(":")[0];
22126
22360
  if (isPublicHost(host)) return c.text("Not found", 404);
22127
22361
  return c.html(cachedHtml("public.html"));
@@ -22140,9 +22374,9 @@ async function logViewerFetch(c, next) {
22140
22374
  duration_ms: Date.now() - start
22141
22375
  });
22142
22376
  }
22143
- app34.use("/vnc-viewer.html", logViewerFetch);
22144
- app34.use("/vnc-popout.html", logViewerFetch);
22145
- app34.get("/vnc-popout.html", (c) => {
22377
+ app35.use("/vnc-viewer.html", logViewerFetch);
22378
+ app35.use("/vnc-popout.html", logViewerFetch);
22379
+ app35.get("/vnc-popout.html", (c) => {
22146
22380
  let html = htmlCache.get("vnc-popout.html");
22147
22381
  if (!html) {
22148
22382
  html = readFileSync26(resolve30(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -22155,7 +22389,7 @@ app34.get("/vnc-popout.html", (c) => {
22155
22389
  }
22156
22390
  return c.html(html);
22157
22391
  });
22158
- app34.post("/api/vnc/client-event", async (c) => {
22392
+ app35.post("/api/vnc/client-event", async (c) => {
22159
22393
  let body;
22160
22394
  try {
22161
22395
  body = await c.req.json();
@@ -22176,20 +22410,20 @@ app34.post("/api/vnc/client-event", async (c) => {
22176
22410
  });
22177
22411
  return c.json({ ok: true });
22178
22412
  });
22179
- app34.get("/g/:slug", (c) => {
22413
+ app35.get("/g/:slug", (c) => {
22180
22414
  return c.html(brandedPublicHtml());
22181
22415
  });
22182
- app34.get("/graph", (c) => {
22416
+ app35.get("/graph", (c) => {
22183
22417
  const host = (c.req.header("host") ?? "").split(":")[0];
22184
22418
  if (isPublicHost(host)) return c.text("Not found", 404);
22185
22419
  return c.html(cachedHtml("graph.html"));
22186
22420
  });
22187
- app34.get("/data", (c) => {
22421
+ app35.get("/data", (c) => {
22188
22422
  const host = (c.req.header("host") ?? "").split(":")[0];
22189
22423
  if (isPublicHost(host)) return c.text("Not found", 404);
22190
22424
  return c.html(cachedHtml("data.html"));
22191
22425
  });
22192
- app34.get("/:slug", async (c, next) => {
22426
+ app35.get("/:slug", async (c, next) => {
22193
22427
  const slug = c.req.param("slug");
22194
22428
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
22195
22429
  const branding = loadBrandingCache(slug);
@@ -22198,10 +22432,10 @@ app34.get("/:slug", async (c, next) => {
22198
22432
  }
22199
22433
  await next();
22200
22434
  });
22201
- app34.use("/*", serveStatic({ root: "./public" }));
22435
+ app35.use("/*", serveStatic({ root: "./public" }));
22202
22436
  var port = parseInt(process.env.PORT ?? "19200", 10);
22203
22437
  var hostname = process.env.HOSTNAME ?? "0.0.0.0";
22204
- var httpServer = serve({ fetch: app34.fetch, port, hostname });
22438
+ var httpServer = serve({ fetch: app35.fetch, port, hostname });
22205
22439
  attachVncWsProxy(httpServer, {
22206
22440
  isPublicHost,
22207
22441
  upstreamHost: "127.0.0.1",
@@ -22247,7 +22481,7 @@ for (const m of SUBAPP_MANIFEST) {
22247
22481
  }
22248
22482
  try {
22249
22483
  const registered = [];
22250
- for (const r of app34.routes ?? []) {
22484
+ for (const r of app35.routes ?? []) {
22251
22485
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
22252
22486
  if (AGENT_SLUG_PATTERN.test(r.path)) {
22253
22487
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });