@rubytech/create-maxy-code 0.1.309 → 0.1.311

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 (187) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
  3. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
  4. package/payload/platform/plugins/admin/skills/specialist-management/SKILL.md +1 -1
  5. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +1 -1
  6. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  7. package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
  8. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -0
  9. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  10. package/payload/platform/services/claude-session-manager/dist/http-server.js +69 -1
  11. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  12. package/payload/platform/services/claude-session-manager/dist/index.js +16 -2
  13. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  14. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +10 -0
  15. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  16. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +22 -2
  17. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  18. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +39 -0
  19. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -0
  20. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +139 -0
  21. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -0
  22. package/payload/platform/services/webchat-channel/dist/instructions.d.ts +1 -0
  23. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
  24. package/payload/platform/services/webchat-channel/dist/instructions.js +31 -0
  25. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  26. package/payload/platform/services/webchat-channel/dist/notification.d.ts +8 -3
  27. package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
  28. package/payload/platform/services/webchat-channel/dist/notification.js +25 -9
  29. package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
  30. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  31. package/payload/platform/services/webchat-channel/dist/server.js +5 -3
  32. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  33. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +8 -0
  34. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  35. package/payload/platform/services/whatsapp-channel/dist/notification.js +10 -0
  36. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  37. package/payload/server/public/assets/AccessGate-ChFLk-rp.js +1 -0
  38. package/payload/server/public/assets/AdminLoginScreens-DU6zgbk5.js +1 -0
  39. package/payload/server/public/assets/AdminShell-BJCYb1v5.js +1 -0
  40. package/payload/server/public/assets/{Checkbox-DMA1hVhn.js → Checkbox-CQGLKMXu.js} +1 -1
  41. package/payload/server/public/assets/OperatorConversations-CHEQTz20.js +1 -0
  42. package/payload/server/public/assets/admin-COHPIWdb.js +1 -0
  43. package/payload/server/public/assets/admin-types-D2qTXuCg.js +1 -0
  44. package/payload/server/public/assets/{arc-Dl9QFDgW.js → arc-J2g2u5Xv.js} +1 -1
  45. package/payload/server/public/assets/architecture-YZFGNWBL-C6nkAxzW.js +1 -0
  46. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CNLQUVi9.js → architectureDiagram-Q4EWVU46-CN0BXxpE.js} +1 -1
  47. package/payload/server/public/assets/audio-attachment-mime-DL06xo72.js +30 -0
  48. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-B-QxfVjk.js → blockDiagram-DXYQGD6D-HX-8wF2p.js} +1 -1
  49. package/payload/server/public/assets/brand-CN7uSSKl.css +1 -0
  50. package/payload/server/public/assets/{browser-eLSiC7_b.js → browser-L7N4tAOl.js} +1 -1
  51. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-NuYFvPDU.js → c4Diagram-AHTNJAMY-wIuarKF5.js} +1 -1
  52. package/payload/server/public/assets/channel-Q39xIXyT.js +1 -0
  53. package/payload/server/public/assets/chat-B_jYIH9a.js +1 -0
  54. package/payload/server/public/assets/{chunk-2KRD3SAO-l5VL1KQm.js → chunk-2KRD3SAO-Buz7egJZ.js} +1 -1
  55. package/payload/server/public/assets/{chunk-336JU56O-C5gVznC2.js → chunk-336JU56O-_JcFXJqc.js} +2 -2
  56. package/payload/server/public/assets/chunk-426QAEUC-CCYjp9C2.js +1 -0
  57. package/payload/server/public/assets/{chunk-4BX2VUAB-BtMVz_Sq.js → chunk-4BX2VUAB-DUR5Dg3M.js} +1 -1
  58. package/payload/server/public/assets/{chunk-4TB4RGXK-C8-dmCuT.js → chunk-4TB4RGXK-BRIqQ9st.js} +1 -1
  59. package/payload/server/public/assets/{chunk-55IACEB6-C5gWvEJW.js → chunk-55IACEB6-CezTHWXL.js} +1 -1
  60. package/payload/server/public/assets/{chunk-5FUZZQ4R-BZ7VZoAC.js → chunk-5FUZZQ4R-DHYUPzF1.js} +1 -1
  61. package/payload/server/public/assets/{chunk-5PVQY5BW-C_ajQOGC.js → chunk-5PVQY5BW-BVn4_fI5.js} +1 -1
  62. package/payload/server/public/assets/{chunk-67CJDMHE-BJOR2dwK.js → chunk-67CJDMHE-BBLA8Mbi.js} +1 -1
  63. package/payload/server/public/assets/{chunk-7N4EOEYR-DvZLpquX.js → chunk-7N4EOEYR-CdWfEI5c.js} +1 -1
  64. package/payload/server/public/assets/{chunk-AA7GKIK3-h5tVsPlW.js → chunk-AA7GKIK3-tS11knCR.js} +1 -1
  65. package/payload/server/public/assets/{chunk-BSJP7CBP-DLOF2-m3.js → chunk-BSJP7CBP-GEu1OOZ6.js} +1 -1
  66. package/payload/server/public/assets/{chunk-CIAEETIT-CQRQMPCf.js → chunk-CIAEETIT-DKrNbbp_.js} +1 -1
  67. package/payload/server/public/assets/{chunk-EDXVE4YY-K9-EfuM2.js → chunk-EDXVE4YY-B0InXNyr.js} +1 -1
  68. package/payload/server/public/assets/{chunk-ENJZ2VHE-DVoy6NvU.js → chunk-ENJZ2VHE-CO7lkHdm.js} +1 -1
  69. package/payload/server/public/assets/{chunk-FMBD7UC4-CQn_2o2b.js → chunk-FMBD7UC4-CMj74lWo.js} +1 -1
  70. package/payload/server/public/assets/{chunk-FOC6F5B3-CuN73goS.js → chunk-FOC6F5B3-CLnKQoXw.js} +1 -1
  71. package/payload/server/public/assets/{chunk-ICPOFSXX-CKhl9J-H.js → chunk-ICPOFSXX-CdiEKIaz.js} +2 -2
  72. package/payload/server/public/assets/{chunk-K5T4RW27-CBskuQmq.js → chunk-K5T4RW27-B6LA3fiv.js} +1 -1
  73. package/payload/server/public/assets/{chunk-KGLVRYIC-Chtjt8xK.js → chunk-KGLVRYIC-DrhRrb8Q.js} +1 -1
  74. package/payload/server/public/assets/{chunk-LIHQZDEY-EOBiBNSH.js → chunk-LIHQZDEY-DVQukevB.js} +1 -1
  75. package/payload/server/public/assets/{chunk-ORNJ4GCN-uPPq-5MN.js → chunk-ORNJ4GCN-ZMLkoDhP.js} +1 -1
  76. package/payload/server/public/assets/{chunk-OYMX7WX6-BRzbxJOT.js → chunk-OYMX7WX6-C0dJkynG.js} +1 -1
  77. package/payload/server/public/assets/chunk-QZHKN3VN-BNBxnHZh.js +1 -0
  78. package/payload/server/public/assets/{chunk-U2HBQHQK-Bndyn5nF.js → chunk-U2HBQHQK-BQ9BPIFZ.js} +1 -1
  79. package/payload/server/public/assets/{chunk-X2U36JSP-BspGBHXW.js → chunk-X2U36JSP-CAonGMOd.js} +1 -1
  80. package/payload/server/public/assets/{chunk-XPW4576I-HgXQ2k9h.js → chunk-XPW4576I-D5C_WNlk.js} +1 -1
  81. package/payload/server/public/assets/{chunk-YZCP3GAM-C7oTyCnw.js → chunk-YZCP3GAM-Ecdvzekb.js} +1 -1
  82. package/payload/server/public/assets/{chunk-ZZ45TVLE-CufWa7QL.js → chunk-ZZ45TVLE-BsFZd1cN.js} +1 -1
  83. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BShusfby.js +1 -0
  84. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D4ivPLFF.js +1 -0
  85. package/payload/server/public/assets/clone-CjEM8LwB.js +1 -0
  86. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BM3yEbF-.js → cose-bilkent-S5V4N54A-DBWHaIwm.js} +1 -1
  87. package/payload/server/public/assets/{dagre-C7WHNZO8.js → dagre-Dr7ZJYeS.js} +1 -1
  88. package/payload/server/public/assets/{dagre-KV5264BT-bcZx3l06.js → dagre-KV5264BT-oIJddk7m.js} +1 -1
  89. package/payload/server/public/assets/data-BmSTKHR1.js +1 -0
  90. package/payload/server/public/assets/{diagram-5BDNPKRD-B7VotaMF.js → diagram-5BDNPKRD-CEVxqOZ4.js} +1 -1
  91. package/payload/server/public/assets/{diagram-G4DWMVQ6-CWWvEsFx.js → diagram-G4DWMVQ6-BovF7Rjx.js} +1 -1
  92. package/payload/server/public/assets/{diagram-MMDJMWI5-DYHVkTYJ.js → diagram-MMDJMWI5-BhrF8zoF.js} +1 -1
  93. package/payload/server/public/assets/{diagram-TYMM5635-CHeB6Ama.js → diagram-TYMM5635-DCUYwxtR.js} +1 -1
  94. package/payload/server/public/assets/{erDiagram-SMLLAGMA-C9gog8QP.js → erDiagram-SMLLAGMA-BS2-HdCg.js} +1 -1
  95. package/payload/server/public/assets/{flatten-QcJDm7yK.js → flatten-BZMXCpLh.js} +1 -1
  96. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B2O9lKTh.js → flowDiagram-DWJPFMVM-BzSFLoea.js} +1 -1
  97. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DEa4AwbR.js → ganttDiagram-T4ZO3ILL-1-3QU7mT.js} +1 -1
  98. package/payload/server/public/assets/gitGraph-7Q5UKJZL-Btp3PwZh.js +1 -0
  99. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BjXPQpBL.js → gitGraphDiagram-UUTBAWPF-fTrJ35Wk.js} +1 -1
  100. package/payload/server/public/assets/{graph-C7Hye_vp.js → graph-Cro3-mgY.js} +2 -2
  101. package/payload/server/public/assets/{graph-labels-YYgGsEVd.js → graph-labels-WQQn6JIJ.js} +1 -1
  102. package/payload/server/public/assets/{graphlib-CBevn2DP.js → graphlib-rlEzI2qD.js} +1 -1
  103. package/payload/server/public/assets/info-OMHHGYJF-CPt2y6_L.js +1 -0
  104. package/payload/server/public/assets/infoDiagram-42DDH7IO-CpXNTMgd.js +2 -0
  105. package/payload/server/public/assets/{isEmpty-BO6BAEn7.js → isEmpty-DaYIrHay.js} +1 -1
  106. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CPLfpvqv.js → ishikawaDiagram-UXIWVN3A-0eU_UtlT.js} +1 -1
  107. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CTHe8MiD.js → journeyDiagram-VCZTEJTY-BKLeZohp.js} +1 -1
  108. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Bm9h1O3Y.js → kanban-definition-6JOO6SKY-Dq72xyaN.js} +1 -1
  109. package/payload/server/public/assets/{line-C31b0rtY.js → line-LQhmDT8k.js} +1 -1
  110. package/payload/server/public/assets/{linear-Cfm_8_pU.js → linear-BGotDbGs.js} +1 -1
  111. package/payload/server/public/assets/{mermaid-parser.core-B3tGwOcE.js → mermaid-parser.core-DoLdho1V.js} +2 -2
  112. package/payload/server/public/assets/{mermaid.core-BM3s85ZW.js → mermaid.core-C1RRyHGm.js} +3 -3
  113. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CaGv_mIB.js → mindmap-definition-QFDTVHPH-vUVVVyV1.js} +1 -1
  114. package/payload/server/public/assets/operator-B4I25isQ.js +1 -0
  115. package/payload/server/public/assets/{ordinal-jLCwuvYg.js → ordinal-BqEhkPyh.js} +1 -1
  116. package/payload/server/public/assets/packet-4T2RLAQJ-Cwc-j_AI.js +1 -0
  117. package/payload/server/public/assets/page-B-6ZQ4JG.js +1 -0
  118. package/payload/server/public/assets/pie-ZZUOXDRM-BZ9fjD1_.js +1 -0
  119. package/payload/server/public/assets/{pieDiagram-DEJITSTG-BhAXps4u.js → pieDiagram-DEJITSTG-B9Pl6Qhc.js} +1 -1
  120. package/payload/server/public/assets/{public-ViXjC_dA.js → public-CX148JKi.js} +3 -3
  121. package/payload/server/public/assets/public-next-BCItsUbZ.js +1 -0
  122. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BWtTdNs8.js → quadrantDiagram-34T5L4WZ-Drn9T81A.js} +1 -1
  123. package/payload/server/public/assets/radar-PYXPWWZC-BNz5Rt9V.js +1 -0
  124. package/payload/server/public/assets/{reduce-Dmi_NdVH.js → reduce-T2IuntYP.js} +1 -1
  125. package/payload/server/public/assets/{requirementDiagram-MS252O5E-CWU0qCcP.js → requirementDiagram-MS252O5E-C0PAItJm.js} +1 -1
  126. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DYvutQld.js → sankeyDiagram-XADWPNL6-BR42Mtwd.js} +1 -1
  127. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-Cir0hBWS.js → sequenceDiagram-FGHM5R23-c2lR9UOS.js} +1 -1
  128. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Be-h8YSS.js → stateDiagram-FHFEXIEX-BcHhtqsZ.js} +1 -1
  129. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BUQ_F4eP.js +1 -0
  130. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-C3C4Wuyk.js → timeline-definition-GMOUNBTQ-Ax32c10H.js} +1 -1
  131. package/payload/server/public/assets/treeView-SZITEDCU-DcVCQgp1.js +1 -0
  132. package/payload/server/public/assets/treemap-W4RFUUIX-Bm12mwGd.js +1 -0
  133. package/payload/server/public/assets/{useSelectionMode-CG_Iel5F.js → useSelectionMode-BHAAhkDg.js} +1 -1
  134. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-mDclw0Sa.js → vennDiagram-DHZGUBPP-BxePewPq.js} +1 -1
  135. package/payload/server/public/assets/wardley-RL74JXVD-47Z3ymtK.js +1 -0
  136. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-mvk-YA9g.js → wardleyDiagram-NUSXRM2D-DmJwZ2f5.js} +1 -1
  137. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-9M7k1hmD.js → xychartDiagram-5P7HB3ND-YjHomudv.js} +1 -1
  138. package/payload/server/public/browser.html +6 -6
  139. package/payload/server/public/chat.html +10 -9
  140. package/payload/server/public/data.html +5 -5
  141. package/payload/server/public/graph.html +8 -8
  142. package/payload/server/public/index.html +10 -9
  143. package/payload/server/public/operator.html +12 -11
  144. package/payload/server/public/public-next.html +11 -10
  145. package/payload/server/public/public.html +8 -8
  146. package/payload/server/server.js +269 -64
  147. package/payload/server/public/assets/AccessGate-CU4Qw6M6.js +0 -1
  148. package/payload/server/public/assets/AdminLoginScreens-DUpRIM1h.js +0 -1
  149. package/payload/server/public/assets/AdminShell-DkoQSsqo.js +0 -1
  150. package/payload/server/public/assets/OperatorConversations-BIHiyyxU.js +0 -1
  151. package/payload/server/public/assets/admin-BHvOMcCh.js +0 -1
  152. package/payload/server/public/assets/architecture-YZFGNWBL-Crq5RSDG.js +0 -1
  153. package/payload/server/public/assets/audio-attachment-mime-DOBET-W1.js +0 -30
  154. package/payload/server/public/assets/brand-4F9ZXBF8.css +0 -1
  155. package/payload/server/public/assets/channel-KT66MFN2.js +0 -1
  156. package/payload/server/public/assets/chat-DedpVKUl.js +0 -1
  157. package/payload/server/public/assets/chunk-426QAEUC-CWMiOm8Y.js +0 -1
  158. package/payload/server/public/assets/chunk-QZHKN3VN-DCzpF46A.js +0 -1
  159. package/payload/server/public/assets/classDiagram-6PBFFD2Q-QOU4HzJJ.js +0 -1
  160. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DcOUai3Z.js +0 -1
  161. package/payload/server/public/assets/clone-CHh05KN-.js +0 -1
  162. package/payload/server/public/assets/data-BcoBY39U.js +0 -1
  163. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BC-u4jgy.js +0 -1
  164. package/payload/server/public/assets/info-OMHHGYJF-DPUetTz-.js +0 -1
  165. package/payload/server/public/assets/infoDiagram-42DDH7IO-q2dl09-M.js +0 -2
  166. package/payload/server/public/assets/operator-WsXhcbBF.js +0 -1
  167. package/payload/server/public/assets/packet-4T2RLAQJ-BcfR-ZwA.js +0 -1
  168. package/payload/server/public/assets/page-BhHTnqv4.js +0 -1
  169. package/payload/server/public/assets/pie-ZZUOXDRM-BiKgZdNB.js +0 -1
  170. package/payload/server/public/assets/public-next-BKECyMz2.js +0 -1
  171. package/payload/server/public/assets/radar-PYXPWWZC-nvCjiW_J.js +0 -1
  172. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CAnmjSj7.js +0 -1
  173. package/payload/server/public/assets/treeView-SZITEDCU-BinXCVyM.js +0 -1
  174. package/payload/server/public/assets/treemap-W4RFUUIX-CSmh20Ze.js +0 -1
  175. package/payload/server/public/assets/wardley-RL74JXVD-BiCmRKWx.js +0 -1
  176. /package/payload/server/public/assets/{_baseFor-D8P3gUw3.js → _baseFor-Y5mTRiRv.js} +0 -0
  177. /package/payload/server/public/assets/{array-CLwNaqU1.js → array-BwJyW1Dp.js} +0 -0
  178. /package/payload/server/public/assets/{brand-C7kj0USi.js → brand-MKGM8WZp.js} +0 -0
  179. /package/payload/server/public/assets/{cytoscape.esm-mZ4wTuB7.js → cytoscape.esm-D95TtHqz.js} +0 -0
  180. /package/payload/server/public/assets/{defaultLocale-D_VMtRaY.js → defaultLocale-kiwRz9Au.js} +0 -0
  181. /package/payload/server/public/assets/{dist-CjjtmoWL.js → dist-DSsFp0Qd.js} +0 -0
  182. /package/payload/server/public/assets/{init-vVpfz1D6.js → init-CKZirZ49.js} +0 -0
  183. /package/payload/server/public/assets/{katex-DaHGEgm7.js → katex-8mXVa4k3.js} +0 -0
  184. /package/payload/server/public/assets/{path-CuyvWNAH.js → path-B0d9ncVi.js} +0 -0
  185. /package/payload/server/public/assets/{preload-helper-TKOBYGYD.js → preload-helper-C5gCWwwF.js} +0 -0
  186. /package/payload/server/public/assets/{rough.esm-JX0wREDd.js → rough.esm-BWqoIFNR.js} +0 -0
  187. /package/payload/server/public/assets/{src-CwB968DO.js → src-DXUM2BJo.js} +0 -0
