@rubytech/create-maxy 1.0.647 → 1.0.649

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 (150) hide show
  1. package/dist/index.js +76 -3
  2. package/package.json +1 -1
  3. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +1 -11
  4. package/payload/platform/plugins/cloudflare/PLUGIN.md +3 -2
  5. package/payload/platform/plugins/cloudflare/scripts/_cdp-authorize.mjs +274 -0
  6. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.sh +69 -0
  7. package/payload/platform/plugins/cloudflare/scripts/list-cf-domains.ts +401 -0
  8. package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +73 -3
  9. package/payload/platform/plugins/cloudflare/skills/setup-tunnel/SKILL.md +4 -2
  10. package/payload/platform/plugins/docs/references/cloudflare.md +1 -0
  11. package/payload/platform/plugins/docs/references/deployment.md +11 -0
  12. package/payload/platform/plugins/docs/references/getting-started.md +2 -0
  13. package/payload/platform/plugins/docs/references/memory-guide.md +2 -2
  14. package/payload/platform/plugins/docs/references/platform.md +6 -0
  15. package/payload/platform/plugins/docs/references/troubleshooting.md +16 -0
  16. package/payload/platform/plugins/memory/references/graph-primitives.md +5 -5
  17. package/payload/platform/templates/dotfiles/.tmux.conf +1 -0
  18. package/payload/platform/templates/systemd/maxy-ttyd.service +20 -0
  19. package/payload/server/public/assets/admin-BtjYSo0M.js +362 -0
  20. package/payload/server/public/assets/admin-kHJ-D0s7.css +1 -0
  21. package/payload/server/public/assets/{arc-DcrodP5U.js → arc-BMhgytDB.js} +1 -1
  22. package/payload/server/public/assets/architecture-YZFGNWBL-S9-oeq_x.js +1 -0
  23. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Cvo_8X6C.js → architectureDiagram-Q4EWVU46-BePoi8XC.js} +1 -1
  24. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CEK06TEn.js → blockDiagram-DXYQGD6D-BkiwLTtq.js} +1 -1
  25. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-QjYUSwTU.js → c4Diagram-AHTNJAMY-bpjPj2Ln.js} +1 -1
  26. package/payload/server/public/assets/channel-D3U0_a1j.js +1 -0
  27. package/payload/server/public/assets/{chunk-2KRD3SAO-BBifNfFc.js → chunk-2KRD3SAO-ZcHg_orY.js} +1 -1
  28. package/payload/server/public/assets/{chunk-336JU56O-B-N_zWuf.js → chunk-336JU56O-BpATJiGl.js} +2 -2
  29. package/payload/server/public/assets/chunk-426QAEUC-Wz6Bpsil.js +1 -0
  30. package/payload/server/public/assets/{chunk-4BX2VUAB-CtDQKj9B.js → chunk-4BX2VUAB-zJekz2NU.js} +1 -1
  31. package/payload/server/public/assets/{chunk-4TB4RGXK-Dnu9n3p1.js → chunk-4TB4RGXK-CLXL19Wd.js} +1 -1
  32. package/payload/server/public/assets/{chunk-55IACEB6-DSLoJJSj.js → chunk-55IACEB6-CzqB8aoU.js} +1 -1
  33. package/payload/server/public/assets/{chunk-5FUZZQ4R-rx-IvMNE.js → chunk-5FUZZQ4R-BoTfWHuW.js} +1 -1
  34. package/payload/server/public/assets/{chunk-5PVQY5BW-B9w9AKCS.js → chunk-5PVQY5BW-RhIfPCRB.js} +1 -1
  35. package/payload/server/public/assets/{chunk-67CJDMHE-C1yEjtiu.js → chunk-67CJDMHE-mM1sFmlz.js} +1 -1
  36. package/payload/server/public/assets/{chunk-7N4EOEYR-C2f3zeVH.js → chunk-7N4EOEYR-GUck0jv1.js} +1 -1
  37. package/payload/server/public/assets/{chunk-AA7GKIK3-B_U-NsDK.js → chunk-AA7GKIK3-BYhfUc1V.js} +1 -1
  38. package/payload/server/public/assets/{chunk-BSJP7CBP-DM6_wafW.js → chunk-BSJP7CBP-CTsYuARh.js} +1 -1
  39. package/payload/server/public/assets/{chunk-CIAEETIT-DG7WkfNj.js → chunk-CIAEETIT-CGsGmUze.js} +1 -1
  40. package/payload/server/public/assets/{chunk-EDXVE4YY-aS3_rdwQ.js → chunk-EDXVE4YY-utELKGQK.js} +1 -1
  41. package/payload/server/public/assets/{chunk-ENJZ2VHE-r1I0uoCf.js → chunk-ENJZ2VHE-CNHjq5xK.js} +1 -1
  42. package/payload/server/public/assets/{chunk-FMBD7UC4-CTm3YRE5.js → chunk-FMBD7UC4-DaRrfk3s.js} +1 -1
  43. package/payload/server/public/assets/{chunk-FOC6F5B3-CAIttx3K.js → chunk-FOC6F5B3-BaeLcJVt.js} +1 -1
  44. package/payload/server/public/assets/{chunk-ICPOFSXX-DQFV4c1l.js → chunk-ICPOFSXX-Di63NBur.js} +2 -2
  45. package/payload/server/public/assets/{chunk-K5T4RW27-B2WCPQBa.js → chunk-K5T4RW27-CTTOezMH.js} +1 -1
  46. package/payload/server/public/assets/{chunk-KGLVRYIC-C6w2sUOF.js → chunk-KGLVRYIC-DCkohKP2.js} +1 -1
  47. package/payload/server/public/assets/{chunk-LIHQZDEY-BT1hcDTK.js → chunk-LIHQZDEY-osQO30uB.js} +1 -1
  48. package/payload/server/public/assets/{chunk-ORNJ4GCN-Brl32BSe.js → chunk-ORNJ4GCN-DoLajOOe.js} +1 -1
  49. package/payload/server/public/assets/{chunk-OYMX7WX6-BCO6n1CX.js → chunk-OYMX7WX6-BSPzqyxs.js} +1 -1
  50. package/payload/server/public/assets/chunk-QZHKN3VN-BAQp1OEl.js +1 -0
  51. package/payload/server/public/assets/{chunk-U2HBQHQK-BvgC0fpb.js → chunk-U2HBQHQK-BZnA7c4T.js} +1 -1
  52. package/payload/server/public/assets/{chunk-X2U36JSP-3yLdcqYf.js → chunk-X2U36JSP-DpQ2OA_c.js} +1 -1
  53. package/payload/server/public/assets/{chunk-XPW4576I-D876RWxK.js → chunk-XPW4576I-BccP1mlQ.js} +1 -1
  54. package/payload/server/public/assets/{chunk-YZCP3GAM-CiuA4hOC.js → chunk-YZCP3GAM-BAkNXu0G.js} +1 -1
  55. package/payload/server/public/assets/{chunk-ZZ45TVLE-COjEBPzv.js → chunk-ZZ45TVLE-DBSm41oP.js} +1 -1
  56. package/payload/server/public/assets/classDiagram-6PBFFD2Q-6EGGLDD_.js +1 -0
  57. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DfAV4tgE.js +1 -0
  58. package/payload/server/public/assets/clone-BoV8noAi.js +1 -0
  59. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-Dap0yL0o.js → cose-bilkent-S5V4N54A-Boeb8aWs.js} +1 -1
  60. package/payload/server/public/assets/{dagre-KV5264BT-DEia9UJj.js → dagre-KV5264BT-BkvWofSp.js} +1 -1
  61. package/payload/server/public/assets/{dagre-DBbjK-Cf.js → dagre-nvPNAunb.js} +1 -1
  62. package/payload/server/public/assets/data-gtcFdXVv.js +1 -0
  63. package/payload/server/public/assets/{diagram-5BDNPKRD-CWSP9MzJ.js → diagram-5BDNPKRD-CMEgyt4E.js} +1 -1
  64. package/payload/server/public/assets/{diagram-G4DWMVQ6-DWRsfitL.js → diagram-G4DWMVQ6-ChorrAF0.js} +1 -1
  65. package/payload/server/public/assets/{diagram-MMDJMWI5-n-jyzS4D.js → diagram-MMDJMWI5-D_iD27po.js} +1 -1
  66. package/payload/server/public/assets/{diagram-TYMM5635-CLPTbfLq.js → diagram-TYMM5635-8qXI1ioG.js} +1 -1
  67. package/payload/server/public/assets/{dist-Tkw8EOuG.js → dist-CrzV1W3-.js} +1 -1
  68. package/payload/server/public/assets/{erDiagram-SMLLAGMA-CmPC9Cnc.js → erDiagram-SMLLAGMA-BFjtKDSB.js} +1 -1
  69. package/payload/server/public/assets/file-DRa7iPfT.js +1 -0
  70. package/payload/server/public/assets/{flatten-Db2kUB5j.js → flatten-ya0TqRLc.js} +1 -1
  71. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DKMNmUbX.js → flowDiagram-DWJPFMVM-Bpd7IL9l.js} +1 -1
  72. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-C5-y3w-l.js → ganttDiagram-T4ZO3ILL-CwOozU85.js} +1 -1
  73. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BOC4CldZ.js +1 -0
  74. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-D9hG5kTg.js → gitGraphDiagram-UUTBAWPF-CcPILiC9.js} +1 -1
  75. package/payload/server/public/assets/graph-ydtwufZX.js +49 -0
  76. package/payload/server/public/assets/{graphlib-StP6GUhM.js → graphlib-B_mcXEVr.js} +1 -1
  77. package/payload/server/public/assets/house-DEu5yOIQ.js +1 -0
  78. package/payload/server/public/assets/info-OMHHGYJF-BSCPTUIx.js +1 -0
  79. package/payload/server/public/assets/infoDiagram-42DDH7IO-T2sn--WJ.js +2 -0
  80. package/payload/server/public/assets/{isEmpty-CXH_nKTs.js → isEmpty-h-wRi_o9.js} +1 -1
  81. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A--K4KOS61.js → ishikawaDiagram-UXIWVN3A-DOP9-Q8H.js} +1 -1
  82. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DE-28YrW.js → journeyDiagram-VCZTEJTY-DGATg0WC.js} +1 -1
  83. package/payload/server/public/assets/{jsx-runtime-DwoXvzmf.js → jsx-runtime-BrB6Lw5Y.js} +1 -1
  84. package/payload/server/public/assets/{jsx-runtime-BQmd8XDE.css → jsx-runtime-C8kAju5f.css} +1 -1
  85. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CxSHjau2.js → kanban-definition-6JOO6SKY-C5PigmKg.js} +1 -1
  86. package/payload/server/public/assets/{line-DbcqYIG0.js → line-DlKKhwkO.js} +1 -1
  87. package/payload/server/public/assets/{linear-DXHoZSN3.js → linear-DD4JiB1l.js} +1 -1
  88. package/payload/server/public/assets/{mermaid-parser.core-CNGUA13J.js → mermaid-parser.core-C8xGCa9p.js} +2 -2
  89. package/payload/server/public/assets/{mermaid.core-IQgx_upQ.js → mermaid.core-CCUSwZB_.js} +3 -3
  90. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-BT9Up6-C.js → mindmap-definition-QFDTVHPH-75k-IVhC.js} +1 -1
  91. package/payload/server/public/assets/{ordinal-CN3oz6oW.js → ordinal-Dwxksj1B.js} +1 -1
  92. package/payload/server/public/assets/packet-4T2RLAQJ-pBa_ZhNI.js +1 -0
  93. package/payload/server/public/assets/pie-ZZUOXDRM-BzYOyiMb.js +1 -0
  94. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BuewQTi6.js → pieDiagram-DEJITSTG-DN5RsDwZ.js} +1 -1
  95. package/payload/server/public/assets/public-D0ymcICW.js +5 -0
  96. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-Cu8y2zQL.js → quadrantDiagram-34T5L4WZ-Sd9x6pNe.js} +1 -1
  97. package/payload/server/public/assets/radar-PYXPWWZC-CTVOaAq6.js +1 -0
  98. package/payload/server/public/assets/{reduce-SDh8_UdG.js → reduce-BUuWaDl2.js} +1 -1
  99. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DiT9bo27.js → requirementDiagram-MS252O5E-BDgifYzj.js} +1 -1
  100. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-EkRnGTxM.js → sankeyDiagram-XADWPNL6-BX9VULNJ.js} +1 -1
  101. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BUiQA3SI.js → sequenceDiagram-FGHM5R23-z3vMxhgE.js} +1 -1
  102. package/payload/server/public/assets/share-2-Cnd_9DYU.js +1 -0
  103. package/payload/server/public/assets/{src-DQQCRlaQ.js → src-Bo15iQ7w.js} +1 -1
  104. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Fij35Tic.js → stateDiagram-FHFEXIEX-DlP0hBxF.js} +1 -1
  105. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DSddQStC.js +1 -0
  106. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BMsyr7wU.js → timeline-definition-GMOUNBTQ-DwQbhKCo.js} +1 -1
  107. package/payload/server/public/assets/treeView-SZITEDCU-OTnF4Qzw.js +1 -0
  108. package/payload/server/public/assets/treemap-W4RFUUIX-DlIRmHFb.js +1 -0
  109. package/payload/server/public/assets/{useVoiceRecorder-C0Fvv_Bt.js → useVoiceRecorder-CFIpzGaB.js} +3 -3
  110. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-6fegYFB3.js → vennDiagram-DHZGUBPP-WTqmZWWa.js} +1 -1
  111. package/payload/server/public/assets/wardley-RL74JXVD-DwMXAC4U.js +1 -0
  112. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BtJ_B35h.js → wardleyDiagram-NUSXRM2D-BUY50x5T.js} +1 -1
  113. package/payload/server/public/assets/x-DitohdYO.js +1 -0
  114. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DJ20B4NY.js → xychartDiagram-5P7HB3ND-Btdq-fDj.js} +1 -1
  115. package/payload/server/public/data.html +7 -5
  116. package/payload/server/public/graph.html +19 -0
  117. package/payload/server/public/index.html +10 -7
  118. package/payload/server/public/public.html +6 -6
  119. package/payload/server/server.js +965 -664
  120. package/payload/server/public/assets/admin-ITLuG4BN.js +0 -352
  121. package/payload/server/public/assets/architecture-YZFGNWBL-C38eyeNF.js +0 -1
  122. package/payload/server/public/assets/channel-D0dIwjlN.js +0 -1
  123. package/payload/server/public/assets/chunk-426QAEUC-C8oXXITm.js +0 -1
  124. package/payload/server/public/assets/chunk-QZHKN3VN-BE_lylks.js +0 -1
  125. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DH37CWIF.js +0 -1
  126. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DNJ7bv8r.js +0 -1
  127. package/payload/server/public/assets/clone-rrGuX3ZR.js +0 -1
  128. package/payload/server/public/assets/data-D8kol1ed.js +0 -1
  129. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CCjgA3FG.js +0 -1
  130. package/payload/server/public/assets/info-OMHHGYJF-B65K6dQJ.js +0 -1
  131. package/payload/server/public/assets/infoDiagram-42DDH7IO-DUJfTICr.js +0 -2
  132. package/payload/server/public/assets/packet-4T2RLAQJ-fp5ishAK.js +0 -1
  133. package/payload/server/public/assets/pie-ZZUOXDRM-Bc3VMuuU.js +0 -1
  134. package/payload/server/public/assets/public-CWuf8cLU.js +0 -5
  135. package/payload/server/public/assets/radar-PYXPWWZC-D9jy5QAa.js +0 -1
  136. package/payload/server/public/assets/share-2-wGga_ldi.js +0 -1
  137. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-DQzhSd8K.js +0 -1
  138. package/payload/server/public/assets/treeView-SZITEDCU-CHyRL9e4.js +0 -1
  139. package/payload/server/public/assets/treemap-W4RFUUIX-DpQ_FOO6.js +0 -1
  140. package/payload/server/public/assets/wardley-RL74JXVD-CWBIAatW.js +0 -1
  141. /package/payload/server/public/assets/{_baseFor-D71p92tl.js → _baseFor-Dn4GSmI6.js} +0 -0
  142. /package/payload/server/public/assets/{array-Bs_owIvv.js → array-DJN9YAVf.js} +0 -0
  143. /package/payload/server/public/assets/{chunk-lgnzUk6H.js → chunk-DD-I1_y5.js} +0 -0
  144. /package/payload/server/public/assets/{cytoscape.esm-DLG5qhup.js → cytoscape.esm-BcJTl1re.js} +0 -0
  145. /package/payload/server/public/assets/{defaultLocale-Du_2bjyv.js → defaultLocale-B4F_XsBB.js} +0 -0
  146. /package/payload/server/public/assets/{init-BYLBkHX_.js → init-DX0Y1qU4.js} +0 -0
  147. /package/payload/server/public/assets/{katex-lkho_UhZ.js → katex-CjHJ1D7d.js} +0 -0
  148. /package/payload/server/public/assets/{path-BO54iFkf.js → path-7vUsG-o2.js} +0 -0
  149. /package/payload/server/public/assets/{preload-helper-DWTEM3RW.js → preload-helper-qlgyTAkD.js} +0 -0
  150. /package/payload/server/public/assets/{rough.esm-BCiZEpQC.js → rough.esm-NLRoWnq-.js} +0 -0
@@ -1201,14 +1201,14 @@ var Hono = class _Hono {
1201
1201
  * app.route("/api", app2) // GET /api/user
1202
1202
  * ```
1203
1203
  */
1204
- route(path2, app29) {
1204
+ route(path2, app30) {
1205
1205
  const subApp = this.basePath(path2);
1206
- app29.routes.map((r) => {
1206
+ app30.routes.map((r) => {
1207
1207
  let handler;
1208
- if (app29.errorHandler === errorHandler) {
1208
+ if (app30.errorHandler === errorHandler) {
1209
1209
  handler = r.handler;
1210
1210
  } else {
1211
- handler = async (c, next) => (await compose([], app29.errorHandler)(c, () => r.handler(c, next))).res;
1211
+ handler = async (c, next) => (await compose([], app30.errorHandler)(c, () => r.handler(c, next))).res;
1212
1212
  handler[COMPOSED_HANDLER] = r.handler;
1213
1213
  }
1214
1214
  subApp.#addRoute(r.method, r.path, handler);
@@ -2526,7 +2526,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
2526
2526
  });
2527
2527
  if (!chunk) {
2528
2528
  if (i === 1) {
2529
- await new Promise((resolve29) => setTimeout(resolve29));
2529
+ await new Promise((resolve30) => setTimeout(resolve30));
2530
2530
  maxReadCount = 3;
2531
2531
  continue;
2532
2532
  }
@@ -2892,8 +2892,8 @@ var serveStatic = (options = { root: "" }) => {
2892
2892
  };
2893
2893
 
2894
2894
  // server/index.ts
2895
- import { readFileSync as readFileSync26, existsSync as existsSync25, watchFile } from "fs";
2896
- import { resolve as resolve28, join as join13, basename as basename7 } from "path";
2895
+ import { readFileSync as readFileSync25, existsSync as existsSync24, watchFile } from "fs";
2896
+ import { resolve as resolve29, join as join13, basename as basename7 } from "path";
2897
2897
  import { homedir as homedir5 } from "os";
2898
2898
 
2899
2899
  // app/lib/vnc-logger.ts
@@ -2982,10 +2982,10 @@ var SCRYPT_R = 8;
2982
2982
  var SCRYPT_P = 1;
2983
2983
  var SCRYPT_KEYLEN = 64;
2984
2984
  function scryptAsync(password, salt) {
2985
- return new Promise((resolve29, reject) => {
2985
+ return new Promise((resolve30, reject) => {
2986
2986
  scrypt(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, r: SCRYPT_R, p: SCRYPT_P }, (err, key) => {
2987
2987
  if (err) reject(err);
2988
- else resolve29(key);
2988
+ else resolve30(key);
2989
2989
  });
2990
2990
  });
2991
2991
  }
@@ -3826,9 +3826,33 @@ Content-Length: 0\r
3826
3826
  socket.destroy();
3827
3827
  }
3828
3828
 
3829
- // server/graph-proxy.ts
3829
+ // server/ws-proxy-terminal.ts
3830
3830
  import { createConnection as createConnection2 } from "net";
3831
- var GRAPH_PREFIX = "/graph";
3831
+
3832
+ // app/lib/terminal-logger.ts
3833
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "fs";
3834
+ import { resolve as resolve3 } from "path";
3835
+ var TERMINAL_LOG_FILE = resolve3(LOG_DIR, "terminal.log");
3836
+ try {
3837
+ mkdirSync2(LOG_DIR, { recursive: true });
3838
+ } catch (err) {
3839
+ console.error(`[terminal-log-fail] mkdir ${LOG_DIR} failed: ${err.message}`);
3840
+ }
3841
+ function terminalLog(phase, fields = {}) {
3842
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
3843
+ const kv = Object.entries(fields).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ");
3844
+ const line = kv.length > 0 ? `[${ts}] [terminal-${phase}] ${kv}
3845
+ ` : `[${ts}] [terminal-${phase}]
3846
+ `;
3847
+ try {
3848
+ appendFileSync2(TERMINAL_LOG_FILE, line);
3849
+ } catch (err) {
3850
+ console.error(`[terminal-log-fail] ${err.message} \u2014 dropped: ${line.slice(0, 300).trim()}`);
3851
+ }
3852
+ }
3853
+
3854
+ // server/ws-proxy-terminal.ts
3855
+ var WS_PATH2 = "/admin/terminal/ws";
3832
3856
  var UPSTREAM_TIMEOUT_MS2 = 5e3;
3833
3857
  var HOP_BY_HOP2 = /* @__PURE__ */ new Set([
3834
3858
  "connection",
@@ -3840,194 +3864,225 @@ var HOP_BY_HOP2 = /* @__PURE__ */ new Set([
3840
3864
  "transfer-encoding",
3841
3865
  "upgrade"
3842
3866
  ]);
3843
- var cachedUpstreamPort = null;
3844
- function resolveUpstreamPort() {
3845
- if (cachedUpstreamPort !== null) return cachedUpstreamPort;
3846
- const uri = process.env.NEO4J_URI;
3847
- if (!uri) {
3848
- throw new Error(
3849
- "[ui/graph-proxy] NEO4J_URI unset \u2014 refusing to default to bolt://localhost:7687 (Task 580)"
3850
- );
3851
- }
3852
- const m = uri.match(/:(\d+)$/);
3853
- const boltPort = m ? parseInt(m[1], 10) : 7687;
3854
- cachedUpstreamPort = boltPort - 213;
3855
- console.error(`[ui/graph-proxy] resolved neo4j_uri=${uri} http_port=${cachedUpstreamPort}`);
3856
- return cachedUpstreamPort;
3857
- }
3858
- var UPSTREAM_HOST = "127.0.0.1";
3859
- function attachGraphHttpRoutes(app29) {
3860
- const handler = async (c) => {
3861
- const raw2 = c.req.raw;
3862
- const url = new URL(raw2.url);
3863
- const upstreamPort = resolveUpstreamPort();
3864
- const pathAfterPrefix = url.pathname.slice(GRAPH_PREFIX.length) || "/";
3865
- const upstreamUrl = `http://${UPSTREAM_HOST}:${upstreamPort}${pathAfterPrefix}${url.search}`;
3866
- const upstreamHeaders = new Headers(raw2.headers);
3867
- for (const h of HOP_BY_HOP2) upstreamHeaders.delete(h);
3868
- upstreamHeaders.set("host", `${UPSTREAM_HOST}:${upstreamPort}`);
3869
- try {
3870
- const upstream = await fetch(upstreamUrl, {
3871
- method: raw2.method,
3872
- headers: upstreamHeaders,
3873
- body: raw2.body,
3874
- // `duplex: 'half'` is required when forwarding a streaming body; TS
3875
- // typings do not yet expose it but the undici runtime supports it.
3876
- ...raw2.body ? { duplex: "half" } : {},
3877
- redirect: "manual"
3878
- });
3879
- const resHeaders = new Headers(upstream.headers);
3880
- for (const h of HOP_BY_HOP2) resHeaders.delete(h);
3881
- const loc = resHeaders.get("location");
3882
- if (loc) {
3883
- const rewritten = rewriteLocation(loc);
3884
- if (rewritten !== loc) resHeaders.set("location", rewritten);
3885
- }
3886
- return new Response(upstream.body, {
3887
- status: upstream.status,
3888
- statusText: upstream.statusText,
3889
- headers: resHeaders
3890
- });
3891
- } catch (err) {
3892
- const msg = err instanceof Error ? err.message : String(err);
3893
- console.error(`[graph-proxy] upstream fetch failed for ${upstreamUrl}: ${msg}`);
3894
- return c.text(`Graph proxy upstream unreachable: ${msg}`, 502);
3895
- }
3896
- };
3897
- app29.all(GRAPH_PREFIX, handler);
3898
- app29.all(`${GRAPH_PREFIX}/*`, handler);
3899
- }
3900
- function attachGraphWsProxy(server, opts) {
3867
+ function attachTerminalWsProxy(server, opts) {
3868
+ const upstreamHost = opts.upstreamHost ?? "127.0.0.1";
3869
+ const upstreamPort = opts.upstreamPort ?? 7681;
3901
3870
  server.on("upgrade", (req, clientSocket, head) => {
3902
3871
  try {
3903
- const url = req.url ?? "";
3904
- const qsIndex = url.indexOf("?");
3905
- const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
3906
- const isGraphPath = pathname === GRAPH_PREFIX || pathname.startsWith(`${GRAPH_PREFIX}/`);
3907
- if (!isGraphPath) {
3908
- if (pathname !== "/websockify") {
3909
- clientSocket.destroy();
3910
- }
3911
- return;
3912
- }
3913
- const hostHeader = (req.headers.host ?? "").split(":")[0];
3914
- const remote = req.socket.remoteAddress;
3915
- const xff = headerString2(req.headers["x-forwarded-for"]);
3916
- const cookie = headerString2(req.headers.cookie);
3917
- const decision = opts.canAccessAdmin({
3918
- host: hostHeader,
3919
- remoteAddress: remote,
3920
- xForwardedFor: xff,
3921
- cookieHeader: cookie,
3922
- isPublicHost: opts.isPublicHost
3923
- });
3924
- if (!decision.allow) {
3925
- const status = decision.reason === "public-host" ? 404 : 401;
3926
- writeStatusAndDestroy2(clientSocket, status, decision.reason === "public-host" ? "Not Found" : "Unauthorized");
3927
- return;
3928
- }
3929
- const originHeader = headerString2(req.headers.origin);
3930
- const originHost = parseOriginHost2(originHeader);
3931
- if (!originHost || originHost !== hostHeader || opts.isPublicHost(originHost)) {
3932
- writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
3933
- return;
3934
- }
3935
- const rewrittenPath = pathname === GRAPH_PREFIX ? "/" : pathname.slice(GRAPH_PREFIX.length);
3936
- const rewrittenUrl = qsIndex === -1 ? rewrittenPath : rewrittenPath + url.slice(qsIndex);
3937
- const upstreamPort = resolveUpstreamPort();
3938
- const upstream = createConnection2({ host: UPSTREAM_HOST, port: upstreamPort });
3939
- upstream.setTimeout(UPSTREAM_TIMEOUT_MS2);
3940
- upstream.once("connect", () => {
3941
- upstream.setTimeout(0);
3942
- const lines = [];
3943
- lines.push(`${req.method ?? "GET"} ${rewrittenUrl} HTTP/${req.httpVersion}`);
3944
- lines.push(`host: ${UPSTREAM_HOST}:${upstreamPort}`);
3945
- for (const [name, value] of Object.entries(req.headers)) {
3946
- if (name === "host") continue;
3947
- if (HOP_BY_HOP2.has(name)) continue;
3948
- if (value == null) continue;
3949
- if (Array.isArray(value)) {
3950
- for (const v of value) lines.push(`${name}: ${v}`);
3951
- } else {
3952
- lines.push(`${name}: ${value}`);
3953
- }
3954
- }
3955
- const upgradeHeader = headerString2(req.headers.upgrade);
3956
- const connectionHeader = headerString2(req.headers.connection);
3957
- if (upgradeHeader) lines.push(`upgrade: ${upgradeHeader}`);
3958
- if (connectionHeader) lines.push(`connection: ${connectionHeader}`);
3959
- upstream.write(lines.join("\r\n") + "\r\n\r\n");
3960
- if (head && head.length > 0) upstream.write(head);
3961
- clientSocket.pipe(upstream);
3962
- upstream.pipe(clientSocket);
3963
- const teardown = () => {
3964
- clientSocket.destroy();
3965
- upstream.destroy();
3966
- };
3967
- clientSocket.once("close", teardown);
3968
- upstream.once("close", teardown);
3969
- clientSocket.once("error", teardown);
3970
- upstream.once("error", teardown);
3971
- });
3972
- upstream.once("timeout", () => {
3973
- writeStatusAndDestroy2(clientSocket, 504, "Gateway Timeout");
3974
- upstream.destroy();
3975
- });
3976
- upstream.once("error", (err) => {
3977
- console.error(`[graph-proxy] ws upstream error: ${err.message}`);
3978
- writeStatusAndDestroy2(clientSocket, 502, "Bad Gateway");
3979
- upstream.destroy();
3872
+ handleUpgrade2(req, clientSocket, head, {
3873
+ isPublicHost: opts.isPublicHost,
3874
+ upstreamHost,
3875
+ upstreamPort
3980
3876
  });
3981
3877
  } catch (err) {
3982
- console.error(`[graph-proxy] upgrade handler exception: ${err.message}`);
3878
+ terminalLog("ws-upgrade", {
3879
+ decision: "rejected",
3880
+ reason: "handler-exception",
3881
+ err: err.message
3882
+ });
3983
3883
  clientSocket.destroy();
3984
3884
  }
3985
3885
  });
3986
3886
  }
3987
- function graphAuthMiddleware(opts) {
3988
- return async (c, next) => {
3989
- const url = new URL(c.req.raw.url);
3990
- if (!url.pathname.startsWith(GRAPH_PREFIX)) return next();
3991
- const hostHeader = (c.req.header("host") ?? "").split(":")[0];
3992
- const incoming = c.env?.incoming;
3993
- const remote = incoming?.socket?.remoteAddress;
3994
- const xff = c.req.header("x-forwarded-for");
3995
- const cookie = c.req.header("cookie");
3996
- const decision = opts.canAccessAdmin({
3887
+ function handleUpgrade2(req, clientSocket, head, opts) {
3888
+ const url = req.url ?? "";
3889
+ const qsIndex = url.indexOf("?");
3890
+ const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
3891
+ if (pathname !== WS_PATH2) {
3892
+ return;
3893
+ }
3894
+ const corrId = newCorrId();
3895
+ const query = qsIndex === -1 ? "" : url.slice(qsIndex + 1);
3896
+ const rawClientCorrId = parseQueryParam2(query, "corrId");
3897
+ const clientCorrId = sanitizeClientCorrId(rawClientCorrId);
3898
+ const hostHeader = (req.headers.host ?? "").split(":")[0];
3899
+ const originHeader = headerString2(req.headers.origin);
3900
+ const remote = req.socket.remoteAddress;
3901
+ const xff = headerString2(req.headers["x-forwarded-for"]);
3902
+ const decision = canAccessAdmin({
3903
+ host: hostHeader,
3904
+ remoteAddress: remote,
3905
+ xForwardedFor: xff,
3906
+ cookieHeader: headerString2(req.headers.cookie),
3907
+ isPublicHost: opts.isPublicHost
3908
+ });
3909
+ if (!decision.allow) {
3910
+ const status = decision.reason === "public-host" ? 404 : 401;
3911
+ terminalLog("ws-upgrade", {
3912
+ corrId,
3913
+ clientCorrId: clientCorrId ?? null,
3914
+ decision: "rejected",
3915
+ reason: decision.reason,
3916
+ ip: remote,
3917
+ xff: xff ?? null,
3918
+ origin: originHeader ?? null,
3919
+ host: hostHeader
3920
+ });
3921
+ writeStatusAndDestroy2(clientSocket, status, decision.reason === "public-host" ? "Not Found" : "Unauthorized");
3922
+ return;
3923
+ }
3924
+ const originHost = parseOriginHost2(originHeader);
3925
+ if (!originHost) {
3926
+ terminalLog("ws-upgrade", {
3927
+ corrId,
3928
+ clientCorrId: clientCorrId ?? null,
3929
+ decision: "rejected",
3930
+ reason: "origin-missing-or-invalid",
3931
+ origin: originHeader ?? null,
3997
3932
  host: hostHeader,
3998
- remoteAddress: remote,
3999
- xForwardedFor: xff,
4000
- cookieHeader: cookie,
4001
- isPublicHost: opts.isPublicHost
3933
+ ip: remote
4002
3934
  });
4003
- if (!decision.allow) {
4004
- return c.text(
4005
- decision.reason === "public-host" ? "Not Found" : "Unauthorized",
4006
- decision.reason === "public-host" ? 404 : 401
4007
- );
3935
+ writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
3936
+ return;
3937
+ }
3938
+ if (originHost !== hostHeader) {
3939
+ terminalLog("ws-upgrade", {
3940
+ corrId,
3941
+ clientCorrId: clientCorrId ?? null,
3942
+ decision: "rejected",
3943
+ reason: "origin-mismatch",
3944
+ origin_host: originHost,
3945
+ host: hostHeader,
3946
+ ip: remote
3947
+ });
3948
+ writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
3949
+ return;
3950
+ }
3951
+ if (opts.isPublicHost(originHost)) {
3952
+ terminalLog("ws-upgrade", {
3953
+ corrId,
3954
+ clientCorrId: clientCorrId ?? null,
3955
+ decision: "rejected",
3956
+ reason: "origin-public-host",
3957
+ origin_host: originHost,
3958
+ host: hostHeader,
3959
+ ip: remote
3960
+ });
3961
+ writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
3962
+ return;
3963
+ }
3964
+ terminalLog("ws-upgrade", {
3965
+ corrId,
3966
+ clientCorrId: clientCorrId ?? null,
3967
+ decision: "accepted",
3968
+ ip: remote,
3969
+ xff: xff ?? null,
3970
+ origin: originHeader ?? null,
3971
+ host: hostHeader,
3972
+ sec_ws_version: headerString2(req.headers["sec-websocket-version"]) ?? null,
3973
+ sec_ws_protocol: headerString2(req.headers["sec-websocket-protocol"]) ?? null
3974
+ });
3975
+ const upstream = createConnection2({ host: opts.upstreamHost, port: opts.upstreamPort });
3976
+ upstream.setTimeout(UPSTREAM_TIMEOUT_MS2);
3977
+ let bytesClientToUpstream = 0;
3978
+ let bytesUpstreamToClient = 0;
3979
+ let closedBy = null;
3980
+ let proxyOpened = false;
3981
+ const finish = (side, reason) => {
3982
+ if (closedBy) return;
3983
+ closedBy = side;
3984
+ if (proxyOpened) {
3985
+ terminalLog("proxy-close", {
3986
+ corrId,
3987
+ closedBy: side,
3988
+ reason,
3989
+ clientBytes: bytesClientToUpstream,
3990
+ upstreamBytes: bytesUpstreamToClient
3991
+ });
4008
3992
  }
4009
- return next();
3993
+ clientSocket.destroy();
3994
+ upstream.destroy();
4010
3995
  };
3996
+ upstream.once("connect", () => {
3997
+ upstream.setTimeout(0);
3998
+ proxyOpened = true;
3999
+ terminalLog("proxy-open", {
4000
+ corrId,
4001
+ upstream: `${opts.upstreamHost}:${opts.upstreamPort}`
4002
+ });
4003
+ const lines = [];
4004
+ lines.push(`${req.method ?? "GET"} ${WS_PATH2} HTTP/${req.httpVersion}`);
4005
+ lines.push(`host: ${opts.upstreamHost}:${opts.upstreamPort}`);
4006
+ for (const [name, value] of Object.entries(req.headers)) {
4007
+ if (name === "host") continue;
4008
+ if (HOP_BY_HOP2.has(name)) continue;
4009
+ if (value == null) continue;
4010
+ if (Array.isArray(value)) {
4011
+ for (const v of value) lines.push(`${name}: ${v}`);
4012
+ } else {
4013
+ lines.push(`${name}: ${value}`);
4014
+ }
4015
+ }
4016
+ const upgradeHeader = headerString2(req.headers.upgrade);
4017
+ const connectionHeader = headerString2(req.headers.connection);
4018
+ if (upgradeHeader) lines.push(`upgrade: ${upgradeHeader}`);
4019
+ if (connectionHeader) lines.push(`connection: ${connectionHeader}`);
4020
+ upstream.write(lines.join("\r\n") + "\r\n\r\n");
4021
+ if (head && head.length > 0) upstream.write(head);
4022
+ clientSocket.on("data", (chunk) => {
4023
+ bytesClientToUpstream += chunk.length;
4024
+ });
4025
+ upstream.on("data", (chunk) => {
4026
+ bytesUpstreamToClient += chunk.length;
4027
+ });
4028
+ clientSocket.pipe(upstream);
4029
+ upstream.pipe(clientSocket);
4030
+ clientSocket.once("close", (hadError) => {
4031
+ finish("client", hadError ? "error" : "normal");
4032
+ });
4033
+ upstream.once("close", (hadError) => {
4034
+ finish("upstream", hadError ? "error" : "normal");
4035
+ });
4036
+ clientSocket.once("error", (err) => {
4037
+ terminalLog("proxy-error", { corrId, side: "client", err: err.message });
4038
+ finish("client", "error");
4039
+ });
4040
+ upstream.once("error", (err) => {
4041
+ terminalLog("proxy-error", { corrId, side: "upstream", err: err.message });
4042
+ finish("upstream", "error");
4043
+ });
4044
+ });
4045
+ upstream.once("timeout", () => {
4046
+ if (proxyOpened) return;
4047
+ terminalLog("proxy-error", {
4048
+ corrId,
4049
+ side: "upstream-connect",
4050
+ err: "timeout",
4051
+ timeout_ms: UPSTREAM_TIMEOUT_MS2
4052
+ });
4053
+ writeStatusAndDestroy2(clientSocket, 504, "Gateway Timeout");
4054
+ upstream.destroy();
4055
+ });
4056
+ upstream.once("error", (err) => {
4057
+ if (proxyOpened) return;
4058
+ terminalLog("proxy-error", {
4059
+ corrId,
4060
+ side: "upstream-connect",
4061
+ err: err.message
4062
+ });
4063
+ writeStatusAndDestroy2(clientSocket, 502, "Bad Gateway");
4064
+ upstream.destroy();
4065
+ });
4066
+ }
4067
+ function parseQueryParam2(query, key) {
4068
+ if (!query) return null;
4069
+ for (const pair of query.split("&")) {
4070
+ const eq = pair.indexOf("=");
4071
+ const k = eq === -1 ? pair : pair.slice(0, eq);
4072
+ if (k !== key) continue;
4073
+ const v = eq === -1 ? "" : pair.slice(eq + 1);
4074
+ try {
4075
+ return decodeURIComponent(v);
4076
+ } catch {
4077
+ return null;
4078
+ }
4079
+ }
4080
+ return null;
4011
4081
  }
4012
4082
  function headerString2(value) {
4013
4083
  if (value == null) return void 0;
4014
4084
  return Array.isArray(value) ? value[0] : value;
4015
4085
  }
4016
- function rewriteLocation(location) {
4017
- try {
4018
- const parsed = new URL(location);
4019
- if (parsed.hostname === UPSTREAM_HOST && parsed.port === String(resolveUpstreamPort())) {
4020
- const pathWithQuery = parsed.pathname + parsed.search + parsed.hash;
4021
- return pathWithQuery.startsWith(GRAPH_PREFIX) ? pathWithQuery : `${GRAPH_PREFIX}${pathWithQuery}`;
4022
- }
4023
- return location;
4024
- } catch {
4025
- if (location.startsWith("/") && !location.startsWith(`${GRAPH_PREFIX}/`) && location !== GRAPH_PREFIX) {
4026
- return `${GRAPH_PREFIX}${location}`;
4027
- }
4028
- return location;
4029
- }
4030
- }
4031
4086
  function parseOriginHost2(origin) {
4032
4087
  if (!origin) return null;
4033
4088
  try {
@@ -4057,9 +4112,9 @@ var AGENT_SLUG_PATTERN = /^\/([a-z][a-z0-9-]{2,49})$/;
4057
4112
  import Anthropic2 from "@anthropic-ai/sdk";
4058
4113
  import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
4059
4114
  import { randomUUID as randomUUID2 } from "crypto";
4060
- import { resolve as resolve6, join as join4 } from "path";
4115
+ import { resolve as resolve7, join as join4 } from "path";
4061
4116
  import { platform as osPlatform } from "os";
4062
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, readdirSync as readdirSync2, existsSync as existsSync6, mkdirSync as mkdirSync4, createWriteStream, statSync as statSync3, unlinkSync as unlinkSync2, cpSync, rmSync as rmSync2, appendFileSync as appendFileSync2, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
4117
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, readdirSync as readdirSync2, existsSync as existsSync6, mkdirSync as mkdirSync5, createWriteStream, statSync as statSync3, unlinkSync as unlinkSync2, cpSync, rmSync as rmSync2, appendFileSync as appendFileSync3, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
4063
4118
  import { lookup as dnsLookup } from "dns/promises";
4064
4119
  import { createConnection as netConnect } from "net";
4065
4120
  import { StringDecoder } from "string_decoder";
@@ -4068,12 +4123,12 @@ import { StringDecoder } from "string_decoder";
4068
4123
  var import_dist = __toESM(require_dist());
4069
4124
  import {
4070
4125
  existsSync as existsSync4,
4071
- mkdirSync as mkdirSync2,
4126
+ mkdirSync as mkdirSync3,
4072
4127
  readFileSync as readFileSync3,
4073
4128
  unlinkSync,
4074
4129
  writeFileSync as writeFileSync2
4075
4130
  } from "fs";
4076
- import { resolve as resolve3, join as join3, dirname } from "path";
4131
+ import { resolve as resolve4, join as join3, dirname } from "path";
4077
4132
  import { homedir as homedir2 } from "os";
4078
4133
  var cachedKeyFilePath = null;
4079
4134
  function resolveKeyFilePath() {
@@ -4104,7 +4159,7 @@ function resolveKeyFilePath() {
4104
4159
  throw err;
4105
4160
  }
4106
4161
  }
4107
- cachedKeyFilePath = resolve3(homedir2(), configDirName2, ".anthropic-api-key");
4162
+ cachedKeyFilePath = resolve4(homedir2(), configDirName2, ".anthropic-api-key");
4108
4163
  return cachedKeyFilePath;
4109
4164
  }
4110
4165
  function readKey() {
@@ -4391,10 +4446,10 @@ async function ensureAuth() {
4391
4446
  // app/lib/vnc.ts
4392
4447
  import { spawnSync, execFileSync } from "child_process";
4393
4448
  import { createConnection as createConnection3 } from "net";
4394
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
4395
- import { resolve as resolve4 } from "path";
4396
- var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "..");
4397
- var VNC_SCRIPT = resolve4(PLATFORM_ROOT2, "scripts/vnc.sh");
4449
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
4450
+ import { resolve as resolve5 } from "path";
4451
+ var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
4452
+ var VNC_SCRIPT = resolve5(PLATFORM_ROOT2, "scripts/vnc.sh");
4398
4453
  var displayMode = process.env.DISPLAY_MODE ?? "virtual";
4399
4454
  if (displayMode === "native") {
4400
4455
  console.log(`[vnc] DISPLAY_MODE=native \u2014 local requests use desktop display, remote requests use VNC`);
@@ -4506,10 +4561,10 @@ async function waitForPort(port2, timeoutMs = 12e3) {
4506
4561
  return false;
4507
4562
  }
4508
4563
  function ensureLogDir() {
4509
- mkdirSync3(LOG_DIR, { recursive: true });
4564
+ mkdirSync4(LOG_DIR, { recursive: true });
4510
4565
  }
4511
4566
  function logPath(name) {
4512
- return resolve4(LOG_DIR, `${name}.log`);
4567
+ return resolve5(LOG_DIR, `${name}.log`);
4513
4568
  }
4514
4569
  async function ensureVnc() {
4515
4570
  const up = await waitForPort(5900, 1e3);
@@ -4587,8 +4642,8 @@ function killChromium() {
4587
4642
  spawnSync("pkill", ["-f", "chromium"], { stdio: "pipe" });
4588
4643
  }
4589
4644
  function writeChromiumWrapper() {
4590
- mkdirSync3(BIN_DIR, { recursive: true });
4591
- const wrapperPath = resolve4(BIN_DIR, "chromium");
4645
+ mkdirSync4(BIN_DIR, { recursive: true });
4646
+ const wrapperPath = resolve5(BIN_DIR, "chromium");
4592
4647
  writeFileSync4(wrapperPath, `#!/bin/bash
4593
4648
  LOG="${LOG_DIR}/chromium.log"
4594
4649
  echo "==== [$(date)] chromium wrapper ====" >> "$LOG"
@@ -4674,12 +4729,12 @@ import neo4j from "neo4j-driver";
4674
4729
  import { randomUUID } from "crypto";
4675
4730
  import { spawn } from "child_process";
4676
4731
  import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, openSync, readSync, closeSync, statSync as statSync2, rmSync } from "fs";
4677
- import { resolve as resolve5 } from "path";
4678
- var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
4732
+ import { resolve as resolve6 } from "path";
4733
+ var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
4679
4734
  var driver = null;
4680
4735
  function readPassword() {
4681
4736
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
4682
- const passwordFile = resolve5(PLATFORM_ROOT3, "config/.neo4j-password");
4737
+ const passwordFile = resolve6(PLATFORM_ROOT3, "config/.neo4j-password");
4683
4738
  try {
4684
4739
  return readFileSync6(passwordFile, "utf-8").trim();
4685
4740
  } catch {
@@ -5355,7 +5410,7 @@ ${userContent}`;
5355
5410
  "dontAsk",
5356
5411
  prompt
5357
5412
  ];
5358
- return new Promise((resolve29) => {
5413
+ return new Promise((resolve30) => {
5359
5414
  let stdout = "";
5360
5415
  let stderr = "";
5361
5416
  const spawnFn = _spawnOverride ?? spawn;
@@ -5373,35 +5428,35 @@ ${userContent}`;
5373
5428
  const timer = setTimeout(() => {
5374
5429
  proc.kill("SIGTERM");
5375
5430
  console.error("[persist] autoLabel: haiku subprocess timed out");
5376
- resolve29(null);
5431
+ resolve30(null);
5377
5432
  }, SESSION_LABEL_TIMEOUT_MS);
5378
5433
  proc.on("error", (err) => {
5379
5434
  clearTimeout(timer);
5380
5435
  console.error(`[persist] autoLabel: subprocess error \u2014 ${err.message}`);
5381
- resolve29(null);
5436
+ resolve30(null);
5382
5437
  });
5383
5438
  proc.on("close", (code) => {
5384
5439
  clearTimeout(timer);
5385
5440
  if (code !== 0) {
5386
5441
  console.error(`[persist] autoLabel: subprocess exited code=${code}${stderr ? ` stderr=${stderr.trim().slice(0, 200)}` : ""}`);
5387
- resolve29(null);
5442
+ resolve30(null);
5388
5443
  return;
5389
5444
  }
5390
5445
  const text = stdout.trim();
5391
5446
  if (!text) {
5392
5447
  console.error("[persist] autoLabel: haiku returned empty response");
5393
- resolve29(null);
5448
+ resolve30(null);
5394
5449
  return;
5395
5450
  }
5396
5451
  if (text === "SKIP") {
5397
5452
  console.error("[persist] autoLabel: haiku returned SKIP \u2014 messages too vague");
5398
- resolve29(null);
5453
+ resolve30(null);
5399
5454
  return;
5400
5455
  }
5401
5456
  const words = text.split(/\s+/).slice(0, SESSION_LABEL_MAX_WORDS);
5402
5457
  const label = words.join(" ");
5403
5458
  console.error(`[persist] autoLabel: haiku response="${label}"`);
5404
- resolve29(label);
5459
+ resolve30(label);
5405
5460
  });
5406
5461
  });
5407
5462
  }
@@ -5673,9 +5728,9 @@ var MAX_RECENT_TOOL_FAILURES = 3;
5673
5728
  var RECENT_FAILURES_TAIL_BYTES = 10 * 1024;
5674
5729
  function readRecentToolFailures(accountId, conversationId) {
5675
5730
  try {
5676
- const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
5677
- const logDir = resolve5(platformRoot3, "..", "data/accounts", accountId, "logs");
5678
- const logPath2 = resolve5(logDir, `claude-agent-stream-${conversationId}.log`);
5731
+ const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
5732
+ const logDir = resolve6(platformRoot3, "..", "data/accounts", accountId, "logs");
5733
+ const logPath2 = resolve6(logDir, `claude-agent-stream-${conversationId}.log`);
5679
5734
  if (!existsSync5(logPath2)) {
5680
5735
  console.error(`[review-tail-skip] path=${logPath2} reason=file-missing \u2014 first turn of conversation, subprocess not yet spawned, or log rotated`);
5681
5736
  return [];
@@ -5832,13 +5887,13 @@ ${taskLines.join("\n")}`);
5832
5887
  let pendingCount = 0;
5833
5888
  let pendingLines = [];
5834
5889
  try {
5835
- const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "..");
5836
- const pendingDir = resolve5(platformRoot3, "..", "data/accounts", accountId, "pending-actions");
5890
+ const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
5891
+ const pendingDir = resolve6(platformRoot3, "..", "data/accounts", accountId, "pending-actions");
5837
5892
  if (existsSync5(pendingDir)) {
5838
5893
  const files = readdirSync(pendingDir).filter((f) => f.endsWith(".json") && !f.startsWith("."));
5839
5894
  for (const file of files) {
5840
5895
  try {
5841
- const raw2 = readFileSync6(resolve5(pendingDir, file), "utf-8");
5896
+ const raw2 = readFileSync6(resolve6(pendingDir, file), "utf-8");
5842
5897
  const action = JSON.parse(raw2);
5843
5898
  if (action.state === "pending") {
5844
5899
  const inputSummary = JSON.stringify(action.hookPayload?.tool_input ?? {}).slice(0, 150);
@@ -5905,8 +5960,8 @@ ${sections.join("\n\n")}
5905
5960
  }
5906
5961
  }
5907
5962
  async function consumeStep7FlagUI(session, accountId) {
5908
- const accountDir = resolve5(PLATFORM_ROOT3, "..", "data/accounts", accountId);
5909
- const flagPath = resolve5(accountDir, "onboarding", "step7-complete");
5963
+ const accountDir = resolve6(PLATFORM_ROOT3, "..", "data/accounts", accountId);
5964
+ const flagPath = resolve6(accountDir, "onboarding", "step7-complete");
5910
5965
  if (!existsSync5(flagPath)) return false;
5911
5966
  let completedAt = (/* @__PURE__ */ new Date()).toISOString();
5912
5967
  try {
@@ -6487,20 +6542,20 @@ function agentLogStream(name, accountDir, conversationId) {
6487
6542
  if (!conversationId) {
6488
6543
  throw new Error(`agentLogStream: conversationId is required (name=${name}) \u2014 use preConversationLogStream for pre-session events`);
6489
6544
  }
6490
- const logDir = resolve6(accountDir, "logs");
6491
- mkdirSync4(logDir, { recursive: true });
6545
+ const logDir = resolve7(accountDir, "logs");
6546
+ mkdirSync5(logDir, { recursive: true });
6492
6547
  purgeOldLogs(logDir, `${name}-`);
6493
- const logPath2 = resolve6(logDir, `${name}-${conversationId}.log`);
6548
+ const logPath2 = resolve7(logDir, `${name}-${conversationId}.log`);
6494
6549
  const stream = createWriteStream(logPath2, { flags: "a" });
6495
6550
  registerStreamLog(stream, { path: logPath2, conversationId, name });
6496
6551
  return stream;
6497
6552
  }
6498
6553
  function preConversationLogStream(name, accountDir) {
6499
- const logDir = resolve6(accountDir, "logs");
6500
- mkdirSync4(logDir, { recursive: true });
6554
+ const logDir = resolve7(accountDir, "logs");
6555
+ mkdirSync5(logDir, { recursive: true });
6501
6556
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6502
6557
  purgeOldLogs(logDir, `preconversation-${name}-`);
6503
- const logPath2 = resolve6(logDir, `preconversation-${name}-${date}.log`);
6558
+ const logPath2 = resolve7(logDir, `preconversation-${name}-${date}.log`);
6504
6559
  const stream = createWriteStream(logPath2, { flags: "a" });
6505
6560
  registerStreamLog(stream, { path: logPath2, conversationId: null, name: `preconversation-${name}` });
6506
6561
  return stream;
@@ -6519,7 +6574,7 @@ function sigtermFlushStreamLogs(reason, source) {
6519
6574
  const line = `[${ts}] [server-sigterm] reason=${reason}${convPart} name=${entry.name} source=${source}
6520
6575
  `;
6521
6576
  try {
6522
- appendFileSync2(entry.path, line);
6577
+ appendFileSync3(entry.path, line);
6523
6578
  } catch (err) {
6524
6579
  const msg = err instanceof Error ? err.message : String(err);
6525
6580
  console.error(`[server-sigterm-flush-err] path=${entry.path} reason=${msg}`);
@@ -6538,7 +6593,7 @@ function purgeOldLogs(logDir, prefix) {
6538
6593
  }
6539
6594
  for (const file of entries) {
6540
6595
  if (!file.startsWith(prefix)) continue;
6541
- const filePath = resolve6(logDir, file);
6596
+ const filePath = resolve7(logDir, file);
6542
6597
  try {
6543
6598
  if (statSync3(filePath).mtimeMs < cutoff) unlinkSync2(filePath);
6544
6599
  } catch (err) {
@@ -6656,8 +6711,8 @@ function sampleProcState(pid) {
6656
6711
  return `proc_err=${JSON.stringify(msg.slice(0, 60))}`;
6657
6712
  }
6658
6713
  }
6659
- var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
6660
- var ACCOUNTS_DIR = resolve6(PLATFORM_ROOT4, "..", "data/accounts");
6714
+ var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve7(process.cwd(), "..");
6715
+ var ACCOUNTS_DIR = resolve7(PLATFORM_ROOT4, "..", "data/accounts");
6661
6716
  if (!existsSync6(PLATFORM_ROOT4)) {
6662
6717
  throw new Error(
6663
6718
  `PLATFORM_ROOT does not exist: ${PLATFORM_ROOT4}
@@ -6666,7 +6721,7 @@ Set the MAXY_PLATFORM_ROOT environment variable to the absolute path of the plat
6666
6721
  }
6667
6722
  function resolveAccount() {
6668
6723
  if (!existsSync6(ACCOUNTS_DIR)) return null;
6669
- const usersFilePath = resolve6(PLATFORM_ROOT4, "config", "users.json");
6724
+ const usersFilePath = resolve7(PLATFORM_ROOT4, "config", "users.json");
6670
6725
  let usersJsonUserId = null;
6671
6726
  if (existsSync6(usersFilePath)) {
6672
6727
  try {
@@ -6684,7 +6739,7 @@ function resolveAccount() {
6684
6739
  let fallback = null;
6685
6740
  for (const entry of entries) {
6686
6741
  if (!entry.isDirectory()) continue;
6687
- const configPath2 = resolve6(ACCOUNTS_DIR, entry.name, "account.json");
6742
+ const configPath2 = resolve7(ACCOUNTS_DIR, entry.name, "account.json");
6688
6743
  if (!existsSync6(configPath2)) continue;
6689
6744
  const raw2 = readFileSync7(configPath2, "utf-8");
6690
6745
  let config;
@@ -6701,7 +6756,7 @@ function resolveAccount() {
6701
6756
  }
6702
6757
  const result = {
6703
6758
  accountId: config.accountId,
6704
- accountDir: resolve6(ACCOUNTS_DIR, entry.name),
6759
+ accountDir: resolve7(ACCOUNTS_DIR, entry.name),
6705
6760
  config
6706
6761
  };
6707
6762
  if (usersJsonUserId && config.admins?.some((a) => a.userId === usersJsonUserId)) {
@@ -6719,7 +6774,7 @@ function resolveAccount() {
6719
6774
  return fallback;
6720
6775
  }
6721
6776
  function readAgentFile(accountDir, agentName, filename) {
6722
- const filePath = resolve6(accountDir, "agents", agentName, filename);
6777
+ const filePath = resolve7(accountDir, "agents", agentName, filename);
6723
6778
  if (!existsSync6(filePath)) return null;
6724
6779
  return readFileSync7(filePath, "utf-8");
6725
6780
  }
@@ -6737,7 +6792,7 @@ function validateAgentSlug(slug) {
6737
6792
  return true;
6738
6793
  }
6739
6794
  function resolveDefaultAgentSlug(accountDir) {
6740
- const configPath2 = resolve6(accountDir, "account.json");
6795
+ const configPath2 = resolve7(accountDir, "account.json");
6741
6796
  if (!existsSync6(configPath2)) {
6742
6797
  console.error("[agent-resolve] account.json not found \u2014 cannot resolve defaultAgent");
6743
6798
  return null;
@@ -6753,7 +6808,7 @@ function resolveDefaultAgentSlug(accountDir) {
6753
6808
  console.error("[agent-resolve] defaultAgent not configured in account.json \u2014 set it via the connect-whatsapp skill");
6754
6809
  return null;
6755
6810
  }
6756
- const agentConfigPath = resolve6(accountDir, "agents", config.defaultAgent, "config.json");
6811
+ const agentConfigPath = resolve7(accountDir, "agents", config.defaultAgent, "config.json");
6757
6812
  if (!existsSync6(agentConfigPath)) {
6758
6813
  console.error(`[agent-resolve] defaultAgent="${config.defaultAgent}" has no config.json at ${agentConfigPath}`);
6759
6814
  return null;
@@ -6826,9 +6881,9 @@ function resolveAgentConfig(accountDir, agentName) {
6826
6881
  }
6827
6882
  let knowledge = null;
6828
6883
  let knowledgeBaked = false;
6829
- const agentDir = resolve6(accountDir, "agents", agentName);
6830
- const knowledgePath = resolve6(agentDir, "KNOWLEDGE.md");
6831
- const summaryPath = resolve6(agentDir, "KNOWLEDGE-SUMMARY.md");
6884
+ const agentDir = resolve7(accountDir, "agents", agentName);
6885
+ const knowledgePath = resolve7(agentDir, "KNOWLEDGE.md");
6886
+ const summaryPath = resolve7(agentDir, "KNOWLEDGE-SUMMARY.md");
6832
6887
  const hasKnowledge = existsSync6(knowledgePath);
6833
6888
  const hasSummary = existsSync6(summaryPath);
6834
6889
  if (hasKnowledge && hasSummary) {
@@ -6864,7 +6919,7 @@ function resolveAgentConfig(accountDir, agentName) {
6864
6919
  return { model, plugins, status, displayName, image, imageShape, showAgentName, knowledge, knowledgeBaked, liveMemory, knowledgeKeywords, budget, accessMode };
6865
6920
  }
6866
6921
  function parsePluginFrontmatter(pluginDir) {
6867
- const pluginPath = resolve6(PLATFORM_ROOT4, "plugins", pluginDir, "PLUGIN.md");
6922
+ const pluginPath = resolve7(PLATFORM_ROOT4, "plugins", pluginDir, "PLUGIN.md");
6868
6923
  if (!existsSync6(pluginPath)) return null;
6869
6924
  let raw2;
6870
6925
  try {
@@ -6927,14 +6982,14 @@ function parsePluginFrontmatter(pluginDir) {
6927
6982
  function autoDeliverPremiumPlugins(purchasedPlugins) {
6928
6983
  if (!purchasedPlugins || purchasedPlugins.length === 0) return;
6929
6984
  const TAG18 = "[premium-auto-deliver]";
6930
- const stagingRoot = resolve6(PLATFORM_ROOT4, "../premium-plugins");
6931
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
6985
+ const stagingRoot = resolve7(PLATFORM_ROOT4, "../premium-plugins");
6986
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
6932
6987
  if (!existsSync6(stagingRoot)) {
6933
6988
  console.log(`${TAG18} no staging directory \u2014 skipping`);
6934
6989
  return;
6935
6990
  }
6936
6991
  for (const pluginName of purchasedPlugins) {
6937
- const stagingDir = resolve6(stagingRoot, pluginName);
6992
+ const stagingDir = resolve7(stagingRoot, pluginName);
6938
6993
  if (!existsSync6(stagingDir)) {
6939
6994
  console.log(`${TAG18} ${pluginName}: not in staging \u2014 skipping`);
6940
6995
  continue;
@@ -6975,12 +7030,12 @@ function autoDeliverPremiumPlugins(purchasedPlugins) {
6975
7030
  let delivered = 0;
6976
7031
  let skipped = 0;
6977
7032
  for (const sub of subPlugins) {
6978
- const target = resolve6(pluginsDir, sub);
6979
- if (existsSync6(resolve6(target, "PLUGIN.md"))) {
7033
+ const target = resolve7(pluginsDir, sub);
7034
+ if (existsSync6(resolve7(target, "PLUGIN.md"))) {
6980
7035
  skipped++;
6981
7036
  continue;
6982
7037
  }
6983
- const source = resolve6(stagingDir, "plugins", sub);
7038
+ const source = resolve7(stagingDir, "plugins", sub);
6984
7039
  if (!existsSync6(source)) {
6985
7040
  console.log(`${TAG18} ${pluginName}/${sub}: source missing in staging \u2014 skipping`);
6986
7041
  continue;
@@ -6994,8 +7049,8 @@ function autoDeliverPremiumPlugins(purchasedPlugins) {
6994
7049
  }
6995
7050
  console.log(`${TAG18} ${pluginName} (bundle): ${delivered} delivered, ${skipped} already present`);
6996
7051
  } else {
6997
- const target = resolve6(pluginsDir, pluginName);
6998
- if (existsSync6(resolve6(target, "PLUGIN.md"))) {
7052
+ const target = resolve7(pluginsDir, pluginName);
7053
+ if (existsSync6(resolve7(target, "PLUGIN.md"))) {
6999
7054
  console.log(`${TAG18} ${pluginName}: already present \u2014 skipping`);
7000
7055
  continue;
7001
7056
  }
@@ -7035,7 +7090,7 @@ function migratePluginRenames(accountDir, config) {
7035
7090
  return name;
7036
7091
  });
7037
7092
  if (!changed) return;
7038
- const configPath2 = resolve6(accountDir, "account.json");
7093
+ const configPath2 = resolve7(accountDir, "account.json");
7039
7094
  try {
7040
7095
  const raw2 = readFileSync7(configPath2, "utf-8");
7041
7096
  const parsed = JSON.parse(raw2);
@@ -7046,9 +7101,9 @@ function migratePluginRenames(accountDir, config) {
7046
7101
  } catch (err) {
7047
7102
  console.error(`${TAG18} failed to update account.json \u2014 ${err instanceof Error ? err.message : String(err)}`);
7048
7103
  }
7049
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
7104
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
7050
7105
  for (const oldName of Object.keys(PLUGIN_RENAMES)) {
7051
- const orphan = resolve6(pluginsDir, oldName);
7106
+ const orphan = resolve7(pluginsDir, oldName);
7052
7107
  if (existsSync6(orphan)) {
7053
7108
  try {
7054
7109
  rmSync2(orphan, { recursive: true });
@@ -7062,13 +7117,13 @@ function migratePluginRenames(accountDir, config) {
7062
7117
  function autoDeliverBundleAgents(accountDir, purchasedPlugins) {
7063
7118
  if (!purchasedPlugins || purchasedPlugins.length === 0) return;
7064
7119
  const TAG18 = "[bundle-agent-deliver]";
7065
- const stagingRoot = resolve6(PLATFORM_ROOT4, "../premium-plugins");
7066
- const specialistsDir = resolve6(accountDir, "specialists", "agents");
7120
+ const stagingRoot = resolve7(PLATFORM_ROOT4, "../premium-plugins");
7121
+ const specialistsDir = resolve7(accountDir, "specialists", "agents");
7067
7122
  if (!existsSync6(stagingRoot)) return;
7068
7123
  if (!existsSync6(specialistsDir)) {
7069
- mkdirSync4(specialistsDir, { recursive: true });
7124
+ mkdirSync5(specialistsDir, { recursive: true });
7070
7125
  }
7071
- const agentsmdPath = resolve6(accountDir, "agents", "admin", "AGENTS.md");
7126
+ const agentsmdPath = resolve7(accountDir, "agents", "admin", "AGENTS.md");
7072
7127
  let agentsmd = "";
7073
7128
  try {
7074
7129
  agentsmd = existsSync6(agentsmdPath) ? readFileSync7(agentsmdPath, "utf-8") : "";
@@ -7076,7 +7131,7 @@ function autoDeliverBundleAgents(accountDir, purchasedPlugins) {
7076
7131
  }
7077
7132
  let delivered = 0;
7078
7133
  for (const pluginName of purchasedPlugins) {
7079
- const bundleAgentsDir = resolve6(stagingRoot, pluginName, "agents");
7134
+ const bundleAgentsDir = resolve7(stagingRoot, pluginName, "agents");
7080
7135
  if (!existsSync6(bundleAgentsDir)) continue;
7081
7136
  let entries;
7082
7137
  try {
@@ -7085,9 +7140,9 @@ function autoDeliverBundleAgents(accountDir, purchasedPlugins) {
7085
7140
  continue;
7086
7141
  }
7087
7142
  for (const filename of entries) {
7088
- const target = resolve6(specialistsDir, filename);
7143
+ const target = resolve7(specialistsDir, filename);
7089
7144
  if (existsSync6(target)) continue;
7090
- const source = resolve6(bundleAgentsDir, filename);
7145
+ const source = resolve7(bundleAgentsDir, filename);
7091
7146
  try {
7092
7147
  cpSync(source, target);
7093
7148
  } catch (err) {
@@ -7127,8 +7182,8 @@ function autoDeliverBundleAgents(accountDir, purchasedPlugins) {
7127
7182
  }
7128
7183
  }
7129
7184
  function assemblePublicPluginContent(pluginDir) {
7130
- const pluginRoot = resolve6(PLATFORM_ROOT4, "plugins", pluginDir);
7131
- const pluginPath = resolve6(pluginRoot, "PLUGIN.md");
7185
+ const pluginRoot = resolve7(PLATFORM_ROOT4, "plugins", pluginDir);
7186
+ const pluginPath = resolve7(pluginRoot, "PLUGIN.md");
7132
7187
  let raw2;
7133
7188
  try {
7134
7189
  raw2 = readFileSync7(pluginPath, "utf-8");
@@ -7140,7 +7195,7 @@ function assemblePublicPluginContent(pluginDir) {
7140
7195
  const parts = [pluginBody];
7141
7196
  let skillCount = 0;
7142
7197
  let refCount = 0;
7143
- const skillsDir = resolve6(pluginRoot, "skills");
7198
+ const skillsDir = resolve7(pluginRoot, "skills");
7144
7199
  let skillDirs;
7145
7200
  try {
7146
7201
  skillDirs = readdirSync2(skillsDir).sort();
@@ -7148,8 +7203,8 @@ function assemblePublicPluginContent(pluginDir) {
7148
7203
  return { body: pluginBody, skillCount: 0, refCount: 0 };
7149
7204
  }
7150
7205
  for (const skillName of skillDirs) {
7151
- const skillDir = resolve6(skillsDir, skillName);
7152
- const skillMdPath = resolve6(skillDir, "SKILL.md");
7206
+ const skillDir = resolve7(skillsDir, skillName);
7207
+ const skillMdPath = resolve7(skillDir, "SKILL.md");
7153
7208
  let skillRaw;
7154
7209
  try {
7155
7210
  skillRaw = readFileSync7(skillMdPath, "utf-8");
@@ -7192,7 +7247,7 @@ function assemblePublicPluginContent(pluginDir) {
7192
7247
  parts.push(`
7193
7248
  <!-- skill: ${skillName} -->`);
7194
7249
  parts.push(skillBody);
7195
- const refsDir = resolve6(skillDir, "references");
7250
+ const refsDir = resolve7(skillDir, "references");
7196
7251
  let refFiles;
7197
7252
  try {
7198
7253
  refFiles = readdirSync2(refsDir).filter((f) => f.endsWith(".md")).filter((f) => !publicExcludeReferences.includes(f)).sort();
@@ -7203,7 +7258,7 @@ function assemblePublicPluginContent(pluginDir) {
7203
7258
  }
7204
7259
  for (const refFile of refFiles) {
7205
7260
  try {
7206
- const refContent = readFileSync7(resolve6(refsDir, refFile), "utf-8").trim();
7261
+ const refContent = readFileSync7(resolve7(refsDir, refFile), "utf-8").trim();
7207
7262
  if (refContent) {
7208
7263
  parts.push(`
7209
7264
  <!-- reference: ${refFile} -->`);
@@ -7221,7 +7276,7 @@ function assemblePublicPluginContent(pluginDir) {
7221
7276
  return { body: parts.join("\n"), skillCount, refCount };
7222
7277
  }
7223
7278
  function loadEmbeddedPlugins(agentType, selectedPlugins, enabledPlugins) {
7224
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
7279
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
7225
7280
  let dirs;
7226
7281
  try {
7227
7282
  dirs = readdirSync2(pluginsDir);
@@ -7274,7 +7329,7 @@ function loadEmbeddedPlugins(agentType, selectedPlugins, enabledPlugins) {
7274
7329
  console.log(`[plugins] loaded ${dir} for public (${assembled.body.length} chars, ${assembled.skillCount} skills, ${assembled.refCount} refs)`);
7275
7330
  }
7276
7331
  } else {
7277
- const pluginPath = resolve6(pluginsDir, dir, "PLUGIN.md");
7332
+ const pluginPath = resolve7(pluginsDir, dir, "PLUGIN.md");
7278
7333
  let raw2;
7279
7334
  try {
7280
7335
  raw2 = readFileSync7(pluginPath, "utf-8");
@@ -7301,7 +7356,7 @@ var mcpToolsCache = /* @__PURE__ */ new Map();
7301
7356
  function fetchMcpToolsList(pluginDir) {
7302
7357
  const cached = mcpToolsCache.get(pluginDir);
7303
7358
  if (cached) return Promise.resolve(cached);
7304
- const serverPath = resolve6(PLATFORM_ROOT4, "plugins", pluginDir, "mcp/dist/index.js");
7359
+ const serverPath = resolve7(PLATFORM_ROOT4, "plugins", pluginDir, "mcp/dist/index.js");
7305
7360
  if (!existsSync6(serverPath)) return Promise.resolve([]);
7306
7361
  const startMs = Date.now();
7307
7362
  return new Promise((resolvePromise) => {
@@ -7414,7 +7469,7 @@ var SPECIALIST_PLUGIN_DOMAINS = {
7414
7469
  // agent, so it retains a full manifest entry for routing clarity.
7415
7470
  };
7416
7471
  async function buildPluginManifest(enabledPlugins) {
7417
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
7472
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
7418
7473
  let dirs;
7419
7474
  try {
7420
7475
  dirs = readdirSync2(pluginsDir);
@@ -7501,16 +7556,16 @@ ${specialist}: ${plugins.join(", ")}`);
7501
7556
  for (let j = 0; j < adminPlugins.length; j++) {
7502
7557
  const { dir, parsed } = adminPlugins[j];
7503
7558
  const mcpTools = adminMcpResults[j];
7504
- const pluginRoot = resolve6(pluginsDir, dir);
7559
+ const pluginRoot = resolve7(pluginsDir, dir);
7505
7560
  const skills = [];
7506
7561
  const references = [];
7507
7562
  const scanDir = (base, prefix, target) => {
7508
- const scanPath = resolve6(pluginRoot, base);
7563
+ const scanPath = resolve7(pluginRoot, base);
7509
7564
  if (!existsSync6(scanPath)) return;
7510
7565
  try {
7511
7566
  const walk = (current, rel) => {
7512
7567
  for (const entry of readdirSync2(current)) {
7513
- const full = resolve6(current, entry);
7568
+ const full = resolve7(current, entry);
7514
7569
  try {
7515
7570
  const stat5 = statSync3(full);
7516
7571
  if (stat5.isDirectory()) {
@@ -7538,7 +7593,7 @@ ${specialist}: ${plugins.join(", ")}`);
7538
7593
  toolLines.push(desc ? ` ${tool.name} \u2014 ${desc}` : ` ${tool.name}`);
7539
7594
  }
7540
7595
  } else if (parsed.tools.length > 0) {
7541
- const serverPath = resolve6(PLATFORM_ROOT4, "plugins", dir, "mcp/dist/index.js");
7596
+ const serverPath = resolve7(PLATFORM_ROOT4, "plugins", dir, "mcp/dist/index.js");
7542
7597
  if (existsSync6(serverPath)) {
7543
7598
  fallbackSourced++;
7544
7599
  console.error(`[plugin-manifest] ${dir}: tools/list empty \u2014 fallback to frontmatter (${parsed.tools.length} tools)`);
@@ -7619,7 +7674,7 @@ function resolveUserAccounts(userId) {
7619
7674
  const entries = readdirSync2(ACCOUNTS_DIR, { withFileTypes: true });
7620
7675
  for (const entry of entries) {
7621
7676
  if (!entry.isDirectory()) continue;
7622
- const configPath2 = resolve6(ACCOUNTS_DIR, entry.name, "account.json");
7677
+ const configPath2 = resolve7(ACCOUNTS_DIR, entry.name, "account.json");
7623
7678
  if (!existsSync6(configPath2)) continue;
7624
7679
  let config;
7625
7680
  try {
@@ -7632,7 +7687,7 @@ function resolveUserAccounts(userId) {
7632
7687
  if (adminEntry) {
7633
7688
  results.push({
7634
7689
  accountId: config.accountId,
7635
- accountDir: resolve6(ACCOUNTS_DIR, entry.name),
7690
+ accountDir: resolve7(ACCOUNTS_DIR, entry.name),
7636
7691
  config,
7637
7692
  role: adminEntry.role
7638
7693
  });
@@ -7849,8 +7904,8 @@ function consumeStalledSubagents(sessionKey) {
7849
7904
  return stalls && stalls.length > 0 ? stalls : void 0;
7850
7905
  }
7851
7906
  function streamLogPathFor(accountId, conversationId) {
7852
- const logDir = resolve6(ACCOUNTS_DIR, accountId, "logs");
7853
- const streamLogPath = resolve6(logDir, `claude-agent-stream-${conversationId}.log`);
7907
+ const logDir = resolve7(ACCOUNTS_DIR, accountId, "logs");
7908
+ const streamLogPath = resolve7(logDir, `claude-agent-stream-${conversationId}.log`);
7854
7909
  return { logDir, streamLogPath };
7855
7910
  }
7856
7911
  function buildSpawnEnv(accountId, accountDir, conversationId) {
@@ -7871,7 +7926,7 @@ var cachedBrandHostname = null;
7871
7926
  function readBrandHostname() {
7872
7927
  if (cachedBrandHostname !== null) return cachedBrandHostname;
7873
7928
  try {
7874
- const brandPath = resolve6(PLATFORM_ROOT4, "config", "brand.json");
7929
+ const brandPath = resolve7(PLATFORM_ROOT4, "config", "brand.json");
7875
7930
  const parsed = JSON.parse(readFileSync7(brandPath, "utf-8"));
7876
7931
  cachedBrandHostname = typeof parsed.hostname === "string" && parsed.hostname.length > 0 ? parsed.hostname : "maxy";
7877
7932
  } catch {
@@ -7909,37 +7964,37 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7909
7964
  const servers = {
7910
7965
  "memory": {
7911
7966
  command: "node",
7912
- args: [resolve6(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js")],
7967
+ args: [resolve7(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js")],
7913
7968
  env: { ...baseEnv, ...userId ? { USER_ID: userId } : {} }
7914
7969
  },
7915
7970
  "contacts": {
7916
7971
  command: "node",
7917
- args: [resolve6(PLATFORM_ROOT4, "plugins/contacts/mcp/dist/index.js")],
7972
+ args: [resolve7(PLATFORM_ROOT4, "plugins/contacts/mcp/dist/index.js")],
7918
7973
  env: { ...baseEnv }
7919
7974
  },
7920
7975
  "whatsapp": {
7921
7976
  command: "node",
7922
- args: [resolve6(PLATFORM_ROOT4, "plugins/whatsapp/mcp/dist/index.js")],
7977
+ args: [resolve7(PLATFORM_ROOT4, "plugins/whatsapp/mcp/dist/index.js")],
7923
7978
  env: { ...baseEnv, PLATFORM_PORT: process.env.PORT ?? "19200" }
7924
7979
  },
7925
7980
  "admin": {
7926
7981
  command: "node",
7927
- args: [resolve6(PLATFORM_ROOT4, "plugins/admin/mcp/dist/index.js")],
7982
+ args: [resolve7(PLATFORM_ROOT4, "plugins/admin/mcp/dist/index.js")],
7928
7983
  env: { ...baseEnv, PLATFORM_PORT: process.env.PORT ?? "19200", ...userId ? { USER_ID: userId } : {} }
7929
7984
  },
7930
7985
  "scheduling": {
7931
7986
  command: "node",
7932
- args: [resolve6(PLATFORM_ROOT4, "plugins/scheduling/mcp/dist/index.js")],
7987
+ args: [resolve7(PLATFORM_ROOT4, "plugins/scheduling/mcp/dist/index.js")],
7933
7988
  env: { ...baseEnv }
7934
7989
  },
7935
7990
  "tasks": {
7936
7991
  command: "node",
7937
- args: [resolve6(PLATFORM_ROOT4, "plugins/tasks/mcp/dist/index.js")],
7992
+ args: [resolve7(PLATFORM_ROOT4, "plugins/tasks/mcp/dist/index.js")],
7938
7993
  env: { ...baseEnv }
7939
7994
  },
7940
7995
  "email": {
7941
7996
  command: "node",
7942
- args: [resolve6(PLATFORM_ROOT4, "plugins/email/mcp/dist/index.js")],
7997
+ args: [resolve7(PLATFORM_ROOT4, "plugins/email/mcp/dist/index.js")],
7943
7998
  env: { ...baseEnv }
7944
7999
  },
7945
8000
  // Workflows MCP — persistent admin-session server for list/get/update/delete/
@@ -7950,7 +8005,7 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7950
8005
  // ToolSearches fruitlessly before degrading to a task-create stand-in (Task 571).
7951
8006
  "workflows": {
7952
8007
  command: "node",
7953
- args: [resolve6(PLATFORM_ROOT4, "plugins/workflows/mcp/dist/index.js")],
8008
+ args: [resolve7(PLATFORM_ROOT4, "plugins/workflows/mcp/dist/index.js")],
7954
8009
  env: { ...baseEnv }
7955
8010
  },
7956
8011
  // Playwright MCP server — browser automation for browser-specialist.
@@ -7972,7 +8027,7 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7972
8027
  // MAXY-PRD.md:627, not in any application-layer filter).
7973
8028
  "graph": {
7974
8029
  command: "node",
7975
- args: [resolve6(PLATFORM_ROOT4, "lib/graph-mcp/dist/index.js")],
8030
+ args: [resolve7(PLATFORM_ROOT4, "lib/graph-mcp/dist/index.js")],
7976
8031
  env: {
7977
8032
  ...baseEnv,
7978
8033
  BRAND: readBrandHostname(),
@@ -7988,7 +8043,7 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7988
8043
  if (tgBotToken) {
7989
8044
  servers["telegram"] = {
7990
8045
  command: "node",
7991
- args: [resolve6(PLATFORM_ROOT4, "plugins/telegram/mcp/dist/index.js")],
8046
+ args: [resolve7(PLATFORM_ROOT4, "plugins/telegram/mcp/dist/index.js")],
7992
8047
  env: { ...baseEnv, TELEGRAM_BOT_TOKEN: tgBotToken }
7993
8048
  };
7994
8049
  } else {
@@ -7996,11 +8051,11 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
7996
8051
  }
7997
8052
  servers["cloudflare"] = {
7998
8053
  command: "node",
7999
- args: [resolve6(PLATFORM_ROOT4, "plugins/cloudflare/mcp/dist/index.js")],
8054
+ args: [resolve7(PLATFORM_ROOT4, "plugins/cloudflare/mcp/dist/index.js")],
8000
8055
  env: { ...baseEnv, PLATFORM_PORT: process.env.PORT ?? "19200" }
8001
8056
  };
8002
8057
  if (Array.isArray(enabledPlugins) && enabledPlugins.length > 0) {
8003
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
8058
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
8004
8059
  let dirs;
8005
8060
  try {
8006
8061
  dirs = readdirSync2(pluginsDir);
@@ -8023,7 +8078,7 @@ function getMcpServers(accountId, conversationId, userId, enabledPlugins) {
8023
8078
  continue;
8024
8079
  }
8025
8080
  }
8026
- const mcpEntry = resolve6(PLATFORM_ROOT4, "plugins", dir, "mcp/dist/index.js");
8081
+ const mcpEntry = resolve7(PLATFORM_ROOT4, "plugins", dir, "mcp/dist/index.js");
8027
8082
  if (!existsSync6(mcpEntry)) continue;
8028
8083
  servers[dir] = {
8029
8084
  command: "node",
@@ -8158,7 +8213,7 @@ var ADMIN_CORE_TOOLS = [
8158
8213
  function getAdminAllowedTools(enabledPlugins) {
8159
8214
  const tools = [...ADMIN_CORE_TOOLS];
8160
8215
  if (Array.isArray(enabledPlugins) && enabledPlugins.length > 0) {
8161
- const pluginsDir = resolve6(PLATFORM_ROOT4, "plugins");
8216
+ const pluginsDir = resolve7(PLATFORM_ROOT4, "plugins");
8162
8217
  let dirs;
8163
8218
  try {
8164
8219
  dirs = readdirSync2(pluginsDir);
@@ -8266,13 +8321,13 @@ ${message.slice(0, QUERY_CLASSIFIER_MSG_CAP)}`
8266
8321
  }
8267
8322
  }
8268
8323
  async function fetchMemoryContext(accountId, query, sessionKey, options) {
8269
- const serverPath = resolve6(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js");
8324
+ const serverPath = resolve7(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js");
8270
8325
  if (!existsSync6(serverPath)) {
8271
8326
  console.error(`[fetchMemoryContext] MCP server not found: ${serverPath}`);
8272
8327
  return null;
8273
8328
  }
8274
8329
  const startMs = Date.now();
8275
- return new Promise((resolve29) => {
8330
+ return new Promise((resolve30) => {
8276
8331
  const proc = spawn2(process.execPath, [serverPath], {
8277
8332
  env: {
8278
8333
  ...process.env,
@@ -8301,7 +8356,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
8301
8356
  } else {
8302
8357
  console.error(`[fetchMemoryContext] failed: ${reason} (${elapsed}ms)${stderrBuf ? ` stderr: ${stderrBuf.slice(0, 500)}` : ""}`);
8303
8358
  }
8304
- resolve29(value);
8359
+ resolve30(value);
8305
8360
  };
8306
8361
  proc.stdout.on("data", (chunk) => {
8307
8362
  buffer += chunk.toString();
@@ -8364,7 +8419,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
8364
8419
  }
8365
8420
  async function compactTrimmedMessages(accountId, trimmedMessages) {
8366
8421
  if (trimmedMessages.length === 0) return true;
8367
- const serverPath = resolve6(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js");
8422
+ const serverPath = resolve7(PLATFORM_ROOT4, "plugins/memory/mcp/dist/index.js");
8368
8423
  if (!existsSync6(serverPath)) return false;
8369
8424
  const briefing = trimmedMessages.map((m) => `[${m.role.toUpperCase()}] ${m.content}`).join("\n\n");
8370
8425
  return new Promise((resolvePromise) => {
@@ -8682,7 +8737,7 @@ Then respond with only: [COMPACTED]`;
8682
8737
  var COMPACTION_TIMEOUT_MS = 45e3;
8683
8738
  async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSessionId, adminModel, conversationId, enabledPlugins) {
8684
8739
  const mcpConfig = JSON.stringify({ mcpServers: getMcpServers(accountId, conversationId, void 0, enabledPlugins) });
8685
- const specialistsDir = resolve6(accountDir, "specialists");
8740
+ const specialistsDir = resolve7(accountDir, "specialists");
8686
8741
  if (!existsSync6(specialistsDir)) agentLogStream("claude-agent-compaction-stream", accountDir, conversationId).write(`[${isoTs()}] [warn] specialists plugin dir missing: ${specialistsDir}
8687
8742
  `);
8688
8743
  const args = [
@@ -8956,7 +9011,7 @@ async function* parseClaudeStream(proc, streamLog, adminModel, conversationId, a
8956
9011
  const { logDir } = streamLogPathFor(accountId, conversationId);
8957
9012
  const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
8958
9013
  for (const s of failed) {
8959
- const stderrPath = resolve6(logDir, `mcp-${s.name}-stderr-${date}.log`);
9014
+ const stderrPath = resolve7(logDir, `mcp-${s.name}-stderr-${date}.log`);
8960
9015
  let tail = "(no stderr file)";
8961
9016
  try {
8962
9017
  const stats = statSync3(stderrPath);
@@ -9598,7 +9653,7 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
9598
9653
  }
9599
9654
  const ccUserId = sessionKey ? getUserIdForSession(sessionKey) : void 0;
9600
9655
  const mcpConfig = JSON.stringify({ mcpServers: getMcpServers(accountId, spawnConvId, ccUserId, enabledPlugins) });
9601
- const specialistsDir = resolve6(accountDir, "specialists");
9656
+ const specialistsDir = resolve7(accountDir, "specialists");
9602
9657
  if (!existsSync6(specialistsDir)) agentLogStream("claude-agent-stream", accountDir, spawnConvId).write(`[${isoTs()}] [warn] specialists plugin dir missing: ${specialistsDir}
9603
9658
  `);
9604
9659
  const args = [
@@ -9939,7 +9994,7 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
9939
9994
  `);
9940
9995
  const managedUserId = getUserIdForSession(sessionKey);
9941
9996
  const mcpConfig = JSON.stringify({ mcpServers: getMcpServers(accountId, managedConvId, managedUserId, enabledPlugins) });
9942
- const specialistsDir = resolve6(accountDir, "specialists");
9997
+ const specialistsDir = resolve7(accountDir, "specialists");
9943
9998
  if (!existsSync6(specialistsDir)) streamLog.write(`[${isoTs()}] [warn] specialists plugin dir missing: ${specialistsDir}
9944
9999
  `);
9945
10000
  const fullMessage = attachments.length > 0 ? message + buildAttachmentMetaText(attachments) : message;
@@ -10602,7 +10657,7 @@ ${sessionContext}`;
10602
10657
  console.log(`[onboarding-inject] accountId=${accountId.slice(0, 8)}\u2026 error=neo4j-unreachable injected=false`);
10603
10658
  } else if (onboardingStep < 8) {
10604
10659
  const GENERIC_FALLBACK = "At every session start, call `onboarding-get`. If `currentStep` is less than 8, load the onboarding skill via `plugin-read` (find its path in the manifest under `admin`) and follow it \u2014 before any business setup. If `onboarding-get` fails (Neo4j unreachable), tell the user and skip onboarding for this session \u2014 it resumes automatically when the graph is available.";
10605
- const skillPath = resolve6(PLATFORM_ROOT4, "plugins/admin/skills/onboarding/SKILL.md");
10660
+ const skillPath = resolve7(PLATFORM_ROOT4, "plugins/admin/skills/onboarding/SKILL.md");
10606
10661
  let skillContent = "";
10607
10662
  try {
10608
10663
  skillContent = readFileSync7(skillPath, "utf-8");
@@ -10655,7 +10710,7 @@ ${body}`;
10655
10710
 
10656
10711
  ${manifest}`;
10657
10712
  }
10658
- const graphRefPath = resolve6(PLATFORM_ROOT4, "plugins/memory/references/graph-primitives.md");
10713
+ const graphRefPath = resolve7(PLATFORM_ROOT4, "plugins/memory/references/graph-primitives.md");
10659
10714
  try {
10660
10715
  const graphRef = readFileSync7(graphRefPath, "utf-8");
10661
10716
  baseSystemPrompt += `
@@ -10883,8 +10938,8 @@ function getLanIp() {
10883
10938
  import { basename as basename2 } from "path";
10884
10939
 
10885
10940
  // app/lib/review-detector/rules.ts
10886
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync7, statSync as statSync4, mkdirSync as mkdirSync5, renameSync } from "fs";
10887
- import { resolve as resolve7, dirname as dirname2 } from "path";
10941
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync7, statSync as statSync4, mkdirSync as mkdirSync6, renameSync } from "fs";
10942
+ import { resolve as resolve8, dirname as dirname2 } from "path";
10888
10943
  var DEFAULT_SCAN_INTERVAL_MS = 5e3;
10889
10944
  var RATE_LIMIT_PATTERN = "rate[- ]?limit(?:ed| reached| hit)|(?:HTTP|status)[^a-z]{0,3}429|too many requests";
10890
10945
  var RATE_LIMIT_PATTERN_V1 = "\\b429\\b|rate.?limit|too.?many.?requests";
@@ -11313,12 +11368,12 @@ function defaultRules() {
11313
11368
  ];
11314
11369
  }
11315
11370
  function rulesFilePath(configDir2) {
11316
- return resolve7(configDir2, "review-rules.json");
11371
+ return resolve8(configDir2, "review-rules.json");
11317
11372
  }
11318
11373
  function ensureRulesFile(configDir2) {
11319
11374
  const path2 = rulesFilePath(configDir2);
11320
11375
  if (existsSync7(path2)) return { created: false, path: path2 };
11321
- mkdirSync5(dirname2(path2), { recursive: true });
11376
+ mkdirSync6(dirname2(path2), { recursive: true });
11322
11377
  const body = {
11323
11378
  scanIntervalMs: DEFAULT_SCAN_INTERVAL_MS,
11324
11379
  rules: defaultRules()
@@ -11496,10 +11551,10 @@ function validateRule(input, label, seenIds) {
11496
11551
  }
11497
11552
 
11498
11553
  // app/lib/review-detector/sources.ts
11499
- import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync5, writeFileSync as writeFileSync7, renameSync as renameSync2, mkdirSync as mkdirSync6, openSync as openSync3, readSync as readSync3, closeSync as closeSync3, readFileSync as readFileSync9 } from "fs";
11500
- import { resolve as resolve8, join as join5, basename, dirname as dirname3 } from "path";
11554
+ import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync5, writeFileSync as writeFileSync7, renameSync as renameSync2, mkdirSync as mkdirSync7, openSync as openSync3, readSync as readSync3, closeSync as closeSync3, readFileSync as readFileSync9 } from "fs";
11555
+ import { resolve as resolve9, join as join5, basename, dirname as dirname3 } from "path";
11501
11556
  function tailStatePath(configDir2) {
11502
- return resolve8(configDir2, "review-state.json");
11557
+ return resolve9(configDir2, "review-state.json");
11503
11558
  }
11504
11559
  function loadTailState(configDir2) {
11505
11560
  const path2 = tailStatePath(configDir2);
@@ -11523,25 +11578,25 @@ function loadTailState(configDir2) {
11523
11578
  }
11524
11579
  function saveTailState(configDir2, state) {
11525
11580
  const path2 = tailStatePath(configDir2);
11526
- mkdirSync6(dirname3(path2), { recursive: true });
11581
+ mkdirSync7(dirname3(path2), { recursive: true });
11527
11582
  const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
11528
11583
  writeFileSync7(tmp, JSON.stringify(state, null, 2) + "\n", "utf-8");
11529
11584
  renameSync2(tmp, path2);
11530
11585
  }
11531
11586
  function discoverSourceFiles(configDir2, accountLogDir2, logicalSource) {
11532
11587
  if (logicalSource === "server") {
11533
- const p = resolve8(configDir2, "logs", "server.log");
11588
+ const p = resolve9(configDir2, "logs", "server.log");
11534
11589
  return existsSync8(p) ? [{ logicalSource: "server", filepath: p }] : [];
11535
11590
  }
11536
11591
  if (logicalSource === "vnc") {
11537
- const p = resolve8(configDir2, "logs", "vnc-boot.log");
11592
+ const p = resolve9(configDir2, "logs", "vnc-boot.log");
11538
11593
  return existsSync8(p) ? [{ logicalSource: "vnc", filepath: p }] : [];
11539
11594
  }
11540
11595
  if (logicalSource === "cloudflared") {
11541
11596
  const files2 = [];
11542
- const daemon = resolve8(configDir2, "logs", "cloudflared.log");
11597
+ const daemon = resolve9(configDir2, "logs", "cloudflared.log");
11543
11598
  if (existsSync8(daemon)) files2.push({ logicalSource: "cloudflared", filepath: daemon });
11544
- const login = resolve8(configDir2, "logs", "cloudflared-login.log");
11599
+ const login = resolve9(configDir2, "logs", "cloudflared-login.log");
11545
11600
  if (existsSync8(login)) files2.push({ logicalSource: "cloudflared", filepath: login });
11546
11601
  return files2;
11547
11602
  }
@@ -11668,31 +11723,31 @@ function fileLastWriteMs(path2) {
11668
11723
  }
11669
11724
  }
11670
11725
  function accountLogDir(accountDir) {
11671
- return resolve8(accountDir, "logs");
11726
+ return resolve9(accountDir, "logs");
11672
11727
  }
11673
11728
  function sourceKey(file) {
11674
11729
  return `${file.logicalSource}:${basename(file.filepath)}`;
11675
11730
  }
11676
11731
 
11677
11732
  // app/lib/review-detector/writer.ts
11678
- import { appendFileSync as appendFileSync3, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync8, renameSync as renameSync3, statSync as statSync6 } from "fs";
11679
- import { resolve as resolve9, dirname as dirname4 } from "path";
11733
+ import { appendFileSync as appendFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync8, renameSync as renameSync3, statSync as statSync6 } from "fs";
11734
+ import { resolve as resolve10, dirname as dirname4 } from "path";
11680
11735
  import { randomUUID as randomUUID3 } from "crypto";
11681
11736
  function reviewLogPath(configDir2) {
11682
- return resolve9(configDir2, "logs", "review.log");
11737
+ return resolve10(configDir2, "logs", "review.log");
11683
11738
  }
11684
11739
  function pendingAlertsPath(configDir2) {
11685
- return resolve9(configDir2, "review-pending-alerts.jsonl");
11740
+ return resolve10(configDir2, "review-pending-alerts.jsonl");
11686
11741
  }
11687
11742
  function reviewLog(configDir2, event) {
11688
11743
  const path2 = reviewLogPath(configDir2);
11689
11744
  try {
11690
- mkdirSync7(dirname4(path2), { recursive: true });
11745
+ mkdirSync8(dirname4(path2), { recursive: true });
11691
11746
  const line = `${new Date(
11692
11747
  typeof event.ts === "number" ? event.ts : Date.now()
11693
11748
  ).toISOString()} [review] ${JSON.stringify(event)}
11694
11749
  `;
11695
- appendFileSync3(path2, line, "utf-8");
11750
+ appendFileSync4(path2, line, "utf-8");
11696
11751
  } catch (err) {
11697
11752
  console.error(`[review] failed to write review log at ${path2}: ${err instanceof Error ? err.message : String(err)}`);
11698
11753
  }
@@ -11804,9 +11859,9 @@ async function upsertReviewAlert(accountId, match2) {
11804
11859
  function queueAlert(configDir2, accountId, match2) {
11805
11860
  const path2 = pendingAlertsPath(configDir2);
11806
11861
  try {
11807
- mkdirSync7(dirname4(path2), { recursive: true });
11862
+ mkdirSync8(dirname4(path2), { recursive: true });
11808
11863
  const line = JSON.stringify({ accountId, match: match2 }) + "\n";
11809
- appendFileSync3(path2, line, "utf-8");
11864
+ appendFileSync4(path2, line, "utf-8");
11810
11865
  } catch (err) {
11811
11866
  console.error(`[review] failed to queue alert at ${path2}: ${err instanceof Error ? err.message : String(err)}`);
11812
11867
  }
@@ -11937,7 +11992,7 @@ async function bootDetector() {
11937
11992
  }
11938
11993
 
11939
11994
  // app/lib/review-detector/scan-loop.ts
11940
- import { resolve as resolve10 } from "path";
11995
+ import { resolve as resolve11 } from "path";
11941
11996
 
11942
11997
  // app/lib/review-detector/evaluator.ts
11943
11998
  var SAMPLE_MAX_CHARS = 500;
@@ -12231,14 +12286,14 @@ async function runScanCycle(runtime) {
12231
12286
  match2 = result.match;
12232
12287
  }
12233
12288
  } else if (rule.type === "file-write-storm") {
12234
- const dir = resolve10(runtime.configDir, rule.watchPath ?? "");
12289
+ const dir = resolve11(runtime.configDir, rule.watchPath ?? "");
12235
12290
  const sinceMs = cycleStart - rule.thresholdWindowMinutes * 6e4;
12236
12291
  const count = countRecentWrites(dir, sinceMs);
12237
12292
  const result = evaluateFileWriteStormRule(rule, count, state, cycleStart);
12238
12293
  state = result.state;
12239
12294
  match2 = result.match;
12240
12295
  } else if (rule.type === "stale-log") {
12241
- const trackedPath = resolve10(runtime.configDir, rule.watchPath ?? "");
12296
+ const trackedPath = resolve11(runtime.configDir, rule.watchPath ?? "");
12242
12297
  const lastMs = fileLastWriteMs(trackedPath);
12243
12298
  const result = evaluateStaleLogRule(rule, lastMs, state, cycleStart);
12244
12299
  state = result.state;
@@ -12478,10 +12533,10 @@ var WhatsAppConfigSchema = z.object({
12478
12533
 
12479
12534
  // app/lib/whatsapp/config-persist.ts
12480
12535
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, existsSync as existsSync10 } from "fs";
12481
- import { resolve as resolve11, join as join6 } from "path";
12536
+ import { resolve as resolve12, join as join6 } from "path";
12482
12537
  var TAG2 = "[whatsapp:config]";
12483
12538
  function configPath(accountDir) {
12484
- return resolve11(accountDir, "account.json");
12539
+ return resolve12(accountDir, "account.json");
12485
12540
  }
12486
12541
  function readConfig(accountDir) {
12487
12542
  const path2 = configPath(accountDir);
@@ -12936,7 +12991,7 @@ var credsSaveQueue = Promise.resolve();
12936
12991
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
12937
12992
  console.error(`${TAG4} draining credential save queue\u2026`);
12938
12993
  const timer = new Promise(
12939
- (resolve29) => setTimeout(() => resolve29("timeout"), timeoutMs)
12994
+ (resolve30) => setTimeout(() => resolve30("timeout"), timeoutMs)
12940
12995
  );
12941
12996
  const result = await Promise.race([
12942
12997
  credsSaveQueue.then(() => "drained"),
@@ -13064,11 +13119,11 @@ async function createWaSocket(opts) {
13064
13119
  return sock;
13065
13120
  }
13066
13121
  async function waitForConnection(sock) {
13067
- return new Promise((resolve29, reject) => {
13122
+ return new Promise((resolve30, reject) => {
13068
13123
  const handler = (update) => {
13069
13124
  if (update.connection === "open") {
13070
13125
  sock.ev.off("connection.update", handler);
13071
- resolve29();
13126
+ resolve30();
13072
13127
  }
13073
13128
  if (update.connection === "close") {
13074
13129
  sock.ev.off("connection.update", handler);
@@ -13182,14 +13237,14 @@ ${inspected}`;
13182
13237
  return inspect2(err, INSPECT_OPTS2);
13183
13238
  }
13184
13239
  function withTimeout(label, promise, timeoutMs) {
13185
- return new Promise((resolve29, reject) => {
13240
+ return new Promise((resolve30, reject) => {
13186
13241
  const timer = setTimeout(() => {
13187
13242
  reject(new Error(`${label} timed out after ${timeoutMs}ms`));
13188
13243
  }, timeoutMs);
13189
13244
  promise.then(
13190
13245
  (value) => {
13191
13246
  clearTimeout(timer);
13192
- resolve29(value);
13247
+ resolve30(value);
13193
13248
  },
13194
13249
  (err) => {
13195
13250
  clearTimeout(timer);
@@ -14389,11 +14444,11 @@ async function connectWithReconnect(conn) {
14389
14444
  console.error(
14390
14445
  `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
14391
14446
  );
14392
- await new Promise((resolve29) => {
14393
- const timer = setTimeout(resolve29, delay);
14447
+ await new Promise((resolve30) => {
14448
+ const timer = setTimeout(resolve30, delay);
14394
14449
  conn.abortController.signal.addEventListener("abort", () => {
14395
14450
  clearTimeout(timer);
14396
- resolve29();
14451
+ resolve30();
14397
14452
  }, { once: true });
14398
14453
  });
14399
14454
  }
@@ -14401,16 +14456,16 @@ async function connectWithReconnect(conn) {
14401
14456
  }
14402
14457
  }
14403
14458
  function waitForDisconnectEvent(conn) {
14404
- return new Promise((resolve29) => {
14459
+ return new Promise((resolve30) => {
14405
14460
  if (!conn.sock) {
14406
- resolve29();
14461
+ resolve30();
14407
14462
  return;
14408
14463
  }
14409
14464
  const sock = conn.sock;
14410
14465
  const handler = (update) => {
14411
14466
  if (update.connection === "close") {
14412
14467
  sock.ev.off("connection.update", handler);
14413
- resolve29();
14468
+ resolve30();
14414
14469
  }
14415
14470
  };
14416
14471
  sock.ev.on("connection.update", handler);
@@ -14620,8 +14675,8 @@ async function handleInboundMessage(conn, msg) {
14620
14675
  const conversationKey = isGroup ? remoteJid : senderPhone;
14621
14676
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
14622
14677
  let resolvePending;
14623
- const sttPending = new Promise((resolve29) => {
14624
- resolvePending = resolve29;
14678
+ const sttPending = new Promise((resolve30) => {
14679
+ resolvePending = resolve30;
14625
14680
  });
14626
14681
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
14627
14682
  try {
@@ -14728,20 +14783,20 @@ async function probeApiKey() {
14728
14783
  return result.status;
14729
14784
  }
14730
14785
  function checkPort(port2, timeoutMs = 500) {
14731
- return new Promise((resolve29) => {
14786
+ return new Promise((resolve30) => {
14732
14787
  const socket = createConnection4(port2, "127.0.0.1");
14733
14788
  socket.setTimeout(timeoutMs);
14734
14789
  socket.once("connect", () => {
14735
14790
  socket.destroy();
14736
- resolve29(true);
14791
+ resolve30(true);
14737
14792
  });
14738
14793
  socket.once("error", () => {
14739
14794
  socket.destroy();
14740
- resolve29(false);
14795
+ resolve30(false);
14741
14796
  });
14742
14797
  socket.once("timeout", () => {
14743
14798
  socket.destroy();
14744
- resolve29(false);
14799
+ resolve30(false);
14745
14800
  });
14746
14801
  });
14747
14802
  }
@@ -14838,14 +14893,14 @@ app.get("/", async (c) => {
14838
14893
  var health_default = app;
14839
14894
 
14840
14895
  // server/routes/session.ts
14841
- import { resolve as resolve12 } from "path";
14842
- import { existsSync as existsSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync8 } from "fs";
14896
+ import { resolve as resolve13 } from "path";
14897
+ import { existsSync as existsSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync9 } from "fs";
14843
14898
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14844
14899
  function writeBrandingCache(accountId, agentSlug, branding) {
14845
14900
  try {
14846
- const cacheDir = resolve12(MAXY_DIR, "branding-cache", accountId);
14847
- mkdirSync8(cacheDir, { recursive: true });
14848
- writeFileSync10(resolve12(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
14901
+ const cacheDir = resolve13(MAXY_DIR, "branding-cache", accountId);
14902
+ mkdirSync9(cacheDir, { recursive: true });
14903
+ writeFileSync10(resolve13(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
14849
14904
  } catch (err) {
14850
14905
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
14851
14906
  }
@@ -14915,8 +14970,8 @@ app2.post("/", async (c) => {
14915
14970
  }
14916
14971
  let agentConfig = null;
14917
14972
  if (account) {
14918
- const agentDir = resolve12(account.accountDir, "agents", agentSlug);
14919
- const agentConfigPath = resolve12(agentDir, "config.json");
14973
+ const agentDir = resolve13(account.accountDir, "agents", agentSlug);
14974
+ const agentConfigPath = resolve13(agentDir, "config.json");
14920
14975
  if (!existsSync12(agentDir) || !existsSync12(agentConfigPath)) {
14921
14976
  return c.json({ error: "Agent not found" }, 404);
14922
14977
  }
@@ -15163,9 +15218,9 @@ ${raw2}`;
15163
15218
  import { randomUUID as randomUUID6 } from "crypto";
15164
15219
  import { mkdir as mkdir2, readFile, stat as stat2, writeFile as writeFile2 } from "fs/promises";
15165
15220
  import { realpathSync } from "fs";
15166
- import { resolve as resolve13, extname, basename as basename3 } from "path";
15167
- var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve13(process.cwd(), "../platform");
15168
- var ATTACHMENTS_ROOT = resolve13(PLATFORM_ROOT5, "..", "data/uploads");
15221
+ import { resolve as resolve14, extname, basename as basename3 } from "path";
15222
+ var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "../platform");
15223
+ var ATTACHMENTS_ROOT = resolve14(PLATFORM_ROOT5, "..", "data/uploads");
15169
15224
  var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
15170
15225
  "image/jpeg",
15171
15226
  "image/png",
@@ -15189,11 +15244,11 @@ function assertSupportedMime(mimeType) {
15189
15244
  }
15190
15245
  async function writeAttachment(scope, filename, mimeType, sizeBytes, buffer) {
15191
15246
  const attachmentId = randomUUID6();
15192
- const dir = resolve13(ATTACHMENTS_ROOT, scope, attachmentId);
15247
+ const dir = resolve14(ATTACHMENTS_ROOT, scope, attachmentId);
15193
15248
  await mkdir2(dir, { recursive: true });
15194
15249
  const ext = extname(filename) || "";
15195
- const storagePath = resolve13(dir, `${attachmentId}${ext}`);
15196
- const metaPath = resolve13(dir, `${attachmentId}.meta.json`);
15250
+ const storagePath = resolve14(dir, `${attachmentId}${ext}`);
15251
+ const metaPath = resolve14(dir, `${attachmentId}.meta.json`);
15197
15252
  const meta = {
15198
15253
  attachmentId,
15199
15254
  scope,
@@ -15871,13 +15926,13 @@ var group_default = app4;
15871
15926
  // app/lib/access-gate.ts
15872
15927
  import neo4j2 from "neo4j-driver";
15873
15928
  import { readFileSync as readFileSync13 } from "fs";
15874
- import { resolve as resolve14 } from "path";
15929
+ import { resolve as resolve15 } from "path";
15875
15930
  import { randomUUID as randomUUID7, randomInt } from "crypto";
15876
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
15931
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
15877
15932
  var driver2 = null;
15878
15933
  function readPassword2() {
15879
15934
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
15880
- const passwordFile = resolve14(PLATFORM_ROOT6, "config/.neo4j-password");
15935
+ const passwordFile = resolve15(PLATFORM_ROOT6, "config/.neo4j-password");
15881
15936
  try {
15882
15937
  return readFileSync13(passwordFile, "utf-8").trim();
15883
15938
  } catch {
@@ -16190,17 +16245,17 @@ async function findActiveGrantByContact(contactValue, agentSlug, accountId) {
16190
16245
  }
16191
16246
 
16192
16247
  // app/lib/brevo-sms.ts
16193
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, mkdirSync as mkdirSync9, existsSync as existsSync13, chmodSync } from "fs";
16248
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, mkdirSync as mkdirSync10, existsSync as existsSync13, chmodSync } from "fs";
16194
16249
  import { dirname as dirname5 } from "path";
16195
- import { resolve as resolve15 } from "path";
16196
- var BREVO_API_KEY_FILE = resolve15(MAXY_DIR, ".brevo-api-key");
16250
+ import { resolve as resolve16 } from "path";
16251
+ var BREVO_API_KEY_FILE = resolve16(MAXY_DIR, ".brevo-api-key");
16197
16252
  var BREVO_API_URL = "https://api.brevo.com/v3/transactionalSMS/sms";
16198
16253
  var BREVO_TIMEOUT_MS = 1e4;
16199
16254
  var BREVO_SENDER = "Maxy";
16200
16255
  var platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
16201
16256
  if (platformRoot2) {
16202
16257
  try {
16203
- const brandPath = resolve15(platformRoot2, "config", "brand.json");
16258
+ const brandPath = resolve16(platformRoot2, "config", "brand.json");
16204
16259
  if (existsSync13(brandPath)) {
16205
16260
  const brand = JSON.parse(readFileSync14(brandPath, "utf-8"));
16206
16261
  if (brand.productName) BREVO_SENDER = brand.productName;
@@ -16837,7 +16892,7 @@ app6.post("/webhook", async (c) => {
16837
16892
  var telegram_default = app6;
16838
16893
 
16839
16894
  // server/routes/whatsapp.ts
16840
- import { join as join9, resolve as resolve16, basename as basename4 } from "path";
16895
+ import { join as join9, resolve as resolve17, basename as basename4 } from "path";
16841
16896
  import { readFile as readFile2, stat as stat3 } from "fs/promises";
16842
16897
  import { realpathSync as realpathSync2, readdirSync as readdirSync4, readFileSync as readFileSync16, existsSync as existsSync15 } from "fs";
16843
16898
 
@@ -16945,8 +17000,8 @@ async function startLogin(opts) {
16945
17000
  resetActiveLogin(accountId);
16946
17001
  let resolveQr = null;
16947
17002
  let rejectQr = null;
16948
- const qrPromise = new Promise((resolve29, reject) => {
16949
- resolveQr = resolve29;
17003
+ const qrPromise = new Promise((resolve30, reject) => {
17004
+ resolveQr = resolve30;
16950
17005
  rejectQr = reject;
16951
17006
  });
16952
17007
  const qrTimer = setTimeout(
@@ -17317,14 +17372,14 @@ app7.post("/config", async (c) => {
17317
17372
  return c.json({ ok: true, slug: currentSlug });
17318
17373
  }
17319
17374
  case "list-public-agents": {
17320
- const agentsDir = resolve16(account.accountDir, "agents");
17375
+ const agentsDir = resolve17(account.accountDir, "agents");
17321
17376
  const agents = [];
17322
17377
  if (existsSync15(agentsDir)) {
17323
17378
  try {
17324
17379
  const entries = readdirSync4(agentsDir, { withFileTypes: true });
17325
17380
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
17326
17381
  if (!entry.isDirectory() || entry.name === "admin") continue;
17327
- const configPath2 = resolve16(agentsDir, entry.name, "config.json");
17382
+ const configPath2 = resolve17(agentsDir, entry.name, "config.json");
17328
17383
  if (!existsSync15(configPath2)) continue;
17329
17384
  try {
17330
17385
  const config = JSON.parse(readFileSync16(configPath2, "utf-8"));
@@ -17402,7 +17457,7 @@ app7.post("/send-document", async (c) => {
17402
17457
  if (!maxyAccountId || !PLATFORM_ROOT7) {
17403
17458
  return c.json({ error: "Cannot validate file path: missing account or platform context" }, 400);
17404
17459
  }
17405
- const accountDir = resolve16(PLATFORM_ROOT7, "..", "data/accounts", maxyAccountId);
17460
+ const accountDir = resolve17(PLATFORM_ROOT7, "..", "data/accounts", maxyAccountId);
17406
17461
  let resolvedPath;
17407
17462
  try {
17408
17463
  resolvedPath = realpathSync2(filePath);
@@ -17539,8 +17594,8 @@ var whatsapp_default = app7;
17539
17594
 
17540
17595
  // server/routes/onboarding.ts
17541
17596
  import { spawn as spawn3, execFileSync as execFileSync2 } from "child_process";
17542
- import { openSync as openSync4, closeSync as closeSync4, writeFileSync as writeFileSync12, writeSync, existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync17, unlinkSync as unlinkSync3 } from "fs";
17543
- import { resolve as resolve17, dirname as dirname6 } from "path";
17597
+ import { openSync as openSync4, closeSync as closeSync4, writeFileSync as writeFileSync12, writeSync, existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync17, unlinkSync as unlinkSync3 } from "fs";
17598
+ import { resolve as resolve18, dirname as dirname6 } from "path";
17544
17599
  import { createHash, randomUUID as randomUUID9 } from "crypto";
17545
17600
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
17546
17601
  function hashPin(pin) {
@@ -17653,7 +17708,7 @@ app8.post("/set-pin", async (c) => {
17653
17708
  }
17654
17709
  const hash = hashPin(body.pin);
17655
17710
  const userId = randomUUID9();
17656
- mkdirSync10(dirname6(USERS_FILE), { recursive: true });
17711
+ mkdirSync11(dirname6(USERS_FILE), { recursive: true });
17657
17712
  writeFileSync12(USERS_FILE, JSON.stringify([{ userId, name: "Owner", pin: hash }]), { mode: 384 });
17658
17713
  console.log(`[set-pin] created users.json: userId=${userId.slice(0, 8)}\u2026 hash=${hash.slice(0, 8)}\u2026`);
17659
17714
  const account = resolveAccount();
@@ -17714,7 +17769,7 @@ app8.post("/skip", async (c) => {
17714
17769
  }
17715
17770
  const { accountId, accountDir } = account;
17716
17771
  let agentName = "Maxy";
17717
- const brandPath = PLATFORM_ROOT8 ? resolve17(PLATFORM_ROOT8, "config", "brand.json") : "";
17772
+ const brandPath = PLATFORM_ROOT8 ? resolve18(PLATFORM_ROOT8, "config", "brand.json") : "";
17718
17773
  if (brandPath && existsSync16(brandPath)) {
17719
17774
  try {
17720
17775
  const brand = JSON.parse(readFileSync17(brandPath, "utf-8"));
@@ -17723,9 +17778,9 @@ app8.post("/skip", async (c) => {
17723
17778
  console.error(`[onboarding-skip] brand.json read failed: ${err instanceof Error ? err.message : String(err)}`);
17724
17779
  }
17725
17780
  }
17726
- const soulPath = resolve17(accountDir, "agents", "admin", "SOUL.md");
17781
+ const soulPath = resolve18(accountDir, "agents", "admin", "SOUL.md");
17727
17782
  try {
17728
- mkdirSync10(dirname6(soulPath), { recursive: true });
17783
+ mkdirSync11(dirname6(soulPath), { recursive: true });
17729
17784
  writeFileSync12(soulPath, `You are ${agentName}, an AI operations manager.
17730
17785
  `);
17731
17786
  console.log(`[onboarding-skip] wrote SOUL.md: ${soulPath}`);
@@ -17764,7 +17819,7 @@ app8.post("/skip", async (c) => {
17764
17819
  var onboarding_default = app8;
17765
17820
 
17766
17821
  // server/routes/client-error.ts
17767
- import { appendFileSync as appendFileSync4, existsSync as existsSync17, renameSync as renameSync4, statSync as statSync7 } from "fs";
17822
+ import { appendFileSync as appendFileSync5, existsSync as existsSync17, renameSync as renameSync4, statSync as statSync7 } from "fs";
17768
17823
  import { join as join10 } from "path";
17769
17824
  var CLIENT_ERRORS_LOG = join10(LOG_DIR, "client-errors.log");
17770
17825
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
@@ -17892,7 +17947,7 @@ app9.post("/", async (c) => {
17892
17947
  tag: typeof body.tag === "string" ? truncate(body.tag, 32) : void 0,
17893
17948
  status: typeof body.status === "number" ? body.status : void 0
17894
17949
  };
17895
- appendFileSync4(CLIENT_ERRORS_LOG, JSON.stringify(payload) + "\n", "utf-8");
17950
+ appendFileSync5(CLIENT_ERRORS_LOG, JSON.stringify(payload) + "\n", "utf-8");
17896
17951
  } catch (err) {
17897
17952
  console.error(`[client-error] append failed: ${err instanceof Error ? err.message : String(err)}`);
17898
17953
  }
@@ -18004,12 +18059,14 @@ app10.post("/", async (c) => {
18004
18059
  var session_default2 = app10;
18005
18060
 
18006
18061
  // server/routes/admin/chat.ts
18007
- import { resolve as resolve18 } from "path";
18062
+ import { resolve as resolve19 } from "path";
18008
18063
 
18009
18064
  // app/lib/script-stream-tailer.ts
18010
- import { createReadStream as createReadStream2, statSync as statSync8 } from "fs";
18065
+ import * as childProcess from "child_process";
18066
+ import { appendFileSync as appendFileSync6, createReadStream as createReadStream2, mkdirSync as mkdirSync12, statSync as statSync8 } from "fs";
18067
+ import { dirname as dirname7 } from "path";
18011
18068
  import { StringDecoder as StringDecoder2 } from "string_decoder";
18012
- var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[(setup-tunnel|reset-tunnel)((?::[^\]]+)?)\] (.*)$/;
18069
+ var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$/;
18013
18070
  function parseLine(line) {
18014
18071
  const m = line.match(SCRIPT_STREAM_RE);
18015
18072
  if (!m) return void 0;
@@ -18102,6 +18159,106 @@ function startScriptStreamTailer(opts) {
18102
18159
  }
18103
18160
  };
18104
18161
  }
18162
+ var SCOPE_TOKEN_RE = /^[a-z][a-z0-9-]*$/;
18163
+ function writeRouteMilestone(streamLogPath, scope, line) {
18164
+ if (!SCOPE_TOKEN_RE.test(scope)) {
18165
+ throw new Error(
18166
+ `writeRouteMilestone: scope "${scope}" must match [a-z][a-z0-9-]* \u2014 the tailer regex won't match otherwise`
18167
+ );
18168
+ }
18169
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
18170
+ try {
18171
+ mkdirSync12(dirname7(streamLogPath), { recursive: true });
18172
+ appendFileSync6(streamLogPath, `[${ts}] [${scope}] ${line}
18173
+ `);
18174
+ } catch (err) {
18175
+ console.error(
18176
+ `[script-stream-tailer] writeRouteMilestone failed path=${streamLogPath} scope=${scope}: ${err instanceof Error ? err.message : String(err)}`
18177
+ );
18178
+ }
18179
+ }
18180
+ function runFormSpawn(opts) {
18181
+ const { scriptPath, args, streamLogPath, correlationId, timeoutMs, log, logErr, broadcast } = opts;
18182
+ return new Promise((resolveP) => {
18183
+ let tailer = null;
18184
+ try {
18185
+ tailer = startScriptStreamTailer({
18186
+ path: streamLogPath,
18187
+ onEvent: (event) => {
18188
+ try {
18189
+ broadcast(correlationId, event);
18190
+ } catch (e) {
18191
+ logErr(
18192
+ `phase=tailer-broadcast-failed detail="${e instanceof Error ? e.message : String(e)}"`
18193
+ );
18194
+ }
18195
+ },
18196
+ onError: (e) => {
18197
+ logErr(`phase=tailer-error message="${e.message.slice(0, 160).replace(/"/g, "'")}"`);
18198
+ }
18199
+ });
18200
+ log(`phase=tailer-started`);
18201
+ } catch (e) {
18202
+ logErr(`phase=tailer-start-failed detail="${e instanceof Error ? e.message : String(e)}"`);
18203
+ tailer = null;
18204
+ }
18205
+ const child = childProcess.spawn(scriptPath, args, {
18206
+ env: { ...process.env, STREAM_LOG_PATH: streamLogPath },
18207
+ stdio: ["ignore", "pipe", "pipe"]
18208
+ });
18209
+ log(`phase=script-spawn pid=${child.pid ?? "unknown"} args="${args.join(" ")}"`);
18210
+ let stdout = "";
18211
+ let stderr = "";
18212
+ let timedOut = false;
18213
+ const killer = setTimeout(() => {
18214
+ timedOut = true;
18215
+ try {
18216
+ child.kill("SIGTERM");
18217
+ } catch {
18218
+ }
18219
+ }, timeoutMs);
18220
+ child.stdout?.on("data", (chunk) => {
18221
+ stdout += chunk.toString("utf-8");
18222
+ });
18223
+ child.stderr?.on("data", (chunk) => {
18224
+ stderr += chunk.toString("utf-8");
18225
+ });
18226
+ let finalized = false;
18227
+ const finalize = async (result) => {
18228
+ if (finalized) return;
18229
+ finalized = true;
18230
+ if (tailer) {
18231
+ try {
18232
+ await tailer.stop();
18233
+ log(`phase=tailer-stopped`);
18234
+ } catch (e) {
18235
+ logErr(
18236
+ `phase=tailer-stop-failed detail="${e instanceof Error ? e.message : String(e)}"`
18237
+ );
18238
+ }
18239
+ }
18240
+ resolveP(result);
18241
+ };
18242
+ child.on("error", (e) => {
18243
+ clearTimeout(killer);
18244
+ void finalize({
18245
+ code: null,
18246
+ signal: null,
18247
+ stdout,
18248
+ stderr: `${stderr}
18249
+ ${e.message}`,
18250
+ timedOut: false
18251
+ });
18252
+ });
18253
+ child.on("exit", (code, signal) => {
18254
+ clearTimeout(killer);
18255
+ log(
18256
+ `phase=script-exit code=${code ?? "null"} signal=${signal ?? "null"} timedOut=${timedOut}`
18257
+ );
18258
+ void finalize({ code, signal, stdout, stderr, timedOut });
18259
+ });
18260
+ });
18261
+ }
18105
18262
 
18106
18263
  // app/lib/admin-sse-registry.ts
18107
18264
  var activeAdminSSEControllers = /* @__PURE__ */ new Set();
@@ -18136,6 +18293,19 @@ function broadcastAdminShutdown(reason) {
18136
18293
  }
18137
18294
  activeAdminSSEControllers.clear();
18138
18295
  }
18296
+ function broadcastToConversation(conversationId, event) {
18297
+ const encoder = new TextEncoder();
18298
+ const frame = encoder.encode(`data: ${JSON.stringify(event)}
18299
+
18300
+ `);
18301
+ for (const entry of activeAdminSSEControllers) {
18302
+ if (entry.conversationId !== conversationId) continue;
18303
+ try {
18304
+ entry.controller.enqueue(frame);
18305
+ } catch {
18306
+ }
18307
+ }
18308
+ }
18139
18309
 
18140
18310
  // server/routes/admin/chat.ts
18141
18311
  function isComponentDone(parsed) {
@@ -18329,7 +18499,7 @@ app11.post("/", requireAdminSession, async (c) => {
18329
18499
  try {
18330
18500
  registerAdminSSE(sseEntry);
18331
18501
  if (sseConvId) {
18332
- const streamLogPath = resolve18(account.accountDir, "logs", `claude-agent-stream-${sseConvId}.log`);
18502
+ const streamLogPath = resolve19(account.accountDir, "logs", `claude-agent-stream-${sseConvId}.log`);
18333
18503
  tailer = startScriptStreamTailer({
18334
18504
  path: streamLogPath,
18335
18505
  onEvent: (event) => {
@@ -18455,7 +18625,7 @@ var compact_default = app12;
18455
18625
 
18456
18626
  // server/routes/admin/logs.ts
18457
18627
  import { existsSync as existsSync19, readdirSync as readdirSync5, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
18458
- import { resolve as resolve19, basename as basename5 } from "path";
18628
+ import { resolve as resolve20, basename as basename5 } from "path";
18459
18629
  var TAIL_BYTES = 8192;
18460
18630
  var app13 = new Hono2();
18461
18631
  app13.get("/", async (c) => {
@@ -18464,13 +18634,13 @@ app13.get("/", async (c) => {
18464
18634
  const conversationIdParam = c.req.query("conversationId");
18465
18635
  const download = c.req.query("download") === "1";
18466
18636
  const account = resolveAccount();
18467
- const accountLogDir2 = account ? resolve19(account.accountDir, "logs") : null;
18637
+ const accountLogDir2 = account ? resolve20(account.accountDir, "logs") : null;
18468
18638
  if (fileParam) {
18469
18639
  const safe = basename5(fileParam);
18470
18640
  const searched = [];
18471
18641
  for (const dir of [accountLogDir2, LOG_DIR]) {
18472
18642
  if (!dir) continue;
18473
- const filePath = resolve19(dir, safe);
18643
+ const filePath = resolve20(dir, safe);
18474
18644
  searched.push(filePath);
18475
18645
  try {
18476
18646
  const content = readFileSync19(filePath, "utf-8");
@@ -18512,7 +18682,7 @@ app13.get("/", async (c) => {
18512
18682
  const searched = [];
18513
18683
  for (const dir of [accountLogDir2, LOG_DIR]) {
18514
18684
  if (!dir) continue;
18515
- const filePath = resolve19(dir, fileName);
18685
+ const filePath = resolve20(dir, fileName);
18516
18686
  searched.push(filePath);
18517
18687
  try {
18518
18688
  const content = readFileSync19(filePath, "utf-8");
@@ -18539,10 +18709,10 @@ app13.get("/", async (c) => {
18539
18709
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
18540
18710
  continue;
18541
18711
  }
18542
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve19(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
18712
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve20(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
18543
18713
  seen.add(name);
18544
18714
  try {
18545
- const content = readFileSync19(resolve19(dir, name));
18715
+ const content = readFileSync19(resolve20(dir, name));
18546
18716
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
18547
18717
  logs[name] = tail.trim() || "(empty)";
18548
18718
  } catch (err) {
@@ -18583,7 +18753,7 @@ var claude_info_default = app14;
18583
18753
  // server/routes/admin/attachment.ts
18584
18754
  import { readFile as readFile3, readdir } from "fs/promises";
18585
18755
  import { existsSync as existsSync20 } from "fs";
18586
- import { resolve as resolve20 } from "path";
18756
+ import { resolve as resolve21 } from "path";
18587
18757
  var app15 = new Hono2();
18588
18758
  app15.get("/:attachmentId", requireAdminSession, async (c) => {
18589
18759
  const attachmentId = c.req.param("attachmentId");
@@ -18595,11 +18765,11 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
18595
18765
  if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
18596
18766
  return new Response("Not found", { status: 404 });
18597
18767
  }
18598
- const dir = resolve20(ATTACHMENTS_ROOT, accountId, attachmentId);
18768
+ const dir = resolve21(ATTACHMENTS_ROOT, accountId, attachmentId);
18599
18769
  if (!existsSync20(dir)) {
18600
18770
  return new Response("Not found", { status: 404 });
18601
18771
  }
18602
- const metaPath = resolve20(dir, `${attachmentId}.meta.json`);
18772
+ const metaPath = resolve21(dir, `${attachmentId}.meta.json`);
18603
18773
  if (!existsSync20(metaPath)) {
18604
18774
  return new Response("Not found", { status: 404 });
18605
18775
  }
@@ -18614,7 +18784,7 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
18614
18784
  if (!dataFile) {
18615
18785
  return new Response("Not found", { status: 404 });
18616
18786
  }
18617
- const filePath = resolve20(dir, dataFile);
18787
+ const filePath = resolve21(dir, dataFile);
18618
18788
  const buffer = await readFile3(filePath);
18619
18789
  return new Response(new Uint8Array(buffer), {
18620
18790
  headers: {
@@ -18628,7 +18798,7 @@ var attachment_default = app15;
18628
18798
 
18629
18799
  // server/routes/admin/account.ts
18630
18800
  import { readFileSync as readFileSync20, writeFileSync as writeFileSync13 } from "fs";
18631
- import { resolve as resolve21 } from "path";
18801
+ import { resolve as resolve22 } from "path";
18632
18802
  var VALID_CONTEXT_MODES = ["managed", "claude-code"];
18633
18803
  var app16 = new Hono2();
18634
18804
  app16.patch("/", requireAdminSession, async (c) => {
@@ -18644,7 +18814,7 @@ app16.patch("/", requireAdminSession, async (c) => {
18644
18814
  }
18645
18815
  const account = resolveAccount();
18646
18816
  if (!account) return c.json({ error: "No account configured" }, 500);
18647
- const configPath2 = resolve21(account.accountDir, "account.json");
18817
+ const configPath2 = resolve22(account.accountDir, "account.json");
18648
18818
  try {
18649
18819
  const raw2 = readFileSync20(configPath2, "utf-8");
18650
18820
  const config = JSON.parse(raw2);
@@ -18660,13 +18830,13 @@ app16.patch("/", requireAdminSession, async (c) => {
18660
18830
  var account_default = app16;
18661
18831
 
18662
18832
  // server/routes/admin/agents.ts
18663
- import { resolve as resolve22 } from "path";
18833
+ import { resolve as resolve23 } from "path";
18664
18834
  import { readdirSync as readdirSync6, readFileSync as readFileSync21, existsSync as existsSync21, rmSync as rmSync3 } from "fs";
18665
18835
  var app17 = new Hono2();
18666
18836
  app17.get("/", (c) => {
18667
18837
  const account = resolveAccount();
18668
18838
  if (!account) return c.json({ agents: [] });
18669
- const agentsDir = resolve22(account.accountDir, "agents");
18839
+ const agentsDir = resolve23(account.accountDir, "agents");
18670
18840
  if (!existsSync21(agentsDir)) return c.json({ agents: [] });
18671
18841
  const agents = [];
18672
18842
  try {
@@ -18674,7 +18844,7 @@ app17.get("/", (c) => {
18674
18844
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
18675
18845
  if (!entry.isDirectory()) continue;
18676
18846
  if (entry.name === "admin") continue;
18677
- const configPath2 = resolve22(agentsDir, entry.name, "config.json");
18847
+ const configPath2 = resolve23(agentsDir, entry.name, "config.json");
18678
18848
  if (!existsSync21(configPath2)) continue;
18679
18849
  try {
18680
18850
  const config = JSON.parse(readFileSync21(configPath2, "utf-8"));
@@ -18703,7 +18873,7 @@ app17.delete("/:slug", (c) => {
18703
18873
  if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
18704
18874
  return c.json({ error: "Invalid agent slug" }, 400);
18705
18875
  }
18706
- const agentDir = resolve22(account.accountDir, "agents", slug);
18876
+ const agentDir = resolve23(account.accountDir, "agents", slug);
18707
18877
  if (!existsSync21(agentDir)) {
18708
18878
  return c.json({ error: "Agent not found" }, 404);
18709
18879
  }
@@ -18719,74 +18889,27 @@ app17.delete("/:slug", (c) => {
18719
18889
  var agents_default = app17;
18720
18890
 
18721
18891
  // server/routes/admin/version.ts
18722
- import { spawn as spawn4 } from "child_process";
18723
- import { existsSync as existsSync23, statSync as statSync10, writeFileSync as writeFileSync14, readFileSync as readFileSync23, openSync as openSync5, closeSync as closeSync5 } from "fs";
18724
- import { resolve as resolve23, join as join11 } from "path";
18725
-
18726
- // app/lib/upgrade-progress-parser.ts
18727
18892
  import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
18728
- var STEP_RE = /\[(\d+)\/(\d+)\]\s+(.+)/;
18729
- var ANSI_RE = /\x1b\[[0-9;?]*[a-zA-Z]/g;
18730
- var stripAnsi = (s) => s.replace(ANSI_RE, "").replace(/\r/g, "").trimEnd();
18731
- var MAX_SUBSTEPS = 20;
18732
- function parseUpgradeProgress(content) {
18733
- const rawLines = content.split("\n");
18734
- let step = 0;
18735
- let total = 0;
18736
- let label = "";
18737
- let markerIdx = -1;
18738
- for (let i = rawLines.length - 1; i >= 0; i--) {
18739
- const match2 = rawLines[i].match(STEP_RE);
18740
- if (match2) {
18741
- step = parseInt(match2[1], 10);
18742
- total = parseInt(match2[2], 10);
18743
- label = match2[3].replace(/\.{3}$/, "").trim();
18744
- markerIdx = i;
18745
- break;
18746
- }
18747
- }
18748
- const subSteps = markerIdx >= 0 ? rawLines.slice(markerIdx + 1).map(stripAnsi).filter((l) => l.length > 0).slice(-MAX_SUBSTEPS) : [];
18749
- const tail = rawLines.slice(-20).join("\n");
18750
- const finished = tail.includes("Open in your browser:");
18751
- const failed = tail.includes("Setup failed:");
18752
- return { step, total, label, started: true, finished, failed, subSteps };
18753
- }
18754
- function readProgressLog(path2) {
18755
- if (!existsSync22(path2)) {
18756
- return { step: 0, total: 0, label: "", started: false, subSteps: [] };
18757
- }
18758
- let content;
18759
- try {
18760
- content = readFileSync22(path2, "utf-8");
18761
- } catch {
18762
- return { step: 0, total: 0, label: "", started: false, subSteps: [] };
18763
- }
18764
- return parseUpgradeProgress(content);
18765
- }
18766
-
18767
- // server/routes/admin/version.ts
18768
- var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
18893
+ import { resolve as resolve24, join as join11 } from "path";
18894
+ var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
18769
18895
  var brandHostname = "maxy";
18770
18896
  var brandNpmPackage = "@rubytech/create-maxy";
18771
18897
  var brandJsonPath = join11(PLATFORM_ROOT9, "config", "brand.json");
18772
- if (existsSync23(brandJsonPath)) {
18898
+ if (existsSync22(brandJsonPath)) {
18773
18899
  try {
18774
- const brand = JSON.parse(readFileSync23(brandJsonPath, "utf-8"));
18900
+ const brand = JSON.parse(readFileSync22(brandJsonPath, "utf-8"));
18775
18901
  if (brand.hostname) brandHostname = brand.hostname;
18776
18902
  if (brand.npm?.packageName) brandNpmPackage = brand.npm.packageName;
18777
18903
  } catch {
18778
18904
  }
18779
18905
  }
18780
- var VERSION_FILE = resolve23(PLATFORM_ROOT9, `config/.${brandHostname}-version`);
18906
+ var VERSION_FILE = resolve24(PLATFORM_ROOT9, `config/.${brandHostname}-version`);
18781
18907
  var NPM_PACKAGE = brandNpmPackage;
18782
18908
  var REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE}/latest`;
18783
18909
  var FETCH_TIMEOUT_MS = 5e3;
18784
- var LOCK_FILE = `/tmp/${brandHostname}-upgrade.lock`;
18785
- var LOG_FILE = `/tmp/${brandHostname}-upgrade.log`;
18786
- var LOCK_MAX_AGE_MS = 20 * 60 * 1e3;
18787
18910
  function readInstalled() {
18788
- if (!existsSync23(VERSION_FILE)) return "unknown";
18789
- const content = readFileSync23(VERSION_FILE, "utf-8").trim();
18911
+ if (!existsSync22(VERSION_FILE)) return "unknown";
18912
+ const content = readFileSync22(VERSION_FILE, "utf-8").trim();
18790
18913
  return content || "unknown";
18791
18914
  }
18792
18915
  async function fetchLatest() {
@@ -18824,23 +18947,6 @@ function isNewer(latest, installed) {
18824
18947
  }
18825
18948
  return false;
18826
18949
  }
18827
- function isLockFresh() {
18828
- if (!existsSync23(LOCK_FILE)) return false;
18829
- try {
18830
- const st = statSync10(LOCK_FILE);
18831
- if (Date.now() - st.mtimeMs >= LOCK_MAX_AGE_MS) return false;
18832
- if (existsSync23(LOG_FILE)) {
18833
- const content = readFileSync23(LOG_FILE, "utf-8");
18834
- const tail = content.slice(-4e3);
18835
- if (tail.includes("Setup failed:") || tail.includes("Open in your browser:")) {
18836
- return false;
18837
- }
18838
- }
18839
- return true;
18840
- } catch {
18841
- return false;
18842
- }
18843
- }
18844
18950
  var app18 = new Hono2();
18845
18951
  app18.get("/", async (c) => {
18846
18952
  const installed = readInstalled();
@@ -18853,56 +18959,6 @@ app18.get("/", async (c) => {
18853
18959
  );
18854
18960
  return c.json({ installed, latest, updateAvailable, clientErrors24h });
18855
18961
  });
18856
- app18.post("/upgrade", requireAdminSession, (c) => {
18857
- if (isLockFresh()) {
18858
- return c.json({ ok: false, error: "upgrade already in progress" }, 409);
18859
- }
18860
- const installerScope = `upgrade-${brandHostname}`;
18861
- try {
18862
- writeFileSync14(LOCK_FILE, String(Date.now()));
18863
- } catch (err) {
18864
- console.error("[admin/version/upgrade] failed to write lock file:", err);
18865
- }
18866
- try {
18867
- writeFileSync14(LOG_FILE, "");
18868
- } catch (err) {
18869
- console.error("[admin/version/upgrade] failed to truncate upgrade log:", err);
18870
- return c.json(
18871
- { ok: false, error: err instanceof Error ? err.message : "failed to prepare upgrade log" },
18872
- 500
18873
- );
18874
- }
18875
- try {
18876
- const logFd = openSync5(LOG_FILE, "a");
18877
- const child = spawn4("systemd-run", [
18878
- "--user",
18879
- "--scope",
18880
- `--unit=${installerScope}`,
18881
- "--",
18882
- "npx",
18883
- "-y",
18884
- `${NPM_PACKAGE}@latest`
18885
- ], {
18886
- detached: true,
18887
- stdio: ["ignore", logFd, logFd],
18888
- env: { ...process.env, npm_config_yes: "true" },
18889
- cwd: resolve23(process.cwd(), "..")
18890
- });
18891
- child.unref();
18892
- closeSync5(logFd);
18893
- console.log(`[admin/version/upgrade] spawned upgrade process (pid ${child.pid} scope ${installerScope})`);
18894
- return c.json({ ok: true, started: true });
18895
- } catch (err) {
18896
- console.error("[admin/version/upgrade] failed to spawn upgrade process:", err);
18897
- return c.json(
18898
- { ok: false, error: err instanceof Error ? err.message : "failed to start upgrade" },
18899
- 500
18900
- );
18901
- }
18902
- });
18903
- app18.get("/upgrade/progress", (c) => {
18904
- return c.json(readProgressLog(LOG_FILE));
18905
- });
18906
18962
  app18.post("/alert-surfaced", async (c) => {
18907
18963
  let installed = "unknown";
18908
18964
  let latest = null;
@@ -19286,10 +19342,9 @@ app22.post("/", async (c) => {
19286
19342
  var events_default = app22;
19287
19343
 
19288
19344
  // server/routes/admin/cloudflare.ts
19289
- import * as childProcess from "child_process";
19290
19345
  import { homedir as homedir4 } from "os";
19291
- import { resolve as resolve25 } from "path";
19292
- import { readFileSync as readFileSync25 } from "fs";
19346
+ import { resolve as resolve26 } from "path";
19347
+ import { readFileSync as readFileSync24 } from "fs";
19293
19348
 
19294
19349
  // app/lib/dns-label.ts
19295
19350
  var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
@@ -19305,14 +19360,14 @@ function isValidDomain(value) {
19305
19360
  }
19306
19361
 
19307
19362
  // app/lib/alias-domains.ts
19308
- import { existsSync as existsSync24, mkdirSync as mkdirSync11, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
19309
- import { dirname as dirname7 } from "path";
19310
- import { resolve as resolve24 } from "path";
19311
- var ALIAS_DOMAINS_PATH = resolve24(MAXY_DIR, "alias-domains.json");
19363
+ import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync23, writeFileSync as writeFileSync14 } from "fs";
19364
+ import { dirname as dirname8 } from "path";
19365
+ import { resolve as resolve25 } from "path";
19366
+ var ALIAS_DOMAINS_PATH = resolve25(MAXY_DIR, "alias-domains.json");
19312
19367
  function readExisting() {
19313
- if (!existsSync24(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
19368
+ if (!existsSync23(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
19314
19369
  try {
19315
- const parsed = JSON.parse(readFileSync24(ALIAS_DOMAINS_PATH, "utf-8"));
19370
+ const parsed = JSON.parse(readFileSync23(ALIAS_DOMAINS_PATH, "utf-8"));
19316
19371
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
19317
19372
  return new Set(parsed.filter((h) => typeof h === "string"));
19318
19373
  } catch {
@@ -19323,17 +19378,18 @@ function addAliasDomain(hostname2) {
19323
19378
  const existing = readExisting();
19324
19379
  if (existing.has(hostname2)) return;
19325
19380
  existing.add(hostname2);
19326
- mkdirSync11(dirname7(ALIAS_DOMAINS_PATH), { recursive: true });
19327
- writeFileSync15(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
19381
+ mkdirSync13(dirname8(ALIAS_DOMAINS_PATH), { recursive: true });
19382
+ writeFileSync14(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
19328
19383
  }
19329
19384
 
19330
19385
  // server/routes/admin/cloudflare.ts
19331
- var SCRIPT_TIMEOUT_MS = 10 * 60 * 1e3;
19386
+ var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
19387
+ var DOMAINS_TIMEOUT_MS = 40 * 1e3;
19332
19388
  function loadBrandInfo() {
19333
- const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
19334
- const brandPath = resolve25(platformRoot3, "config", "brand.json");
19389
+ const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
19390
+ const brandPath = resolve26(platformRoot3, "config", "brand.json");
19335
19391
  try {
19336
- const parsed = JSON.parse(readFileSync25(brandPath, "utf-8"));
19392
+ const parsed = JSON.parse(readFileSync24(brandPath, "utf-8"));
19337
19393
  const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
19338
19394
  const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
19339
19395
  return { hostname: hostname2, configDir: configDir2 };
@@ -19376,42 +19432,116 @@ function validateBody(body) {
19376
19432
  }
19377
19433
  return null;
19378
19434
  }
19379
- function runScript(scriptPath, args, streamLogPath, log) {
19380
- return new Promise((resolveP) => {
19381
- const child = childProcess.spawn(scriptPath, args, {
19382
- env: { ...process.env, STREAM_LOG_PATH: streamLogPath },
19383
- stdio: ["ignore", "pipe", "pipe"]
19384
- });
19385
- log(`phase=script-spawn pid=${child.pid ?? "unknown"} args="${args.join(" ")}"`);
19386
- let stdout = "";
19387
- let stderr = "";
19388
- let timedOut = false;
19389
- const killer = setTimeout(() => {
19390
- timedOut = true;
19391
- try {
19392
- child.kill("SIGTERM");
19393
- } catch {
19394
- }
19395
- }, SCRIPT_TIMEOUT_MS);
19396
- child.stdout?.on("data", (chunk) => {
19397
- stdout += chunk.toString("utf-8");
19398
- });
19399
- child.stderr?.on("data", (chunk) => {
19400
- stderr += chunk.toString("utf-8");
19401
- });
19402
- child.on("error", (e) => {
19403
- clearTimeout(killer);
19404
- resolveP({ code: null, signal: null, stdout, stderr: `${stderr}
19405
- ${e.message}`, timedOut: false });
19406
- });
19407
- child.on("exit", (code, signal) => {
19408
- clearTimeout(killer);
19409
- log(`phase=script-exit code=${code ?? "null"} signal=${signal ?? "null"} timedOut=${timedOut}`);
19410
- resolveP({ code, signal, stdout, stderr, timedOut });
19411
- });
19412
- });
19413
- }
19414
19435
  var app23 = new Hono2();
19436
+ function fieldFromReason(reason) {
19437
+ switch (reason) {
19438
+ case "not-signed-in":
19439
+ return "dashboard";
19440
+ case "cdp-unreachable":
19441
+ case "target-create-failed":
19442
+ case "ws-connect-failed":
19443
+ case "navigate-failed":
19444
+ case "runtime-error":
19445
+ case "table-wait-timeout":
19446
+ case "entry-missing":
19447
+ case "wrapper-timeout":
19448
+ default:
19449
+ return "script";
19450
+ }
19451
+ }
19452
+ app23.get("/domains", requireAdminSession, async (c) => {
19453
+ const started = Date.now();
19454
+ const sessionKey = c.var.sessionKey;
19455
+ let correlationId;
19456
+ let sessionKeyTail;
19457
+ let streamLogPath;
19458
+ function tag() {
19459
+ if (!correlationId) return "";
19460
+ return ` conversationId=${correlationId} session_key=${sessionKeyTail ?? "unknown"}`;
19461
+ }
19462
+ function log(line) {
19463
+ console.log(`[cloudflare-domains] ${line}${tag()}`);
19464
+ }
19465
+ function logErr(line) {
19466
+ console.error(`[cloudflare-domains] ${line}${tag()}`);
19467
+ }
19468
+ function err(field, message, output) {
19469
+ logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
19470
+ if (streamLogPath) {
19471
+ writeRouteMilestone(
19472
+ streamLogPath,
19473
+ "cloudflare-domains",
19474
+ `phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`
19475
+ );
19476
+ }
19477
+ const body = {
19478
+ ok: false,
19479
+ field,
19480
+ message,
19481
+ output,
19482
+ correlationId,
19483
+ streamLogPath
19484
+ };
19485
+ return c.json(body, 200);
19486
+ }
19487
+ const accountId = getAccountIdForSession(sessionKey);
19488
+ correlationId = getConversationIdForSession(sessionKey);
19489
+ sessionKeyTail = sessionKey.slice(-8);
19490
+ if (!accountId) return err("session", "No account bound to session \u2014 refresh chat.");
19491
+ if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
19492
+ streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
19493
+ log(`phase=stream-log-resolved path=${streamLogPath}`);
19494
+ const brand = loadBrandInfo();
19495
+ const scriptPath = resolve26(homedir4(), "list-cf-domains.sh");
19496
+ const result = await runFormSpawn({
19497
+ scriptPath,
19498
+ args: [brand.hostname],
19499
+ streamLogPath,
19500
+ correlationId,
19501
+ timeoutMs: DOMAINS_TIMEOUT_MS,
19502
+ log,
19503
+ logErr,
19504
+ broadcast: broadcastToConversation
19505
+ });
19506
+ const combined = `${result.stdout}${result.stderr ? `
19507
+ ---
19508
+ ${result.stderr}` : ""}`;
19509
+ if (result.code !== 0) {
19510
+ const reasonMatch = result.stderr.match(/reason=([a-z0-9-]+)/);
19511
+ const reason = reasonMatch ? reasonMatch[1] : void 0;
19512
+ const field = fieldFromReason(reason);
19513
+ const message = reason ? `Domain discovery failed: ${reason}` : result.timedOut ? `Domain discovery timed out after ${DOMAINS_TIMEOUT_MS / 1e3}s` : `Domain discovery exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
19514
+ return err(field, message, combined);
19515
+ }
19516
+ let domains;
19517
+ try {
19518
+ const parsed = JSON.parse(result.stdout.trim());
19519
+ if (!Array.isArray(parsed) || !parsed.every((d) => typeof d === "string")) {
19520
+ throw new Error("response is not string[]");
19521
+ }
19522
+ domains = parsed;
19523
+ } catch (e) {
19524
+ return err(
19525
+ "script",
19526
+ `Domain discovery returned malformed output: ${e instanceof Error ? e.message : String(e)}`,
19527
+ combined
19528
+ );
19529
+ }
19530
+ const success = {
19531
+ ok: true,
19532
+ domains,
19533
+ correlationId,
19534
+ streamLogPath
19535
+ };
19536
+ const total = Date.now() - started;
19537
+ log(`phase=response-sent total_ms=${total} count=${domains.length}`);
19538
+ writeRouteMilestone(
19539
+ streamLogPath,
19540
+ "cloudflare-domains",
19541
+ `phase=response-sent total_ms=${total} count=${domains.length}`
19542
+ );
19543
+ return c.json(success, 200);
19544
+ });
19415
19545
  app23.post("/setup", requireAdminSession, async (c) => {
19416
19546
  const started = Date.now();
19417
19547
  const sessionKey = c.var.sessionKey;
@@ -19430,6 +19560,13 @@ app23.post("/setup", requireAdminSession, async (c) => {
19430
19560
  }
19431
19561
  function err(field, message, output) {
19432
19562
  logErr(`phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`);
19563
+ if (streamLogPath) {
19564
+ writeRouteMilestone(
19565
+ streamLogPath,
19566
+ "cloudflare-setup",
19567
+ `phase=error field=${field} reason="${message.slice(0, 160).replace(/"/g, "'")}"`
19568
+ );
19569
+ }
19433
19570
  const body2 = {
19434
19571
  ok: false,
19435
19572
  field,
@@ -19480,16 +19617,25 @@ app23.post("/setup", requireAdminSession, async (c) => {
19480
19617
  }
19481
19618
  streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
19482
19619
  log(`phase=stream-log-resolved path=${streamLogPath}`);
19483
- const scriptPath = resolve25(homedir4(), "setup-tunnel.sh");
19620
+ const scriptPath = resolve26(homedir4(), "setup-tunnel.sh");
19484
19621
  const args = [brand.hostname, String(port2), adminFqdn];
19485
19622
  if (publicFqdn) args.push(publicFqdn);
19486
19623
  if (apex) args.push(apex);
19487
- const result = await runScript(scriptPath, args, streamLogPath, log);
19624
+ const result = await runFormSpawn({
19625
+ scriptPath,
19626
+ args,
19627
+ streamLogPath,
19628
+ correlationId,
19629
+ timeoutMs: SETUP_TIMEOUT_MS,
19630
+ log,
19631
+ logErr,
19632
+ broadcast: broadcastToConversation
19633
+ });
19488
19634
  const combined = `${result.stdout}${result.stderr ? `
19489
19635
  ---
19490
19636
  ${result.stderr}` : ""}`;
19491
19637
  if (result.code !== 0) {
19492
- const reason = result.timedOut ? `Timed out after ${SCRIPT_TIMEOUT_MS / 1e3}s` : `Exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
19638
+ const reason = result.timedOut ? `Timed out after ${SETUP_TIMEOUT_MS / 1e3}s` : `Exited with code ${result.code ?? "null"}${result.signal ? ` (signal ${result.signal})` : ""}`;
19493
19639
  return err("script", reason, combined);
19494
19640
  }
19495
19641
  const candidates = [publicFqdn, apex].filter((h) => typeof h === "string" && h.length > 0);
@@ -19517,6 +19663,11 @@ ${result.stderr}` : ""}`;
19517
19663
  }
19518
19664
  const total = Date.now() - started;
19519
19665
  log(`phase=done total_ms=${total} aliases=${aliasesWritten.length}`);
19666
+ writeRouteMilestone(
19667
+ streamLogPath,
19668
+ "cloudflare-setup",
19669
+ `phase=done total_ms=${total} aliases=${aliasesWritten.length}`
19670
+ );
19520
19671
  const success = {
19521
19672
  ok: true,
19522
19673
  output: combined,
@@ -19535,17 +19686,17 @@ var cloudflare_default = app23;
19535
19686
  import { createReadStream as createReadStream3 } from "fs";
19536
19687
  import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
19537
19688
  import { realpathSync as realpathSync4 } from "fs";
19538
- import { basename as basename6, join as join12, resolve as resolve27, sep as sep2 } from "path";
19689
+ import { basename as basename6, join as join12, resolve as resolve28, sep as sep2 } from "path";
19539
19690
  import { Readable as Readable3 } from "stream";
19540
19691
 
19541
19692
  // app/lib/data-path.ts
19542
19693
  import { realpathSync as realpathSync3 } from "fs";
19543
- import { resolve as resolve26, normalize, sep, relative } from "path";
19544
- var PLATFORM_ROOT10 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "../platform");
19545
- var DATA_ROOT = resolve26(PLATFORM_ROOT10, "..", "data");
19694
+ import { resolve as resolve27, normalize, sep, relative } from "path";
19695
+ var PLATFORM_ROOT10 = process.env.MAXY_PLATFORM_ROOT ?? resolve27(process.cwd(), "../platform");
19696
+ var DATA_ROOT = resolve27(PLATFORM_ROOT10, "..", "data");
19546
19697
  function resolveDataPath(raw2) {
19547
19698
  const cleaned = normalize("/" + (raw2 ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
19548
- const absolute = resolve26(DATA_ROOT, cleaned);
19699
+ const absolute = resolve27(DATA_ROOT, cleaned);
19549
19700
  let dataRootReal;
19550
19701
  try {
19551
19702
  dataRootReal = realpathSync3(DATA_ROOT);
@@ -19754,8 +19905,8 @@ app24.post("/upload", requireAdminSession, async (c) => {
19754
19905
  }
19755
19906
  const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
19756
19907
  const finalName = `${Date.now()}-${safeName}`;
19757
- const destDir = resolve27(DATA_ROOT, "uploads", accountId);
19758
- const destPath = resolve27(destDir, finalName);
19908
+ const destDir = resolve28(DATA_ROOT, "uploads", accountId);
19909
+ const destPath = resolve28(destDir, finalName);
19759
19910
  try {
19760
19911
  await mkdir3(destDir, { recursive: true });
19761
19912
  const dataRootReal = realpathSync4(DATA_ROOT);
@@ -19813,9 +19964,152 @@ app25.get("/", requireAdminSession, async (c) => {
19813
19964
  });
19814
19965
  var graph_search_default = app25;
19815
19966
 
19816
- // server/routes/admin/file-attach.ts
19967
+ // app/lib/graph-labels.ts
19968
+ var GRAPH_LABEL_COLOURS = {
19969
+ // Business identity
19970
+ LocalBusiness: "#2E5090",
19971
+ Service: "#3A6BB0",
19972
+ PriceSpecification: "#5B8DD0",
19973
+ OpeningHoursSpecification: "#7AAFE8",
19974
+ // People
19975
+ Person: "#C2410C",
19976
+ UserProfile: "#EA580C",
19977
+ Preference: "#F97316",
19978
+ AdminUser: "#9A3412",
19979
+ AccessGrant: "#7C2D12",
19980
+ // Knowledge
19981
+ KnowledgeDocument: "#16A34A",
19982
+ Section: "#22C55E",
19983
+ Chunk: "#4ADE80",
19984
+ DigitalDocument: "#15803D",
19985
+ CreativeWork: "#86EFAC",
19986
+ Question: "#A7F3D0",
19987
+ FAQPage: "#34D399",
19988
+ DefinedTerm: "#10B981",
19989
+ Review: "#059669",
19990
+ ImageObject: "#6EE7B7",
19991
+ // Conversational
19992
+ Conversation: "#7C3AED",
19993
+ Message: "#A78BFA",
19994
+ ToolCall: "#C4B5FD",
19995
+ // Tasks / projects / events
19996
+ Task: "#DB2777",
19997
+ Project: "#BE185D",
19998
+ Event: "#EC4899",
19999
+ // Workflows
20000
+ Workflow: "#0891B2",
20001
+ WorkflowStep: "#06B6D4",
20002
+ WorkflowRun: "#22D3EE",
20003
+ StepResult: "#67E8F9",
20004
+ // Onboarding
20005
+ OnboardingState: "#8B5CF6",
20006
+ // Email
20007
+ Email: "#65A30D",
20008
+ EmailAccount: "#84CC16"
20009
+ };
20010
+ var ALL_GRAPH_LABELS = Object.freeze(
20011
+ Object.keys(GRAPH_LABEL_COLOURS)
20012
+ );
20013
+ function isKnownLabel(label) {
20014
+ return Object.prototype.hasOwnProperty.call(GRAPH_LABEL_COLOURS, label);
20015
+ }
20016
+
20017
+ // server/routes/admin/graph-subgraph.ts
20018
+ var DEFAULT_LIMIT2 = 200;
20019
+ var MAX_LIMIT2 = 500;
20020
+ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
20021
+ "embedding",
20022
+ "passwordHash",
20023
+ "magicToken",
20024
+ "otpCode",
20025
+ "sessionKey"
20026
+ ]);
19817
20027
  var app26 = new Hono2();
19818
- app26.post("/", async (c) => {
20028
+ app26.get("/", requireAdminSession, async (c) => {
20029
+ const sessionKey = c.var.sessionKey;
20030
+ const accountId = getAccountIdForSession(sessionKey);
20031
+ if (!accountId) {
20032
+ console.error('[graph-page] auth-rejected reason="no account for session"');
20033
+ return c.json({ error: "Account not found for session" }, 401);
20034
+ }
20035
+ const rawLimit = c.req.query("limit");
20036
+ const parsedLimit = rawLimit ? parseInt(rawLimit, 10) : DEFAULT_LIMIT2;
20037
+ const limit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, MAX_LIMIT2) : DEFAULT_LIMIT2;
20038
+ const rawLabels = c.req.query("labels");
20039
+ const labels = rawLabels ? rawLabels.split(",").map((s) => s.trim()).filter(Boolean) : [];
20040
+ for (const label of labels) {
20041
+ if (!isKnownLabel(label)) {
20042
+ return c.json(
20043
+ { error: `unknown label "${label}" \u2014 not registered in graph-labels.ts` },
20044
+ 400
20045
+ );
20046
+ }
20047
+ }
20048
+ const started = Date.now();
20049
+ const session = getSession();
20050
+ try {
20051
+ const cypher = labels.length > 0 ? buildCypher(true) : buildCypher(false);
20052
+ const params = { accountId, limit };
20053
+ if (labels.length > 0) params.labels = labels;
20054
+ const result = await session.run(cypher, params);
20055
+ const record = result.records[0];
20056
+ const rawNodes = record?.get("nodes") ?? [];
20057
+ const rawEdges = record?.get("edges") ?? [];
20058
+ const nodes = rawNodes.map(pruneNode);
20059
+ const edges = rawEdges.filter((e) => e && e.id != null);
20060
+ const elapsed = Date.now() - started;
20061
+ console.error(
20062
+ `[graph-page] load account=${accountId} nodes=${nodes.length} edges=${edges.length} ms=${elapsed}`
20063
+ );
20064
+ return c.json({ nodes, edges });
20065
+ } catch (err) {
20066
+ const elapsed = Date.now() - started;
20067
+ const message = err instanceof Error ? err.message : String(err);
20068
+ console.error(`[graph-page] error stage=fetch reason="${message}" ms=${elapsed}`);
20069
+ return c.json({ error: `Graph data unavailable: ${message}` }, 503);
20070
+ } finally {
20071
+ try {
20072
+ await session.close();
20073
+ } catch {
20074
+ }
20075
+ }
20076
+ });
20077
+ function buildCypher(filtered) {
20078
+ const labelGuard = filtered ? "AND any(lbl IN labels(n) WHERE lbl IN $labels)" : "";
20079
+ return `
20080
+ MATCH (n)
20081
+ WHERE n.accountId = $accountId ${labelGuard}
20082
+ WITH n ORDER BY coalesce(n.updatedAt, n.createdAt, '') DESC
20083
+ LIMIT toInteger($limit)
20084
+ WITH collect(n) AS nodes, collect(elementId(n)) AS nodeIds
20085
+ UNWIND nodes AS n
20086
+ OPTIONAL MATCH (n)-[r]-(m)
20087
+ WHERE elementId(m) IN nodeIds
20088
+ WITH nodes,
20089
+ collect(DISTINCT CASE WHEN r IS NULL THEN null ELSE {
20090
+ id: elementId(r),
20091
+ from: elementId(startNode(r)),
20092
+ to: elementId(endNode(r)),
20093
+ type: type(r)
20094
+ } END) AS rawEdges
20095
+ RETURN
20096
+ [x IN nodes | {id: elementId(x), labels: labels(x), properties: properties(x)}] AS nodes,
20097
+ [e IN rawEdges WHERE e IS NOT NULL] AS edges
20098
+ `;
20099
+ }
20100
+ function pruneNode(node) {
20101
+ const properties = {};
20102
+ for (const [key, value] of Object.entries(node.properties ?? {})) {
20103
+ if (STRIPPED_PROPERTIES.has(key)) continue;
20104
+ properties[key] = value;
20105
+ }
20106
+ return { id: node.id, labels: node.labels, properties };
20107
+ }
20108
+ var graph_subgraph_default = app26;
20109
+
20110
+ // server/routes/admin/file-attach.ts
20111
+ var app27 = new Hono2();
20112
+ app27.post("/", async (c) => {
19819
20113
  try {
19820
20114
  const body = await c.req.json();
19821
20115
  const { filePath, accountId } = body;
@@ -19838,39 +20132,40 @@ app26.post("/", async (c) => {
19838
20132
  return c.json({ error: message }, 500);
19839
20133
  }
19840
20134
  });
19841
- var file_attach_default = app26;
20135
+ var file_attach_default = app27;
19842
20136
 
19843
20137
  // server/routes/admin/index.ts
19844
- var app27 = new Hono2();
19845
- app27.route("/session", session_default2);
19846
- app27.route("/chat", chat_default2);
19847
- app27.route("/compact", compact_default);
19848
- app27.route("/logs", logs_default);
19849
- app27.route("/claude-info", claude_info_default);
19850
- app27.route("/attachment", attachment_default);
19851
- app27.route("/account", account_default);
19852
- app27.route("/agents", agents_default);
19853
- app27.route("/version", version_default);
19854
- app27.route("/sessions", sessions_default);
19855
- app27.route("/browser", browser_default);
19856
- app27.route("/device-browser", device_browser_default);
19857
- app27.route("/events", events_default);
19858
- app27.route("/cloudflare", cloudflare_default);
19859
- app27.route("/files", files_default);
19860
- app27.route("/graph-search", graph_search_default);
19861
- app27.route("/file-attach", file_attach_default);
19862
- var admin_default = app27;
20138
+ var app28 = new Hono2();
20139
+ app28.route("/session", session_default2);
20140
+ app28.route("/chat", chat_default2);
20141
+ app28.route("/compact", compact_default);
20142
+ app28.route("/logs", logs_default);
20143
+ app28.route("/claude-info", claude_info_default);
20144
+ app28.route("/attachment", attachment_default);
20145
+ app28.route("/account", account_default);
20146
+ app28.route("/agents", agents_default);
20147
+ app28.route("/version", version_default);
20148
+ app28.route("/sessions", sessions_default);
20149
+ app28.route("/browser", browser_default);
20150
+ app28.route("/device-browser", device_browser_default);
20151
+ app28.route("/events", events_default);
20152
+ app28.route("/cloudflare", cloudflare_default);
20153
+ app28.route("/files", files_default);
20154
+ app28.route("/graph-search", graph_search_default);
20155
+ app28.route("/graph-subgraph", graph_subgraph_default);
20156
+ app28.route("/file-attach", file_attach_default);
20157
+ var admin_default = app28;
19863
20158
 
19864
20159
  // server/index.ts
19865
20160
  var PLATFORM_ROOT11 = process.env.MAXY_PLATFORM_ROOT || "";
19866
20161
  var BRAND_JSON_PATH = PLATFORM_ROOT11 ? join13(PLATFORM_ROOT11, "config", "brand.json") : "";
19867
20162
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
19868
- if (BRAND_JSON_PATH && !existsSync25(BRAND_JSON_PATH)) {
20163
+ if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
19869
20164
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
19870
20165
  }
19871
- if (BRAND_JSON_PATH && existsSync25(BRAND_JSON_PATH)) {
20166
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
19872
20167
  try {
19873
- const parsed = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
20168
+ const parsed = JSON.parse(readFileSync25(BRAND_JSON_PATH, "utf-8"));
19874
20169
  BRAND = { ...BRAND, ...parsed };
19875
20170
  } catch (err) {
19876
20171
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -19892,8 +20187,8 @@ var brandLoginOpts = {
19892
20187
  var ALIAS_DOMAINS_PATH2 = join13(homedir5(), BRAND.configDir, "alias-domains.json");
19893
20188
  function loadAliasDomains() {
19894
20189
  try {
19895
- if (!existsSync25(ALIAS_DOMAINS_PATH2)) return null;
19896
- const parsed = JSON.parse(readFileSync26(ALIAS_DOMAINS_PATH2, "utf-8"));
20190
+ if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
20191
+ const parsed = JSON.parse(readFileSync25(ALIAS_DOMAINS_PATH2, "utf-8"));
19897
20192
  if (!Array.isArray(parsed)) {
19898
20193
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
19899
20194
  return null;
@@ -19917,9 +20212,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
19917
20212
  function isPublicHost(host) {
19918
20213
  return host.startsWith("public.") || aliasDomains.has(host);
19919
20214
  }
19920
- var app28 = new Hono2();
19921
- app28.use("*", clientIpMiddleware);
19922
- app28.use("*", async (c, next) => {
20215
+ var app29 = new Hono2();
20216
+ app29.use("*", clientIpMiddleware);
20217
+ app29.use("*", async (c, next) => {
19923
20218
  await next();
19924
20219
  c.header("X-Content-Type-Options", "nosniff");
19925
20220
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -19942,7 +20237,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
19942
20237
  "/g/"
19943
20238
  ];
19944
20239
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
19945
- app28.use("*", async (c, next) => {
20240
+ app29.use("*", async (c, next) => {
19946
20241
  const host = (c.req.header("host") ?? "").split(":")[0];
19947
20242
  if (!isPublicHost(host)) {
19948
20243
  await next();
@@ -19982,7 +20277,7 @@ function resolveRemoteAuthOpts() {
19982
20277
  return brandLoginOpts;
19983
20278
  }
19984
20279
  var MAX_LOGIN_BODY = 8 * 1024;
19985
- app28.post("/__remote-auth/login", async (c) => {
20280
+ app29.post("/__remote-auth/login", async (c) => {
19986
20281
  const clientIp = c.var.clientIp || "unknown";
19987
20282
  const rateLimited = checkRateLimit(clientIp);
19988
20283
  if (rateLimited) {
@@ -20018,7 +20313,7 @@ app28.post("/__remote-auth/login", async (c) => {
20018
20313
  }
20019
20314
  });
20020
20315
  });
20021
- app28.get("/__remote-auth/logout", (c) => {
20316
+ app29.get("/__remote-auth/logout", (c) => {
20022
20317
  const cookieHeader = c.req.header("cookie");
20023
20318
  const token = parseCookie(cookieHeader, "__remote_session");
20024
20319
  if (token) invalidateRemoteSession(token);
@@ -20031,7 +20326,7 @@ app28.get("/__remote-auth/logout", (c) => {
20031
20326
  }
20032
20327
  });
20033
20328
  });
20034
- app28.post("/__remote-auth/change-password", async (c) => {
20329
+ app29.post("/__remote-auth/change-password", async (c) => {
20035
20330
  const clientIp = c.var.clientIp || "unknown";
20036
20331
  const rateLimited = checkRateLimit(clientIp);
20037
20332
  if (rateLimited) {
@@ -20080,13 +20375,13 @@ app28.post("/__remote-auth/change-password", async (c) => {
20080
20375
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
20081
20376
  }
20082
20377
  });
20083
- app28.get("/__remote-auth/setup", (c) => {
20378
+ app29.get("/__remote-auth/setup", (c) => {
20084
20379
  if (isRemoteAuthConfigured()) {
20085
20380
  return c.redirect("/");
20086
20381
  }
20087
20382
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
20088
20383
  });
20089
- app28.post("/__remote-auth/set-initial-password", async (c) => {
20384
+ app29.post("/__remote-auth/set-initial-password", async (c) => {
20090
20385
  if (isRemoteAuthConfigured()) {
20091
20386
  return c.redirect("/");
20092
20387
  }
@@ -20122,10 +20417,10 @@ app28.post("/__remote-auth/set-initial-password", async (c) => {
20122
20417
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
20123
20418
  }
20124
20419
  });
20125
- app28.get("/api/remote-auth/status", (c) => {
20420
+ app29.get("/api/remote-auth/status", (c) => {
20126
20421
  return c.json({ configured: isRemoteAuthConfigured() });
20127
20422
  });
20128
- app28.post("/api/remote-auth/set-password", async (c) => {
20423
+ app29.post("/api/remote-auth/set-password", async (c) => {
20129
20424
  let body;
20130
20425
  try {
20131
20426
  body = await c.req.json();
@@ -20155,9 +20450,9 @@ app28.post("/api/remote-auth/set-password", async (c) => {
20155
20450
  return c.json({ error: "Failed to save password" }, 500);
20156
20451
  }
20157
20452
  });
20158
- app28.route("/api/_client-error", client_error_default);
20453
+ app29.route("/api/_client-error", client_error_default);
20159
20454
  console.log("[client-error-route] mounted");
20160
- app28.use("*", async (c, next) => {
20455
+ app29.use("*", async (c, next) => {
20161
20456
  const host = (c.req.header("host") ?? "").split(":")[0];
20162
20457
  const path2 = c.req.path;
20163
20458
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -20197,15 +20492,15 @@ function parseCookie(cookieHeader, name) {
20197
20492
  return null;
20198
20493
  }
20199
20494
  }
20200
- app28.route("/api/health", health_default);
20201
- app28.route("/api/session", session_default);
20202
- app28.route("/api/chat", chat_default);
20203
- app28.route("/api/group", group_default);
20204
- app28.route("/api/access", access_default);
20205
- app28.route("/api/telegram", telegram_default);
20206
- app28.route("/api/whatsapp", whatsapp_default);
20207
- app28.route("/api/onboarding", onboarding_default);
20208
- app28.route("/api/admin", admin_default);
20495
+ app29.route("/api/health", health_default);
20496
+ app29.route("/api/session", session_default);
20497
+ app29.route("/api/chat", chat_default);
20498
+ app29.route("/api/group", group_default);
20499
+ app29.route("/api/access", access_default);
20500
+ app29.route("/api/telegram", telegram_default);
20501
+ app29.route("/api/whatsapp", whatsapp_default);
20502
+ app29.route("/api/onboarding", onboarding_default);
20503
+ app29.route("/api/admin", admin_default);
20209
20504
  var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
20210
20505
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
20211
20506
  var IMAGE_MIME = {
@@ -20217,7 +20512,7 @@ var IMAGE_MIME = {
20217
20512
  ".svg": "image/svg+xml",
20218
20513
  ".ico": "image/x-icon"
20219
20514
  };
20220
- app28.get("/agent-assets/:slug/:filename", (c) => {
20515
+ app29.get("/agent-assets/:slug/:filename", (c) => {
20221
20516
  const slug = c.req.param("slug");
20222
20517
  const filename = c.req.param("filename");
20223
20518
  if (!SAFE_SLUG_RE.test(slug)) {
@@ -20233,26 +20528,26 @@ app28.get("/agent-assets/:slug/:filename", (c) => {
20233
20528
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
20234
20529
  return c.text("Not found", 404);
20235
20530
  }
20236
- const filePath = resolve28(account.accountDir, "agents", slug, "assets", filename);
20237
- const expectedDir = resolve28(account.accountDir, "agents", slug, "assets");
20531
+ const filePath = resolve29(account.accountDir, "agents", slug, "assets", filename);
20532
+ const expectedDir = resolve29(account.accountDir, "agents", slug, "assets");
20238
20533
  if (!filePath.startsWith(expectedDir + "/")) {
20239
20534
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
20240
20535
  return c.text("Forbidden", 403);
20241
20536
  }
20242
- if (!existsSync25(filePath)) {
20537
+ if (!existsSync24(filePath)) {
20243
20538
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
20244
20539
  return c.text("Not found", 404);
20245
20540
  }
20246
20541
  const ext = "." + filename.split(".").pop()?.toLowerCase();
20247
20542
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
20248
20543
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
20249
- const body = readFileSync26(filePath);
20544
+ const body = readFileSync25(filePath);
20250
20545
  return c.body(body, 200, {
20251
20546
  "Content-Type": contentType,
20252
20547
  "Cache-Control": "public, max-age=3600"
20253
20548
  });
20254
20549
  });
20255
- app28.get("/generated/:filename", (c) => {
20550
+ app29.get("/generated/:filename", (c) => {
20256
20551
  const filename = c.req.param("filename");
20257
20552
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
20258
20553
  console.error(`[generated] serve file=${filename} status=403`);
@@ -20263,20 +20558,20 @@ app28.get("/generated/:filename", (c) => {
20263
20558
  console.error(`[generated] serve file=${filename} status=404`);
20264
20559
  return c.text("Not found", 404);
20265
20560
  }
20266
- const filePath = resolve28(account.accountDir, "generated", filename);
20267
- const expectedDir = resolve28(account.accountDir, "generated");
20561
+ const filePath = resolve29(account.accountDir, "generated", filename);
20562
+ const expectedDir = resolve29(account.accountDir, "generated");
20268
20563
  if (!filePath.startsWith(expectedDir + "/")) {
20269
20564
  console.error(`[generated] serve file=${filename} status=403`);
20270
20565
  return c.text("Forbidden", 403);
20271
20566
  }
20272
- if (!existsSync25(filePath)) {
20567
+ if (!existsSync24(filePath)) {
20273
20568
  console.error(`[generated] serve file=${filename} status=404`);
20274
20569
  return c.text("Not found", 404);
20275
20570
  }
20276
20571
  const ext = "." + filename.split(".").pop()?.toLowerCase();
20277
20572
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
20278
20573
  console.log(`[generated] serve file=${filename} status=200`);
20279
- const body = readFileSync26(filePath);
20574
+ const body = readFileSync25(filePath);
20280
20575
  return c.body(body, 200, {
20281
20576
  "Content-Type": contentType,
20282
20577
  "Cache-Control": "public, max-age=86400"
@@ -20285,9 +20580,9 @@ app28.get("/generated/:filename", (c) => {
20285
20580
  var htmlCache = /* @__PURE__ */ new Map();
20286
20581
  var brandLogoPath = "/brand/maxy-monochrome.png";
20287
20582
  var brandIconPath = "/brand/maxy-monochrome.png";
20288
- if (BRAND_JSON_PATH && existsSync25(BRAND_JSON_PATH)) {
20583
+ if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
20289
20584
  try {
20290
- const fullBrand = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
20585
+ const fullBrand = JSON.parse(readFileSync25(BRAND_JSON_PATH, "utf-8"));
20291
20586
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
20292
20587
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
20293
20588
  } catch {
@@ -20305,8 +20600,8 @@ function readInstalledVersion() {
20305
20600
  try {
20306
20601
  if (!PLATFORM_ROOT11) return "unknown";
20307
20602
  const versionFile = join13(PLATFORM_ROOT11, "config", `.${BRAND.hostname}-version`);
20308
- if (!existsSync25(versionFile)) return "unknown";
20309
- const content = readFileSync26(versionFile, "utf-8").trim();
20603
+ if (!existsSync24(versionFile)) return "unknown";
20604
+ const content = readFileSync25(versionFile, "utf-8").trim();
20310
20605
  return content || "unknown";
20311
20606
  } catch {
20312
20607
  return "unknown";
@@ -20347,7 +20642,7 @@ var clientErrorReporterScript = `<script>
20347
20642
  function cachedHtml(file) {
20348
20643
  let html = htmlCache.get(file);
20349
20644
  if (!html) {
20350
- html = readFileSync26(resolve28(process.cwd(), "public", file), "utf-8");
20645
+ html = readFileSync25(resolve29(process.cwd(), "public", file), "utf-8");
20351
20646
  html = html.replace("<title>Maxy</title>", `<title>${escapeHtml2(BRAND.productName)}</title>`);
20352
20647
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml2(brandFaviconPath)}"`);
20353
20648
  const headInjection = file === "index.html" ? `${brandScript}
@@ -20365,13 +20660,13 @@ function loadBrandingCache(agentSlug) {
20365
20660
  const configDir2 = join13(homedir5(), BRAND.configDir);
20366
20661
  try {
20367
20662
  const accountJsonPath = join13(configDir2, "account.json");
20368
- if (!existsSync25(accountJsonPath)) return null;
20369
- const account = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
20663
+ if (!existsSync24(accountJsonPath)) return null;
20664
+ const account = JSON.parse(readFileSync25(accountJsonPath, "utf-8"));
20370
20665
  const accountId = account.accountId;
20371
20666
  if (!accountId) return null;
20372
20667
  const cachePath = join13(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
20373
- if (!existsSync25(cachePath)) return null;
20374
- return JSON.parse(readFileSync26(cachePath, "utf-8"));
20668
+ if (!existsSync24(cachePath)) return null;
20669
+ return JSON.parse(readFileSync25(cachePath, "utf-8"));
20375
20670
  } catch {
20376
20671
  return null;
20377
20672
  }
@@ -20380,8 +20675,8 @@ function resolveDefaultSlug() {
20380
20675
  try {
20381
20676
  const configDir2 = join13(homedir5(), BRAND.configDir);
20382
20677
  const accountJsonPath = join13(configDir2, "account.json");
20383
- if (!existsSync25(accountJsonPath)) return null;
20384
- const account = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
20678
+ if (!existsSync24(accountJsonPath)) return null;
20679
+ const account = JSON.parse(readFileSync25(accountJsonPath, "utf-8"));
20385
20680
  return account.defaultAgent || null;
20386
20681
  } catch {
20387
20682
  return null;
@@ -20417,7 +20712,7 @@ function brandedPublicHtml(agentSlug) {
20417
20712
  function escapeHtml2(s) {
20418
20713
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
20419
20714
  }
20420
- app28.get("/", (c) => {
20715
+ app29.get("/", (c) => {
20421
20716
  const host = (c.req.header("host") ?? "").split(":")[0];
20422
20717
  if (isPublicHost(host)) {
20423
20718
  const defaultSlug = resolveDefaultSlug();
@@ -20425,12 +20720,12 @@ app28.get("/", (c) => {
20425
20720
  }
20426
20721
  return c.html(cachedHtml("index.html"));
20427
20722
  });
20428
- app28.get("/public", (c) => {
20723
+ app29.get("/public", (c) => {
20429
20724
  const host = (c.req.header("host") ?? "").split(":")[0];
20430
20725
  if (isPublicHost(host)) return c.text("Not found", 404);
20431
20726
  return c.html(cachedHtml("public.html"));
20432
20727
  });
20433
- app28.get("/chat", (c) => {
20728
+ app29.get("/chat", (c) => {
20434
20729
  const host = (c.req.header("host") ?? "").split(":")[0];
20435
20730
  if (isPublicHost(host)) return c.text("Not found", 404);
20436
20731
  return c.html(cachedHtml("public.html"));
@@ -20449,12 +20744,12 @@ async function logViewerFetch(c, next) {
20449
20744
  duration_ms: Date.now() - start
20450
20745
  });
20451
20746
  }
20452
- app28.use("/vnc-viewer.html", logViewerFetch);
20453
- app28.use("/vnc-popout.html", logViewerFetch);
20454
- app28.get("/vnc-popout.html", (c) => {
20747
+ app29.use("/vnc-viewer.html", logViewerFetch);
20748
+ app29.use("/vnc-popout.html", logViewerFetch);
20749
+ app29.get("/vnc-popout.html", (c) => {
20455
20750
  let html = htmlCache.get("vnc-popout.html");
20456
20751
  if (!html) {
20457
- html = readFileSync26(resolve28(process.cwd(), "public", "vnc-popout.html"), "utf-8");
20752
+ html = readFileSync25(resolve29(process.cwd(), "public", "vnc-popout.html"), "utf-8");
20458
20753
  const name = escapeHtml2(BRAND.productName);
20459
20754
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
20460
20755
  html = html.replace("</head>", ` ${brandScript}
@@ -20464,7 +20759,7 @@ app28.get("/vnc-popout.html", (c) => {
20464
20759
  }
20465
20760
  return c.html(html);
20466
20761
  });
20467
- app28.post("/api/vnc/client-event", async (c) => {
20762
+ app29.post("/api/vnc/client-event", async (c) => {
20468
20763
  let body;
20469
20764
  try {
20470
20765
  body = await c.req.json();
@@ -20485,18 +20780,20 @@ app28.post("/api/vnc/client-event", async (c) => {
20485
20780
  });
20486
20781
  return c.json({ ok: true });
20487
20782
  });
20488
- app28.get("/g/:slug", (c) => {
20783
+ app29.get("/g/:slug", (c) => {
20489
20784
  return c.html(brandedPublicHtml());
20490
20785
  });
20491
- app28.use("/graph/*", graphAuthMiddleware({ isPublicHost, canAccessAdmin }));
20492
- app28.use("/graph", graphAuthMiddleware({ isPublicHost, canAccessAdmin }));
20493
- attachGraphHttpRoutes(app28);
20494
- app28.get("/data", (c) => {
20786
+ app29.get("/graph", (c) => {
20787
+ const host = (c.req.header("host") ?? "").split(":")[0];
20788
+ if (isPublicHost(host)) return c.text("Not found", 404);
20789
+ return c.html(cachedHtml("graph.html"));
20790
+ });
20791
+ app29.get("/data", (c) => {
20495
20792
  const host = (c.req.header("host") ?? "").split(":")[0];
20496
20793
  if (isPublicHost(host)) return c.text("Not found", 404);
20497
20794
  return c.html(cachedHtml("data.html"));
20498
20795
  });
20499
- app28.get("/:slug", async (c, next) => {
20796
+ app29.get("/:slug", async (c, next) => {
20500
20797
  const slug = c.req.param("slug");
20501
20798
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
20502
20799
  const branding = loadBrandingCache(slug);
@@ -20505,16 +20802,20 @@ app28.get("/:slug", async (c, next) => {
20505
20802
  }
20506
20803
  await next();
20507
20804
  });
20508
- app28.use("/*", serveStatic({ root: "./public" }));
20805
+ app29.use("/*", serveStatic({ root: "./public" }));
20509
20806
  var port = parseInt(process.env.PORT ?? "19200", 10);
20510
20807
  var hostname = process.env.HOSTNAME ?? "0.0.0.0";
20511
- var httpServer = serve({ fetch: app28.fetch, port, hostname });
20808
+ var httpServer = serve({ fetch: app29.fetch, port, hostname });
20512
20809
  attachVncWsProxy(httpServer, {
20513
20810
  isPublicHost,
20514
20811
  upstreamHost: "127.0.0.1",
20515
20812
  upstreamPort: 6080
20516
20813
  });
20517
- attachGraphWsProxy(httpServer, { isPublicHost, canAccessAdmin });
20814
+ attachTerminalWsProxy(httpServer, {
20815
+ isPublicHost,
20816
+ upstreamHost: "127.0.0.1",
20817
+ upstreamPort: 7681
20818
+ });
20518
20819
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
20519
20820
  var SUBAPP_MANIFEST = [
20520
20821
  { prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
@@ -20534,7 +20835,7 @@ for (const m of SUBAPP_MANIFEST) {
20534
20835
  }
20535
20836
  try {
20536
20837
  const registered = [];
20537
- for (const r of app28.routes ?? []) {
20838
+ for (const r of app29.routes ?? []) {
20538
20839
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
20539
20840
  if (AGENT_SLUG_PATTERN.test(r.path)) {
20540
20841
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
@@ -20548,8 +20849,8 @@ try {
20548
20849
  (async () => {
20549
20850
  try {
20550
20851
  let userId = "";
20551
- if (existsSync25(USERS_FILE)) {
20552
- const users = JSON.parse(readFileSync26(USERS_FILE, "utf-8").trim() || "[]");
20852
+ if (existsSync24(USERS_FILE)) {
20853
+ const users = JSON.parse(readFileSync25(USERS_FILE, "utf-8").trim() || "[]");
20553
20854
  userId = users[0]?.userId ?? "";
20554
20855
  }
20555
20856
  await backfillNullUserIdConversations(userId);
@@ -20575,7 +20876,7 @@ if (bootAccountConfig?.whatsapp) {
20575
20876
  }
20576
20877
  init({
20577
20878
  configDir: configDirForWhatsApp,
20578
- platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
20879
+ platformRoot: resolve29(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
20579
20880
  accountConfig: bootAccountConfig,
20580
20881
  onMessage: async (msg) => {
20581
20882
  try {