@rubytech/create-maxy-code 0.1.88 → 0.1.91

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 (130) hide show
  1. package/dist/__tests__/entitlement-flag.test.js +43 -0
  2. package/dist/__tests__/tier-flag.test.js +53 -0
  3. package/dist/index.js +99 -0
  4. package/dist/port-resolution.js +1 -1
  5. package/dist/tier-flag.js +85 -0
  6. package/package.json +1 -1
  7. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +54 -0
  8. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -0
  9. package/payload/platform/lib/admin-conversation-purge/dist/index.js +84 -0
  10. package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -0
  11. package/payload/platform/lib/admin-conversation-purge/src/index.ts +120 -0
  12. package/payload/platform/lib/admin-conversation-purge/tsconfig.json +8 -0
  13. package/payload/platform/lib/graph-trash/dist/index.d.ts +12 -1
  14. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
  15. package/payload/platform/lib/graph-trash/dist/index.js +8 -1
  16. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
  17. package/payload/platform/lib/graph-trash/src/index.ts +20 -2
  18. package/payload/platform/package.json +2 -2
  19. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  20. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  21. package/payload/platform/plugins/admin/hooks/__tests__/askuserquestion-investigate-gate.test.sh +176 -0
  22. package/payload/platform/plugins/admin/hooks/askuserquestion-investigate-gate.sh +257 -0
  23. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +2 -0
  24. package/payload/platform/plugins/docs/references/admin-session.md +5 -1
  25. package/payload/platform/plugins/docs/references/linkedin-extension.md +49 -0
  26. package/payload/platform/plugins/linkedin-extension/.claude-plugin/plugin.json +8 -0
  27. package/payload/platform/plugins/linkedin-extension/PLUGIN.md +58 -0
  28. package/payload/platform/plugins/linkedin-extension/extension/README.md +44 -0
  29. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/profile.html +34 -0
  30. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/thread.html +36 -0
  31. package/payload/platform/plugins/linkedin-extension/extension/assets/pill.css +52 -0
  32. package/payload/platform/plugins/linkedin-extension/extension/background/sw.js +60 -0
  33. package/payload/platform/plugins/linkedin-extension/extension/content/extractors.js +127 -0
  34. package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +82 -0
  35. package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +84 -0
  36. package/payload/platform/plugins/linkedin-extension/extension/manifest.json +32 -0
  37. package/payload/platform/plugins/linkedin-extension/extension/options/options.html +33 -0
  38. package/payload/platform/plugins/linkedin-extension/extension/options/options.js +30 -0
  39. package/payload/platform/plugins/linkedin-extension/skills/linkedin-extension/SKILL.md +91 -0
  40. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +14 -0
  41. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -1
  42. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +28 -0
  43. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -1
  44. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts +2 -0
  45. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts.map +1 -0
  46. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +168 -0
  47. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -0
  48. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +22 -3
  49. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -1
  50. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +61 -13
  51. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -1
  52. package/payload/platform/scripts/seed-neo4j.sh +12 -0
  53. package/payload/platform/templates/agents/admin/IDENTITY.md +3 -1
  54. package/payload/platform/templates/specialists/agents/database-operator.md +6 -2
  55. package/payload/premium-plugins/real-agent/plugins/brochures/skills/make-brochure/SKILL.md +1 -1
  56. package/payload/server/public/assets/{ChatInput-BzjU6OoA.css → ChatInput-dLWJ0Q8I.css} +1 -1
  57. package/payload/server/public/assets/{Checkbox-BWLS5Isf.js → Checkbox-Bx8mRHQ3.js} +1 -1
  58. package/payload/server/public/assets/{admin-DjU0q63n.js → admin-C57bDUgs.js} +6 -6
  59. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-lcncWUol.js → architectureDiagram-Q4EWVU46-BEW_bD50.js} +1 -1
  60. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-SqlxCp6m.js → blockDiagram-DXYQGD6D-DFLT98C3.js} +1 -1
  61. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DWzvXvDc.js → c4Diagram-AHTNJAMY-BemKtROA.js} +1 -1
  62. package/payload/server/public/assets/channel-CfpByn-m.js +1 -0
  63. package/payload/server/public/assets/{chunk-336JU56O-Bz-tPZhS.js → chunk-336JU56O-BL8fGJ7_.js} +2 -2
  64. package/payload/server/public/assets/{chunk-426QAEUC-MYkbqx1u.js → chunk-426QAEUC-BD6by0MP.js} +1 -1
  65. package/payload/server/public/assets/{chunk-4TB4RGXK-DfZRQtaZ.js → chunk-4TB4RGXK-DX-cb6Nd.js} +1 -1
  66. package/payload/server/public/assets/{chunk-5FUZZQ4R-BFMrOiNe.js → chunk-5FUZZQ4R-B2QqtIZS.js} +1 -1
  67. package/payload/server/public/assets/{chunk-5PVQY5BW-64laDovl.js → chunk-5PVQY5BW-CzJWmsmd.js} +1 -1
  68. package/payload/server/public/assets/{chunk-EDXVE4YY-dClAHBNd.js → chunk-EDXVE4YY-DP9vcvEU.js} +1 -1
  69. package/payload/server/public/assets/{chunk-ENJZ2VHE-Bz4gXG1p.js → chunk-ENJZ2VHE-D5xWEjF0.js} +1 -1
  70. package/payload/server/public/assets/{chunk-ICPOFSXX-D5pWrJcN.js → chunk-ICPOFSXX-AKduf9o4.js} +1 -1
  71. package/payload/server/public/assets/{chunk-OYMX7WX6-BCiWtqaK.js → chunk-OYMX7WX6-D6jsVNyQ.js} +1 -1
  72. package/payload/server/public/assets/{chunk-U2HBQHQK-Brql314T.js → chunk-U2HBQHQK-BNAnTYh8.js} +1 -1
  73. package/payload/server/public/assets/{chunk-X2U36JSP-C-79tMym.js → chunk-X2U36JSP-UdQhYDnh.js} +1 -1
  74. package/payload/server/public/assets/{chunk-YZCP3GAM-G4idHEoZ.js → chunk-YZCP3GAM-DSSmSGmS.js} +1 -1
  75. package/payload/server/public/assets/{chunk-ZZ45TVLE-DyHGASIn.js → chunk-ZZ45TVLE-Czm7IDMC.js} +1 -1
  76. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DNc9R1IX.js +1 -0
  77. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DM1DQh8N.js +1 -0
  78. package/payload/server/public/assets/clone-BSrNdvLW.js +1 -0
  79. package/payload/server/public/assets/{dagre-KV5264BT--Bba_VRf.js → dagre-KV5264BT-CBuRCJE7.js} +1 -1
  80. package/payload/server/public/assets/{dagre-DfJ8a8tG.js → dagre-hSIMHJcO.js} +1 -1
  81. package/payload/server/public/assets/data-3n20lir5.js +1 -0
  82. package/payload/server/public/assets/{diagram-5BDNPKRD-CfUotMr9.js → diagram-5BDNPKRD-dbMrH0le.js} +1 -1
  83. package/payload/server/public/assets/{diagram-G4DWMVQ6-BWZJChPS.js → diagram-G4DWMVQ6-DBc6hs9a.js} +1 -1
  84. package/payload/server/public/assets/{diagram-MMDJMWI5-BExS6IWb.js → diagram-MMDJMWI5-ubSGybUk.js} +1 -1
  85. package/payload/server/public/assets/{diagram-TYMM5635-DQ4t_wIt.js → diagram-TYMM5635-WxL3cv-9.js} +1 -1
  86. package/payload/server/public/assets/{erDiagram-SMLLAGMA-f1sfB-AQ.js → erDiagram-SMLLAGMA-CrBBOAN8.js} +1 -1
  87. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CZexxT3v.js → flowDiagram-DWJPFMVM-CXUq5Hzt.js} +1 -1
  88. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BNcFUX4K.js → ganttDiagram-T4ZO3ILL-vTCBnYVS.js} +1 -1
  89. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-soyylUaR.js → gitGraphDiagram-UUTBAWPF-BHrj_bRa.js} +1 -1
  90. package/payload/server/public/assets/graph-ChwMpxn_.js +1 -0
  91. package/payload/server/public/assets/graph-labels-CUgJgIwl.js +1 -0
  92. package/payload/server/public/assets/{graphlib-B2ezMQY4.js → graphlib-CDO75l2X.js} +1 -1
  93. package/payload/server/public/assets/{infoDiagram-42DDH7IO-4xmenbOP.js → infoDiagram-42DDH7IO-CcQdaOhi.js} +1 -1
  94. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-C_D6CqVq.js → ishikawaDiagram-UXIWVN3A-3KvltFgV.js} +1 -1
  95. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DUDx0c35.js → journeyDiagram-VCZTEJTY-DZCXaGFE.js} +1 -1
  96. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BNr7ErhZ.js → kanban-definition-6JOO6SKY-DAIAKy1-.js} +1 -1
  97. package/payload/server/public/assets/{lib-iKom7FFe.js → lib-CCLURO3E.js} +1 -1
  98. package/payload/server/public/assets/{line-Dvs5wrj5.js → line-C8iCE2Wx.js} +1 -1
  99. package/payload/server/public/assets/{mermaid-parser.core-D0ksZQlW.js → mermaid-parser.core-ElvUhnV9.js} +1 -1
  100. package/payload/server/public/assets/{mermaid.core--Btu4mYy.js → mermaid.core-7dSH31Ao.js} +3 -3
  101. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DfyZTghB.js → mindmap-definition-QFDTVHPH-FZ0rcfac.js} +1 -1
  102. package/payload/server/public/assets/{page-BnBmdRbo.js → page-D3bFmqF4.js} +1 -1
  103. package/payload/server/public/assets/{page-x6ZXWwMx.js → page-DNjUtT5q.js} +18 -17
  104. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BiG9YoLj.js → pieDiagram-DEJITSTG-CDuvMZbO.js} +1 -1
  105. package/payload/server/public/assets/{public-DW7yINk7.js → public-g_2skbnY.js} +3 -3
  106. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CVufUsie.js → quadrantDiagram-34T5L4WZ-xDjhkqNc.js} +1 -1
  107. package/payload/server/public/assets/{requirementDiagram-MS252O5E-UKCptCPk.js → requirementDiagram-MS252O5E-BPKpyT0n.js} +1 -1
  108. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-e8iZYL5P.js → sankeyDiagram-XADWPNL6-BvFIrihC.js} +1 -1
  109. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CfZqVRxe.js → sequenceDiagram-FGHM5R23-C6G1oAE0.js} +1 -1
  110. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DrWX8OY8.js → stateDiagram-FHFEXIEX-DbOJT_Xh.js} +1 -1
  111. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Ce4GFk-H.js +1 -0
  112. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Blec2Yhc.js → timeline-definition-GMOUNBTQ-D1DSxHh6.js} +1 -1
  113. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BtACuGgu.js → vennDiagram-DHZGUBPP-BYoSeMdo.js} +1 -1
  114. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BWT7orYV.js → wardleyDiagram-NUSXRM2D-DH3kZdea.js} +1 -1
  115. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DBzoIRiJ.js → xychartDiagram-5P7HB3ND-C6MROMLG.js} +1 -1
  116. package/payload/server/public/data.html +5 -5
  117. package/payload/server/public/graph.html +6 -6
  118. package/payload/server/public/index.html +8 -8
  119. package/payload/server/public/public.html +5 -5
  120. package/payload/server/server-init.cjs +35 -3
  121. package/payload/server/server.js +547 -118
  122. package/payload/server/public/assets/channel-dZdJT-Ou.js +0 -1
  123. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CP8AWLB9.js +0 -1
  124. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-bUe6tAo9.js +0 -1
  125. package/payload/server/public/assets/clone-gXHQCPU0.js +0 -1
  126. package/payload/server/public/assets/data-Bt6BTjvP.js +0 -1
  127. package/payload/server/public/assets/graph-labels-BeDsoEVY.js +0 -1
  128. package/payload/server/public/assets/graph-szVcmw8D.js +0 -1
  129. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CvKXSO97.js +0 -1
  130. /package/payload/server/public/assets/{ChatInput-AR8ym-HW.js → ChatInput-DoS80kaC.js} +0 -0
