@rubytech/create-maxy-code 0.1.88 → 0.1.90

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