@@ -4871,6 +4871,10 @@ function crossesForeignAccountPartition(relPath, accountId) {
4871
4871
  if (!ACCOUNT_UUID_RE.test(owner)) return false;
4872
4872
  return owner !== accountId;
4873
4873
  }
4874
+ function isWithinOwnAccountPartition(relPath, accountId) {
4875
+ const segs = relPath.split("/").filter(Boolean);
4876
+ return segs.length >= 2 && segs[0] === "accounts" && segs[1] === accountId;
4877
+ }
4874
4878
  function resolveUnderRoot(raw, rootAbs, rootLabel) {
4875
4879
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
4876
4880
  const absolute = resolve5(rootAbs, cleaned);
@@ -6591,12 +6595,32 @@ import { basename as basename2, dirname, join as join10, resolve as resolve11, s
6591
6595
  // server/routes/admin/sidebar-sessions.ts
6592
6596
  import { readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
6593
6597
  import { join as join8, resolve as resolve10 } from "path";
6598
+
6599
+ // app/lib/whatsapp-reader/select-sessions.ts
6600
+ function isReaderChannelSession(role, channel) {
6601
+ return role === "admin" && (channel === "whatsapp" || channel === "telegram") || role === "public" && (channel === "whatsapp" || channel === "webchat");
6602
+ }
6603
+ function selectReaderChannelSessions(rows) {
6604
+ return rows.filter((r) => isReaderChannelSession(r.role, r.channel)).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
6605
+ sessionId: r.sessionId,
6606
+ projectDir: r.projectDir,
6607
+ title: r.title,
6608
+ senderId: r.senderId,
6609
+ startedAt: r.startedAt,
6610
+ channel: r.channel,
6611
+ role: r.role,
6612
+ operatorName: null,
6613
+ whatsappName: null,
6614
+ lastMessageAt: r.lastMessageAt,
6615
+ modelGated: r.modelGated
6616
+ }));
6617
+ }
6618
+
6619
+ // server/routes/admin/sidebar-sessions.ts
6594
6620
  var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