@@ -344,8 +344,11 @@ var require_dist = __commonJS({
344
344
  try {
345
345
  await onEmpty(c);
346
346
  } catch (err) {
347
- process.stderr.write(`[trash:empty-run] onEmpty side-effect failed for elementId=${c.elementId}: ${err instanceof Error ? err.message : String(err)}
347
+ const id8 = c.elementId.slice(0, 8);
348
+ const message = err instanceof Error ? err.message : String(err);
349
+ process.stderr.write(`[trash:empty-run] reason=onEmpty-failed elementId=${id8} labels=${c.labels.join(",")} message=${message}
348
350
  `);
351
+ continue;
349
352
  }
350
353
  }
351
354
  await session.run(`MATCH (n) WHERE elementId(n) = $eid DETACH DELETE n`, { eid: c.elementId });
@@ -598,6 +601,7 @@ var serveStatic = (options = { root: "" }) => {
598
601
  import { readFileSync as readFileSync20, existsSync as existsSync22, watchFile } from "fs";
599
602
  import { resolve as resolve23, join as join13, basename as basename5 } from "path";
600
603
  import { homedir as homedir4 } from "os";
604
+ import { monitorEventLoopDelay } from "perf_hooks";
601
605
 
602
606
  // app/lib/agent-slug-pattern.ts
603
607
  var AGENT_SLUG_PATTERN = /^\/([a-z][a-z0-9-]{2,49})$/;
@@ -7191,29 +7195,22 @@ import crypto from "crypto";
7191
7195
  import { resolve as resolvePath } from "path";
7192
7196
  import { existsSync as existsSync13, mkdirSync as mkdirSync3, createWriteStream } from "fs";
7193
7197
 
7194
- // app/lib/admin-conversation-cascade.ts
7195
- async function cascadeAdminConversationDelete(args) {
7196
- const started = Date.now();
7198
+ // ../lib/admin-conversation-purge/src/index.ts
7199
+ async function purgeAdminConversationJsonls(args) {
7197
7200
  const fetchImpl = args.fetchImpl ?? fetch;
7198
7201
  const log = args.logger ?? ((line) => console.log(line));
7199
7202
  const id8 = args.conversationId.slice(0, 8);
7200
- let claudeSessionIds;
7201
- try {
7202
- claudeSessionIds = args.claudeSessionIds ?? await getConversationClaudeSessionIds(args.conversationId, args.accountId);
7203
- } catch (err) {
7204
- const message = err instanceof Error ? err.message : String(err);
7205
- log(`[admin-conversation-delete] conversationId=${id8} reason=graph-delete-failed claudeSessionIds-purged= message=transcript-resolve:${message}`);
7206
- return { ok: false, reason: "graph-delete-failed", claudeSessionIdsPurged: [], message };
7207
- }
7208
7203
  const purged = [];
7209
- for (const sessionId of claudeSessionIds) {
7204
+ for (const sessionId of args.claudeSessionIds) {
7210
7205
  const url = `${args.managerBase}/${encodeURIComponent(sessionId)}`;
7211
7206
  let res;
7212
7207
  try {
7213
7208
  res = await fetchImpl(url, { method: "DELETE" });
7214
7209
  } catch (err) {
7215
7210
  const message2 = err instanceof Error ? err.message : String(err);
7216
- log(`[admin-conversation-delete] conversationId=${id8} reason=jsonl-purge-failed claudeSessionId=${sessionId.slice(0, 8)} message=${message2}`);
7211
+ log(
7212
+ `[admin-conversation-delete] conversationId=${id8} reason=jsonl-purge-failed claudeSessionId=${sessionId.slice(0, 8)} message=${message2}`
7213
+ );
7217
7214
  return {
7218
7215
  ok: false,
7219
7216
  reason: "jsonl-purge-failed",
@@ -7228,8 +7225,15 @@ async function cascadeAdminConversationDelete(args) {
7228
7225
  continue;
7229
7226
  }
7230
7227
  if (res.status === 409) {
7231
- log(`[admin-conversation-delete] conversationId=${id8} reason=pty-still-alive claudeSessionId=${sessionId.slice(0, 8)}`);
7232
- return { ok: false, reason: "pty-still-alive", claudeSessionId: sessionId };
7228
+ log(
7229
+ `[admin-conversation-delete] conversationId=${id8} reason=pty-still-alive claudeSessionId=${sessionId.slice(0, 8)}`
7230
+ );
7231
+ return {
7232
+ ok: false,
7233
+ reason: "pty-still-alive",
7234
+ claudeSessionId: sessionId,
7235
+ claudeSessionIdsPurged: purged
7236
+ };
7233
7237
  }
7234
7238
  let message = `manager returned ${res.status}`;
7235
7239
  try {
@@ -7238,7 +7242,9 @@ async function cascadeAdminConversationDelete(args) {
7238
7242
  else if (typeof body.error === "string") message = body.error;
7239
7243
  } catch {
7240
7244
  }
7241
- log(`[admin-conversation-delete] conversationId=${id8} reason=jsonl-purge-failed claudeSessionId=${sessionId.slice(0, 8)} message=${message}`);
7245
+ log(
7246
+ `[admin-conversation-delete] conversationId=${id8} reason=jsonl-purge-failed claudeSessionId=${sessionId.slice(0, 8)} message=${message}`
7247
+ );
7242
7248
  return {
7243
7249
  ok: false,
7244
7250
  reason: "jsonl-purge-failed",
@@ -7248,6 +7254,45 @@ async function cascadeAdminConversationDelete(args) {
7248
7254
  message
7249
7255
  };
7250
7256
  }
7257
+ return { ok: true, claudeSessionIdsPurged: purged };
7258
+ }
7259
+
7260
+ // app/lib/admin-conversation-cascade.ts
7261
+ async function cascadeAdminConversationDelete(args) {
7262
+ const started = Date.now();
7263
+ const fetchImpl = args.fetchImpl ?? fetch;
7264
+ const log = args.logger ?? ((line) => console.log(line));
7265
+ const id8 = args.conversationId.slice(0, 8);
7266
+ let claudeSessionIds;
7267
+ try {
7268
+ claudeSessionIds = args.claudeSessionIds ?? await getConversationClaudeSessionIds(args.conversationId, args.accountId);
7269
+ } catch (err) {
7270
+ const message = err instanceof Error ? err.message : String(err);
7271
+ log(`[admin-conversation-delete] conversationId=${id8} reason=graph-delete-failed claudeSessionIds-purged= message=transcript-resolve:${message}`);
7272
+ return { ok: false, reason: "graph-delete-failed", claudeSessionIdsPurged: [], message };
7273
+ }
7274
+ const purgeOutcome = await purgeAdminConversationJsonls({
7275
+ conversationId: args.conversationId,
7276
+ accountId: args.accountId,
7277
+ managerBase: args.managerBase,
7278
+ claudeSessionIds,
7279
+ fetchImpl,
7280
+ logger: log
7281
+ });
7282
+ if (!purgeOutcome.ok) {
7283
+ if (purgeOutcome.reason === "pty-still-alive") {
7284
+ return { ok: false, reason: "pty-still-alive", claudeSessionId: purgeOutcome.claudeSessionId };
7285
+ }
7286
+ return {
7287
+ ok: false,
7288
+ reason: "jsonl-purge-failed",
7289
+ claudeSessionId: purgeOutcome.claudeSessionId,
7290
+ claudeSessionIdsPurged: purgeOutcome.claudeSessionIdsPurged,
7291
+ status: purgeOutcome.status,
7292
+ message: purgeOutcome.message
7293
+ };
7294
+ }
7295
+ const purged = purgeOutcome.claudeSessionIdsPurged;
7251
7296
  let found;
7252
7297
  try {
7253
7298
  ({ found } = await deleteConversation(args.conversationId));
@@ -8695,13 +8740,13 @@ async function cdpNavigateNewTab(url, opts = {}) {
8695
8740
  // server/routes/admin/device-browser.ts
8696
8741
  var app18 = new Hono();
8697
8742
  app18.post("/navigate", async (c) => {
8698
- const TAG21 = "[device-url:click]";
8743
+ const TAG22 = "[device-url:click]";
8699
8744
  let body;
8700
8745
  try {
8701
8746
  body = await c.req.json();
8702
8747
  } catch (err) {
8703
8748
  const detail = err instanceof Error ? err.message : String(err);
8704
- console.error(`${TAG21} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
8749
+ console.error(`${TAG22} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
8705
8750
  return c.json(
8706
8751
  { ok: false, navigateResult: "error", browser: "fallback", detail: "Request body was not valid JSON" },
8707
8752
  400
@@ -8711,7 +8756,7 @@ app18.post("/navigate", async (c) => {
8711
8756
  const intent = typeof body.intent === "string" ? body.intent : "";
8712
8757
  const hostname2 = typeof body.hostname === "string" ? body.hostname : "";
8713
8758
  if (!url) {
8714
- console.error(`${TAG21} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
8759
+ console.error(`${TAG22} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
8715
8760
  return c.json(
8716
8761
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url field is required" },
8717
8762
  400
@@ -8721,7 +8766,7 @@ app18.post("/navigate", async (c) => {
8721
8766
  try {
8722
8767
  parsed = new URL(url);
8723
8768
  } catch {
8724
- console.error(`${TAG21} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
8769
+ console.error(`${TAG22} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
8725
8770
  return c.json(
8726
8771
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url is not a valid URL" },
8727
8772
  400
@@ -8729,7 +8774,7 @@ app18.post("/navigate", async (c) => {
8729
8774
  }
8730
8775
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
8731
8776
  console.error(
8732
- `${TAG21} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
8777
+ `${TAG22} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
8733
8778
  );
8734
8779
  return c.json(
8735
8780
  {
@@ -8745,7 +8790,7 @@ app18.post("/navigate", async (c) => {
8745
8790
  const cdpOk = await ensureCdp(transport);
8746
8791
  if (!cdpOk) {
8747
8792
  console.error(
8748
- `${TAG21} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
8793
+ `${TAG22} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
8749
8794
  );
8750
8795
  return c.json(
8751
8796
  {
@@ -8761,7 +8806,7 @@ app18.post("/navigate", async (c) => {
8761
8806
  const browser = outcome.result === "ok" ? "vnc" : "fallback";
8762
8807
  const detailStr = outcome.detail ? ` detail=${JSON.stringify(outcome.detail.length > 230 ? outcome.detail.slice(0, 227) + "..." : outcome.detail)}` : "";
8763
8808
  console.error(
8764
- `${TAG21} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
8809
+ `${TAG22} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
8765
8810
  );
8766
8811
  if (outcome.result !== "ok") {
8767
8812
  return c.json(
@@ -8792,18 +8837,18 @@ var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
8792
8837
  ]);
8793
8838
  var app19 = new Hono();
8794
8839
  app19.post("/", async (c) => {
8795
- const TAG21 = "[admin:events]";
8840
+ const TAG22 = "[admin:events]";
8796
8841
  let body;
8797
8842
  try {
8798
8843
  body = await c.req.json();
8799
8844
  } catch (err) {
8800
8845
  const detail = err instanceof Error ? err.message : String(err);
8801
- console.error(`${TAG21} reject reason=body-not-json detail=${detail}`);
8846
+ console.error(`${TAG22} reject reason=body-not-json detail=${detail}`);
8802
8847
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
8803
8848
  }
8804
8849
  const event = typeof body.event === "string" ? body.event : "";
8805
8850
  if (!ALLOWED_EVENTS2.has(event)) {
8806
- console.error(`${TAG21} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
8851
+ console.error(`${TAG22} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
8807
8852
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
8808
8853
  }
8809
8854
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -11633,7 +11678,7 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
11633
11678
  var graph_subgraph_default = app23;
11634
11679
 
11635
11680
  // server/routes/admin/graph-delete.ts
11636
- var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
11681
+ var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
11637
11682
  var app24 = new Hono();
11638
11683
  app24.post("/", requireAdminSession, async (c) => {
11639
11684
  const cacheKey = c.var.cacheKey;
@@ -11663,17 +11708,108 @@ app24.post("/", requireAdminSession, async (c) => {
11663
11708
  const lookup = await session.run(
11664
11709
  `MATCH (n)
11665
11710
  WHERE elementId(n) = $elementId AND n.accountId = $accountId
11666
- RETURN labels(n) AS labels LIMIT 1`,
11711
+ RETURN labels(n) AS labels, n.conversationId AS conversationId LIMIT 1`,
11667
11712
  { elementId, accountId }
11668
11713
  );
11669
11714
  if (lookup.records.length === 0) {
11670
11715
  const elapsed2 = Date.now() - started;
11671
11716
  console.error(
11672
- `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels= result=not-found ms=${elapsed2}`
11717
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels= route=trash result=not-found ms=${elapsed2}`
11673
11718
  );
11674
11719
  return c.json({ error: "Node not found" }, 404);
11675
11720
  }
11676
11721
  const preflightLabels = lookup.records[0].get("labels") ?? [];
11722
+ const conversationId = lookup.records[0].get("conversationId");
11723
+ if (preflightLabels.includes("AdminConversation")) {
11724
+ if (!conversationId) {
11725
+ const elapsed3 = Date.now() - started;
11726
+ console.error(
11727
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${preflightLabels.join(",")} route=cascade result=error ms=${elapsed3} err="AdminConversation node has no conversationId"`
11728
+ );
11729
+ return c.json({ error: "AdminConversation node is missing conversationId" }, 500);
11730
+ }
11731
+ const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "graph-page-cascade" });
11732
+ const managerBase3 = `http://127.0.0.1:${managerPort}`;
11733
+ try {
11734
+ await session.close();
11735
+ } catch {
11736
+ }
11737
+ const outcome = await cascadeAdminConversationDelete({
11738
+ conversationId,
11739
+ accountId,
11740
+ managerBase: managerBase3
11741
+ });
11742
+ const elapsed2 = Date.now() - started;
11743
+ const labelSummary2 = preflightLabels.join(",");
11744
+ if (outcome.ok) {
11745
+ console.error(
11746
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary2} route=cascade result=ok ms=${elapsed2}`
11747
+ );
11748
+ const response2 = {
11749
+ route: "cascade",
11750
+ elementId,
11751
+ conversationId,
11752
+ labels: preflightLabels,
11753
+ claudeSessionIds: outcome.claudeSessionIds
11754
+ };
11755
+ return c.json(response2);
11756
+ }
11757
+ if (outcome.reason === "pty-still-alive") {
11758
+ console.error(
11759
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary2} route=cascade result=pty-still-alive claudeSessionId=${outcome.claudeSessionId.slice(0, 8)} ms=${elapsed2}`
11760
+ );
11761
+ return c.json(
11762
+ {
11763
+ error: "pty-still-alive",
11764
+ detail: "stop the session before deleting",
11765
+ claudeSessionId: outcome.claudeSessionId,
11766
+ conversationId
11767
+ },
11768
+ 409
11769
+ );
11770
+ }
11771
+ if (outcome.reason === "conversation-not-found") {
11772
+ console.error(
11773
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary2} route=cascade result=ok-already-gone ms=${elapsed2}`
11774
+ );
11775
+ const response2 = {
11776
+ route: "cascade",
11777
+ elementId,
11778
+ conversationId,
11779
+ labels: preflightLabels,
11780
+ claudeSessionIds: []
11781
+ };
11782
+ return c.json(response2);
11783
+ }
11784
+ if (outcome.reason === "jsonl-purge-failed") {
11785
+ console.error(
11786
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary2} route=cascade result=jsonl-purge-failed claudeSessionId=${outcome.claudeSessionId.slice(0, 8)} ms=${elapsed2} err="${outcome.message}"`
11787
+ );
11788
+ const status = outcome.status >= 400 && outcome.status < 600 ? outcome.status : 502;
11789
+ return c.json(
11790
+ {
11791
+ error: "jsonl-purge-failed",
11792
+ detail: outcome.message,
11793
+ claudeSessionId: outcome.claudeSessionId,
11794
+ conversationId,
11795
+ claudeSessionIdsPurged: outcome.claudeSessionIdsPurged
11796
+ },
11797
+ status
11798
+ );
11799
+ }
11800
+ console.error(
11801
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary2} route=cascade result=graph-delete-failed ms=${elapsed2} err="${outcome.message}"`
11802
+ );
11803
+ return c.json(
11804
+ {
11805
+ error: "graph-delete-failed",
11806
+ detail: outcome.message,
11807
+ conversationId,
11808
+ claudeSessionIdsPurged: outcome.claudeSessionIdsPurged
11809
+ },
11810
+ 500
11811
+ );
11812
+ }
11677
11813
  const result = await trashNode({
11678
11814
  session,
11679
11815
  accountId,
@@ -11683,9 +11819,10 @@ app24.post("/", requireAdminSession, async (c) => {
11683
11819
  const elapsed = Date.now() - started;
11684
11820
  const labelSummary = (result.labels.length > 0 ? result.labels : preflightLabels).join(",");
11685
11821
  console.error(
11686
- `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary} result=ok ms=${elapsed}`
11822
+ `[graph-page] delete account=${accountId} elementId=${elementId} by=${by} labels=${labelSummary} route=trash result=ok ms=${elapsed}`
11687
11823
  );
11688
11824
  const response = {
11825
+ route: "trash",
11689
11826
  elementId: result.nodeId,
11690
11827
  labels: result.labels.length > 0 ? result.labels : preflightLabels,
11691
11828
  trashedAt: result.trashedAt,
@@ -11977,9 +12114,137 @@ var WRITE_CYPHER = `
11977
12114
  `;
11978
12115
  var graph_default_view_default = app27;
11979
12116
 
11980
- // server/routes/admin/file-attach.ts
12117
+ // server/routes/admin/session-defaults.ts
11981
12118
  var app28 = new Hono();
11982
- app28.post("/", async (c) => {
12119
+ var MODE_OPTIONS = ["default", "acceptEdits", "plan", "auto", "bypassPermissions"];
12120
+ var MODEL_OPTIONS = ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"];
12121
+ app28.get("/", requireAdminSession, async (c) => {
12122
+ const cacheKey = c.var.cacheKey;
12123
+ const accountId = getAccountIdForSession(cacheKey);
12124
+ const userId = getUserIdForSession(cacheKey);
12125
+ if (!accountId || !userId) {
12126
+ console.error('[session-defaults] rejected op=load reason="missing account or user context"');
12127
+ return c.json({ error: "Account and user context required for session defaults" }, 401);
12128
+ }
12129
+ const started = Date.now();
12130
+ const session = getSession();
12131
+ try {
12132
+ const result = await session.executeRead(async (tx) => {
12133
+ return await tx.run(READ_CYPHER2, { accountId, userId });
12134
+ });
12135
+ const record = result.records[0];
12136
+ const rawMode = record?.get("permissionMode");
12137
+ const rawModel = record?.get("model");
12138
+ const permissionMode = MODE_OPTIONS.includes(rawMode ?? "") ? rawMode : "default";
12139
+ const model = MODEL_OPTIONS.includes(rawModel ?? "") ? rawModel : null;
12140
+ const elapsed = Date.now() - started;
12141
+ console.error(
12142
+ `[session-defaults] load account=${accountId} user=${userId} permissionMode=${permissionMode} model=${model ?? "null"} ms=${elapsed}`
12143
+ );
12144
+ return c.json({ permissionMode, model });
12145
+ } catch (err) {
12146
+ const elapsed = Date.now() - started;
12147
+ const message = err instanceof Error ? err.message : String(err);
12148
+ console.error(
12149
+ `[session-defaults] rejected op=load account=${accountId} reason="${message}" ms=${elapsed}`
12150
+ );
12151
+ return c.json({ error: `Session defaults unavailable: ${message}` }, 503);
12152
+ } finally {
12153
+ try {
12154
+ await session.close();
12155
+ } catch {
12156
+ }
12157
+ }
12158
+ });
12159
+ app28.put("/", requireAdminSession, async (c) => {
12160
+ const cacheKey = c.var.cacheKey;
12161
+ const accountId = getAccountIdForSession(cacheKey);
12162
+ const userId = getUserIdForSession(cacheKey);
12163
+ if (!accountId || !userId) {
12164
+ console.error('[session-defaults] rejected op=save reason="missing account or user context"');
12165
+ return c.json({ error: "Account and user context required for session defaults" }, 401);
12166
+ }
12167
+ const body = await safeJson(c);
12168
+ if (!body) {
12169
+ return c.json({ error: "Request body must be JSON" }, 400);
12170
+ }
12171
+ const validation = validateBody3(body);
12172
+ if (!validation.ok) {
12173
+ console.error(
12174
+ `[session-defaults] rejected op=save account=${accountId} reason="${validation.reason}"`
12175
+ );
12176
+ return c.json({ error: validation.reason }, 400);
12177
+ }
12178
+ const { permissionMode, model } = validation;
12179
+ const started = Date.now();
12180
+ const session = getSession();
12181
+ try {
12182
+ await session.executeWrite(async (tx) => {
12183
+ return await tx.run(WRITE_CYPHER2, {
12184
+ accountId,
12185
+ userId,
12186
+ permissionMode,
12187
+ model,
12188
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
12189
+ });
12190
+ });
12191
+ const elapsed = Date.now() - started;
12192
+ console.error(
12193
+ `[session-defaults] save account=${accountId} user=${userId} permissionMode=${permissionMode} model=${model ?? "null"} ms=${elapsed}`
12194
+ );
12195
+ return c.json({ permissionMode, model });
12196
+ } catch (err) {
12197
+ const elapsed = Date.now() - started;
12198
+ const message = err instanceof Error ? err.message : String(err);
12199
+ console.error(
12200
+ `[session-defaults] rejected op=save account=${accountId} reason="${message}" ms=${elapsed}`
12201
+ );
12202
+ return c.json({ error: `Failed to save session defaults: ${message}` }, 503);
12203
+ } finally {
12204
+ try {
12205
+ await session.close();
12206
+ } catch {
12207
+ }
12208
+ }
12209
+ });
12210
+ function validateBody3(body) {
12211
+ if (typeof body.permissionMode !== "string") {
12212
+ return { ok: false, reason: "permissionMode must be a string" };
12213
+ }
12214
+ if (!MODE_OPTIONS.includes(body.permissionMode)) {
12215
+ return { ok: false, reason: `permissionMode "${body.permissionMode}" is not one of ${MODE_OPTIONS.join(", ")}` };
12216
+ }
12217
+ if (!("model" in body)) {
12218
+ return { ok: false, reason: "model is required (use null for no override)" };
12219
+ }
12220
+ if (body.model !== null && typeof body.model !== "string") {
12221
+ return { ok: false, reason: "model must be a string or null" };
12222
+ }
12223
+ if (body.model !== null && !MODEL_OPTIONS.includes(body.model)) {
12224
+ return { ok: false, reason: `model "${body.model}" is not one of ${MODEL_OPTIONS.join(", ")} (or null)` };
12225
+ }
12226
+ return {
12227
+ ok: true,
12228
+ permissionMode: body.permissionMode,
12229
+ model: body.model
12230
+ };
12231
+ }
12232
+ var READ_CYPHER2 = `
12233
+ OPTIONAL MATCH (p:SpawnPreference {accountId: $accountId, userId: $userId})
12234
+ RETURN p.permissionMode AS permissionMode, p.model AS model
12235
+ `;
12236
+ var WRITE_CYPHER2 = `
12237
+ MERGE (p:SpawnPreference {accountId: $accountId, userId: $userId})
12238
+ SET p.permissionMode = $permissionMode,
12239
+ p.model = $model,
12240
+ p.updatedAt = $updatedAt
12241
+ RETURN p.permissionMode AS permissionMode
12242
+ `;
12243
+ var session_defaults_default = app28;
12244
+
12245
+ // server/routes/admin/file-attach.ts
12246
+ var app29 = new Hono();
12247
+ app29.post("/", async (c) => {
11983
12248
  try {
11984
12249
  const body = await c.req.json();
11985
12250
  const { filePath, accountId } = body;
@@ -12002,7 +12267,7 @@ app28.post("/", async (c) => {
12002
12267
  return c.json({ error: message }, 500);
12003
12268
  }
12004
12269
  });
12005
- var file_attach_default = app28;
12270
+ var file_attach_default = app29;
12006
12271
 
12007
12272
  // server/routes/admin/sidebar-artefacts.ts
12008
12273
  import neo4j2 from "neo4j-driver";
@@ -12012,8 +12277,8 @@ import { existsSync as existsSync16 } from "fs";
12012
12277
  var LIMIT = 50;
12013
12278
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
12014
12279
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
12015
- var app29 = new Hono();
12016
- app29.get("/", requireAdminSession, async (c) => {
12280
+ var app30 = new Hono();
12281
+ app30.get("/", requireAdminSession, async (c) => {
12017
12282
  const cacheKey = c.var.cacheKey;
12018
12283
  const accountId = getAccountIdForSession(cacheKey);
12019
12284
  if (!accountId) {
@@ -12219,7 +12484,7 @@ function isWithin(target, root) {
12219
12484
  const rel = relative2(root, target);
12220
12485
  return !rel.startsWith("..") && !isAbsolute(rel);
12221
12486
  }
12222
- var sidebar_artefacts_default = app29;
12487
+ var sidebar_artefacts_default = app30;
12223
12488
 
12224
12489
  // server/routes/admin/sidebar-artefact-save.ts
12225
12490
  import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
@@ -12227,8 +12492,8 @@ import { resolve as resolve18 } from "path";
12227
12492
  import { existsSync as existsSync17 } from "fs";
12228
12493
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
12229
12494
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12230
- var app30 = new Hono();
12231
- app30.post("/", requireAdminSession, async (c) => {
12495
+ var app31 = new Hono();
12496
+ app31.post("/", requireAdminSession, async (c) => {
12232
12497
  const cacheKey = c.var.cacheKey;
12233
12498
  const accountId = getAccountIdForSession(cacheKey);
12234
12499
  if (!accountId) return c.json({ error: "Account not found for session" }, 401);
@@ -12340,15 +12605,15 @@ async function resolveSavePath(id, accountId, accountDir) {
12340
12605
  function relPath(absPath, root) {
12341
12606
  return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
12342
12607
  }
12343
- var sidebar_artefact_save_default = app30;
12608
+ var sidebar_artefact_save_default = app31;
12344
12609
 
12345
12610
  // server/routes/admin/sidebar-artefact-content.ts
12346
12611
  import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
12347
12612
  import { existsSync as existsSync18 } from "fs";
12348
12613
  import { resolve as resolve19 } from "path";
12349
12614
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12350
- var app31 = new Hono();
12351
- app31.get("/", requireAdminSession, async (c) => {
12615
+ var app32 = new Hono();
12616
+ app32.get("/", requireAdminSession, async (c) => {
12352
12617
  const cacheKey = c.var.cacheKey;
12353
12618
  const accountId = getAccountIdForSession(cacheKey);
12354
12619
  if (!accountId) return new Response("Unauthorized", { status: 401 });
@@ -12389,7 +12654,7 @@ app31.get("/", requireAdminSession, async (c) => {
12389
12654
  }
12390
12655
  });
12391
12656
  });
12392
- var sidebar_artefact_content_default = app31;
12657
+ var sidebar_artefact_content_default = app32;
12393
12658
 
12394
12659
  // server/routes/admin/health.ts
12395
12660
  import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
@@ -12434,8 +12699,8 @@ async function probeConversationDb() {
12434
12699
  });
12435
12700
  }
12436
12701
  }
12437
- var app32 = new Hono();
12438
- app32.get("/", async (c) => {
12702
+ var app33 = new Hono();
12703
+ app33.get("/", async (c) => {
12439
12704
  const version = readVersion();
12440
12705
  const probe = await probeConversationDb();
12441
12706
  const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
@@ -12457,38 +12722,187 @@ app32.get("/", async (c) => {
12457
12722
  uptimeMs
12458
12723
  });
12459
12724
  });
12460
- var health_default2 = app32;
12725
+ var health_default2 = app33;
12726
+
12727
+ // server/routes/admin/linkedin-ingest.ts
12728
+ var TAG20 = "[linkedin-ingest-route]";
12729
+ var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
12730
+ var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
12731
+ var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
12732
+ function rejectSchema(reason, missing = []) {
12733
+ return { ok: false, status: 400, error: "schema", reason, missing };
12734
+ }
12735
+ function validate(body) {
12736
+ if (!body || typeof body !== "object") return rejectSchema("not-object");
12737
+ const b = body;
12738
+ const missing = [];
12739
+ if (b.source !== "linkedin") missing.push("source");
12740
+ if (b.kind !== "profile" && b.kind !== "thread") missing.push("kind");
12741
+ if (typeof b.capturedAt !== "string" || !ISO.test(b.capturedAt)) missing.push("capturedAt");
12742
+ if (typeof b.pageUrl !== "string" || !LINKEDIN_URL.test(b.pageUrl)) missing.push("pageUrl");
12743
+ if (typeof b.dispatchId !== "string" || !UUID.test(b.dispatchId)) missing.push("dispatchId");
12744
+ if (missing.length) return rejectSchema("envelope", missing);
12745
+ if (b.kind === "profile") {
12746
+ const p = b.profile;
12747
+ if (!p || typeof p !== "object") return rejectSchema("profile-shape", ["profile"]);
12748
+ const pMissing = [];
12749
+ if (typeof p.name !== "string" || !p.name.trim()) pMissing.push("profile.name");
12750
+ if (typeof p.headline !== "string") pMissing.push("profile.headline");
12751
+ if (typeof p.bodyText !== "string" || !p.bodyText.trim()) pMissing.push("profile.bodyText");
12752
+ if (pMissing.length) return rejectSchema("profile-shape", pMissing);
12753
+ } else {
12754
+ const t = b.thread;
12755
+ if (!t || typeof t !== "object") return rejectSchema("thread-shape", ["thread"]);
12756
+ const tMissing = [];
12757
+ if (!Array.isArray(t.participants) || t.participants.length === 0) tMissing.push("thread.participants");
12758
+ if (typeof t.bodyText !== "string" || !t.bodyText.trim()) tMissing.push("thread.bodyText");
12759
+ if (tMissing.length) return rejectSchema("thread-shape", tMissing);
12760
+ }
12761
+ return { ok: true, envelope: b };
12762
+ }
12763
+ function buildInitialMessage(env) {
12764
+ const header = [
12765
+ "LinkedIn ingest \u2014 dispatchId=" + env.dispatchId,
12766
+ "kind=" + env.kind,
12767
+ "sourceUrl=" + env.pageUrl,
12768
+ "capturedAt=" + env.capturedAt
12769
+ ].join(" \xB7 ");
12770
+ if (env.kind === "profile" && env.profile) {
12771
+ const p = env.profile;
12772
+ return [
12773
+ header,
12774
+ "",
12775
+ "Surface: LinkedIn profile. Run the document-ingest skill in document mode against the body below, anchored to a Person subject for this profile.",
12776
+ "",
12777
+ "Conservative-extraction rules apply (see Task 234 spec):",
12778
+ "- One :KnowledgeDocument MERGE keyed on sourceUrl=" + env.pageUrl + " with the verbatim body as body, plus one :Section:Note child with the summary.",
12779
+ "- MERGE :Person on canonical key (name + sourceUrl). When the body assertively states currentCompany, MERGE :Organization and create (:Person)-[:WORKS_AT]->(:Organization).",
12780
+ "- MERGE any other derived entities only when assertively stated in the body. Use whatever ontology label fits (:Event, :Task, :Service, :PriceSpecification, \u2026). Each carries sourceUrl=" + env.pageUrl + ".",
12781
+ "- (:KD)-[:MENTIONS]->(:Person) for the subject, (:KD)-[:MENTIONS]->(:Organization) for the employer, (:KD)-[:MENTIONS]->(<derived entity>) for each.",
12782
+ "- No :Communication, :ConversationArchive, or :Message nodes \u2014 those belong to other flows.",
12783
+ "",
12784
+ "Subject (assertive):",
12785
+ "- name=" + p.name,
12786
+ "- headline=" + p.headline,
12787
+ "- location=" + (p.location || "(none)"),
12788
+ "- currentTitle=" + (p.currentTitle || "(none)"),
12789
+ "- currentCompany=" + (p.currentCompany || "(none)"),
12790
+ "",
12791
+ "Body (verbatim, write to :KnowledgeDocument.body):",
12792
+ p.bodyText
12793
+ ].join("\n");
12794
+ }
12795
+ if (env.kind === "thread" && env.thread) {
12796
+ const t = env.thread;
12797
+ const participantList = t.participants.map(function(p) {
12798
+ return p.name + (p.profileUrl ? " (" + p.profileUrl + ")" : "");
12799
+ }).join(", ");
12800
+ return [
12801
+ header,
12802
+ "",
12803
+ "Surface: LinkedIn DM thread. Run the document-ingest skill in document mode against the transcript below.",
12804
+ "",
12805
+ "Conservative-extraction rules apply (see Task 234 spec):",
12806
+ "- One :KnowledgeDocument MERGE keyed on sourceUrl=" + env.pageUrl + " with the verbatim transcript as body, plus one :Section:Note child with the summary.",
12807
+ "- (:KD)-[:PARTICIPANT]->(:Person) for each participant. MERGE :Person on (name, profileUrl) where present.",
12808
+ "- MERGE any derived entity only when assertively stated. Whatever ontology label fits: :Event {startDate, endDate} with ATTENDED_BY edges for scheduled meetings; :Task {kind, name, status} with RAISED_BY/ABOUT edges for actions without a scheduled time; :Service/:PriceSpecification when an offer or price is discussed. Each carries sourceUrl=" + env.pageUrl + ".",
12809
+ "- (:KD)-[:MENTIONS]->(<derived entity>) for every derived entity. Person-attached insights stay in the :Section:Note body plus a (:KD)-[:MENTIONS]->(:Person) edge \u2014 no standalone insight node.",
12810
+ "- No :Communication, :ConversationArchive, or :Message nodes \u2014 those belong to other flows.",
12811
+ "",
12812
+ "Participants:",
12813
+ participantList,
12814
+ "",
12815
+ "Transcript (verbatim, write to :KnowledgeDocument.body):",
12816
+ t.bodyText
12817
+ ].join("\n");
12818
+ }
12819
+ return header;
12820
+ }
12821
+ var app34 = new Hono();
12822
+ app34.post("/", requireAdminSession, async (c) => {
12823
+ let body;
12824
+ try {
12825
+ body = await c.req.json();
12826
+ } catch {
12827
+ console.error(TAG20 + " rejected status=400 reason=schema:body-not-json");
12828
+ return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
12829
+ }
12830
+ const v = validate(body);
12831
+ if (!v.ok) {
12832
+ console.error(TAG20 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
12833
+ return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
12834
+ }
12835
+ const envelope = v.envelope;
12836
+ const cacheKey = c.var.cacheKey ?? "";
12837
+ const senderId = getAccountIdForSession(cacheKey) ?? "";
12838
+ if (!senderId) {
12839
+ console.error(TAG20 + " rejected status=500 reason=admin-account-not-resolved");
12840
+ return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
12841
+ }
12842
+ const userId = getUserIdForSession(cacheKey) ?? void 0;
12843
+ const payloadBytes = JSON.stringify(envelope).length;
12844
+ console.log(
12845
+ TAG20 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
12846
+ );
12847
+ const initialMessage = buildInitialMessage(envelope);
12848
+ const spawnStart = Date.now();
12849
+ const { response, claudeSessionId } = await performSpawnWithInitialMessage({
12850
+ senderId,
12851
+ userId,
12852
+ role: "admin",
12853
+ channel: "linkedin-extension",
12854
+ permissionMode: void 0,
12855
+ hidden: true,
12856
+ specialist: "database-operator",
12857
+ model: void 0,
12858
+ initialMessage
12859
+ });
12860
+ if (!response.ok) {
12861
+ const detail = await response.text().catch(() => "");
12862
+ console.error(
12863
+ TAG20 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + response.status + " ms=" + (Date.now() - spawnStart) + " detail=" + detail.slice(0, 200)
12864
+ );
12865
+ return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: response.status, detail: detail.slice(0, 500) }, 502);
12866
+ }
12867
+ console.log(
12868
+ TAG20 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + (claudeSessionId ?? "unknown") + " ms=" + (Date.now() - spawnStart)
12869
+ );
12870
+ return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
12871
+ });
12872
+ var linkedin_ingest_default = app34;
12461
12873
 
12462
12874
  // server/routes/admin/index.ts
12463
- var app33 = new Hono();
12464
- app33.route("/session", session_default);
12465
- app33.route("/new-session-failure", new_session_failure_default);
12466
- app33.route("/new-session-submit", new_session_submit_default);
12467
- app33.route("/logs", logs_default);
12468
- app33.route("/claude-info", claude_info_default);
12469
- app33.route("/attachment", attachment_default);
12470
- app33.route("/agents", agents_default);
12471
- app33.route("/sessions", sessions_default);
12472
- app33.route("/claude-sessions", claude_sessions_default);
12473
- app33.route("/log-ingest", log_ingest_default);
12474
- app33.route("/browser", browser_default);
12475
- app33.route("/browser-iframe", browser_iframe_default);
12476
- app33.route("/device-browser", device_browser_default);
12477
- app33.route("/events", events_default);
12478
- app33.route("/cloudflare", cloudflare_default);
12479
- app33.route("/files", files_default);
12480
- app33.route("/graph-search", graph_search_default);
12481
- app33.route("/graph-subgraph", graph_subgraph_default);
12482
- app33.route("/graph-delete", graph_delete_default);
12483
- app33.route("/graph-restore", graph_restore_default);
12484
- app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12485
- app33.route("/graph-default-view", graph_default_view_default);
12486
- app33.route("/file-attach", file_attach_default);
12487
- app33.route("/sidebar-artefacts", sidebar_artefacts_default);
12488
- app33.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12489
- app33.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12490
- app33.route("/health-brand", health_default2);
12491
- var admin_default = app33;
12875
+ var app35 = new Hono();
12876
+ app35.route("/session", session_default);
12877
+ app35.route("/new-session-failure", new_session_failure_default);
12878
+ app35.route("/new-session-submit", new_session_submit_default);
12879
+ app35.route("/logs", logs_default);
12880
+ app35.route("/claude-info", claude_info_default);
12881
+ app35.route("/attachment", attachment_default);
12882
+ app35.route("/agents", agents_default);
12883
+ app35.route("/sessions", sessions_default);
12884
+ app35.route("/claude-sessions", claude_sessions_default);
12885
+ app35.route("/log-ingest", log_ingest_default);
12886
+ app35.route("/browser", browser_default);
12887
+ app35.route("/browser-iframe", browser_iframe_default);
12888
+ app35.route("/device-browser", device_browser_default);
12889
+ app35.route("/events", events_default);
12890
+ app35.route("/cloudflare", cloudflare_default);
12891
+ app35.route("/files", files_default);
12892
+ app35.route("/graph-search", graph_search_default);
12893
+ app35.route("/graph-subgraph", graph_subgraph_default);
12894
+ app35.route("/graph-delete", graph_delete_default);
12895
+ app35.route("/graph-restore", graph_restore_default);
12896
+ app35.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12897
+ app35.route("/graph-default-view", graph_default_view_default);
12898
+ app35.route("/session-defaults", session_defaults_default);
12899
+ app35.route("/file-attach", file_attach_default);
12900
+ app35.route("/sidebar-artefacts", sidebar_artefacts_default);
12901
+ app35.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12902
+ app35.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12903
+ app35.route("/health-brand", health_default2);
12904
+ app35.route("/linkedin-ingest", linkedin_ingest_default);
12905
+ var admin_default = app35;
12492
12906
 
12493
12907
  // server/routes/sites.ts
12494
12908
  import { existsSync as existsSync20, readFileSync as readFileSync18, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
@@ -12523,8 +12937,8 @@ function getExt(p) {
12523
12937
  if (idx < p.lastIndexOf("/")) return "";
12524
12938
  return p.slice(idx).toLowerCase();
12525
12939
  }
12526
- var app34 = new Hono();
12527
- app34.get("/:rel{.*}", (c) => {
12940
+ var app36 = new Hono();
12941
+ app36.get("/:rel{.*}", (c) => {
12528
12942
  const reqPath = c.req.path;
12529
12943
  const rawRel = c.req.param("rel") ?? "";
12530
12944
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -12627,7 +13041,7 @@ app34.get("/:rel{.*}", (c) => {
12627
13041
  "X-Content-Type-Options": "nosniff"
12628
13042
  });
12629
13043
  });
12630
- var sites_default = app34;
13044
+ var sites_default = app36;
12631
13045
 
12632
13046
  // app/lib/graph-health.ts
12633
13047
  var HOUR_MS = 60 * 60 * 1e3;
@@ -12711,7 +13125,7 @@ function startGraphHealthTimer() {
12711
13125
  }
12712
13126
 
12713
13127
  // app/lib/whatsapp/inbound/claude-bridge.ts
12714
- var TAG20 = "[whatsapp-adaptor]";
13128
+ var TAG21 = "[whatsapp-adaptor]";
12715
13129
  function whatsappTurnTimeoutMs() {
12716
13130
  return Number(process.env.WHATSAPP_PTY_TURN_TIMEOUT_MS ?? String(5 * 6e4));
12717
13131
  }
@@ -12732,7 +13146,7 @@ async function dispatchToClaude(input) {
12732
13146
  await input.reply(result.turnText);
12733
13147
  } catch (err) {
12734
13148
  const m = err instanceof Error ? err.message : String(err);
12735
- console.error(`${TAG20} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
13149
+ console.error(`${TAG21} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
12736
13150
  }
12737
13151
  }
12738
13152
  function startReaper2() {
@@ -13034,9 +13448,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
13034
13448
  function isPublicHost(host) {
13035
13449
  return host.startsWith("public.") || aliasDomains.has(host);
13036
13450
  }
13037
- var app35 = new Hono();
13038
- app35.use("*", clientIpMiddleware);
13039
- app35.use("*", async (c, next) => {
13451
+ var app37 = new Hono();
13452
+ app37.use("*", clientIpMiddleware);
13453
+ app37.use("*", async (c, next) => {
13040
13454
  await next();
13041
13455
  c.header("X-Content-Type-Options", "nosniff");
13042
13456
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -13046,7 +13460,7 @@ app35.use("*", async (c, next) => {
13046
13460
  );
13047
13461
  });
13048
13462
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
13049
- app35.use("*", async (c, next) => {
13463
+ app37.use("*", async (c, next) => {
13050
13464
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
13051
13465
  await next();
13052
13466
  return;
@@ -13079,7 +13493,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
13079
13493
  "/sites/"
13080
13494
  ];
13081
13495
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
13082
- app35.use("*", async (c, next) => {
13496
+ app37.use("*", async (c, next) => {
13083
13497
  const host = (c.req.header("host") ?? "").split(":")[0];
13084
13498
  if (!isPublicHost(host)) {
13085
13499
  await next();
@@ -13119,7 +13533,7 @@ function resolveRemoteAuthOpts() {
13119
13533
  return brandLoginOpts;
13120
13534
  }
13121
13535
  var MAX_LOGIN_BODY = 8 * 1024;
13122
- app35.post("/__remote-auth/login", async (c) => {
13536
+ app37.post("/__remote-auth/login", async (c) => {
13123
13537
  const client = clientFrom(c);
13124
13538
  const clientIp = client.ip || "unknown";
13125
13539
  if (!requestIsTlsTerminated(c)) {
@@ -13164,7 +13578,7 @@ app35.post("/__remote-auth/login", async (c) => {
13164
13578
  }
13165
13579
  });
13166
13580
  });
13167
- app35.get("/__remote-auth/logout", (c) => {
13581
+ app37.get("/__remote-auth/logout", (c) => {
13168
13582
  const client = clientFrom(c);
13169
13583
  const clientIp = client.ip || "unknown";
13170
13584
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -13177,7 +13591,7 @@ app35.get("/__remote-auth/logout", (c) => {
13177
13591
  }
13178
13592
  });
13179
13593
  });
13180
- app35.post("/__remote-auth/change-password", async (c) => {
13594
+ app37.post("/__remote-auth/change-password", async (c) => {
13181
13595
  const client = clientFrom(c);
13182
13596
  const clientIp = client.ip || "unknown";
13183
13597
  const rateLimited = checkRateLimit(client);
@@ -13228,13 +13642,13 @@ app35.post("/__remote-auth/change-password", async (c) => {
13228
13642
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
13229
13643
  }
13230
13644
  });
13231
- app35.get("/__remote-auth/setup", (c) => {
13645
+ app37.get("/__remote-auth/setup", (c) => {
13232
13646
  if (isRemoteAuthConfigured()) {
13233
13647
  return c.redirect("/");
13234
13648
  }
13235
13649
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
13236
13650
  });
13237
- app35.post("/__remote-auth/set-initial-password", async (c) => {
13651
+ app37.post("/__remote-auth/set-initial-password", async (c) => {
13238
13652
  if (isRemoteAuthConfigured()) {
13239
13653
  return c.redirect("/");
13240
13654
  }
@@ -13272,10 +13686,10 @@ app35.post("/__remote-auth/set-initial-password", async (c) => {
13272
13686
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
13273
13687
  }
13274
13688
  });
13275
- app35.get("/api/remote-auth/status", (c) => {
13689
+ app37.get("/api/remote-auth/status", (c) => {
13276
13690
  return c.json({ configured: isRemoteAuthConfigured() });
13277
13691
  });
13278
- app35.post("/api/remote-auth/set-password", async (c) => {
13692
+ app37.post("/api/remote-auth/set-password", async (c) => {
13279
13693
  let body;
13280
13694
  try {
13281
13695
  body = await c.req.json();
@@ -13306,9 +13720,9 @@ app35.post("/api/remote-auth/set-password", async (c) => {
13306
13720
  return c.json({ error: "Failed to save password" }, 500);
13307
13721
  }
13308
13722
  });
13309
- app35.route("/api/_client-error", client_error_default);
13723
+ app37.route("/api/_client-error", client_error_default);
13310
13724
  console.log("[client-error-route] mounted");
13311
- app35.use("*", async (c, next) => {
13725
+ app37.use("*", async (c, next) => {
13312
13726
  const host = (c.req.header("host") ?? "").split(":")[0];
13313
13727
  const path2 = c.req.path;
13314
13728
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -13348,11 +13762,11 @@ app35.use("*", async (c, next) => {
13348
13762
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
13349
13763
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
13350
13764
  });
13351
- app35.route("/api/health", health_default);
13352
- app35.route("/api/chat", chat_default);
13353
- app35.route("/api/whatsapp", whatsapp_default);
13354
- app35.route("/api/onboarding", onboarding_default);
13355
- app35.route("/api/admin", admin_default);
13765
+ app37.route("/api/health", health_default);
13766
+ app37.route("/api/chat", chat_default);
13767
+ app37.route("/api/whatsapp", whatsapp_default);
13768
+ app37.route("/api/onboarding", onboarding_default);
13769
+ app37.route("/api/admin", admin_default);
13356
13770
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
13357
13771
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
13358
13772
  var IMAGE_MIME = {
@@ -13364,7 +13778,7 @@ var IMAGE_MIME = {
13364
13778
  ".svg": "image/svg+xml",
13365
13779
  ".ico": "image/x-icon"
13366
13780
  };
13367
- app35.get("/agent-assets/:slug/:filename", (c) => {
13781
+ app37.get("/agent-assets/:slug/:filename", (c) => {
13368
13782
  const slug = c.req.param("slug");
13369
13783
  const filename = c.req.param("filename");
13370
13784
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -13399,7 +13813,7 @@ app35.get("/agent-assets/:slug/:filename", (c) => {
13399
13813
  "Cache-Control": "public, max-age=3600"
13400
13814
  });
13401
13815
  });
13402
- app35.get("/generated/:filename", (c) => {
13816
+ app37.get("/generated/:filename", (c) => {
13403
13817
  const filename = c.req.param("filename");
13404
13818
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
13405
13819
  console.error(`[generated] serve file=${filename} status=403`);
@@ -13429,7 +13843,7 @@ app35.get("/generated/:filename", (c) => {
13429
13843
  "Cache-Control": "public, max-age=86400"
13430
13844
  });
13431
13845
  });
13432
- app35.route("/sites", sites_default);
13846
+ app37.route("/sites", sites_default);
13433
13847
  var htmlCache = /* @__PURE__ */ new Map();
13434
13848
  var brandLogoPath = "/brand/maxy-monochrome.png";
13435
13849
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -13566,7 +13980,7 @@ function brandedPublicHtml(agentSlug) {
13566
13980
  function escapeHtml(s) {
13567
13981
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
13568
13982
  }
13569
- app35.get("/", (c) => {
13983
+ app37.get("/", (c) => {
13570
13984
  const host = (c.req.header("host") ?? "").split(":")[0];
13571
13985
  if (isPublicHost(host)) {
13572
13986
  const defaultSlug = resolveDefaultSlug();
@@ -13574,12 +13988,12 @@ app35.get("/", (c) => {
13574
13988
  }
13575
13989
  return c.html(cachedHtml("index.html"));
13576
13990
  });
13577
- app35.get("/public", (c) => {
13991
+ app37.get("/public", (c) => {
13578
13992
  const host = (c.req.header("host") ?? "").split(":")[0];
13579
13993
  if (isPublicHost(host)) return c.text("Not found", 404);
13580
13994
  return c.html(cachedHtml("public.html"));
13581
13995
  });
13582
- app35.get("/chat", (c) => {
13996
+ app37.get("/chat", (c) => {
13583
13997
  const host = (c.req.header("host") ?? "").split(":")[0];
13584
13998
  if (isPublicHost(host)) return c.text("Not found", 404);
13585
13999
  return c.html(cachedHtml("public.html"));
@@ -13598,9 +14012,9 @@ async function logViewerFetch(c, next) {
13598
14012
  duration_ms: Date.now() - start
13599
14013
  });
13600
14014
  }
13601
- app35.use("/vnc-viewer.html", logViewerFetch);
13602
- app35.use("/vnc-popout.html", logViewerFetch);
13603
- app35.get("/vnc-popout.html", (c) => {
14015
+ app37.use("/vnc-viewer.html", logViewerFetch);
14016
+ app37.use("/vnc-popout.html", logViewerFetch);
14017
+ app37.get("/vnc-popout.html", (c) => {
13604
14018
  let html = htmlCache.get("vnc-popout.html");
13605
14019
  if (!html) {
13606
14020
  html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -13613,7 +14027,7 @@ app35.get("/vnc-popout.html", (c) => {
13613
14027
  }
13614
14028
  return c.html(html);
13615
14029
  });
13616
- app35.post("/api/vnc/client-event", async (c) => {
14030
+ app37.post("/api/vnc/client-event", async (c) => {
13617
14031
  let body;
13618
14032
  try {
13619
14033
  body = await c.req.json();
@@ -13634,25 +14048,25 @@ app35.post("/api/vnc/client-event", async (c) => {
13634
14048
  });
13635
14049
  return c.json({ ok: true });
13636
14050
  });
13637
- app35.get("/g/:slug", (c) => {
14051
+ app37.get("/g/:slug", (c) => {
13638
14052
  return c.html(brandedPublicHtml());
13639
14053
  });
13640
- app35.get("/graph", (c) => {
14054
+ app37.get("/graph", (c) => {
13641
14055
  const host = (c.req.header("host") ?? "").split(":")[0];
13642
14056
  if (isPublicHost(host)) return c.text("Not found", 404);
13643
14057
  return c.html(cachedHtml("graph.html"));
13644
14058
  });
13645
- app35.get("/sessions", (c) => {
14059
+ app37.get("/sessions", (c) => {
13646
14060
  const host = (c.req.header("host") ?? "").split(":")[0];
13647
14061
  if (isPublicHost(host)) return c.text("Not found", 404);
13648
14062
  return c.html(cachedHtml("sessions.html"));
13649
14063
  });
13650
- app35.get("/data", (c) => {
14064
+ app37.get("/data", (c) => {
13651
14065
  const host = (c.req.header("host") ?? "").split(":")[0];
13652
14066
  if (isPublicHost(host)) return c.text("Not found", 404);
13653
14067
  return c.html(cachedHtml("data.html"));
13654
14068
  });
13655
- app35.get("/:slug", async (c, next) => {
14069
+ app37.get("/:slug", async (c, next) => {
13656
14070
  const slug = c.req.param("slug");
13657
14071
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
13658
14072
  const branding = loadBrandingCache(slug);
@@ -13662,16 +14076,31 @@ app35.get("/:slug", async (c, next) => {
13662
14076
  await next();
13663
14077
  });
13664
14078
  if (brandFaviconPath !== "/favicon.ico") {
13665
- app35.get("/favicon.ico", (c) => {
14079
+ app37.get("/favicon.ico", (c) => {
13666
14080
  c.header("Cache-Control", "public, max-age=300");
13667
14081
  return c.redirect(brandFaviconPath, 302);
13668
14082
  });
13669
14083
  }
13670
- app35.use("/*", serveStatic({ root: "./public" }));
14084
+ app37.use("/*", serveStatic({ root: "./public" }));
13671
14085
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
13672
14086
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
13673
- var httpServer = serve({ fetch: app35.fetch, port, hostname });
14087
+ var httpServer = serve({ fetch: app37.fetch, port, hostname });
13674
14088
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
14089
+ {
14090
+ const loopHist = monitorEventLoopDelay({ resolution: 50 });
14091
+ loopHist.enable();
14092
+ const LOG_THRESHOLD_MS = 1e3;
14093
+ const WINDOW_MS2 = 3e4;
14094
+ const lagTimer = setInterval(() => {
14095
+ const maxMs = loopHist.max / 1e6;
14096
+ const p99Ms = loopHist.percentile(99) / 1e6;
14097
+ loopHist.reset();
14098
+ if (maxMs >= LOG_THRESHOLD_MS) {
14099
+ console.error(`[event-loop] lag p99=${Math.round(p99Ms)} max=${Math.round(maxMs)} window=${WINDOW_MS2 / 1e3}s`);
14100
+ }
14101
+ }, WINDOW_MS2);
14102
+ lagTimer.unref();
14103
+ }
13675
14104
  console.log("[boot] auth-mode summary: oauth=8 api-key=1 (api-key consumer: invokePublicAgent only)");
13676
14105
  var SUBAPP_MANIFEST = [
13677
14106
  { prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
@@ -13687,7 +14116,7 @@ for (const m of SUBAPP_MANIFEST) {
13687
14116
  }
13688
14117
  try {
13689
14118
  const registered = [];
13690
- for (const r of app35.routes ?? []) {
14119
+ for (const r of app37.routes ?? []) {
13691
14120
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
13692
14121
  if (AGENT_SLUG_PATTERN.test(r.path)) {
13693
14122
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });