@rubytech/create-maxy-code 0.1.191 → 0.1.192

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 (168) hide show
  1. package/dist/__tests__/brew-resolve.test.js +1 -1
  2. package/dist/__tests__/macos-darwin-branch.test.js +1 -1
  3. package/dist/index.js +2 -2
  4. package/package.json +1 -1
  5. package/payload/platform/lib/mcp-eager/dist/index.d.ts +55 -0
  6. package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -1
  7. package/payload/platform/lib/mcp-eager/dist/index.js +76 -0
  8. package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -1
  9. package/payload/platform/lib/mcp-eager/package.json +7 -0
  10. package/payload/platform/lib/mcp-eager/src/index.ts +101 -0
  11. package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-admin-tool-gate.test.sh +102 -0
  12. package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +4 -4
  13. package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +56 -0
  14. package/payload/platform/plugins/browser/mcp/dist/index.js +19 -19
  15. package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/email/mcp/dist/index.js +12 -12
  17. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/index.js +8 -8
  19. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  20. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  21. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +35 -0
  22. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  23. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
  24. package/payload/platform/plugins/url-get/mcp/dist/index.js +2 -2
  25. package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
  26. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +34 -1
  28. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  29. package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.d.ts +116 -0
  30. package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.d.ts.map +1 -0
  31. package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.js +125 -0
  32. package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.js.map +1 -0
  33. package/payload/premium-plugins/writer-craft/lib/mcp-eager/package.json +7 -0
  34. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
  35. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +5 -4
  36. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
  37. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +5 -4
  38. package/payload/server/public/assets/AdminShell-CdgotOLV.js +1 -0
  39. package/payload/server/public/assets/{Checkbox-g2WZRfCt.js → Checkbox-DsHqjzGj.js} +1 -1
  40. package/payload/server/public/assets/admin-CWOprOdW.js +1 -0
  41. package/payload/server/public/assets/{arc-DMDAZHAN.js → arc-aUiRP9AS.js} +1 -1
  42. package/payload/server/public/assets/architecture-YZFGNWBL--v-pJPNp.js +1 -0
  43. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BVKxPUIS.js → architectureDiagram-Q4EWVU46-DROzw8rH.js} +1 -1
  44. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BpD-1G1V.js → blockDiagram-DXYQGD6D-Dw9sieJu.js} +1 -1
  45. package/payload/server/public/assets/{brand-BGvv6AYI.js → brand-DKUA91KU.js} +1 -1
  46. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CFl9Dr6U.js → c4Diagram-AHTNJAMY-fnwntjFK.js} +1 -1
  47. package/payload/server/public/assets/channel-DEl-UCEn.js +1 -0
  48. package/payload/server/public/assets/{chunk-2KRD3SAO-Di4bO8ir.js → chunk-2KRD3SAO-BK3470lx.js} +1 -1
  49. package/payload/server/public/assets/{chunk-336JU56O-B2Uc6pEC.js → chunk-336JU56O-DVpyamlA.js} +2 -2
  50. package/payload/server/public/assets/chunk-426QAEUC-yiGugjCx.js +1 -0
  51. package/payload/server/public/assets/{chunk-4BX2VUAB-DyEhFk-Z.js → chunk-4BX2VUAB-BOvVdJLf.js} +1 -1
  52. package/payload/server/public/assets/{chunk-4TB4RGXK-Dvf5uiFR.js → chunk-4TB4RGXK-BAPL_MqI.js} +1 -1
  53. package/payload/server/public/assets/{chunk-55IACEB6-BRJOZLpU.js → chunk-55IACEB6-BwZyF7vR.js} +1 -1
  54. package/payload/server/public/assets/{chunk-5FUZZQ4R-DUQR1rF9.js → chunk-5FUZZQ4R-Ba-5D35r.js} +1 -1
  55. package/payload/server/public/assets/{chunk-5PVQY5BW-OTvNug7K.js → chunk-5PVQY5BW-BtDS8-t9.js} +1 -1
  56. package/payload/server/public/assets/{chunk-67CJDMHE-BG6-9r6c.js → chunk-67CJDMHE-D5bhMrtY.js} +1 -1
  57. package/payload/server/public/assets/{chunk-7N4EOEYR-BvMbitX7.js → chunk-7N4EOEYR-Si7Lgrwc.js} +1 -1
  58. package/payload/server/public/assets/{chunk-AA7GKIK3-CE8mGBD5.js → chunk-AA7GKIK3-DMuHtDqO.js} +1 -1
  59. package/payload/server/public/assets/{chunk-BSJP7CBP-DP7LTBll.js → chunk-BSJP7CBP-L79XKVcb.js} +1 -1
  60. package/payload/server/public/assets/{chunk-CIAEETIT-VfnIdN-h.js → chunk-CIAEETIT-C0O7Upmg.js} +1 -1
  61. package/payload/server/public/assets/{chunk-EDXVE4YY-CRAsAWbD.js → chunk-EDXVE4YY-CqcdpDg_.js} +1 -1
  62. package/payload/server/public/assets/{chunk-ENJZ2VHE-BNllMoi_.js → chunk-ENJZ2VHE-CaBy9U1e.js} +1 -1
  63. package/payload/server/public/assets/{chunk-FMBD7UC4-w-yBZsN2.js → chunk-FMBD7UC4-C_E43NFJ.js} +1 -1
  64. package/payload/server/public/assets/{chunk-FOC6F5B3-f9cFywhd.js → chunk-FOC6F5B3-D9lWWHAu.js} +1 -1
  65. package/payload/server/public/assets/{chunk-ICPOFSXX-vTeVS4qd.js → chunk-ICPOFSXX-BdPjOce4.js} +2 -2
  66. package/payload/server/public/assets/{chunk-K5T4RW27-B_ZUrFUq.js → chunk-K5T4RW27-DuhsNH4c.js} +1 -1
  67. package/payload/server/public/assets/{chunk-KGLVRYIC-CcWTvRlI.js → chunk-KGLVRYIC-B4-A1Abi.js} +1 -1
  68. package/payload/server/public/assets/{chunk-LIHQZDEY-D-5-peQw.js → chunk-LIHQZDEY-BxqgHRgT.js} +1 -1
  69. package/payload/server/public/assets/{chunk-ORNJ4GCN-B4Z5L25I.js → chunk-ORNJ4GCN-DEYQ5WaJ.js} +1 -1
  70. package/payload/server/public/assets/{chunk-OYMX7WX6-BdSFcvNa.js → chunk-OYMX7WX6-CK6wx_FD.js} +1 -1
  71. package/payload/server/public/assets/chunk-QZHKN3VN-Bd-GrQM6.js +1 -0
  72. package/payload/server/public/assets/{chunk-U2HBQHQK-BpFXup4D.js → chunk-U2HBQHQK-DyZFy43o.js} +1 -1
  73. package/payload/server/public/assets/{chunk-X2U36JSP-DF-6QHx4.js → chunk-X2U36JSP-CMTofLbX.js} +1 -1
  74. package/payload/server/public/assets/{chunk-XPW4576I-m1Y_r88I.js → chunk-XPW4576I-CBfZXZDB.js} +1 -1
  75. package/payload/server/public/assets/{chunk-YZCP3GAM-CKgDoLRT.js → chunk-YZCP3GAM-YfFrkYbQ.js} +1 -1
  76. package/payload/server/public/assets/{chunk-ZZ45TVLE-B0ACvZCZ.js → chunk-ZZ45TVLE-BVfvS5n3.js} +1 -1
  77. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BZ9e1dmR.js +1 -0
  78. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B1_4kXdN.js +1 -0
  79. package/payload/server/public/assets/clone-CNXfxCnl.js +1 -0
  80. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BhtgY3T7.js → cose-bilkent-S5V4N54A-Br2gjtEO.js} +1 -1
  81. package/payload/server/public/assets/{dagre-3yl9rfxR.js → dagre-ComHkUs6.js} +1 -1
  82. package/payload/server/public/assets/{dagre-KV5264BT-D-Ux4uwL.js → dagre-KV5264BT-BB-QqzpF.js} +1 -1
  83. package/payload/server/public/assets/data-DEsRsfI1.js +1 -0
  84. package/payload/server/public/assets/{diagram-5BDNPKRD-D-MOMikl.js → diagram-5BDNPKRD-CpQQszhw.js} +1 -1
  85. package/payload/server/public/assets/{diagram-G4DWMVQ6-DKdFcnhf.js → diagram-G4DWMVQ6-DLdElVzs.js} +1 -1
  86. package/payload/server/public/assets/{diagram-MMDJMWI5-ajamR766.js → diagram-MMDJMWI5-JQ3ceLSO.js} +1 -1
  87. package/payload/server/public/assets/{diagram-TYMM5635-D2Pbk2Kk.js → diagram-TYMM5635-D_-AtVPR.js} +1 -1
  88. package/payload/server/public/assets/{erDiagram-SMLLAGMA-v3o948pk.js → erDiagram-SMLLAGMA-Dq50MKD-.js} +1 -1
  89. package/payload/server/public/assets/{flatten-BsWEYbBB.js → flatten-Bo6YRmWl.js} +1 -1
  90. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-byC1a6GE.js → flowDiagram-DWJPFMVM-CEdKm-zL.js} +1 -1
  91. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-Dybzs-Sw.js → ganttDiagram-T4ZO3ILL-CpTomdNN.js} +1 -1
  92. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CI0s_tqn.js +1 -0
  93. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DvzXYLuW.js → gitGraphDiagram-UUTBAWPF-VU-gjbee.js} +1 -1
  94. package/payload/server/public/assets/graph-BXaY_xoS.js +51 -0
  95. package/payload/server/public/assets/graph-labels-EqZyoU25.js +1 -0
  96. package/payload/server/public/assets/{graphlib-DvH_spaA.js → graphlib-nLzyerxi.js} +1 -1
  97. package/payload/server/public/assets/info-OMHHGYJF-g3gYW7Qm.js +1 -0
  98. package/payload/server/public/assets/infoDiagram-42DDH7IO-ThwX5Xgr.js +2 -0
  99. package/payload/server/public/assets/{isEmpty-BWl67LAZ.js → isEmpty-D6Kr-M1M.js} +1 -1
  100. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CpY5W64P.js → ishikawaDiagram-UXIWVN3A-DaKxxHLW.js} +1 -1
  101. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-ymMAQVdm.js → journeyDiagram-VCZTEJTY-DtMAHpWz.js} +1 -1
  102. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-_NX9hNK3.js → kanban-definition-6JOO6SKY-s898dJRu.js} +1 -1
  103. package/payload/server/public/assets/{line-Dz7zKWX-.js → line-D96q2CLD.js} +1 -1
  104. package/payload/server/public/assets/{linear-0O14Y6uf.js → linear-DOh_6k2k.js} +1 -1
  105. package/payload/server/public/assets/{mermaid-parser.core-BCWd1en6.js → mermaid-parser.core-CqFLtzz8.js} +2 -2
  106. package/payload/server/public/assets/{mermaid.core-gSoFkVoN.js → mermaid.core-o9rmBTu-.js} +3 -3
  107. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-QuIyK2bd.js → mindmap-definition-QFDTVHPH-BM8KKsaM.js} +1 -1
  108. package/payload/server/public/assets/{ordinal-krseTxxN.js → ordinal-BDi6f4xk.js} +1 -1
  109. package/payload/server/public/assets/packet-4T2RLAQJ-CT0TB9HI.js +1 -0
  110. package/payload/server/public/assets/pie-ZZUOXDRM-CXLe7TFF.js +1 -0
  111. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DHK0yy7U.js → pieDiagram-DEJITSTG-B66Y-dcU.js} +1 -1
  112. package/payload/server/public/assets/public-ClAaV52O.js +35 -0
  113. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wK1jwWo5.js → quadrantDiagram-34T5L4WZ-Bv4mojq8.js} +1 -1
  114. package/payload/server/public/assets/radar-PYXPWWZC-DnPLBl-D.js +1 -0
  115. package/payload/server/public/assets/{reduce-tk-xY6Fv.js → reduce-CGi9ik8i.js} +1 -1
  116. package/payload/server/public/assets/{requirementDiagram-MS252O5E-W_mH85_d.js → requirementDiagram-MS252O5E-BNYdfEKS.js} +1 -1
  117. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-nGAM-YLQ.js → sankeyDiagram-XADWPNL6-Do8BgX92.js} +1 -1
  118. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-SMfUCwBH.js → sequenceDiagram-FGHM5R23-VN57FKth.js} +1 -1
  119. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CYKXFirH.js → stateDiagram-FHFEXIEX-CCtRfCg0.js} +1 -1
  120. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Cz319KBI.js +1 -0
  121. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DethbNFa.js → timeline-definition-GMOUNBTQ-ja01S9Wd.js} +1 -1
  122. package/payload/server/public/assets/treeView-SZITEDCU-C3cb7Xwe.js +1 -0
  123. package/payload/server/public/assets/treemap-W4RFUUIX-Dc7G3Bgm.js +1 -0
  124. package/payload/server/public/assets/useSelectionMode-ejMSaa52.js +5 -0
  125. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BUlJTe9Z.js → vennDiagram-DHZGUBPP-wWbiL1f6.js} +1 -1
  126. package/payload/server/public/assets/wardley-RL74JXVD-DtgibWAt.js +1 -0
  127. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CL1TvZ7j.js → wardleyDiagram-NUSXRM2D-BZgue-PK.js} +1 -1
  128. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Cav10l-Z.js → xychartDiagram-5P7HB3ND-B_ynYRnW.js} +1 -1
  129. package/payload/server/public/data.html +4 -4
  130. package/payload/server/public/graph.html +5 -5
  131. package/payload/server/public/index.html +5 -7
  132. package/payload/server/public/public.html +4 -4
  133. package/payload/server/server.js +535 -494
  134. package/payload/server/public/assets/admin-DFxXLXfg.js +0 -216
  135. package/payload/server/public/assets/architecture-YZFGNWBL-COhEvUpo.js +0 -1
  136. package/payload/server/public/assets/channel-BTEFjudQ.js +0 -1
  137. package/payload/server/public/assets/chunk-426QAEUC-CcIGcm29.js +0 -1
  138. package/payload/server/public/assets/chunk-QZHKN3VN-CWh_0JsP.js +0 -1
  139. package/payload/server/public/assets/classDiagram-6PBFFD2Q-ClkdniKF.js +0 -1
  140. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-kjJetfh2.js +0 -1
  141. package/payload/server/public/assets/clone-BllVm2iY.js +0 -1
  142. package/payload/server/public/assets/data-DtYcqL1G.js +0 -1
  143. package/payload/server/public/assets/gitGraph-7Q5UKJZL-DeTNsAO0.js +0 -1
  144. package/payload/server/public/assets/graph-C-XPyGsO.js +0 -1
  145. package/payload/server/public/assets/graph-labels-CZin3myX.js +0 -1
  146. package/payload/server/public/assets/info-OMHHGYJF-DJJ9GlS6.js +0 -1
  147. package/payload/server/public/assets/infoDiagram-42DDH7IO-C2FeU8nE.js +0 -2
  148. package/payload/server/public/assets/lib-BEvO-mE0.js +0 -33
  149. package/payload/server/public/assets/packet-4T2RLAQJ-CGbvGkvF.js +0 -1
  150. package/payload/server/public/assets/page-CKlvbjKn.js +0 -1
  151. package/payload/server/public/assets/page-DSj21hpG.js +0 -51
  152. package/payload/server/public/assets/pie-ZZUOXDRM-BZy8rjFn.js +0 -1
  153. package/payload/server/public/assets/public-BnS9zREj.js +0 -7
  154. package/payload/server/public/assets/radar-PYXPWWZC-DcfWIVXr.js +0 -1
  155. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B9ZwM8kx.js +0 -1
  156. package/payload/server/public/assets/treeView-SZITEDCU-3WugwVdj.js +0 -1
  157. package/payload/server/public/assets/treemap-W4RFUUIX-Cf5mDLlu.js +0 -1
  158. package/payload/server/public/assets/wardley-RL74JXVD-Bv4md4b3.js +0 -1
  159. /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
  160. /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
  161. /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
  162. /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
  163. /package/payload/server/public/assets/{dist-Bd4S37oi.js → dist-BzAsli7o.js} +0 -0
  164. /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
  165. /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
  166. /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
  167. /package/payload/server/public/assets/{rough.esm-DKRO8IF-.js → rough.esm-DRO6hWPh.js} +0 -0
  168. /package/payload/server/public/assets/{src-B6XdH6xq.js → src-CWiyyVfn.js} +0 -0