6595
6621
  var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
6596
- var PUBLIC_ROLE = "public";
6597
6622
  var ADMIN_ROLE = "admin";
6598
6623
  var WEBCHAT_CHANNEL = "webchat";
6599
- var WHATSAPP_CHANNEL = "whatsapp";
6600
6624
  var app3 = new Hono();
6601
6625
  function claudeConfigDir() {
6602
6626
  return process.env.CLAUDE_CONFIG_DIR ?? null;
@@ -6814,8 +6838,8 @@ app3.get("/", requireAdminSession, async (c) => {
6814
6838
  const seenIds = /* @__PURE__ */ new Set();
6815
6839
  let liveCount = 0;
6816
6840
  let subagentCount = 0;
6817
- let nonResumableCount = 0;
6818
6841
  let archivedCount = 0;
6842
+ let excludedChannelCount = 0;
6819
6843
  const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
6820
6844
  const personIdBySession = /* @__PURE__ */ new Map();
6821
6845
  const adminUserIdBySession = /* @__PURE__ */ new Map();
@@ -6843,7 +6867,10 @@ app3.get("/", requireAdminSession, async (c) => {
6843
6867
  titleSourceCounts[resolved.source] += 1;
6844
6868
  const metaPath = join8(projectDir, `${sessionId}.meta.json`);
6845
6869
  const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId } = readSidecarMeta(metaPath);
6846
- const resumable = !(role === PUBLIC_ROLE && (sidecarChannel === WEBCHAT_CHANNEL || sidecarChannel === WHATSAPP_CHANNEL));
6870
+ if (isReaderChannelSession(role, sidecarChannel)) {
6871
+ excludedChannelCount += 1;
6872
+ continue;
6873
+ }
6847
6874
  if (personId) personIdBySession.set(sessionId, personId);
6848
6875
  if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
6849
6876
  adminUserIdBySession.set(sessionId, adminUserId);
@@ -6858,14 +6885,12 @@ app3.get("/", requireAdminSession, async (c) => {
6858
6885
  pid,
6859
6886
  projectDir,
6860
6887
  bridgeIds,
6861
- resumable,
6862
6888
  archived,
6863
6889
  channel: resolved.channel,
6864
6890
  personName: null
6865
6891
  });
6866
6892
  if (live) liveCount += 1;
6867
6893
  if (isSubagent) subagentCount += 1;
6868
- if (!resumable) nonResumableCount += 1;
6869
6894
  if (archived) archivedCount += 1;
6870
6895
  }
6871
6896
  let personNameCount = 0;
@@ -6896,29 +6921,12 @@ app3.get("/", requireAdminSession, async (c) => {
6896
6921
  }
6897
6922
  rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
6898
6923
  console.log(
6899
- `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} nonResumable=${nonResumableCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
6924
+ `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
6900
6925
  );
6901
6926
  return c.json({ sessions: rows, accountId });
6902
6927
  });
6903
6928
  var sidebar_sessions_default = app3;
6904
6929
 
6905
- // app/lib/whatsapp-reader/select-sessions.ts
6906
- function selectReaderChannelSessions(rows) {
6907
- return rows.filter((r) => r.role === "admin" && (r.channel === "whatsapp" || r.channel === "telegram") || r.role === "public" && (r.channel === "whatsapp" || r.channel === "webchat")).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
6908
- sessionId: r.sessionId,
6909
- projectDir: r.projectDir,
6910
- title: r.title,
6911
- senderId: r.senderId,
6912
- startedAt: r.startedAt,
6913
- channel: r.channel,
6914
- role: r.role,
6915
- operatorName: null,
6916
- whatsappName: null,
6917
- lastMessageAt: r.lastMessageAt,
6918
- modelGated: r.modelGated
6919
- }));
6920
- }
6921
-
6922
6930
  // app/lib/admin-identity/pin-validator.ts
6923
6931
  import { createHash } from "crypto";
6924
6932
  import { existsSync as existsSync6, readFileSync as readFileSync10, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
@@ -7121,6 +7129,7 @@ function isModelGated(turns) {
7121
7129
  }
7122
7130
  function parseTranscript(lines) {
7123
7131
  const out = [];
7132
+ const queuedPendingSuppress = /* @__PURE__ */ new Map();
7124
7133
  for (const line of lines) {
7125
7134
  if (!line || line[0] !== "{") continue;
7126
7135
  let row;
@@ -7145,12 +7154,26 @@ function parseTranscript(lines) {
7145
7154
  out.push(...assistantTurns(msg?.content, ts));
7146
7155
  continue;
7147
7156
  }
7157
+ if (row.type === "queue-operation" && row.operation === "enqueue") {
7158
+ const content = asString(row.content);
7159
+ if (content !== null && CHANNEL_WRAPPER2.test(content)) {
7160
+ const u = unwrapChannel(content);
7161
+ out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
7162
+ queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
7163
+ }
7164
+ continue;
7165
+ }
7148
7166
  if (row.type === "attachment") {
7149
7167
  const att = row.attachment;
7150
7168
  const isChannelQueued = att?.type === "queued_command" && att.isMeta === true && typeof att.origin === "object" && att.origin !== null && att.origin.kind === "channel" && typeof att.prompt === "string";
7151
7169
  if (isChannelQueued) {
7152
7170
  const u = unwrapChannel(att.prompt);
7153
- out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
7171
+ const armed = queuedPendingSuppress.get(u.text) ?? 0;
7172
+ if (armed > 0) {
7173
+ queuedPendingSuppress.set(u.text, armed - 1);
7174
+ } else {
7175
+ out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
7176
+ }
7154
7177
  }
7155
7178
  continue;
7156
7179
  }
@@ -7208,9 +7231,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7208
7231
  const sessionId = basename2(path2).replace(/\.jsonl$/, "");
7209
7232
  const projectDir = dirname(path2);
7210
7233
  const meta = readSidecarMeta(join10(projectDir, `${sessionId}.meta.json`));
7211
- const isAdminChannel = meta.role === "admin" && (meta.channel === "whatsapp" || meta.channel === "telegram");
7212
- const isPublicChannel = meta.role === "public" && (meta.channel === "whatsapp" || meta.channel === "webchat");
7213
- if (!isAdminChannel && !isPublicChannel) continue;
7234
+ if (!isReaderChannelSession(meta.role, meta.channel)) continue;
7214
7235
  let body = "";
7215
7236
  try {
7216
7237
  body = readFileSync11(path2, "utf8");
@@ -7463,8 +7484,11 @@ function filterDeliveredFrames(lines) {
7463
7484
  const turns = [];
7464
7485
  let dropped = 0;
7465
7486
  for (const turn of parseTranscript(lines)) {
7466
- if (isDeliveredKind(turn.kind, PUBLIC_DELIVERED_KINDS)) turns.push(turn);
7467
- else dropped++;
7487
+ if (!isDeliveredKind(turn.kind, PUBLIC_DELIVERED_KINDS)) {
7488
+ dropped++;
7489
+ continue;
7490
+ }
7491
+ turns.push(turn.kind === "agent-error" ? { ...turn, raw: "" } : turn);
7468
7492
  }
7469
7493
  return { turns, dropped };
7470
7494
  }
@@ -7627,7 +7651,7 @@ var public_reader_default = app5;
7627
7651
  // server/routes/webchat.ts
7628
7652
  import { basename as basename4, dirname as dirname3 } from "path";
7629
7653
  import { join as join13 } from "path";
7630
- import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, writeFileSync as writeFileSync6 } from "fs";
7654
+ import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
7631
7655
 
7632
7656
  // server/canonical-webchat-override.ts
7633
7657
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
@@ -7700,6 +7724,14 @@ function locateSidecar(sessionId) {
7700
7724
  function sessionSidecarExists(sessionId) {
7701
7725
  return locateSidecar(sessionId) !== null;
7702
7726
  }
7727
+ function jsonlSizeBytes(projectDir, sessionId) {
7728
+ if (projectDir === null) return null;
7729
+ try {
7730
+ return statSync6(join13(projectDir, `${sessionId}.jsonl`)).size;
7731
+ } catch {
7732
+ return null;
7733
+ }
7734
+ }
7703
7735
  function conflictingBinding(channel) {
7704
7736
  return channel !== null && channel !== "webchat" ? channel : null;
7705
7737
  }
@@ -7787,6 +7819,8 @@ async function reapplyLeversViaManager() {
7787
7819
  return false;
7788
7820
  }
7789
7821
  }
7822
+ var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
7823
+ var sendSeq = 0;
7790
7824
  function createWebchatRoutes(deps) {
7791
7825
  const app51 = new Hono();
7792
7826
  app51.post("/send", requireAdminSession, async (c) => {
@@ -7918,6 +7952,30 @@ ${note}` : note;
7918
7952
  } else {
7919
7953
  await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text });
7920
7954
  }
7955
+ const sendId = ++sendSeq;
7956
+ let turnSessionId = deliverySessionId;
7957
+ if (turnSessionId === void 0) {
7958
+ let canonAccount;
7959
+ try {
7960
+ canonAccount = resolveAccount();
7961
+ } catch {
7962
+ canonAccount = null;
7963
+ }
7964
+ turnSessionId = resolveCanonicalSessionId(accountId, canonAccount?.accountDir ?? null);
7965
+ }
7966
+ const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
7967
+ const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
7968
+ console.error(`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
7969
+ const turnTimer = setTimeout(() => {
7970
+ const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
7971
+ const grew = now !== null && (baseline === null || now > baseline);
7972
+ if (grew) {
7973
+ console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
7974
+ } else {
7975
+ console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
7976
+ }
7977
+ }, WEBCHAT_SEND_TURN_WINDOW_MS);
7978
+ if (turnTimer.unref) turnTimer.unref();
7921
7979
  return c.json({ ok: true });
7922
7980
  });
7923
7981
  app51.post("/settings", requireAdminSession, async (c) => {
@@ -7977,7 +8035,7 @@ ${note}` : note;
7977
8035
  const { projectDir: projectDir2, channel } = locateSession(target);
7978
8036
  const known = projectDir2 !== null || sessionSidecarExists(target);
7979
8037
  const indicators2 = await fetchComposerIndicators(target);
7980
- return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), known, ...indicators2, ...readLevers() });
8038
+ return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), ...indicators2, ...readLevers() });
7981
8039
  }
7982
8040
  let account;
7983
8041
  try {
@@ -7997,7 +8055,7 @@ ${note}` : note;
7997
8055
  }
7998
8056
  }
7999
8057
  const indicators = await fetchComposerIndicators(sessionId);
8000
- return c.json({ sessionId, projectDir, ...indicators, ...readLevers(account) });
8058
+ return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
8001
8059
  });
8002
8060
  return app51;
8003
8061
  }
@@ -9138,7 +9196,7 @@ import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeF
9138
9196
  import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
9139
9197
 
9140
9198
  // ../lib/admins-write/src/index.ts
9141
- import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
9199
+ import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync7 } from "fs";
9142
9200
  import { dirname as dirname4, join as join16 } from "path";
9143
9201
  function logLine(input, result) {
9144
9202
  const userIdShort = input.userId.slice(0, 8);
@@ -9238,7 +9296,7 @@ function checkAdminAuthInvariant(input) {
9238
9296
  if (entry.startsWith(".")) continue;
9239
9297
  const accountDir = join16(input.accountsDir, entry);
9240
9298
  try {
9241
- if (!statSync6(accountDir).isDirectory()) continue;
9299
+ if (!statSync7(accountDir).isDirectory()) continue;
9242
9300
  } catch {
9243
9301
  continue;
9244
9302
  }
@@ -9530,7 +9588,7 @@ app8.delete("/set-pin", async (c) => {
9530
9588
  var onboarding_default = app8;
9531
9589
 
9532
9590
  // server/routes/client-error.ts
9533
- import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync7 } from "fs";
9591
+ import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync8 } from "fs";
9534
9592
  import { join as join17 } from "path";
9535
9593
  var CLIENT_ERRORS_LOG = join17(LOG_DIR, "client-errors.log");
9536
9594
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
@@ -9576,7 +9634,7 @@ function stackHead(stack) {
9576
9634
  function rotateIfNeeded() {
9577
9635
  try {
9578
9636
  if (!existsSync13(CLIENT_ERRORS_LOG)) return;
9579
- const stats = statSync7(CLIENT_ERRORS_LOG);
9637
+ const stats = statSync8(CLIENT_ERRORS_LOG);
9580
9638
  if (stats.size < MAX_LOG_SIZE) return;
9581
9639
  renameSync4(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
9582
9640
  } catch (err) {
@@ -9857,7 +9915,7 @@ app10.post("/", async (c) => {
9857
9915
  var session_default = app10;
9858
9916
 
9859
9917
  // server/routes/admin/logs.ts
9860
- import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
9918
+ import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync9 } from "fs";
9861
9919
  import { resolve as resolve16, basename as basename5 } from "path";
9862
9920
 
9863
9921
  // app/lib/logs-read-resolve.ts
@@ -9897,7 +9955,7 @@ app11.get("/", async (c) => {
9897
9955
  searched.push(filePath);
9898
9956
  try {
9899
9957
  const buffer = readFileSync18(filePath);
9900
- const onDiskBytes = statSync8(filePath).size;
9958
+ const onDiskBytes = statSync9(filePath).size;
9901
9959
  const headers = {
9902
9960
  "Content-Type": "text/plain; charset=utf-8",
9903
9961
  "Content-Length": String(buffer.byteLength)
@@ -9962,7 +10020,7 @@ app11.get("/", async (c) => {
9962
10020
  try {
9963
10021
  const filename = basename5(hit.path);
9964
10022
  const buffer = readFileSync18(hit.path);
9965
- const onDiskBytes = statSync8(hit.path).size;
10023
+ const onDiskBytes = statSync9(hit.path).size;
9966
10024
  const headers = {
9967
10025
  "Content-Type": "text/plain; charset=utf-8",
9968
10026
  "Content-Length": String(buffer.byteLength)
@@ -10005,7 +10063,7 @@ app11.get("/", async (c) => {
10005
10063
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
10006
10064
  continue;
10007
10065
  }
10008
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync8(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
10066
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
10009
10067
  seen.add(name);
10010
10068
  try {
10011
10069
  const content = readFileSync18(resolve16(dir, name));
@@ -10868,7 +10926,7 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
10868
10926
  var sessions_default = app15;
10869
10927
 
10870
10928
  // app/lib/claude-agent/spawn-context.ts
10871
- import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync9 } from "fs";
10929
+ import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync10 } from "fs";
10872
10930
  import { dirname as dirname5, resolve as resolve19, join as join19 } from "path";
10873
10931
  async function resolveOwnerProfileBlock(accountId, userId) {
10874
10932
  if (!userId) return { ok: false, reason: "missing-user-id" };
@@ -10883,6 +10941,18 @@ async function resolveOwnerProfileBlock(accountId, userId) {
10883
10941
  return { ok: false, reason: "neo4j-unreachable" };
10884
10942
  }
10885
10943
  }
10944
+ async function resolveAuthenticatedName(accountId, userId) {
10945
+ if (!userId) return void 0;
10946
+ try {
10947
+ const res = await loadAdminUserName(accountId, userId);
10948
+ return res.source === "neo4j" ? res.joined : void 0;
10949
+ } catch (err) {
10950
+ console.error(
10951
+ `[spawn-context] resolveAuthenticatedName failed: ${err instanceof Error ? err.message : String(err)}`
10952
+ );
10953
+ return void 0;
10954
+ }
10955
+ }
10886
10956
  function frontmatterField(manifest, field2) {
10887
10957
  const fm = manifest.match(/^---\r?\n([\s\S]*?)\r?\n---/);
10888
10958
  if (!fm) return null;
@@ -10959,7 +11029,7 @@ function listPluginDirs() {
10959
11029
  for (const name of readdirSync12(platformPlugins)) {
10960
11030
  const dir = join19(platformPlugins, name);
10961
11031
  try {
10962
- if (statSync9(dir).isDirectory()) out.set(name, dir);
11032
+ if (statSync10(dir).isDirectory()) out.set(name, dir);
10963
11033
  } catch {
10964
11034
  }
10965
11035
  }
@@ -10973,7 +11043,7 @@ function listPluginDirs() {
10973
11043
  for (const name of readdirSync12(bundlePlugins)) {
10974
11044
  const dir = join19(bundlePlugins, name);
10975
11045
  try {
10976
- if (statSync9(dir).isDirectory()) out.set(name, dir);
11046
+ if (statSync10(dir).isDirectory()) out.set(name, dir);
10977
11047
  } catch {
10978
11048
  }
10979
11049
  }
@@ -11410,7 +11480,7 @@ var events_default = app18;
11410
11480
 
11411
11481
  // server/routes/admin/files.ts
11412
11482
  import { createReadStream as createReadStream2 } from "fs";
11413
- import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
11483
+ import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2, rename } from "fs/promises";
11414
11484
  import { realpathSync as realpathSync4 } from "fs";
11415
11485
  import { basename as basename7, dirname as dirname6, join as join21, resolve as resolve22, sep as sep6 } from "path";
11416
11486
  import { Readable as Readable2 } from "stream";
@@ -12273,6 +12343,44 @@ function isProtectedFromDeletion(relPath) {
12273
12343
  }
12274
12344
  return { protected: false };
12275
12345
  }
12346
+ function isProtectedFromRename(relPath) {
12347
+ if (isProtectedFromDeletion(relPath).protected) return true;
12348
+ const segments = relPath.split("/").filter(Boolean);
12349
+ const base = segments[segments.length - 1] ?? "";
12350
+ if (segments.length === 2 && segments[0] === "accounts") return true;
12351
+ if (segments.length === 3 && segments[0] === "accounts" && segments[2] === "uploads") {
12352
+ return true;
12353
+ }
12354
+ if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE3.test(segments[3])) {
12355
+ return true;
12356
+ }
12357
+ if (parseAttachmentPath(relPath) !== null) return true;
12358
+ if (UUID_RE3.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
12359
+ return true;
12360
+ }
12361
+ return false;
12362
+ }
12363
+ function isValidEntryName(name) {
12364
+ if (typeof name !== "string" || name.length === 0) return false;
12365
+ if (name === "." || name === "..") return false;
12366
+ return !/[\\/\0]/.test(name);
12367
+ }
12368
+ function resolveOwnAccountWrite(rawPath, accountId, endpoint) {
12369
+ const res = resolveDataPath(rawPath);
12370
+ if (!res.ok) {
12371
+ if (res.status === 403) console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${res.resolved ?? "n/a"}"`);
12372
+ return { ok: false, status: res.status, error: res.error };
12373
+ }
12374
+ if (crossesForeignAccountPartition(res.relative, accountId)) {
12375
+ console.error(`[data] account-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
12376
+ return { ok: false, status: 404, error: "Not found" };
12377
+ }
12378
+ if (!isWithinOwnAccountPartition(res.relative, accountId)) {
12379
+ console.error(`[data] write-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
12380
+ return { ok: false, status: 403, error: "Path is outside your account folder" };
12381
+ }
12382
+ return { ok: true, absolute: res.absolute, relative: res.relative };
12383
+ }
12276
12384
  async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
12277
12385
  if (!attachmentId) return false;
12278
12386
  const session = getSession();
@@ -12456,14 +12564,18 @@ app19.post("/upload", requireAdminSession, async (c) => {
12456
12564
  }
12457
12565
  const safeName = basename7(file.name).replace(/[\0/\\]/g, "_");
12458
12566
  const finalName = `${Date.now()}-${safeName}`;
12459
- const destDir = resolve22(DATA_ROOT, "accounts", accountId, "uploads");
12567
+ const rawDir = formData.get("path");
12568
+ const dest = resolveOwnAccountWrite(typeof rawDir === "string" ? rawDir : "", accountId, "POST /api/admin/files/upload");
12569
+ if (!dest.ok) return c.json({ error: dest.error }, dest.status);
12570
+ const destDir = dest.absolute;
12460
12571
  const destPath = resolve22(destDir, finalName);
12461
12572
  try {
12462
- await mkdir3(destDir, { recursive: true });
12573
+ const info = await stat4(destDir);
12574
+ if (!info.isDirectory()) return c.json({ error: "Upload destination is not a directory" }, 400);
12463
12575
  const dataRootReal = realpathSync4(DATA_ROOT);
12464
12576
  const destDirReal = realpathSync4(destDir);
12465
12577
  if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
12466
- console.error(`[data] path-traversal-blocked requested="accounts/${accountId}/uploads" resolved="${destDirReal}"`);
12578
+ console.error(`[data] path-traversal-blocked requested="${dest.relative}" resolved="${destDirReal}"`);
12467
12579
  return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
12468
12580
  }
12469
12581
  const buffer = Buffer.from(await file.arrayBuffer());
@@ -12473,7 +12585,7 @@ app19.post("/upload", requireAdminSession, async (c) => {
12473
12585
  console.error(`[data] file-upload error filename="${safeName}" err="${message}"`);
12474
12586
  return c.json({ error: message }, 500);
12475
12587
  }
12476
- const relativeDest = `accounts/${accountId}/uploads/${finalName}`;
12588
+ const relativeDest = `${dest.relative}/${finalName}`;
12477
12589
  console.error(`[data] file-upload filename="${safeName}" size=${file.size} dest="${relativeDest}"`);
12478
12590
  void indexFile(accountId, relativeDest).catch((err) => {
12479
12591
  console.error(`[data] file-upload index-failed dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
@@ -12561,6 +12673,91 @@ app19.delete("/", requireAdminSession, async (c) => {
12561
12673
  return c.json({ error: message }, 500);
12562
12674
  }
12563
12675
  });
12676
+ app19.post("/folder", requireAdminSession, async (c) => {
12677
+ const cacheKey = c.var.cacheKey;
12678
+ const accountId = getAccountIdForSession(cacheKey);
12679
+ if (!accountId) {
12680
+ console.error(`[data] auth-rejected endpoint="POST /api/admin/files/folder" reason="no account for session"`);
12681
+ return c.json({ error: "Account not found for session" }, 401);
12682
+ }
12683
+ let body;
12684
+ try {
12685
+ body = await c.req.json();
12686
+ } catch {
12687
+ return c.json({ error: "Invalid JSON body" }, 400);
12688
+ }
12689
+ const rawPath = typeof body.path === "string" ? body.path : "";
12690
+ const name = typeof body.name === "string" ? body.name : "";
12691
+ if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
12692
+ const parent = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
12693
+ if (!parent.ok) return c.json({ error: parent.error }, parent.status);
12694
+ const newAbs = resolve22(parent.absolute, name);
12695
+ const newRel = `${parent.relative}/${name}`;
12696
+ try {
12697
+ const info = await stat4(parent.absolute);
12698
+ if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
12699
+ await mkdir3(newAbs, { recursive: false });
12700
+ } catch (err) {
12701
+ const code = err.code;
12702
+ if (code === "EEXIST") return c.json({ error: "A file or folder with that name already exists" }, 409);
12703
+ if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
12704
+ const message = err instanceof Error ? err.message : String(err);
12705
+ console.error(`[data] folder-create error path="${newRel}" err="${message}"`);
12706
+ return c.json({ error: message }, 500);
12707
+ }
12708
+ console.error(`[data] folder-create path="${newRel}"`);
12709
+ return c.json({ path: newRel });
12710
+ });
12711
+ app19.post("/rename", requireAdminSession, async (c) => {
12712
+ const cacheKey = c.var.cacheKey;
12713
+ const accountId = getAccountIdForSession(cacheKey);
12714
+ if (!accountId) {
12715
+ console.error(`[data] auth-rejected endpoint="POST /api/admin/files/rename" reason="no account for session"`);
12716
+ return c.json({ error: "Account not found for session" }, 401);
12717
+ }
12718
+ let body;
12719
+ try {
12720
+ body = await c.req.json();
12721
+ } catch {
12722
+ return c.json({ error: "Invalid JSON body" }, 400);
12723
+ }
12724
+ const rawPath = typeof body.path === "string" ? body.path : "";
12725
+ const newName = typeof body.newName === "string" ? body.newName : "";
12726
+ if (!isValidEntryName(newName)) return c.json({ error: "Invalid name" }, 400);
12727
+ const src = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/rename");
12728
+ if (!src.ok) return c.json({ error: src.error }, src.status);
12729
+ if (isProtectedFromRename(src.relative)) {
12730
+ console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
12731
+ return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
12732
+ }
12733
+ const destAbs = resolve22(dirname6(src.absolute), newName);
12734
+ const newRel = `${dirname6(src.relative)}/${newName}`.replace(/^\.\//, "");
12735
+ if (isProtectedFromRename(newRel)) {
12736
+ console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
12737
+ return c.json({ error: "That name is reserved" }, 403);
12738
+ }
12739
+ try {
12740
+ let collision = true;
12741
+ try {
12742
+ await stat4(destAbs);
12743
+ } catch (e) {
12744
+ if (e.code === "ENOENT") collision = false;
12745
+ }
12746
+ if (collision) return c.json({ error: "A file or folder with that name already exists" }, 409);
12747
+ await rename(src.absolute, destAbs);
12748
+ } catch (err) {
12749
+ const code = err.code;
12750
+ if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
12751
+ const message = err instanceof Error ? err.message : String(err);
12752
+ console.error(`[data] file-rename error from="${src.relative}" to="${newRel}" err="${message}"`);
12753
+ return c.json({ error: message }, 500);
12754
+ }
12755
+ console.error(`[data] file-rename from="${src.relative}" to="${newRel}"`);
12756
+ void reconcileFileIndex(accountId).catch((err) => {
12757
+ console.error(`[data] file-rename reconcile-failed account=${accountId.slice(0, 8)}\u2026 err="${err instanceof Error ? err.message : String(err)}"`);
12758
+ });
12759
+ return c.json({ path: newRel });
12760
+ });
12564
12761
  var files_default = app19;
12565
12762
 
12566
12763
  // ../lib/graph-search/src/index.ts
@@ -14871,7 +15068,7 @@ var session_archive_default = app29;
14871
15068
 
14872
15069
  // server/routes/admin/session-rc-spawn.ts
14873
15070
  import { randomUUID as randomUUID10 } from "crypto";
14874
- function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId) {
15071
+ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId, authenticatedName) {
14875
15072
  const operator = isOperatorHost(host, operatorDomains);
14876
15073
  const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
14877
15074
  const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
@@ -14890,6 +15087,7 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
14890
15087
  payload.webchatChannel = webchatChannelDescriptor(key);
14891
15088
  if (name) payload.name = name;
14892
15089
  if (adminUserId) payload.adminUserId = adminUserId;
15090
+ if (authenticatedName) payload.authenticatedName = authenticatedName;
14893
15091
  } else {
14894
15092
  sessionId = resumeId;
14895
15093
  payload.sessionId = resumeId;
@@ -14899,7 +15097,9 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
14899
15097
  }
14900
15098
  function shapeWebchatResponse(sessionId, manager) {
14901
15099
  const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
14902
- return { sessionId, outcome, target: `/chat?session=${sessionId}` };
15100
+ const redirected = manager?.redirected === true && typeof manager?.sessionId === "string";
15101
+ const landed = redirected ? manager.sessionId : sessionId;
15102
+ return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
14903
15103
  }
14904
15104
  var app30 = new Hono();
14905
15105
  app30.post("/", requireAdminSession, async (c) => {
@@ -14912,7 +15112,9 @@ app30.post("/", requireAdminSession, async (c) => {
14912
15112
  const host = (c.req.header("host") ?? "").split(":")[0];
14913
15113
  const cacheKey = c.get("cacheKey");
14914
15114
  const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
14915
- const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID10, adminUserId);
15115
+ const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
15116
+ const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
15117
+ const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID10, adminUserId, authenticatedName);
14916
15118
  const spawnReqId = randomUUID10();
14917
15119
  console.log(
14918
15120
  `[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
@@ -14980,7 +15182,7 @@ function isSelectableModel(id) {
14980
15182
  }
14981
15183
 
14982
15184
  // server/routes/admin/session-reseat.ts
14983
- function resolveReseatPlan(body, mintId = randomUUID11, adminUserId) {
15185
+ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticatedName) {
14984
15186
  const sessionId = mintId();
14985
15187
  const key = `session:${sessionId}`;
14986
15188
  const payload = {
@@ -14994,6 +15196,7 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId) {
14994
15196
  };
14995
15197
  if (body.name) payload.name = body.name;
14996
15198
  if (adminUserId) payload.adminUserId = adminUserId;
15199
+ if (authenticatedName) payload.authenticatedName = authenticatedName;
14997
15200
  return { sessionId, payload };
14998
15201
  }
14999
15202
  var app31 = new Hono();
@@ -15016,7 +15219,9 @@ app31.post("/", requireAdminSession, async (c) => {
15016
15219
  try {
15017
15220
  const cacheKey = c.get("cacheKey");
15018
15221
  const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
15019
- const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID11, adminUserId);
15222
+ const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
15223
+ const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
15224
+ const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID11, adminUserId, authenticatedName);
15020
15225
  const reseatReqId = randomUUID11();
15021
15226
  console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
15022
15227
  let res;
@@ -15046,8 +15251,8 @@ app31.post("/", requireAdminSession, async (c) => {
15046
15251
  try {
15047
15252
  const account = resolveAccount();
15048
15253
  if (account) {
15049
- const accountId = resolvePlatformAccountId();
15050
- const canonicalId = adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
15254
+ const accountId2 = resolvePlatformAccountId();
15255
+ const canonicalId = adminSessionIdFor(accountId2, WEBCHAT_ADMIN_KEY);
15051
15256
  const currentOverride = readCanonicalOverrideId(account.accountDir);
15052
15257
  if (fromSessionId === canonicalId || fromSessionId === currentOverride) {
15053
15258
  writeCanonicalOverrideId(account.accountDir, plan.sessionId);
@@ -16057,7 +16262,7 @@ app44.route("/request-magic-link", request_magic_link_default);
16057
16262
  var access_default = app44;
16058
16263
 
16059
16264
  // server/routes/sites.ts
16060
- import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync10 } from "fs";
16265
+ import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
16061
16266
  import { resolve as resolve26 } from "path";
16062
16267
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
16063
16268
  var MIME = {
@@ -16123,7 +16328,7 @@ app45.get("/:rel{.*}", (c) => {
16123
16328
  }
16124
16329
  let stat7;
16125
16330
  try {
16126
- stat7 = existsSync23(filePath) ? statSync10(filePath) : null;
16331
+ stat7 = existsSync23(filePath) ? statSync11(filePath) : null;
16127
16332
  } catch {
16128
16333
  stat7 = null;
16129
16334
  }
@@ -17251,7 +17456,7 @@ async function startFileWatcher(opts = {}) {
17251
17456
  }
17252
17457
 
17253
17458
  // app/lib/migrate-uploads.ts
17254
- import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
17459
+ import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
17255
17460
  import { dirname as dirname8, relative as relative4, resolve as resolve29 } from "path";
17256
17461
  var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17257
17462
  async function walkFiles(dir) {
@@ -17285,7 +17490,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
17285
17490
  const suffix = relative4(srcDir, oldAbs);
17286
17491
  const newAbs = resolve29(destDir, suffix);
17287
17492
  await mkdir5(dirname8(newAbs), { recursive: true });
17288
- await rename(oldAbs, newAbs);
17493
+ await rename2(oldAbs, newAbs);
17289
17494
  moved++;
17290
17495
  const oldRel = relative4(dataRoot, oldAbs);
17291
17496
  const newRel = relative4(dataRoot, newAbs);
@@ -17374,7 +17579,7 @@ async function migrateUploads(opts = {}) {
17374
17579
  }
17375
17580
 
17376
17581
  // app/lib/migrate-admin-webchat-sidecars.ts
17377
- import { readdir as readdir6, readFile as readFile6, rename as rename2, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
17582
+ import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
17378
17583
  import { existsSync as existsSync26 } from "fs";
17379
17584
  import { join as join24 } from "path";
17380
17585
  var ADMIN_ROLE2 = "admin";
@@ -17402,7 +17607,7 @@ async function writeRaw(path2, obj) {
17402
17607
  const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
17403
17608
  try {
17404
17609
  await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
17405
- await rename2(tmp, path2);
17610
+ await rename3(tmp, path2);
17406
17611
  } catch (err) {
17407
17612
  try {
17408
17613
  if (existsSync26(tmp)) await unlink3(tmp);
@@ -18537,7 +18742,7 @@ function broadcastAdminShutdown(reason) {
18537
18742
 
18538
18743
  // ../lib/entitlement/src/index.ts
18539
18744
  import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
18540
- import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
18745
+ import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync12 } from "fs";
18541
18746
  import { resolve as resolve30 } from "path";
18542
18747
 
18543
18748
  // ../lib/entitlement/src/canonicalize.ts
@@ -18589,7 +18794,7 @@ function resolveEntitlement(brand, account) {
18589
18794
  if (!existsSync27(entitlementPath)) {
18590
18795
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
18591
18796
  }
18592
- const stat7 = statSync11(entitlementPath);
18797
+ const stat7 = statSync12(entitlementPath);
18593
18798
  const key = memoKey(stat7.mtimeMs, account);
18594
18799
  if (memo && memo.key === key) {
18595
18800
  return memo.result;