@@ -815,8 +815,8 @@ var serveStatic = (options = { root: "" }) => {
815
815
  };
816
816
 
817
817
  // server/index.ts
818
- import { readFileSync as readFileSync20, existsSync as existsSync23, watchFile } from "fs";
819
- import { resolve as resolve24, join as join15, basename as basename5 } from "path";
818
+ import { readFileSync as readFileSync20, existsSync as existsSync22, watchFile } from "fs";
819
+ import { resolve as resolve23, join as join15, basename as basename6 } from "path";
820
820
  import { homedir as homedir2 } from "os";
821
821
  import { monitorEventLoopDelay } from "perf_hooks";
822
822
 
@@ -1274,7 +1274,7 @@ var credsSaveQueue = Promise.resolve();
1274
1274
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
1275
1275
  console.error(`${TAG2} draining credential save queue\u2026`);
1276
1276
  const timer2 = new Promise(
1277
- (resolve25) => setTimeout(() => resolve25("timeout"), timeoutMs)
1277
+ (resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
1278
1278
  );
1279
1279
  const result = await Promise.race([
1280
1280
  credsSaveQueue.then(() => "drained"),
@@ -1402,11 +1402,11 @@ async function createWaSocket(opts) {
1402
1402
  return sock;
1403
1403
  }
1404
1404
  async function waitForConnection(sock) {
1405
- return new Promise((resolve25, reject) => {
1405
+ return new Promise((resolve24, reject) => {
1406
1406
  const handler = (update) => {
1407
1407
  if (update.connection === "open") {
1408
1408
  sock.ev.off("connection.update", handler);
1409
- resolve25();
1409
+ resolve24();
1410
1410
  }
1411
1411
  if (update.connection === "close") {
1412
1412
  sock.ev.off("connection.update", handler);
@@ -1520,14 +1520,14 @@ ${inspected}`;
1520
1520
  return inspect2(err, INSPECT_OPTS2);
1521
1521
  }
1522
1522
  function withTimeout(label, promise, timeoutMs) {
1523
- return new Promise((resolve25, reject) => {
1523
+ return new Promise((resolve24, reject) => {
1524
1524
  const timer2 = setTimeout(() => {
1525
1525
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
1526
1526
  }, timeoutMs);
1527
1527
  promise.then(
1528
1528
  (value) => {
1529
1529
  clearTimeout(timer2);
1530
- resolve25(value);
1530
+ resolve24(value);
1531
1531
  },
1532
1532
  (err) => {
1533
1533
  clearTimeout(timer2);
@@ -2062,8 +2062,8 @@ async function persistWhatsAppMessage(input) {
2062
2062
  const { givenName, familyName } = splitName(input.pushName);
2063
2063
  const prev = sessionWriteLocks.get(input.cacheKey);
2064
2064
  let release;
2065
- const mine = new Promise((resolve25) => {
2066
- release = resolve25;
2065
+ const mine = new Promise((resolve24) => {
2066
+ release = resolve24;
2067
2067
  });
2068
2068
  const chained = (prev ?? Promise.resolve()).then(() => mine);
2069
2069
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -3099,11 +3099,11 @@ async function connectWithReconnect(conn) {
3099
3099
  console.error(
3100
3100
  `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3101
3101
  );
3102
- await new Promise((resolve25) => {
3103
- const timer2 = setTimeout(resolve25, delay);
3102
+ await new Promise((resolve24) => {
3103
+ const timer2 = setTimeout(resolve24, delay);
3104
3104
  conn.abortController.signal.addEventListener("abort", () => {
3105
3105
  clearTimeout(timer2);
3106
- resolve25();
3106
+ resolve24();
3107
3107
  }, { once: true });
3108
3108
  });
3109
3109
  }
@@ -3111,16 +3111,16 @@ async function connectWithReconnect(conn) {
3111
3111
  }
3112
3112
  }
3113
3113
  function waitForDisconnectEvent(conn) {
3114
- return new Promise((resolve25) => {
3114
+ return new Promise((resolve24) => {
3115
3115
  if (!conn.sock) {
3116
- resolve25();
3116
+ resolve24();
3117
3117
  return;
3118
3118
  }
3119
3119
  const sock = conn.sock;
3120
3120
  const handler = (update) => {
3121
3121
  if (update.connection === "close") {
3122
3122
  sock.ev.off("connection.update", handler);
3123
- resolve25();
3123
+ resolve24();
3124
3124
  }
3125
3125
  };
3126
3126
  sock.ev.on("connection.update", handler);
@@ -3382,8 +3382,8 @@ async function handleInboundMessage(conn, msg) {
3382
3382
  const conversationKey = isGroup ? remoteJid : senderPhone;
3383
3383
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
3384
3384
  let resolvePending;
3385
- const sttPending = new Promise((resolve25) => {
3386
- resolvePending = resolve25;
3385
+ const sttPending = new Promise((resolve24) => {
3386
+ resolvePending = resolve24;
3387
3387
  });
3388
3388
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
3389
3389
  try {
@@ -3787,20 +3787,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
3787
3787
 
3788
3788
  // server/routes/health.ts
3789
3789
  function checkPort(port2, timeoutMs = 500) {
3790
- return new Promise((resolve25) => {
3790
+ return new Promise((resolve24) => {
3791
3791
  const socket = createConnection2(port2, "127.0.0.1");
3792
3792
  socket.setTimeout(timeoutMs);
3793
3793
  socket.once("connect", () => {
3794
3794
  socket.destroy();
3795
- resolve25(true);
3795
+ resolve24(true);
3796
3796
  });
3797
3797
  socket.once("error", () => {
3798
3798
  socket.destroy();
3799
- resolve25(false);
3799
+ resolve24(false);
3800
3800
  });
3801
3801
  socket.once("timeout", () => {
3802
3802
  socket.destroy();
3803
- resolve25(false);
3803
+ resolve24(false);
3804
3804
  });
3805
3805
  });
3806
3806
  }
@@ -4536,12 +4536,12 @@ async function dispatchOnce(input) {
4536
4536
  });
4537
4537
  if (!entry) return { error: "spawn-failed" };
4538
4538
  entry.lastInboundAt = Date.now();
4539
- let resolve25;
4539
+ let resolve24;
4540
4540
  const turnPromise = new Promise((r) => {
4541
- resolve25 = r;
4541
+ resolve24 = r;
4542
4542
  });
4543
4543
  const listener = (text) => {
4544
- resolve25(text);
4544
+ resolve24(text);
4545
4545
  };
4546
4546
  entry.subscribers.add(listener);
4547
4547
  const writeOk = await writeInput(entry, input.text);
@@ -4983,8 +4983,8 @@ async function startLogin(opts) {
4983
4983
  resetActiveLogin(accountId);
4984
4984
  let resolveQr = null;
4985
4985
  let rejectQr = null;
4986
- const qrPromise = new Promise((resolve25, reject) => {
4987
- resolveQr = resolve25;
4986
+ const qrPromise = new Promise((resolve24, reject) => {
4987
+ resolveQr = resolve24;
4988
4988
  rejectQr = reject;
4989
4989
  });
4990
4990
  const qrTimer = setTimeout(
@@ -8769,11 +8769,23 @@ async function cascadeDeleteDocument(params) {
8769
8769
  // app/lib/file-index.ts
8770
8770
  import * as fsp from "fs/promises";
8771
8771
  import { resolve as resolve13, relative as relative2, join as join11, basename as basename3, extname as extname2, sep as sep3 } from "path";
8772
+ import { tmpdir as tmpdir2 } from "os";
8772
8773
  import { execFile as execFile2 } from "child_process";
8773
8774
  import { promisify as promisify2 } from "util";
8774
8775
  var execFileAsync2 = promisify2(execFile2);
8775
8776
  var CONTENT_CAP = 1e5;
8776
- var RECONCILE_DEBOUNCE_MS = 1e4;
8777
+ var OCR_TIMEOUT_MS = 3e4;
8778
+ var OCR_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
8779
+ ".png",
8780
+ ".jpg",
8781
+ ".jpeg",
8782
+ ".gif",
8783
+ ".webp",
8784
+ ".tiff",
8785
+ ".tif",
8786
+ ".bmp"
8787
+ ]);
8788
+ var RECONCILE_DEBOUNCE_MS = 5 * 60 * 1e3;
8777
8789
  var lastReconcileAt = /* @__PURE__ */ new Map();
8778
8790
  var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
8779
8791
  ".txt",
@@ -8826,26 +8838,60 @@ async function extractPdf(absolute) {
8826
8838
  });
8827
8839
  return stdout.trim();
8828
8840
  }
8841
+ async function ocrPdf(absolute) {
8842
+ const outPdf = join11(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
8843
+ try {
8844
+ await execFileAsync2(
8845
+ "ocrmypdf",
8846
+ ["--skip-text", "--quiet", "--output-type", "pdf", absolute, outPdf],
8847
+ { maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
8848
+ );
8849
+ const { stdout } = await execFileAsync2("pdftotext", [outPdf, "-"], {
8850
+ maxBuffer: 10 * 1024 * 1024,
8851
+ timeout: OCR_TIMEOUT_MS
8852
+ });
8853
+ return stdout.trim();
8854
+ } finally {
8855
+ await fsp.rm(outPdf, { force: true });
8856
+ }
8857
+ }
8858
+ async function ocrImage(absolute) {
8859
+ const { stdout } = await execFileAsync2(
8860
+ "tesseract",
8861
+ [absolute, "-", "-l", "eng", "--psm", "3"],
8862
+ { maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
8863
+ );
8864
+ return stdout.trim();
8865
+ }
8829
8866
  function stripHtml(html) {
8830
8867
  return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
8831
8868
  }
8832
8869
  async function extractFileContent(absolute) {
8833
8870
  const ext = extname2(absolute).toLowerCase();
8834
8871
  try {
8835
- if (ext === ".pdf") return (await extractPdf(absolute)).slice(0, CONTENT_CAP);
8872
+ if (ext === ".pdf") {
8873
+ const text = (await extractPdf(absolute)).slice(0, CONTENT_CAP);
8874
+ if (text.length > 0) return { content: text, route: "pdftotext" };
8875
+ const ocred = (await ocrPdf(absolute)).slice(0, CONTENT_CAP);
8876
+ return ocred.length > 0 ? { content: ocred, route: "ocr-pdf" } : { content: "", route: "name-only" };
8877
+ }
8836
8878
  if (HTML_EXTENSIONS.has(ext)) {
8837
8879
  const raw = await fsp.readFile(absolute, "utf-8");
8838
- return stripHtml(raw).slice(0, CONTENT_CAP);
8880
+ return { content: stripHtml(raw).slice(0, CONTENT_CAP), route: "html" };
8839
8881
  }
8840
8882
  if (TEXT_EXTENSIONS.has(ext)) {
8841
8883
  const raw = await fsp.readFile(absolute, "utf-8");
8842
- return raw.slice(0, CONTENT_CAP);
8884
+ return { content: raw.slice(0, CONTENT_CAP), route: "text" };
8843
8885
  }
8844
- return "";
8886
+ if (OCR_IMAGE_EXTENSIONS.has(ext)) {
8887
+ const ocred = (await ocrImage(absolute)).slice(0, CONTENT_CAP);
8888
+ return ocred.length > 0 ? { content: ocred, route: "ocr-image" } : { content: "", route: "name-only" };
8889
+ }
8890
+ return { content: "", route: "name-only" };
8845
8891
  } catch (err) {
8846
8892
  const msg = err instanceof Error ? err.message : String(err);
8847
8893
  console.error(`[file-index] extract-failed path="${relative2(DATA_ROOT, absolute)}" err="${msg}"`);
8848
- return "";
8894
+ return { content: "", route: "name-only" };
8849
8895
  }
8850
8896
  }
8851
8897
  async function readDisplayName(absolute) {
@@ -8909,9 +8955,86 @@ async function upsertFileArtifact(session, f) {
8909
8955
  f
8910
8956
  );
8911
8957
  }
8958
+ async function linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolutePath) {
8959
+ const res = await session.run(
8960
+ `MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
8961
+ OPTIONAL MATCH (d:KnowledgeDocument {accountId: $accountId, sourcePath: $absolutePath})
8962
+ WHERE NOT d:Trashed
8963
+ FOREACH (_ IN CASE WHEN d IS NULL THEN [] ELSE [1] END |
8964
+ MERGE (f)-[:INGESTED_AS]->(d))
8965
+ RETURN elementId(d) AS docId`,
8966
+ { accountId, relativePath, absolutePath }
8967
+ );
8968
+ const docId = res.records[0]?.get("docId");
8969
+ if (docId) {
8970
+ console.error(
8971
+ `[file-index] linked-kd account=${accountId} relativePath="${relativePath}" docId=${docId.slice(0, 12)}`
8972
+ );
8973
+ }
8974
+ }
8975
+ async function findLinkedKnowledgeDocs(session, accountId, relativePaths) {
8976
+ if (relativePaths.length === 0) return [];
8977
+ const res = await session.run(
8978
+ `MATCH (f:FileArtifact {accountId: $accountId})-[:INGESTED_AS]->(d:KnowledgeDocument)
8979
+ WHERE f.relativePath IN $relativePaths AND NOT d:Trashed
8980
+ OPTIONAL MATCH (d)-[:HAS_SECTION]->(s:Section)
8981
+ OPTIONAL MATCH (s)-[:HAS_CHUNK]->(c:Chunk)
8982
+ WITH d, collect(DISTINCT s) AS ss, collect(DISTINCT c) AS cc
8983
+ RETURN elementId(d) AS docId,
8984
+ [x IN ss WHERE x IS NOT NULL | elementId(x)] AS sectionIds,
8985
+ [x IN cc WHERE x IS NOT NULL | elementId(x)] AS chunkIds`,
8986
+ { accountId, relativePaths }
8987
+ );
8988
+ return res.records.map((rec) => ({
8989
+ docId: rec.get("docId"),
8990
+ sectionIds: rec.get("sectionIds") ?? [],
8991
+ chunkIds: rec.get("chunkIds") ?? []
8992
+ }));
8993
+ }
8994
+ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths) {
8995
+ const linked = await findLinkedKnowledgeDocs(session, accountId, relativePaths);
8996
+ let kds = 0, sections = 0, chunks = 0;
8997
+ for (const { docId, sectionIds, chunkIds } of linked) {
8998
+ try {
8999
+ await trashNode({
9000
+ session,
9001
+ accountId,
9002
+ elementId: docId,
9003
+ by: "file-index:cascade",
9004
+ reason: "physical file removed from FileArtifact index"
9005
+ });
9006
+ kds++;
9007
+ for (const sid of sectionIds) {
9008
+ await trashNode({
9009
+ session,
9010
+ accountId,
9011
+ elementId: sid,
9012
+ by: `file-index:cascade:from-${docId}`,
9013
+ reason: `cascade from KnowledgeDocument ${docId}`
9014
+ });
9015
+ sections++;
9016
+ }
9017
+ for (const cid of chunkIds) {
9018
+ await trashNode({
9019
+ session,
9020
+ accountId,
9021
+ elementId: cid,
9022
+ by: `file-index:cascade:from-${docId}`,
9023
+ reason: `cascade from KnowledgeDocument ${docId}`
9024
+ });
9025
+ chunks++;
9026
+ }
9027
+ } catch (err) {
9028
+ console.error(
9029
+ `[file-index] cascade-trash-failed account=${accountId} docId=${docId.slice(0, 12)} err="${err.message}"`
9030
+ );
9031
+ }
9032
+ }
9033
+ return { kds, sections, chunks };
9034
+ }
8912
9035
  async function buildArtifact(accountId, wf, embed2) {
8913
9036
  const name = basename3(wf.absolute);
8914
- const content = await extractFileContent(wf.absolute);
9037
+ const { content, route } = await extractFileContent(wf.absolute);
8915
9038
  const displayName = await readDisplayName(wf.absolute);
8916
9039
  const embedInput = `${name}
8917
9040
  ${content}`.slice(0, CONTENT_CAP);
@@ -8923,7 +9046,7 @@ ${content}`.slice(0, CONTENT_CAP);
8923
9046
  console.error(`[file-index] embed-failed path="${wf.relativePath}" err="${err.message}"`);
8924
9047
  }
8925
9048
  console.error(
8926
- `[file-index] index-file account=${accountId} path="${wf.relativePath}" chars=${content.length} embed-ms=${Date.now() - embedStart}`
9049
+ `[file-index] index-file account=${accountId} path="${wf.relativePath}" extractor=${route} chars=${content.length} embed-ms=${Date.now() - embedStart}`
8927
9050
  );
8928
9051
  return {
8929
9052
  accountId,
@@ -8982,14 +9105,29 @@ async function reconcileFileIndex(accountId, opts) {
8982
9105
  const unchanged = prior && prior.sizeBytes === wf.sizeBytes && prior.modifiedAt === wf.modifiedAt && prior.hasEmbedding;
8983
9106
  if (unchanged) {
8984
9107
  skipped++;
8985
- continue;
9108
+ } else {
9109
+ await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
9110
+ upserted++;
8986
9111
  }
8987
- await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
8988
- upserted++;
9112
+ await linkFileArtifactToKnowledgeDocument(session, accountId, wf.relativePath, wf.absolute);
8989
9113
  }
8990
9114
  let pruned = 0;
9115
+ let cascadeKds = 0, cascadeSections = 0, cascadeChunks = 0;
8991
9116
  if (clean) {
8992
9117
  const foundPaths = walked.map((w) => w.relativePath);
9118
+ const goneRes = await session.run(
9119
+ `MATCH (f:FileArtifact {accountId: $accountId})
9120
+ WHERE NOT f.relativePath IN $foundPaths
9121
+ RETURN f.relativePath AS rp`,
9122
+ { accountId, foundPaths }
9123
+ );
9124
+ const gonePaths = goneRes.records.map((r) => r.get("rp"));
9125
+ if (gonePaths.length > 0) {
9126
+ const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, gonePaths);
9127
+ cascadeKds = cascade.kds;
9128
+ cascadeSections = cascade.sections;
9129
+ cascadeChunks = cascade.chunks;
9130
+ }
8993
9131
  const pruneRes = await session.run(
8994
9132
  `MATCH (f:FileArtifact {accountId: $accountId})
8995
9133
  WHERE NOT f.relativePath IN $foundPaths
@@ -9001,7 +9139,7 @@ async function reconcileFileIndex(accountId, opts) {
9001
9139
  pruned = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
9002
9140
  }
9003
9141
  console.error(
9004
- `[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} clean=${clean} ms=${Date.now() - t0}`
9142
+ `[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} cascade-kds=${cascadeKds} cascade-sections=${cascadeSections} cascade-chunks=${cascadeChunks} clean=${clean} ms=${Date.now() - t0}`
9005
9143
  );
9006
9144
  return { walked: walked.length, upserted, skipped, pruned };
9007
9145
  });
@@ -9030,10 +9168,12 @@ async function indexFile(accountId, relativePath, opts) {
9030
9168
  modifiedAt: st.mtime.toISOString()
9031
9169
  };
9032
9170
  await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
9171
+ await linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolute);
9033
9172
  });
9034
9173
  }
9035
9174
  async function dropFileIndex(accountId, relativePath, opts) {
9036
9175
  await withSession(opts, async (session) => {
9176
+ const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, [relativePath]);
9037
9177
  const res = await session.run(
9038
9178
  `MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
9039
9179
  DETACH DELETE f
@@ -9042,7 +9182,9 @@ async function dropFileIndex(accountId, relativePath, opts) {
9042
9182
  );
9043
9183
  const c = res.records[0]?.get("dropped");
9044
9184
  const dropped = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
9045
- console.error(`[file-index] drop account=${accountId} path="${relativePath}" dropped=${dropped}`);
9185
+ console.error(
9186
+ `[file-index] drop account=${accountId} path="${relativePath}" dropped=${dropped} cascade-kds=${cascade.kds} cascade-sections=${cascade.sections} cascade-chunks=${cascade.chunks}`
9187
+ );
9046
9188
  });
9047
9189
  }
9048
9190
 
@@ -9139,7 +9281,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
9139
9281
  var app15 = new Hono();
9140
9282
  app15.get("/", requireAdminSession, async (c) => {
9141
9283
  const cacheKey = c.var.cacheKey;
9142
- if (!getAccountIdForSession(cacheKey)) {
9284
+ const accountId = getAccountIdForSession(cacheKey);
9285
+ if (!accountId) {
9143
9286
  console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
9144
9287
  return c.json({ error: "Account not found for session" }, 401);
9145
9288
  }
@@ -9152,17 +9295,26 @@ app15.get("/", requireAdminSession, async (c) => {
9152
9295
  return c.json({ error: resolution.error }, resolution.status);
9153
9296
  }
9154
9297
  const { absolute, relative: relPath2 } = resolution;
9298
+ if (crossesForeignAccountPartition(relPath2, accountId)) {
9299
+ console.error(`[data] account-scope-blocked endpoint="/api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
9300
+ return c.json({ error: "Not found" }, 404);
9301
+ }
9155
9302
  try {
9156
9303
  const info = await stat4(absolute);
9157
9304
  if (!info.isDirectory()) {
9158
9305
  return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
9159
9306
  }
9160
9307
  const names = await readdir3(absolute);
9308
+ const segs = relPath2.split("/").filter(Boolean);
9309
+ const isAccountParent = segs.length === 1 && (segs[0] === "accounts" || segs[0] === "uploads");
9161
9310
  const entries = [];
9162
9311
  for (const name of names) {
9163
9312
  if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
9164
9313
  continue;
9165
9314
  }
9315
+ if (isAccountParent && UUID_RE3.test(name) && name !== accountId) {
9316
+ continue;
9317
+ }
9166
9318
  try {
9167
9319
  const entryPath = join12(absolute, name);
9168
9320
  const s = await stat4(entryPath);
@@ -9340,6 +9492,10 @@ app15.delete("/", requireAdminSession, async (c) => {
9340
9492
  return c.json({ error: resolution.error }, resolution.status);
9341
9493
  }
9342
9494
  const { absolute, relative: relPath2 } = resolution;
9495
+ if (crossesForeignAccountPartition(relPath2, accountId)) {
9496
+ console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
9497
+ return c.json({ error: "Not found" }, 404);
9498
+ }
9343
9499
  const base = basename4(absolute);
9344
9500
  const segments = relPath2.split("/").filter(Boolean);
9345
9501
  if (base === "account.json" || segments.includes(".git")) {
@@ -11397,126 +11553,14 @@ var WRITE_CYPHER = `
11397
11553
  var graph_default_view_default = app21;
11398
11554
 
11399
11555
  // server/routes/admin/sidebar-artefacts.ts
11400
- import neo4j2 from "neo4j-driver";
11401
- import { readFile as readFile5, readdir as readdir4, stat as stat5 } from "fs/promises";
11402
- import { resolve as resolve16, relative as relative4, isAbsolute, sep as sep6 } from "path";
11556
+ import { readdir as readdir4, stat as stat5 } from "fs/promises";
11557
+ import { resolve as resolve15, relative as relative3, isAbsolute, sep as sep5, basename as basename5 } from "path";
11403
11558
  import { existsSync as existsSync16 } from "fs";
11404
-
11405
- // app/lib/doc-source-resolve.ts
11406
- import { readdirSync as readdirSync8, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
11407
- import { relative as relative3, resolve as resolve15, sep as sep5 } from "path";
11408
- function containedFile(absPath, root) {
11409
- try {
11410
- const real = realpathSync5(absPath);
11411
- const rootReal = realpathSync5(root);
11412
- if (real !== rootReal && !real.startsWith(rootReal + sep5)) return null;
11413
- return statSync7(real).isFile() ? real : null;
11414
- } catch {
11415
- return null;
11416
- }
11417
- }
11418
- function dataFileInDir(dir) {
11419
- let entries;
11420
- try {
11421
- entries = readdirSync8(dir, { withFileTypes: true }).flatMap((e) => e.isFile() ? [e.name] : []);
11422
- } catch {
11423
- return null;
11424
- }
11425
- const file = entries.find((e) => !e.endsWith(".meta.json"));
11426
- return file ? resolve15(dir, file) : null;
11427
- }
11428
- function mapToDownloadRoot(absPath, roots) {
11429
- const underData = containedFile(absPath, roots.dataRoot);
11430
- if (underData) {
11431
- return { root: "data", relPath: relative3(realpathSync5(roots.dataRoot), underData), absReal: underData };
11432
- }
11433
- if (roots.claudeUploadsRoot) {
11434
- const underClaude = containedFile(absPath, roots.claudeUploadsRoot);
11435
- if (underClaude) {
11436
- return {
11437
- root: "claude-uploads",
11438
- relPath: relative3(realpathSync5(roots.claudeUploadsRoot), underClaude),
11439
- absReal: underClaude
11440
- };
11441
- }
11442
- }
11443
- return null;
11444
- }
11445
- function resolveDocDownload(input, roots) {
11446
- const { accountId, attachmentId, name, sourcePath, sourceType } = input;
11447
- if (sourcePath) {
11448
- const mapped = mapToDownloadRoot(sourcePath, roots);
11449
- if (mapped) {
11450
- return { ok: true, absPath: mapped.absReal, root: mapped.root, relPath: mapped.relPath, via: "stored" };
11451
- }
11452
- }
11453
- if (attachmentId) {
11454
- const uploadsDir = resolve15(roots.attachmentsRoot, accountId, attachmentId);
11455
- const file = dataFileInDir(uploadsDir);
11456
- if (file) {
11457
- const real = containedFile(file, roots.dataRoot);
11458
- if (real) {
11459
- return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "uploads" };
11460
- }
11461
- }
11462
- }
11463
- if (attachmentId && roots.claudeUploadsRoot) {
11464
- const claudeDir = resolve15(roots.claudeUploadsRoot, attachmentId);
11465
- const file = dataFileInDir(claudeDir);
11466
- if (file) {
11467
- const real = containedFile(file, roots.claudeUploadsRoot);
11468
- if (real) {
11469
- return {
11470
- ok: true,
11471
- absPath: real,
11472
- root: "claude-uploads",
11473
- relPath: relative3(realpathSync5(roots.claudeUploadsRoot), real),
11474
- via: "claude-uploads"
11475
- };
11476
- }
11477
- }
11478
- }
11479
- if (name) {
11480
- const outputFile = resolve15(roots.accountsDir, accountId, "output", name);
11481
- const real = containedFile(outputFile, roots.dataRoot);
11482
- if (real) {
11483
- return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "output" };
11484
- }
11485
- }
11486
- return { ok: false, reason: sourceType === "web" ? "no-persisted-file" : "unresolved" };
11487
- }
11488
-
11489
- // server/routes/admin/sidebar-artefacts.ts
11490
11559
  var LIMIT = 50;
11491
- var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11492
11560
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
11493
11561
  function toDataRootRelPath(absPath) {
11494
- if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep6)) return null;
11495
- return relative4(DATA_ROOT, absPath);
11496
- }
11497
- function resolveDocDownloadRow(meta) {
11498
- const result = resolveDocDownload(
11499
- {
11500
- accountId: meta.accountId,
11501
- attachmentId: meta.attachmentId,
11502
- name: meta.name,
11503
- sourcePath: meta.sourcePath,
11504
- sourceType: meta.sourceType
11505
- },
11506
- {
11507
- dataRoot: DATA_ROOT,
11508
- attachmentsRoot: ATTACHMENTS_ROOT,
11509
- accountsDir: ACCOUNTS_DIR,
11510
- claudeUploadsRoot: CLAUDE_UPLOADS_ROOT
11511
- }
11512
- );
11513
- const aid = meta.attachmentId ? meta.attachmentId.slice(0, 8) : "none";
11514
- if (result.ok) {
11515
- console.log(`[admin/sidebar-artefacts] download-resolved id=${aid} via=${result.via} root=${result.root}`);
11516
- return { downloadPath: result.relPath, downloadRoot: result.root };
11517
- }
11518
- console.log(`[admin/sidebar-artefacts] not-downloadable id=${aid} reason=${result.reason}`);
11519
- return { downloadPath: null, downloadRoot: null };
11562
+ if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep5)) return null;
11563
+ return relative3(DATA_ROOT, absPath);
11520
11564
  }
11521
11565
  var app22 = new Hono();
11522
11566
  app22.get("/", requireAdminSession, async (c) => {
@@ -11526,118 +11570,64 @@ app22.get("/", requireAdminSession, async (c) => {
11526
11570
  return c.json({ error: "Account not found for session" }, 401);
11527
11571
  }
11528
11572
  const start = Date.now();
11529
- const docs = await fetchKnowledgeDocs(accountId);
11530
- if (docs === null) {
11573
+ const outputs = await fetchOutputArtefacts(accountId);
11574
+ if (outputs === null) {
11531
11575
  return c.json({ error: "Failed to load artefacts" }, 500);
11532
11576
  }
11533
- const accountDir = resolve16(ACCOUNTS_DIR, accountId);
11577
+ const accountDir = resolve15(ACCOUNTS_DIR, accountId);
11534
11578
  const agents = await fetchAgentTemplateRows(accountDir);
11535
- const artefacts = [...docs, ...agents].sort(
11579
+ const artefacts = [...outputs, ...agents].sort(
11536
11580
  (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
11537
11581
  ).slice(0, LIMIT);
11538
11582
  const ms = Date.now() - start;
11539
11583
  console.log(
11540
- `[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} docs=${docs.length} agents=${agents.length} ms=${ms}`
11584
+ `[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} outputs=${outputs.length} agents=${agents.length} ms=${ms}`
11541
11585
  );
11542
11586
  return c.json({ artefacts });
11543
11587
  });
11544
- async function fetchKnowledgeDocs(accountId) {
11588
+ async function fetchOutputArtefacts(accountId) {
11545
11589
  const session = getSession();
11546
- let metas = [];
11547
11590
  try {
11548
11591
  const result = await session.run(
11549
- `MATCH (d:KnowledgeDocument { accountId: $accountId })
11550
- WHERE d.deletedAt IS NULL AND NOT d:Trashed
11551
- RETURN d.attachmentId AS id, d.name AS name, d.updatedAt AS updatedAt,
11552
- d.attachmentId AS attachmentId, d.encodingFormat AS mimeType,
11553
- d.sourcePath AS sourcePath, d.sourceType AS sourceType
11554
- ORDER BY d.updatedAt DESC
11555
- LIMIT $limit`,
11556
- { accountId, limit: neo4j2.int(LIMIT) }
11557
- );
11558
- metas = result.records.map((r) => ({
11559
- id: r.get("id"),
11560
- name: r.get("name") ?? "",
11561
- updatedAt: r.get("updatedAt") ?? "",
11562
- attachmentId: r.get("attachmentId"),
11563
- mimeType: r.get("mimeType") ?? "",
11564
- sourcePath: r.get("sourcePath") ?? null,
11565
- sourceType: r.get("sourceType") ?? null
11566
- }));
11592
+ `MATCH (f:FileArtifact { accountId: $accountId })
11593
+ WHERE f.relativePath CONTAINS '/output/'
11594
+ RETURN f.relativePath AS relativePath,
11595
+ f.displayName AS displayName,
11596
+ f.mimeType AS mimeType,
11597
+ f.modifiedAt AS modifiedAt
11598
+ ORDER BY f.modifiedAt DESC
11599
+ LIMIT 50`,
11600
+ { accountId }
11601
+ );
11602
+ return result.records.map((r) => {
11603
+ const relativePath = r.get("relativePath");
11604
+ const displayName = r.get("displayName") ?? null;
11605
+ const mimeType = r.get("mimeType") ?? "";
11606
+ const modifiedAt = r.get("modifiedAt") ?? "";
11607
+ return {
11608
+ id: `output-file:${relativePath}`,
11609
+ name: displayName ?? basename5(relativePath),
11610
+ kind: "output-file",
11611
+ updatedAt: modifiedAt,
11612
+ editable: false,
11613
+ mimeType,
11614
+ downloadPath: relativePath,
11615
+ downloadRoot: "data"
11616
+ };
11617
+ });
11567
11618
  } catch (err) {
11568
11619
  const message = err instanceof Error ? err.message : String(err);
11569
11620
  console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
11570
- await session.close();
11571
11621
  return null;
11572
11622
  } finally {
11573
11623
  await session.close();
11574
11624
  }
11575
- return Promise.all(metas.map(async (m) => {
11576
- const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
11577
- const { downloadPath, downloadRoot } = resolveDocDownloadRow({
11578
- accountId,
11579
- attachmentId: m.attachmentId,
11580
- name: m.name,
11581
- sourcePath: m.sourcePath,
11582
- sourceType: m.sourceType
11583
- });
11584
- return {
11585
- id: m.id,
11586
- name: m.name,
11587
- kind: "knowledge-doc",
11588
- updatedAt: m.updatedAt,
11589
- content,
11590
- editable: skipReason === null,
11591
- mimeType: m.mimeType,
11592
- skipReason,
11593
- downloadPath,
11594
- downloadRoot
11595
- };
11596
- }));
11597
- }
11598
- async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
11599
- if (!attachmentId) {
11600
- logSkip(displayName, "null-attachmentId", mimeType);
11601
- return { content: "", skipReason: "null-attachmentId" };
11602
- }
11603
- const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
11604
- if (!isText) {
11605
- logSkip(displayName, "non-text-mime", mimeType);
11606
- return { content: "", skipReason: "non-text-mime" };
11607
- }
11608
- const accountDir = resolve16(ATTACHMENTS_ROOT, accountId);
11609
- const dir = resolve16(accountDir, attachmentId);
11610
- try {
11611
- validateFilePathInAccount(dir, accountDir);
11612
- } catch {
11613
- logSkip(displayName, "containment-rejected", mimeType);
11614
- return { content: "", skipReason: "containment-rejected" };
11615
- }
11616
- try {
11617
- const entries = await readdir4(dir);
11618
- const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
11619
- if (!dataFile) {
11620
- logSkip(displayName, "missing-on-disk", mimeType);
11621
- return { content: "", skipReason: "missing-on-disk" };
11622
- }
11623
- return { content: await readFile5(resolve16(dir, dataFile), "utf-8"), skipReason: null };
11624
- } catch (err) {
11625
- const message = err instanceof Error ? err.message : String(err);
11626
- console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
11627
- logSkip(displayName, "missing-on-disk", mimeType);
11628
- return { content: "", skipReason: "missing-on-disk" };
11629
- }
11630
- }
11631
- function logSkip(name, reason, mimeType) {
11632
- console.log(
11633
- `[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
11634
- );
11635
11625
  }
11636
11626
  async function fetchAgentTemplateRows(accountDir) {
11637
11627
  const rows = [];
11638
11628
  for (const filename of ADMIN_AGENT_FILES) {
11639
- const overridePath = resolve16(accountDir, "agents", "admin", filename);
11640
- const bundledPath = resolve16(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11629
+ const overridePath = resolve15(accountDir, "agents", "admin", filename);
11630
+ const bundledPath = resolve15(PLATFORM_ROOT, "templates", "agents", "admin", filename);
11641
11631
  const labelStem = filename.replace(/\.md$/, "");
11642
11632
  const row = await readAgentTemplateRow({
11643
11633
  id: `agent-template:admin:${filename}`,
@@ -11651,12 +11641,12 @@ async function fetchAgentTemplateRows(accountDir) {
11651
11641
  });
11652
11642
  if (row) rows.push(row);
11653
11643
  }
11654
- const overrideDir = resolve16(accountDir, "specialists", "agents");
11655
- const bundledDir = resolve16(PLATFORM_ROOT, "templates", "specialists", "agents");
11644
+ const overrideDir = resolve15(accountDir, "specialists", "agents");
11645
+ const bundledDir = resolve15(PLATFORM_ROOT, "templates", "specialists", "agents");
11656
11646
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
11657
11647
  for (const filename of specialistNames) {
11658
- const overridePath = resolve16(overrideDir, filename);
11659
- const bundledPath = resolve16(bundledDir, filename);
11648
+ const overridePath = resolve15(overrideDir, filename);
11649
+ const bundledPath = resolve15(bundledDir, filename);
11660
11650
  const row = await readAgentTemplateRow({
11661
11651
  id: `agent-template:specialist:${filename}`,
11662
11652
  displayName: filename.replace(/\.md$/, ""),
@@ -11711,20 +11701,15 @@ async function readAgentTemplateRow(inp) {
11711
11701
  }
11712
11702
  if (!chosenPath) return null;
11713
11703
  try {
11714
- const [content, st] = await Promise.all([
11715
- readFile5(chosenPath, "utf-8"),
11716
- stat5(chosenPath)
11717
- ]);
11704
+ const st = await stat5(chosenPath);
11718
11705
  const dlPath = toDataRootRelPath(chosenPath);
11719
11706
  return {
11720
11707
  id: inp.id,
11721
11708
  name: inp.displayName,
11722
11709
  kind: "agent-template",
11723
11710
  updatedAt: st.mtime.toISOString(),
11724
- content,
11725
11711
  editable: inp.editable,
11726
11712
  mimeType: "text/markdown",
11727
- skipReason: null,
11728
11713
  // Override paths live under <accountDir> (inside DATA_ROOT) and are
11729
11714
  // downloadable; bundled-fallback templates live under PLATFORM_ROOT
11730
11715
  // (outside DATA_ROOT) → null, so the client shows "not downloadable".
@@ -11742,14 +11727,14 @@ async function readAgentTemplateRow(inp) {
11742
11727
  }
11743
11728
  }
11744
11729
  function isWithin(target, root) {
11745
- const rel = relative4(root, target);
11730
+ const rel = relative3(root, target);
11746
11731
  return !rel.startsWith("..") && !isAbsolute(rel);
11747
11732
  }
11748
11733
  var sidebar_artefacts_default = app22;
11749
11734
 
11750
11735
  // server/routes/admin/sidebar-artefact-save.ts
11751
11736
  import { mkdir as mkdir4, readdir as readdir5, stat as stat6, writeFile as writeFile5 } from "fs/promises";
11752
- import { resolve as resolve17 } from "path";
11737
+ import { resolve as resolve16 } from "path";
11753
11738
  import { existsSync as existsSync17 } from "fs";
11754
11739
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
11755
11740
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
@@ -11762,7 +11747,7 @@ app23.post("/", requireAdminSession, async (c) => {
11762
11747
  if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
11763
11748
  return c.json({ error: "id and content required" }, 400);
11764
11749
  }
11765
- const accountDir = resolve17(ACCOUNTS_DIR, accountId);
11750
+ const accountDir = resolve16(ACCOUNTS_DIR, accountId);
11766
11751
  const resolved = await resolveSavePath(body.id, accountId, accountDir);
11767
11752
  if (resolved.kind === "heal-race") {
11768
11753
  c.header("Retry-After", "2");
@@ -11807,17 +11792,17 @@ async function resolveSavePath(id, accountId, accountDir) {
11807
11792
  if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
11808
11793
  return { kind: "reject", status: 400, reason: "invalid-id" };
11809
11794
  }
11810
- const parent = resolve17(accountDir, "agents", "admin");
11795
+ const parent = resolve16(accountDir, "agents", "admin");
11811
11796
  await mkdir4(parent, { recursive: true });
11812
11797
  try {
11813
11798
  validateFilePathInAccount(parent, accountDir);
11814
11799
  } catch {
11815
11800
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11816
11801
  }
11817
- return { kind: "admin-template", path: resolve17(parent, filename) };
11802
+ return { kind: "admin-template", path: resolve16(parent, filename) };
11818
11803
  }
11819
11804
  if (UUID_RE4.test(id)) {
11820
- const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
11805
+ const dir = resolve16(ATTACHMENTS_ROOT, accountId, id);
11821
11806
  if (!existsSync17(dir)) {
11822
11807
  const attShort = id.slice(0, 8);
11823
11808
  if (isHealPending(accountId, id)) {
@@ -11850,7 +11835,7 @@ async function resolveSavePath(id, accountId, accountDir) {
11850
11835
  }
11851
11836
  }
11852
11837
  try {
11853
- validateFilePathInAccount(dir, resolve17(ATTACHMENTS_ROOT, accountId));
11838
+ validateFilePathInAccount(dir, resolve16(ATTACHMENTS_ROOT, accountId));
11854
11839
  } catch {
11855
11840
  return { kind: "reject", status: 400, reason: "containment-rejected" };
11856
11841
  }
@@ -11859,7 +11844,7 @@ async function resolveSavePath(id, accountId, accountDir) {
11859
11844
  if (!dataFile) {
11860
11845
  return { kind: "reject", status: 400, reason: "not-found" };
11861
11846
  }
11862
- return { kind: "knowledge-doc", path: resolve17(dir, dataFile) };
11847
+ return { kind: "knowledge-doc", path: resolve16(dir, dataFile) };
11863
11848
  }
11864
11849
  return { kind: "reject", status: 400, reason: "invalid-id" };
11865
11850
  }
@@ -11868,57 +11853,8 @@ function relPath(absPath, root) {
11868
11853
  }
11869
11854
  var sidebar_artefact_save_default = app23;
11870
11855
 
11871
- // server/routes/admin/sidebar-artefact-content.ts
11872
- import { readFile as readFile6, readdir as readdir6 } from "fs/promises";
11873
- import { existsSync as existsSync18 } from "fs";
11874
- import { resolve as resolve18 } from "path";
11875
- var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11876
- var app24 = new Hono();
11877
- app24.get("/", requireAdminSession, async (c) => {
11878
- const cacheKey = c.var.cacheKey;
11879
- const accountId = getAccountIdForSession(cacheKey);
11880
- if (!accountId) return new Response("Unauthorized", { status: 401 });
11881
- const id = c.req.query("id") ?? "";
11882
- if (!UUID_RE5.test(id)) {
11883
- console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11884
- return new Response("Not found", { status: 404 });
11885
- }
11886
- const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
11887
- if (!existsSync18(dir)) {
11888
- console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11889
- return new Response("Not found", { status: 404 });
11890
- }
11891
- let meta;
11892
- try {
11893
- meta = JSON.parse(await readFile6(resolve18(dir, `${id}.meta.json`), "utf-8"));
11894
- } catch {
11895
- console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11896
- return new Response("Not found", { status: 404 });
11897
- }
11898
- const entries = await readdir6(dir);
11899
- const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
11900
- if (!dataFile) {
11901
- console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11902
- return new Response("Not found", { status: 404 });
11903
- }
11904
- const start = Date.now();
11905
- const buffer = await readFile6(resolve18(dir, dataFile));
11906
- const ms = Date.now() - start;
11907
- console.log(
11908
- `[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
11909
- );
11910
- return new Response(new Uint8Array(buffer), {
11911
- headers: {
11912
- "Content-Type": meta.mimeType,
11913
- "Content-Disposition": `inline; filename="${meta.filename}"`,
11914
- "Cache-Control": "private, max-age=3600"
11915
- }
11916
- });
11917
- });
11918
- var sidebar_artefact_content_default = app24;
11919
-
11920
11856
  // server/routes/admin/system-stats.ts
11921
- import { readFile as readFile7 } from "fs/promises";
11857
+ import { readFile as readFile5 } from "fs/promises";
11922
11858
  import { cpus, loadavg, totalmem, freemem } from "os";
11923
11859
  function parseCpuStat(blob) {
11924
11860
  const line = blob.split("\n", 1)[0] ?? "";
@@ -11962,11 +11898,11 @@ function parseMeminfo(blob) {
11962
11898
  }
11963
11899
  var SAMPLE_DELAY_MS = 100;
11964
11900
  async function sampleLinux() {
11965
- const a = parseCpuStat(await readFile7("/proc/stat", "utf-8"));
11901
+ const a = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
11966
11902
  await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
11967
- const b = parseCpuStat(await readFile7("/proc/stat", "utf-8"));
11968
- const meminfo = parseMeminfo(await readFile7("/proc/meminfo", "utf-8"));
11969
- const loadavgRaw = (await readFile7("/proc/loadavg", "utf-8")).trim();
11903
+ const b = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
11904
+ const meminfo = parseMeminfo(await readFile5("/proc/meminfo", "utf-8"));
11905
+ const loadavgRaw = (await readFile5("/proc/loadavg", "utf-8")).trim();
11970
11906
  const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
11971
11907
  if (![l1, l5, l15].every(Number.isFinite)) {
11972
11908
  throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
@@ -12012,8 +11948,8 @@ async function sample() {
12012
11948
  if (process.platform === "linux") return sampleLinux();
12013
11949
  return sampleOsFallback();
12014
11950
  }
12015
- var app25 = new Hono();
12016
- app25.get("/", async (c) => {
11951
+ var app24 = new Hono();
11952
+ app24.get("/", async (c) => {
12017
11953
  const started = Date.now();
12018
11954
  if (!inflight) {
12019
11955
  inflight = sample().finally(() => {
@@ -12036,26 +11972,26 @@ app25.get("/", async (c) => {
12036
11972
  return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
12037
11973
  }
12038
11974
  });
12039
- var system_stats_default = app25;
11975
+ var system_stats_default = app24;
12040
11976
 
12041
11977
  // server/routes/admin/health.ts
12042
- import { existsSync as existsSync19, readFileSync as readFileSync14 } from "fs";
12043
- import { resolve as resolve19, join as join13 } from "path";
12044
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
11978
+ import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
11979
+ import { resolve as resolve17, join as join13 } from "path";
11980
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
12045
11981
  var brandHostname = "maxy";
12046
11982
  var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
12047
- if (existsSync19(brandJsonPath)) {
11983
+ if (existsSync18(brandJsonPath)) {
12048
11984
  try {
12049
11985
  const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
12050
11986
  if (brand.hostname) brandHostname = brand.hostname;
12051
11987
  } catch {
12052
11988
  }
12053
11989
  }
12054
- var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
11990
+ var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
12055
11991
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
12056
11992
  var PROBE_TIMEOUT_MS = 1e3;
12057
11993
  function readVersion() {
12058
- if (!existsSync19(VERSION_FILE)) return "unknown";
11994
+ if (!existsSync18(VERSION_FILE)) return "unknown";
12059
11995
  return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
12060
11996
  }
12061
11997
  async function probeConversationDb() {
@@ -12081,8 +12017,8 @@ async function probeConversationDb() {
12081
12017
  });
12082
12018
  }
12083
12019
  }
12084
- var app26 = new Hono();
12085
- app26.get("/", async (c) => {
12020
+ var app25 = new Hono();
12021
+ app25.get("/", async (c) => {
12086
12022
  const version = readVersion();
12087
12023
  const probe = await probeConversationDb();
12088
12024
  const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
@@ -12104,7 +12040,7 @@ app26.get("/", async (c) => {
12104
12040
  uptimeMs
12105
12041
  });
12106
12042
  });
12107
- var health_default2 = app26;
12043
+ var health_default2 = app25;
12108
12044
 
12109
12045
  // server/routes/admin/linkedin-ingest.ts
12110
12046
  var TAG20 = "[linkedin-ingest-route]";
@@ -12200,8 +12136,8 @@ function buildInitialMessage(env) {
12200
12136
  }
12201
12137
  return header;
12202
12138
  }
12203
- var app27 = new Hono();
12204
- app27.post("/", requireAdminSession, async (c) => {
12139
+ var app26 = new Hono();
12140
+ app26.post("/", requireAdminSession, async (c) => {
12205
12141
  let body;
12206
12142
  try {
12207
12143
  body = await c.req.json();
@@ -12255,10 +12191,10 @@ app27.post("/", requireAdminSession, async (c) => {
12255
12191
  );
12256
12192
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
12257
12193
  });
12258
- var linkedin_ingest_default = app27;
12194
+ var linkedin_ingest_default = app26;
12259
12195
 
12260
12196
  // server/routes/admin/post-turn-context.ts
12261
- import neo4j3 from "neo4j-driver";
12197
+ import neo4j2 from "neo4j-driver";
12262
12198
  var TAG21 = "[post-turn-context]";
12263
12199
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
12264
12200
  "embedding",
@@ -12271,10 +12207,10 @@ function isLoopbackAddr2(addr) {
12271
12207
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
12272
12208
  }
12273
12209
  function convertValue(value) {
12274
- if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
12210
+ if (neo4j2.isDateTime(value) || neo4j2.isDate(value) || neo4j2.isLocalDateTime(value) || neo4j2.isLocalTime(value) || neo4j2.isTime(value) || neo4j2.isDuration(value)) {
12275
12211
  return value.toString();
12276
12212
  }
12277
- if (neo4j3.isInt(value)) {
12213
+ if (neo4j2.isInt(value)) {
12278
12214
  return value.inSafeRange() ? value.toNumber() : value.toString();
12279
12215
  }
12280
12216
  if (Array.isArray(value)) {
@@ -12297,8 +12233,8 @@ function pruneProperties(raw) {
12297
12233
  }
12298
12234
  return out;
12299
12235
  }
12300
- var app28 = new Hono();
12301
- app28.get("/", async (c) => {
12236
+ var app27 = new Hono();
12237
+ app27.get("/", async (c) => {
12302
12238
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
12303
12239
  if (!isLoopbackAddr2(remoteAddr)) {
12304
12240
  console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -12358,10 +12294,10 @@ app28.get("/", async (c) => {
12358
12294
  await session.close();
12359
12295
  }
12360
12296
  });
12361
- var post_turn_context_default = app28;
12297
+ var post_turn_context_default = app27;
12362
12298
 
12363
12299
  // server/routes/admin/public-session-context.ts
12364
- import neo4j4 from "neo4j-driver";
12300
+ import neo4j3 from "neo4j-driver";
12365
12301
  var TAG22 = "[public-session-context]";
12366
12302
  var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
12367
12303
  "embedding",
@@ -12374,10 +12310,10 @@ function isLoopbackAddr3(addr) {
12374
12310
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
12375
12311
  }
12376
12312
  function convertValue2(value) {
12377
- if (neo4j4.isDateTime(value) || neo4j4.isDate(value) || neo4j4.isLocalDateTime(value) || neo4j4.isLocalTime(value) || neo4j4.isTime(value) || neo4j4.isDuration(value)) {
12313
+ if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
12378
12314
  return value.toString();
12379
12315
  }
12380
- if (neo4j4.isInt(value)) {
12316
+ if (neo4j3.isInt(value)) {
12381
12317
  return value.inSafeRange() ? value.toNumber() : value.toString();
12382
12318
  }
12383
12319
  if (Array.isArray(value)) {
@@ -12400,8 +12336,8 @@ function pruneProperties2(raw) {
12400
12336
  }
12401
12337
  return out;
12402
12338
  }
12403
- var app29 = new Hono();
12404
- app29.get("/", async (c) => {
12339
+ var app28 = new Hono();
12340
+ app28.get("/", async (c) => {
12405
12341
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
12406
12342
  if (!isLoopbackAddr3(remoteAddr)) {
12407
12343
  console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -12460,15 +12396,15 @@ app29.get("/", async (c) => {
12460
12396
  await session.close();
12461
12397
  }
12462
12398
  });
12463
- var public_session_context_default = app29;
12399
+ var public_session_context_default = app28;
12464
12400
 
12465
12401
  // server/routes/admin/public-session-exit.ts
12466
12402
  var TAG23 = "[public-session-exit-route]";
12467
12403
  function isLoopbackAddr4(addr) {
12468
12404
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
12469
12405
  }
12470
- var app30 = new Hono();
12471
- app30.post("/", async (c) => {
12406
+ var app29 = new Hono();
12407
+ app29.post("/", async (c) => {
12472
12408
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
12473
12409
  if (!isLoopbackAddr4(remoteAddr)) {
12474
12410
  console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -12495,15 +12431,15 @@ app30.post("/", async (c) => {
12495
12431
  handlePublicSessionExit(sessionId);
12496
12432
  return c.json({ ok: true });
12497
12433
  });
12498
- var public_session_exit_default = app30;
12434
+ var public_session_exit_default = app29;
12499
12435
 
12500
12436
  // server/routes/admin/access-session-evict.ts
12501
12437
  var TAG24 = "[access-session-evict]";
12502
12438
  function isLoopbackAddr5(addr) {
12503
12439
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
12504
12440
  }
12505
- var app31 = new Hono();
12506
- app31.post("/", async (c) => {
12441
+ var app30 = new Hono();
12442
+ app30.post("/", async (c) => {
12507
12443
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
12508
12444
  if (!isLoopbackAddr5(remoteAddr)) {
12509
12445
  console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
@@ -12531,48 +12467,47 @@ app31.post("/", async (c) => {
12531
12467
  console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
12532
12468
  return c.json({ ok: true, dropped });
12533
12469
  });
12534
- var access_session_evict_default = app31;
12470
+ var access_session_evict_default = app30;
12535
12471
 
12536
12472
  // server/routes/admin/index.ts
12537
- var app32 = new Hono();
12538
- app32.route("/session", session_default);
12539
- app32.route("/logs", logs_default);
12540
- app32.route("/claude-info", claude_info_default);
12541
- app32.route("/attachment", attachment_default);
12542
- app32.route("/agents", agents_default);
12543
- app32.route("/sessions", sessions_default);
12544
- app32.route("/claude-sessions", claude_sessions_default);
12545
- app32.route("/log-ingest", log_ingest_default);
12546
- app32.route("/events", events_default);
12547
- app32.route("/files", files_default);
12548
- app32.route("/graph-search", graph_search_default);
12549
- app32.route("/graph-subgraph", graph_subgraph_default);
12550
- app32.route("/graph-delete", graph_delete_default);
12551
- app32.route("/graph-restore", graph_restore_default);
12552
- app32.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12553
- app32.route("/graph-default-view", graph_default_view_default);
12554
- app32.route("/sidebar-artefacts", sidebar_artefacts_default);
12555
- app32.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12556
- app32.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12557
- app32.route("/system-stats", system_stats_default);
12558
- app32.route("/health-brand", health_default2);
12559
- app32.route("/linkedin-ingest", linkedin_ingest_default);
12560
- app32.route("/post-turn-context", post_turn_context_default);
12561
- app32.route("/public-session-context", public_session_context_default);
12562
- app32.route("/public-session-exit", public_session_exit_default);
12563
- app32.route("/access-session-evict", access_session_evict_default);
12564
- var admin_default = app32;
12473
+ var app31 = new Hono();
12474
+ app31.route("/session", session_default);
12475
+ app31.route("/logs", logs_default);
12476
+ app31.route("/claude-info", claude_info_default);
12477
+ app31.route("/attachment", attachment_default);
12478
+ app31.route("/agents", agents_default);
12479
+ app31.route("/sessions", sessions_default);
12480
+ app31.route("/claude-sessions", claude_sessions_default);
12481
+ app31.route("/log-ingest", log_ingest_default);
12482
+ app31.route("/events", events_default);
12483
+ app31.route("/files", files_default);
12484
+ app31.route("/graph-search", graph_search_default);
12485
+ app31.route("/graph-subgraph", graph_subgraph_default);
12486
+ app31.route("/graph-delete", graph_delete_default);
12487
+ app31.route("/graph-restore", graph_restore_default);
12488
+ app31.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12489
+ app31.route("/graph-default-view", graph_default_view_default);
12490
+ app31.route("/sidebar-artefacts", sidebar_artefacts_default);
12491
+ app31.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12492
+ app31.route("/system-stats", system_stats_default);
12493
+ app31.route("/health-brand", health_default2);
12494
+ app31.route("/linkedin-ingest", linkedin_ingest_default);
12495
+ app31.route("/post-turn-context", post_turn_context_default);
12496
+ app31.route("/public-session-context", public_session_context_default);
12497
+ app31.route("/public-session-exit", public_session_exit_default);
12498
+ app31.route("/access-session-evict", access_session_evict_default);
12499
+ var admin_default = app31;
12565
12500
 
12566
12501
  // app/lib/access-gate.ts
12567
- import neo4j5 from "neo4j-driver";
12502
+ import neo4j4 from "neo4j-driver";
12568
12503
  import { readFileSync as readFileSync15 } from "fs";
12569
- import { resolve as resolve20 } from "path";
12504
+ import { resolve as resolve18 } from "path";
12570
12505
  import { randomUUID as randomUUID8 } from "crypto";
12571
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
12506
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
12572
12507
  var driver = null;
12573
12508
  function readPassword() {
12574
12509
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
12575
- const passwordFile = resolve20(PLATFORM_ROOT7, "config/.neo4j-password");
12510
+ const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
12576
12511
  try {
12577
12512
  return readFileSync15(passwordFile, "utf-8").trim();
12578
12513
  } catch {
@@ -12592,7 +12527,7 @@ function getDriver() {
12592
12527
  const user = process.env.NEO4J_USER ?? "neo4j";
12593
12528
  const password = readPassword();
12594
12529
  console.error(`[ui/access-gate] resolved neo4j_uri=${uri}`);
12595
- driver = neo4j5.driver(uri, neo4j5.auth.basic(user, password), {
12530
+ driver = neo4j4.driver(uri, neo4j4.auth.basic(user, password), {
12596
12531
  maxConnectionPoolSize: 5
12597
12532
  });
12598
12533
  }
@@ -12775,8 +12710,8 @@ async function generateNewMagicToken(grantId) {
12775
12710
  var TAG25 = "[access-verify]";
12776
12711
  var MINT_TAG = "[access-session-mint]";
12777
12712
  var COOKIE_NAME = "__access_session";
12778
- var app33 = new Hono();
12779
- app33.post("/", async (c) => {
12713
+ var app32 = new Hono();
12714
+ app32.post("/", async (c) => {
12780
12715
  const ip = c.var.clientIp || "unknown";
12781
12716
  let body;
12782
12717
  try {
@@ -12858,13 +12793,13 @@ app33.post("/", async (c) => {
12858
12793
  displayName: grant.displayName
12859
12794
  });
12860
12795
  });
12861
- var verify_token_default = app33;
12796
+ var verify_token_default = app32;
12862
12797
 
12863
12798
  // app/lib/access-email.ts
12864
12799
  import { spawn as spawn2 } from "child_process";
12865
- import { resolve as resolve21 } from "path";
12866
- var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
12867
- var SEND_SCRIPT = resolve21(
12800
+ import { resolve as resolve19 } from "path";
12801
+ var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
12802
+ var SEND_SCRIPT = resolve19(
12868
12803
  PLATFORM_ROOT8,
12869
12804
  "plugins",
12870
12805
  "email",
@@ -12921,9 +12856,9 @@ async function sendMagicLinkEmail(payload) {
12921
12856
 
12922
12857
  // server/routes/access/request-magic-link.ts
12923
12858
  var TAG26 = "[access-request-link]";
12924
- var app34 = new Hono();
12859
+ var app33 = new Hono();
12925
12860
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
12926
- app34.post("/", async (c) => {
12861
+ app33.post("/", async (c) => {
12927
12862
  let body;
12928
12863
  try {
12929
12864
  body = await c.req.json();
@@ -12997,17 +12932,17 @@ app34.post("/", async (c) => {
12997
12932
  );
12998
12933
  return c.json({ message: VISITOR_MESSAGE }, 200);
12999
12934
  });
13000
- var request_magic_link_default = app34;
12935
+ var request_magic_link_default = app33;
13001
12936
 
13002
12937
  // server/routes/access/index.ts
13003
- var app35 = new Hono();
13004
- app35.route("/verify-token", verify_token_default);
13005
- app35.route("/request-magic-link", request_magic_link_default);
13006
- var access_default = app35;
12938
+ var app34 = new Hono();
12939
+ app34.route("/verify-token", verify_token_default);
12940
+ app34.route("/request-magic-link", request_magic_link_default);
12941
+ var access_default = app34;
13007
12942
 
13008
12943
  // server/routes/sites.ts
13009
- import { existsSync as existsSync20, readFileSync as readFileSync16, realpathSync as realpathSync6, statSync as statSync8 } from "fs";
13010
- import { resolve as resolve22 } from "path";
12944
+ import { existsSync as existsSync19, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
12945
+ import { resolve as resolve20 } from "path";
13011
12946
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
13012
12947
  var MIME = {
13013
12948
  ".html": "text/html; charset=utf-8",
@@ -13038,8 +12973,8 @@ function getExt(p) {
13038
12973
  if (idx < p.lastIndexOf("/")) return "";
13039
12974
  return p.slice(idx).toLowerCase();
13040
12975
  }
13041
- var app36 = new Hono();
13042
- app36.get("/:rel{.*}", (c) => {
12976
+ var app35 = new Hono();
12977
+ app35.get("/:rel{.*}", (c) => {
13043
12978
  const reqPath = c.req.path;
13044
12979
  const rawRel = c.req.param("rel") ?? "";
13045
12980
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -13064,19 +12999,19 @@ app36.get("/:rel{.*}", (c) => {
13064
12999
  }
13065
13000
  segments.push(seg);
13066
13001
  }
13067
- const rootDir = resolve22(account.accountDir, "sites");
13068
- let filePath = segments.length === 0 ? rootDir : resolve22(rootDir, ...segments);
13002
+ const rootDir = resolve20(account.accountDir, "sites");
13003
+ let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
13069
13004
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
13070
13005
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
13071
13006
  return c.text("Forbidden", 403);
13072
13007
  }
13073
- let stat7;
13008
+ let stat8;
13074
13009
  try {
13075
- stat7 = existsSync20(filePath) ? statSync8(filePath) : null;
13010
+ stat8 = existsSync19(filePath) ? statSync7(filePath) : null;
13076
13011
  } catch {
13077
- stat7 = null;
13012
+ stat8 = null;
13078
13013
  }
13079
- if (stat7?.isDirectory() && !reqPath.endsWith("/")) {
13014
+ if (stat8?.isDirectory() && !reqPath.endsWith("/")) {
13080
13015
  const search = new URL(c.req.url).search;
13081
13016
  const target = `${reqPath}/${search}`;
13082
13017
  console.log(
@@ -13084,22 +13019,22 @@ app36.get("/:rel{.*}", (c) => {
13084
13019
  );
13085
13020
  return c.redirect(target, 301);
13086
13021
  }
13087
- if (stat7?.isDirectory()) {
13088
- filePath = resolve22(filePath, "index.html");
13022
+ if (stat8?.isDirectory()) {
13023
+ filePath = resolve20(filePath, "index.html");
13089
13024
  }
13090
13025
  if (!filePath.startsWith(rootDir + "/")) {
13091
13026
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
13092
13027
  return c.text("Forbidden", 403);
13093
13028
  }
13094
- if (!existsSync20(filePath)) {
13029
+ if (!existsSync19(filePath)) {
13095
13030
  console.error(`[sites] not-found path=${reqPath} status=404`);
13096
13031
  return c.text("Not found", 404);
13097
13032
  }
13098
13033
  let realPath;
13099
13034
  let realRoot;
13100
13035
  try {
13101
- realPath = realpathSync6(filePath);
13102
- realRoot = realpathSync6(rootDir);
13036
+ realPath = realpathSync5(filePath);
13037
+ realRoot = realpathSync5(rootDir);
13103
13038
  } catch {
13104
13039
  console.error(`[sites] not-found path=${reqPath} status=404`);
13105
13040
  return c.text("Not found", 404);
@@ -13142,7 +13077,7 @@ app36.get("/:rel{.*}", (c) => {
13142
13077
  "X-Content-Type-Options": "nosniff"
13143
13078
  });
13144
13079
  });
13145
- var sites_default = app36;
13080
+ var sites_default = app35;
13146
13081
 
13147
13082
  // app/lib/visitor-token.ts
13148
13083
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
@@ -13222,7 +13157,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
13222
13157
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
13223
13158
 
13224
13159
  // app/lib/brand-config.ts
13225
- import { existsSync as existsSync21, readFileSync as readFileSync18 } from "fs";
13160
+ import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
13226
13161
  import { join as join14 } from "path";
13227
13162
  var cached2 = null;
13228
13163
  var cachedAttempted = false;
@@ -13232,7 +13167,7 @@ function readBrandConfig() {
13232
13167
  const platformRoot = process.env.MAXY_PLATFORM_ROOT;
13233
13168
  if (!platformRoot) return null;
13234
13169
  const brandPath = join14(platformRoot, "config", "brand.json");
13235
- if (!existsSync21(brandPath)) return null;
13170
+ if (!existsSync20(brandPath)) return null;
13236
13171
  try {
13237
13172
  cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
13238
13173
  return cached2;
@@ -13242,7 +13177,7 @@ function readBrandConfig() {
13242
13177
  }
13243
13178
 
13244
13179
  // server/routes/visitor-consent.ts
13245
- var app37 = new Hono();
13180
+ var app36 = new Hono();
13246
13181
  var CONSENT_COOKIE_NAME = "mxy_consent";
13247
13182
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
13248
13183
  var DEFAULT_CONSENT_COPY = {
@@ -13287,17 +13222,17 @@ function siteSlugFromReferer(referer) {
13287
13222
  return "";
13288
13223
  }
13289
13224
  }
13290
- app37.options("/consent", (c) => {
13225
+ app36.options("/consent", (c) => {
13291
13226
  const origin = getOrigin(c);
13292
13227
  setCorsHeaders(c, origin);
13293
13228
  return c.body(null, 204);
13294
13229
  });
13295
- app37.options("/brand-config", (c) => {
13230
+ app36.options("/brand-config", (c) => {
13296
13231
  const origin = getOrigin(c);
13297
13232
  setCorsHeaders(c, origin);
13298
13233
  return c.body(null, 204);
13299
13234
  });
13300
- app37.post("/consent", async (c) => {
13235
+ app36.post("/consent", async (c) => {
13301
13236
  const origin = getOrigin(c);
13302
13237
  setCorsHeaders(c, origin);
13303
13238
  let raw;
@@ -13337,7 +13272,7 @@ app37.post("/consent", async (c) => {
13337
13272
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
13338
13273
  return c.body(null, 204);
13339
13274
  });
13340
- app37.get("/brand-config", (c) => {
13275
+ app36.get("/brand-config", (c) => {
13341
13276
  const origin = getOrigin(c);
13342
13277
  setCorsHeaders(c, origin);
13343
13278
  const brand = readBrandConfig();
@@ -13347,7 +13282,7 @@ app37.get("/brand-config", (c) => {
13347
13282
  c.header("Cache-Control", "public, max-age=300");
13348
13283
  return c.json({ consent: { copy, palette } });
13349
13284
  });
13350
- var visitor_consent_default = app37;
13285
+ var visitor_consent_default = app36;
13351
13286
 
13352
13287
  // server/routes/listings.ts
13353
13288
  function getCookie(headerValue, name) {
@@ -13374,8 +13309,8 @@ function appendConsentParams(pageUrl, token) {
13374
13309
  }
13375
13310
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
13376
13311
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
13377
- var app38 = new Hono();
13378
- app38.get("/:slug/click", async (c) => {
13312
+ var app37 = new Hono();
13313
+ app37.get("/:slug/click", async (c) => {
13379
13314
  const slug = c.req.param("slug") ?? "";
13380
13315
  const rawSession = c.req.query("session") ?? "";
13381
13316
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -13439,10 +13374,10 @@ app38.get("/:slug/click", async (c) => {
13439
13374
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
13440
13375
  return c.redirect(redirectUrl, 302);
13441
13376
  });
13442
- var listings_default = app38;
13377
+ var listings_default = app37;
13443
13378
 
13444
13379
  // server/routes/visitor-event.ts
13445
- var app39 = new Hono();
13380
+ var app38 = new Hono();
13446
13381
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
13447
13382
  var buckets = /* @__PURE__ */ new Map();
13448
13383
  var RATE_LIMIT = 60;
@@ -13509,12 +13444,12 @@ function originAllowed(origin, allowlist) {
13509
13444
  return false;
13510
13445
  }
13511
13446
  }
13512
- app39.options("/event", (c) => {
13447
+ app38.options("/event", (c) => {
13513
13448
  const origin = getOrigin2(c);
13514
13449
  setCorsHeaders2(c, origin);
13515
13450
  return c.body(null, 204);
13516
13451
  });
13517
- app39.post("/event", async (c) => {
13452
+ app38.post("/event", async (c) => {
13518
13453
  const origin = getOrigin2(c);
13519
13454
  setCorsHeaders2(c, origin);
13520
13455
  const ua = c.req.header("user-agent") ?? "";
@@ -13719,7 +13654,7 @@ async function writeEvent(opts) {
13719
13654
  );
13720
13655
  }
13721
13656
  }
13722
- var visitor_event_default = app39;
13657
+ var visitor_event_default = app38;
13723
13658
 
13724
13659
  // app/lib/graph-health.ts
13725
13660
  var HOUR_MS = 60 * 60 * 1e3;
@@ -13802,6 +13737,109 @@ function startGraphHealthTimer() {
13802
13737
  if (typeof timer.unref === "function") timer.unref();
13803
13738
  }
13804
13739
 
13740
+ // app/lib/file-watcher.ts
13741
+ import * as fsp2 from "fs/promises";
13742
+ import { resolve as resolve21, sep as sep6 } from "path";
13743
+ var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
13744
+ var DEFAULT_COALESCE_MS = 500;
13745
+ var ROOTS = ["uploads", "accounts"];
13746
+ function _routeEvent(rootName, filename) {
13747
+ if (!filename) return null;
13748
+ const segs = filename.split(sep6).filter(Boolean);
13749
+ if (segs.length < 2) return null;
13750
+ const accountId = segs[0];
13751
+ if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
13752
+ return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
13753
+ }
13754
+ async function startFileWatcher(opts = {}) {
13755
+ const dataRoot = opts.dataRoot ?? DATA_ROOT;
13756
+ const coalesceMs = opts.coalesceMs ?? DEFAULT_COALESCE_MS;
13757
+ const indexFn = opts.index ?? indexFile;
13758
+ const dropFn = opts.drop ?? dropFileIndex;
13759
+ for (const r of ROOTS) {
13760
+ try {
13761
+ await fsp2.mkdir(resolve21(dataRoot, r), { recursive: true });
13762
+ } catch (err) {
13763
+ console.error(
13764
+ `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
13765
+ );
13766
+ return { stop: async () => {
13767
+ } };
13768
+ }
13769
+ }
13770
+ const controller = new AbortController();
13771
+ const timers = /* @__PURE__ */ new Map();
13772
+ function schedule(relativePath, accountId) {
13773
+ const existing = timers.get(relativePath);
13774
+ if (existing) clearTimeout(existing);
13775
+ const t = setTimeout(() => {
13776
+ timers.delete(relativePath);
13777
+ void runHook(relativePath, accountId);
13778
+ }, coalesceMs);
13779
+ timers.set(relativePath, t);
13780
+ }
13781
+ async function runHook(relativePath, accountId) {
13782
+ const absolute = resolve21(dataRoot, relativePath);
13783
+ let exists = false;
13784
+ try {
13785
+ const st = await fsp2.stat(absolute);
13786
+ exists = st.isFile();
13787
+ } catch (err) {
13788
+ const code = err.code;
13789
+ if (code !== "ENOENT") {
13790
+ console.error(`[file-watcher] stat-error path="${relativePath}" err="${err.message}"`);
13791
+ }
13792
+ }
13793
+ try {
13794
+ if (exists) {
13795
+ await indexFn(accountId, relativePath);
13796
+ } else {
13797
+ await dropFn(accountId, relativePath);
13798
+ }
13799
+ } catch (err) {
13800
+ console.error(`[file-watcher] hook-failed path="${relativePath}" err="${err.message}"`);
13801
+ } finally {
13802
+ opts.onSettled?.(relativePath);
13803
+ }
13804
+ }
13805
+ async function watchRoot(rootName) {
13806
+ const absRoot = resolve21(dataRoot, rootName);
13807
+ try {
13808
+ const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
13809
+ for await (const event of iter) {
13810
+ const routed = _routeEvent(rootName, event.filename);
13811
+ if (!routed) continue;
13812
+ schedule(routed.relativePath, routed.accountId);
13813
+ }
13814
+ } catch (err) {
13815
+ const code = err.code;
13816
+ const name = err.name;
13817
+ if (code === "ABORT_ERR" || name === "AbortError") return;
13818
+ console.error(`[file-watcher] loop-error root="${rootName}" err="${err.message}"`);
13819
+ }
13820
+ }
13821
+ for (const r of ROOTS) void watchRoot(r);
13822
+ const sigHandler = () => {
13823
+ void stop();
13824
+ };
13825
+ process.once("SIGTERM", sigHandler);
13826
+ process.once("SIGINT", sigHandler);
13827
+ let stopped = false;
13828
+ async function stop() {
13829
+ if (stopped) return;
13830
+ stopped = true;
13831
+ process.off("SIGTERM", sigHandler);
13832
+ process.off("SIGINT", sigHandler);
13833
+ controller.abort();
13834
+ for (const t of timers.values()) clearTimeout(t);
13835
+ timers.clear();
13836
+ }
13837
+ console.error(
13838
+ `[file-watcher] started roots=${ROOTS.join(",")} dataRoot="${dataRoot}" coalesce-ms=${coalesceMs}`
13839
+ );
13840
+ return { stop };
13841
+ }
13842
+
13805
13843
  // app/lib/whatsapp/inbound/claude-bridge.ts
13806
13844
  var TAG27 = "[whatsapp-adaptor]";
13807
13845
  function whatsappTurnTimeoutMs() {
@@ -13863,8 +13901,8 @@ function broadcastAdminShutdown(reason) {
13863
13901
 
13864
13902
  // ../lib/entitlement/src/index.ts
13865
13903
  import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
13866
- import { existsSync as existsSync22, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
13867
- import { resolve as resolve23 } from "path";
13904
+ import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
13905
+ import { resolve as resolve22 } from "path";
13868
13906
 
13869
13907
  // ../lib/entitlement/src/canonicalize.ts
13870
13908
  function canonicalize(value) {
@@ -13899,7 +13937,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
13899
13937
  var GRACE_DAYS = 7;
13900
13938
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
13901
13939
  function pubkeyPath(brand) {
13902
- return resolve23(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
13940
+ return resolve22(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
13903
13941
  }
13904
13942
  var memo = null;
13905
13943
  function memoKey(mtimeMs, account) {
@@ -13911,12 +13949,12 @@ function resolveEntitlement(brand, account) {
13911
13949
  if (brand.commercialMode !== true) {
13912
13950
  return logResolved(implicitTrust(account), null);
13913
13951
  }
13914
- const entitlementPath = resolve23(brand.configDir, "entitlement.json");
13915
- if (!existsSync22(entitlementPath)) {
13952
+ const entitlementPath = resolve22(brand.configDir, "entitlement.json");
13953
+ if (!existsSync21(entitlementPath)) {
13916
13954
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
13917
13955
  }
13918
- const stat7 = statSync9(entitlementPath);
13919
- const key = memoKey(stat7.mtimeMs, account);
13956
+ const stat8 = statSync8(entitlementPath);
13957
+ const key = memoKey(stat8.mtimeMs, account);
13920
13958
  if (memo && memo.key === key) {
13921
13959
  return memo.result;
13922
13960
  }
@@ -14104,10 +14142,10 @@ function clientFrom(c) {
14104
14142
  var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
14105
14143
  var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
14106
14144
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
14107
- if (BRAND_JSON_PATH && !existsSync23(BRAND_JSON_PATH)) {
14145
+ if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
14108
14146
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
14109
14147
  }
14110
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
14148
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
14111
14149
  try {
14112
14150
  const parsed = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
14113
14151
  BRAND = { ...BRAND, ...parsed };
@@ -14131,7 +14169,7 @@ var brandLoginOpts = {
14131
14169
  var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
14132
14170
  function loadAliasDomains() {
14133
14171
  try {
14134
- if (!existsSync23(ALIAS_DOMAINS_PATH)) return null;
14172
+ if (!existsSync22(ALIAS_DOMAINS_PATH)) return null;
14135
14173
  const parsed = JSON.parse(readFileSync20(ALIAS_DOMAINS_PATH, "utf-8"));
14136
14174
  if (!Array.isArray(parsed)) {
14137
14175
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
@@ -14156,9 +14194,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
14156
14194
  function isPublicHost(host) {
14157
14195
  return host.startsWith("public.") || aliasDomains.has(host);
14158
14196
  }
14159
- var app40 = new Hono();
14160
- app40.use("*", clientIpMiddleware);
14161
- app40.use("*", async (c, next) => {
14197
+ var app39 = new Hono();
14198
+ app39.use("*", clientIpMiddleware);
14199
+ app39.use("*", async (c, next) => {
14162
14200
  await next();
14163
14201
  c.header("X-Content-Type-Options", "nosniff");
14164
14202
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -14168,7 +14206,7 @@ app40.use("*", async (c, next) => {
14168
14206
  );
14169
14207
  });
14170
14208
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
14171
- app40.use("*", async (c, next) => {
14209
+ app39.use("*", async (c, next) => {
14172
14210
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
14173
14211
  await next();
14174
14212
  return;
@@ -14201,7 +14239,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
14201
14239
  "/sites/"
14202
14240
  ];
14203
14241
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
14204
- app40.use("*", async (c, next) => {
14242
+ app39.use("*", async (c, next) => {
14205
14243
  const host = (c.req.header("host") ?? "").split(":")[0];
14206
14244
  if (!isPublicHost(host)) {
14207
14245
  await next();
@@ -14241,7 +14279,7 @@ function resolveRemoteAuthOpts() {
14241
14279
  return brandLoginOpts;
14242
14280
  }
14243
14281
  var MAX_LOGIN_BODY = 8 * 1024;
14244
- app40.post("/__remote-auth/login", async (c) => {
14282
+ app39.post("/__remote-auth/login", async (c) => {
14245
14283
  const client = clientFrom(c);
14246
14284
  const clientIp = client.ip || "unknown";
14247
14285
  if (!requestIsTlsTerminated(c)) {
@@ -14286,7 +14324,7 @@ app40.post("/__remote-auth/login", async (c) => {
14286
14324
  }
14287
14325
  });
14288
14326
  });
14289
- app40.get("/__remote-auth/logout", (c) => {
14327
+ app39.get("/__remote-auth/logout", (c) => {
14290
14328
  const client = clientFrom(c);
14291
14329
  const clientIp = client.ip || "unknown";
14292
14330
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -14299,7 +14337,7 @@ app40.get("/__remote-auth/logout", (c) => {
14299
14337
  }
14300
14338
  });
14301
14339
  });
14302
- app40.post("/__remote-auth/change-password", async (c) => {
14340
+ app39.post("/__remote-auth/change-password", async (c) => {
14303
14341
  const client = clientFrom(c);
14304
14342
  const clientIp = client.ip || "unknown";
14305
14343
  const rateLimited = checkRateLimit(client);
@@ -14350,13 +14388,13 @@ app40.post("/__remote-auth/change-password", async (c) => {
14350
14388
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
14351
14389
  }
14352
14390
  });
14353
- app40.get("/__remote-auth/setup", (c) => {
14391
+ app39.get("/__remote-auth/setup", (c) => {
14354
14392
  if (isRemoteAuthConfigured()) {
14355
14393
  return c.redirect("/");
14356
14394
  }
14357
14395
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
14358
14396
  });
14359
- app40.post("/__remote-auth/set-initial-password", async (c) => {
14397
+ app39.post("/__remote-auth/set-initial-password", async (c) => {
14360
14398
  if (isRemoteAuthConfigured()) {
14361
14399
  return c.redirect("/");
14362
14400
  }
@@ -14394,10 +14432,10 @@ app40.post("/__remote-auth/set-initial-password", async (c) => {
14394
14432
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
14395
14433
  }
14396
14434
  });
14397
- app40.get("/api/remote-auth/status", (c) => {
14435
+ app39.get("/api/remote-auth/status", (c) => {
14398
14436
  return c.json({ configured: isRemoteAuthConfigured() });
14399
14437
  });
14400
- app40.post("/api/remote-auth/set-password", async (c) => {
14438
+ app39.post("/api/remote-auth/set-password", async (c) => {
14401
14439
  let body;
14402
14440
  try {
14403
14441
  body = await c.req.json();
@@ -14428,9 +14466,9 @@ app40.post("/api/remote-auth/set-password", async (c) => {
14428
14466
  return c.json({ error: "Failed to save password" }, 500);
14429
14467
  }
14430
14468
  });
14431
- app40.route("/api/_client-error", client_error_default);
14469
+ app39.route("/api/_client-error", client_error_default);
14432
14470
  console.log("[client-error-route] mounted");
14433
- app40.use("*", async (c, next) => {
14471
+ app39.use("*", async (c, next) => {
14434
14472
  const host = (c.req.header("host") ?? "").split(":")[0];
14435
14473
  const path2 = c.req.path;
14436
14474
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -14463,12 +14501,12 @@ app40.use("*", async (c, next) => {
14463
14501
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
14464
14502
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
14465
14503
  });
14466
- app40.route("/api/health", health_default);
14467
- app40.route("/api/chat", chat_default);
14468
- app40.route("/api/whatsapp", whatsapp_default);
14469
- app40.route("/api/onboarding", onboarding_default);
14470
- app40.route("/api/admin", admin_default);
14471
- app40.route("/api/access", access_default);
14504
+ app39.route("/api/health", health_default);
14505
+ app39.route("/api/chat", chat_default);
14506
+ app39.route("/api/whatsapp", whatsapp_default);
14507
+ app39.route("/api/onboarding", onboarding_default);
14508
+ app39.route("/api/admin", admin_default);
14509
+ app39.route("/api/access", access_default);
14472
14510
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
14473
14511
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
14474
14512
  var IMAGE_MIME = {
@@ -14480,7 +14518,7 @@ var IMAGE_MIME = {
14480
14518
  ".svg": "image/svg+xml",
14481
14519
  ".ico": "image/x-icon"
14482
14520
  };
14483
- app40.get("/agent-assets/:slug/:filename", (c) => {
14521
+ app39.get("/agent-assets/:slug/:filename", (c) => {
14484
14522
  const slug = c.req.param("slug");
14485
14523
  const filename = c.req.param("filename");
14486
14524
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -14496,13 +14534,13 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
14496
14534
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
14497
14535
  return c.text("Not found", 404);
14498
14536
  }
14499
- const filePath = resolve24(account.accountDir, "agents", slug, "assets", filename);
14500
- const expectedDir = resolve24(account.accountDir, "agents", slug, "assets");
14537
+ const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
14538
+ const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
14501
14539
  if (!filePath.startsWith(expectedDir + "/")) {
14502
14540
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
14503
14541
  return c.text("Forbidden", 403);
14504
14542
  }
14505
- if (!existsSync23(filePath)) {
14543
+ if (!existsSync22(filePath)) {
14506
14544
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
14507
14545
  return c.text("Not found", 404);
14508
14546
  }
@@ -14515,7 +14553,7 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
14515
14553
  "Cache-Control": "public, max-age=3600"
14516
14554
  });
14517
14555
  });
14518
- app40.get("/generated/:filename", (c) => {
14556
+ app39.get("/generated/:filename", (c) => {
14519
14557
  const filename = c.req.param("filename");
14520
14558
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
14521
14559
  console.error(`[generated] serve file=${filename} status=403`);
@@ -14526,13 +14564,13 @@ app40.get("/generated/:filename", (c) => {
14526
14564
  console.error(`[generated] serve file=${filename} status=404`);
14527
14565
  return c.text("Not found", 404);
14528
14566
  }
14529
- const filePath = resolve24(account.accountDir, "generated", filename);
14530
- const expectedDir = resolve24(account.accountDir, "generated");
14567
+ const filePath = resolve23(account.accountDir, "generated", filename);
14568
+ const expectedDir = resolve23(account.accountDir, "generated");
14531
14569
  if (!filePath.startsWith(expectedDir + "/")) {
14532
14570
  console.error(`[generated] serve file=${filename} status=403`);
14533
14571
  return c.text("Forbidden", 403);
14534
14572
  }
14535
- if (!existsSync23(filePath)) {
14573
+ if (!existsSync22(filePath)) {
14536
14574
  console.error(`[generated] serve file=${filename} status=404`);
14537
14575
  return c.text("Not found", 404);
14538
14576
  }
@@ -14545,14 +14583,14 @@ app40.get("/generated/:filename", (c) => {
14545
14583
  "Cache-Control": "public, max-age=86400"
14546
14584
  });
14547
14585
  });
14548
- app40.route("/sites", sites_default);
14549
- app40.route("/listings", listings_default);
14550
- app40.route("/v", visitor_event_default);
14551
- app40.route("/v", visitor_consent_default);
14586
+ app39.route("/sites", sites_default);
14587
+ app39.route("/listings", listings_default);
14588
+ app39.route("/v", visitor_event_default);
14589
+ app39.route("/v", visitor_consent_default);
14552
14590
  var htmlCache = /* @__PURE__ */ new Map();
14553
14591
  var brandLogoPath = "/brand/maxy-monochrome.png";
14554
14592
  var brandIconPath = "/brand/maxy-monochrome.png";
14555
- if (BRAND_JSON_PATH && existsSync23(BRAND_JSON_PATH)) {
14593
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
14556
14594
  try {
14557
14595
  const fullBrand = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
14558
14596
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
@@ -14572,7 +14610,7 @@ function readInstalledVersion() {
14572
14610
  try {
14573
14611
  if (!PLATFORM_ROOT9) return "unknown";
14574
14612
  const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
14575
- if (!existsSync23(versionFile)) return "unknown";
14613
+ if (!existsSync22(versionFile)) return "unknown";
14576
14614
  const content = readFileSync20(versionFile, "utf-8").trim();
14577
14615
  return content || "unknown";
14578
14616
  } catch {
@@ -14614,7 +14652,7 @@ var clientErrorReporterScript = `<script>
14614
14652
  function cachedHtml(file) {
14615
14653
  let html = htmlCache.get(file);
14616
14654
  if (!html) {
14617
- html = readFileSync20(resolve24(process.cwd(), "public", file), "utf-8");
14655
+ html = readFileSync20(resolve23(process.cwd(), "public", file), "utf-8");
14618
14656
  const productNameEsc = escapeHtml(BRAND.productName);
14619
14657
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
14620
14658
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -14633,12 +14671,12 @@ function loadBrandingCache(agentSlug) {
14633
14671
  const configDir2 = join15(homedir2(), BRAND.configDir);
14634
14672
  try {
14635
14673
  const accountJsonPath = join15(configDir2, "account.json");
14636
- if (!existsSync23(accountJsonPath)) return null;
14674
+ if (!existsSync22(accountJsonPath)) return null;
14637
14675
  const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
14638
14676
  const accountId = account.accountId;
14639
14677
  if (!accountId) return null;
14640
14678
  const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
14641
- if (!existsSync23(cachePath)) return null;
14679
+ if (!existsSync22(cachePath)) return null;
14642
14680
  return JSON.parse(readFileSync20(cachePath, "utf-8"));
14643
14681
  } catch {
14644
14682
  return null;
@@ -14648,7 +14686,7 @@ function resolveDefaultSlug() {
14648
14686
  try {
14649
14687
  const configDir2 = join15(homedir2(), BRAND.configDir);
14650
14688
  const accountJsonPath = join15(configDir2, "account.json");
14651
- if (!existsSync23(accountJsonPath)) return null;
14689
+ if (!existsSync22(accountJsonPath)) return null;
14652
14690
  const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
14653
14691
  return account.defaultAgent || null;
14654
14692
  } catch {
@@ -14685,7 +14723,7 @@ function brandedPublicHtml(agentSlug) {
14685
14723
  function escapeHtml(s) {
14686
14724
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
14687
14725
  }
14688
- app40.get("/", (c) => {
14726
+ app39.get("/", (c) => {
14689
14727
  const host = (c.req.header("host") ?? "").split(":")[0];
14690
14728
  if (isPublicHost(host)) {
14691
14729
  const defaultSlug = resolveDefaultSlug();
@@ -14693,12 +14731,12 @@ app40.get("/", (c) => {
14693
14731
  }
14694
14732
  return c.html(cachedHtml("index.html"));
14695
14733
  });
14696
- app40.get("/public", (c) => {
14734
+ app39.get("/public", (c) => {
14697
14735
  const host = (c.req.header("host") ?? "").split(":")[0];
14698
14736
  if (isPublicHost(host)) return c.text("Not found", 404);
14699
14737
  return c.html(cachedHtml("public.html"));
14700
14738
  });
14701
- app40.get("/chat", (c) => {
14739
+ app39.get("/chat", (c) => {
14702
14740
  const host = (c.req.header("host") ?? "").split(":")[0];
14703
14741
  if (isPublicHost(host)) return c.text("Not found", 404);
14704
14742
  return c.html(cachedHtml("public.html"));
@@ -14717,12 +14755,12 @@ async function logViewerFetch(c, next) {
14717
14755
  duration_ms: Date.now() - start
14718
14756
  });
14719
14757
  }
14720
- app40.use("/vnc-viewer.html", logViewerFetch);
14721
- app40.use("/vnc-popout.html", logViewerFetch);
14722
- app40.get("/vnc-popout.html", (c) => {
14758
+ app39.use("/vnc-viewer.html", logViewerFetch);
14759
+ app39.use("/vnc-popout.html", logViewerFetch);
14760
+ app39.get("/vnc-popout.html", (c) => {
14723
14761
  let html = htmlCache.get("vnc-popout.html");
14724
14762
  if (!html) {
14725
- html = readFileSync20(resolve24(process.cwd(), "public", "vnc-popout.html"), "utf-8");
14763
+ html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
14726
14764
  const name = escapeHtml(BRAND.productName);
14727
14765
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
14728
14766
  html = html.replace("</head>", ` ${brandScript}
@@ -14732,7 +14770,7 @@ app40.get("/vnc-popout.html", (c) => {
14732
14770
  }
14733
14771
  return c.html(html);
14734
14772
  });
14735
- app40.post("/api/vnc/client-event", async (c) => {
14773
+ app39.post("/api/vnc/client-event", async (c) => {
14736
14774
  let body;
14737
14775
  try {
14738
14776
  body = await c.req.json();
@@ -14753,25 +14791,25 @@ app40.post("/api/vnc/client-event", async (c) => {
14753
14791
  });
14754
14792
  return c.json({ ok: true });
14755
14793
  });
14756
- app40.get("/g/:slug", (c) => {
14794
+ app39.get("/g/:slug", (c) => {
14757
14795
  return c.html(brandedPublicHtml());
14758
14796
  });
14759
- app40.get("/graph", (c) => {
14797
+ app39.get("/graph", (c) => {
14760
14798
  const host = (c.req.header("host") ?? "").split(":")[0];
14761
14799
  if (isPublicHost(host)) return c.text("Not found", 404);
14762
14800
  return c.html(cachedHtml("graph.html"));
14763
14801
  });
14764
- app40.get("/sessions", (c) => {
14802
+ app39.get("/sessions", (c) => {
14765
14803
  const host = (c.req.header("host") ?? "").split(":")[0];
14766
14804
  if (isPublicHost(host)) return c.text("Not found", 404);
14767
14805
  return c.html(cachedHtml("sessions.html"));
14768
14806
  });
14769
- app40.get("/data", (c) => {
14807
+ app39.get("/data", (c) => {
14770
14808
  const host = (c.req.header("host") ?? "").split(":")[0];
14771
14809
  if (isPublicHost(host)) return c.text("Not found", 404);
14772
14810
  return c.html(cachedHtml("data.html"));
14773
14811
  });
14774
- app40.get("/:slug", async (c, next) => {
14812
+ app39.get("/:slug", async (c, next) => {
14775
14813
  const slug = c.req.param("slug");
14776
14814
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
14777
14815
  const branding = loadBrandingCache(slug);
@@ -14781,15 +14819,15 @@ app40.get("/:slug", async (c, next) => {
14781
14819
  await next();
14782
14820
  });
14783
14821
  if (brandFaviconPath !== "/favicon.ico") {
14784
- app40.get("/favicon.ico", (c) => {
14822
+ app39.get("/favicon.ico", (c) => {
14785
14823
  c.header("Cache-Control", "public, max-age=300");
14786
14824
  return c.redirect(brandFaviconPath, 302);
14787
14825
  });
14788
14826
  }
14789
- app40.use("/*", serveStatic({ root: "./public" }));
14827
+ app39.use("/*", serveStatic({ root: "./public" }));
14790
14828
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
14791
14829
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
14792
- var httpServer = serve({ fetch: app40.fetch, port, hostname });
14830
+ var httpServer = serve({ fetch: app39.fetch, port, hostname });
14793
14831
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
14794
14832
  {
14795
14833
  const loopHist = monitorEventLoopDelay({ resolution: 50 });
@@ -14825,7 +14863,7 @@ for (const m of SUBAPP_MANIFEST) {
14825
14863
  }
14826
14864
  try {
14827
14865
  const registered = [];
14828
- for (const r of app40.routes ?? []) {
14866
+ for (const r of app39.routes ?? []) {
14829
14867
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
14830
14868
  if (AGENT_SLUG_PATTERN.test(r.path)) {
14831
14869
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -14847,7 +14885,7 @@ try {
14847
14885
  }
14848
14886
  (async () => {
14849
14887
  try {
14850
- if (!existsSync23(USERS_FILE)) return;
14888
+ if (!existsSync22(USERS_FILE)) return;
14851
14889
  const usersRaw = readFileSync20(USERS_FILE, "utf-8").trim();
14852
14890
  if (!usersRaw) return;
14853
14891
  const users = JSON.parse(usersRaw);
@@ -14864,6 +14902,9 @@ try {
14864
14902
  }
14865
14903
  })();
14866
14904
  startGraphHealthTimer();
14905
+ void startFileWatcher().catch((err) => {
14906
+ console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
14907
+ });
14867
14908
  try {
14868
14909
  const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
14869
14910
  console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
@@ -14882,7 +14923,7 @@ try {
14882
14923
  } catch (err) {
14883
14924
  console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
14884
14925
  }
14885
- var configDirForWhatsApp = basename5(MAXY_DIR) || ".maxy";
14926
+ var configDirForWhatsApp = basename6(MAXY_DIR) || ".maxy";
14886
14927
  var bootAccount = resolveAccount();
14887
14928
  var bootAccountConfig = bootAccount?.config;
14888
14929
  var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
@@ -14940,7 +14981,7 @@ if (bootAccountConfig?.whatsapp) {
14940
14981
  }
14941
14982
  init({
14942
14983
  configDir: configDirForWhatsApp,
14943
- platformRoot: resolve24(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
14984
+ platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
14944
14985
  accountConfig: bootAccountConfig,
14945
14986
  onMessage: async (msg) => {
14946
14987
  if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {