@rubytech/create-maxy-code 0.1.307 → 0.1.309

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 (206) hide show
  1. package/dist/__tests__/claude-ptys-slice.test.js +1 -1
  2. package/dist/__tests__/cloudflared-slice.test.js +1 -1
  3. package/dist/__tests__/macos-darwin-branch.test.js +4 -6
  4. package/package.json +1 -1
  5. package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +142 -0
  6. package/payload/platform/lib/admin-access-password/dist/index.d.ts +49 -0
  7. package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -0
  8. package/payload/platform/lib/admin-access-password/dist/index.js +198 -0
  9. package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -0
  10. package/payload/platform/lib/admin-access-password/src/index.ts +176 -0
  11. package/payload/platform/lib/admin-access-password/tsconfig.json +8 -0
  12. package/payload/platform/lib/models/dist/index.d.ts +13 -0
  13. package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
  14. package/payload/platform/lib/models/dist/index.js +20 -1
  15. package/payload/platform/lib/models/dist/index.js.map +1 -1
  16. package/payload/platform/lib/models/src/index.ts +19 -0
  17. package/payload/platform/package.json +2 -2
  18. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  19. package/payload/platform/plugins/admin/mcp/dist/index.js +63 -19
  20. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  21. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +8 -2
  22. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +23 -3
  23. package/payload/platform/plugins/docs/references/admin-ui.md +21 -1
  24. package/payload/platform/plugins/docs/references/internals.md +1 -1
  25. package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
  26. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  28. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  29. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +4 -0
  30. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  31. package/payload/platform/services/claude-session-manager/dist/http-server.js +193 -1
  32. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +12 -0
  34. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +52 -1
  36. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
  38. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +9 -3
  39. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
  40. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +8 -0
  41. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
  42. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +7 -0
  43. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
  44. package/payload/platform/services/webchat-channel/dist/instructions.d.ts +8 -0
  45. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -0
  46. package/payload/platform/services/webchat-channel/dist/instructions.js +44 -0
  47. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -0
  48. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  49. package/payload/platform/services/webchat-channel/dist/server.js +11 -18
  50. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  51. package/payload/server/{chunk-4QFPGAUZ.js → chunk-J6WDAWFJ.js} +190 -82
  52. package/payload/server/maxy-edge.js +1 -1
  53. package/payload/server/public/assets/AccessGate-CU4Qw6M6.js +1 -0
  54. package/payload/server/public/assets/AdminLoginScreens-DUpRIM1h.js +1 -0
  55. package/payload/server/public/assets/AdminShell-DkoQSsqo.js +1 -0
  56. package/payload/server/public/assets/{Checkbox-DoPOlZTV.js → Checkbox-DMA1hVhn.js} +1 -1
  57. package/payload/server/public/assets/OperatorConversations-BIHiyyxU.js +1 -0
  58. package/payload/server/public/assets/admin-BHvOMcCh.js +1 -0
  59. package/payload/server/public/assets/{arc-DxSm8tli.js → arc-Dl9QFDgW.js} +1 -1
  60. package/payload/server/public/assets/architecture-YZFGNWBL-Crq5RSDG.js +1 -0
  61. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-7JSAh0vL.js → architectureDiagram-Q4EWVU46-CNLQUVi9.js} +1 -1
  62. package/payload/server/public/assets/{audio-attachment-mime-BA10IzqQ.js → audio-attachment-mime-DOBET-W1.js} +3 -3
  63. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DLoVmHKD.js → blockDiagram-DXYQGD6D-B-QxfVjk.js} +1 -1
  64. package/payload/server/public/assets/brand-4F9ZXBF8.css +1 -0
  65. package/payload/server/public/assets/{brand-BaRMO3mZ.js → brand-C7kj0USi.js} +1 -1
  66. package/payload/server/public/assets/browser-eLSiC7_b.js +1 -0
  67. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Nv1G0o9P.js → c4Diagram-AHTNJAMY-NuYFvPDU.js} +1 -1
  68. package/payload/server/public/assets/channel-KT66MFN2.js +1 -0
  69. package/payload/server/public/assets/chat-DedpVKUl.js +1 -0
  70. package/payload/server/public/assets/{chunk-2KRD3SAO-BpqPMhoA.js → chunk-2KRD3SAO-l5VL1KQm.js} +1 -1
  71. package/payload/server/public/assets/{chunk-336JU56O-DgXHlVU_.js → chunk-336JU56O-C5gVznC2.js} +2 -2
  72. package/payload/server/public/assets/chunk-426QAEUC-CWMiOm8Y.js +1 -0
  73. package/payload/server/public/assets/{chunk-4BX2VUAB-nwyZSZH8.js → chunk-4BX2VUAB-BtMVz_Sq.js} +1 -1
  74. package/payload/server/public/assets/{chunk-4TB4RGXK-Tfxz9LHX.js → chunk-4TB4RGXK-C8-dmCuT.js} +1 -1
  75. package/payload/server/public/assets/{chunk-55IACEB6-6FMJQGXG.js → chunk-55IACEB6-C5gWvEJW.js} +1 -1
  76. package/payload/server/public/assets/{chunk-5FUZZQ4R-g2FgZF3D.js → chunk-5FUZZQ4R-BZ7VZoAC.js} +1 -1
  77. package/payload/server/public/assets/{chunk-5PVQY5BW-DtLwXsPH.js → chunk-5PVQY5BW-C_ajQOGC.js} +1 -1
  78. package/payload/server/public/assets/{chunk-67CJDMHE-K91CP5ZU.js → chunk-67CJDMHE-BJOR2dwK.js} +1 -1
  79. package/payload/server/public/assets/{chunk-7N4EOEYR-BGpCQhqK.js → chunk-7N4EOEYR-DvZLpquX.js} +1 -1
  80. package/payload/server/public/assets/{chunk-AA7GKIK3-jkDbInck.js → chunk-AA7GKIK3-h5tVsPlW.js} +1 -1
  81. package/payload/server/public/assets/{chunk-BSJP7CBP-mDosdzGs.js → chunk-BSJP7CBP-DLOF2-m3.js} +1 -1
  82. package/payload/server/public/assets/{chunk-CIAEETIT-DhBxewpQ.js → chunk-CIAEETIT-CQRQMPCf.js} +1 -1
  83. package/payload/server/public/assets/{chunk-EDXVE4YY-B7c-9Emg.js → chunk-EDXVE4YY-K9-EfuM2.js} +1 -1
  84. package/payload/server/public/assets/{chunk-ENJZ2VHE-Cqhhncox.js → chunk-ENJZ2VHE-DVoy6NvU.js} +1 -1
  85. package/payload/server/public/assets/{chunk-FMBD7UC4-BpDq6wj1.js → chunk-FMBD7UC4-CQn_2o2b.js} +1 -1
  86. package/payload/server/public/assets/{chunk-FOC6F5B3-Ds02-ktu.js → chunk-FOC6F5B3-CuN73goS.js} +1 -1
  87. package/payload/server/public/assets/{chunk-ICPOFSXX-BTX5POFr.js → chunk-ICPOFSXX-CKhl9J-H.js} +2 -2
  88. package/payload/server/public/assets/{chunk-K5T4RW27-Du1PXXBU.js → chunk-K5T4RW27-CBskuQmq.js} +1 -1
  89. package/payload/server/public/assets/{chunk-KGLVRYIC-siasOAf8.js → chunk-KGLVRYIC-Chtjt8xK.js} +1 -1
  90. package/payload/server/public/assets/{chunk-LIHQZDEY-xf1rbZtf.js → chunk-LIHQZDEY-EOBiBNSH.js} +1 -1
  91. package/payload/server/public/assets/{chunk-ORNJ4GCN-DeTLQ_LD.js → chunk-ORNJ4GCN-uPPq-5MN.js} +1 -1
  92. package/payload/server/public/assets/{chunk-OYMX7WX6-DQ7_oVJn.js → chunk-OYMX7WX6-BRzbxJOT.js} +1 -1
  93. package/payload/server/public/assets/chunk-QZHKN3VN-DCzpF46A.js +1 -0
  94. package/payload/server/public/assets/{chunk-U2HBQHQK-CXmFUKgn.js → chunk-U2HBQHQK-Bndyn5nF.js} +1 -1
  95. package/payload/server/public/assets/{chunk-X2U36JSP-Bj8-8Wkz.js → chunk-X2U36JSP-BspGBHXW.js} +1 -1
  96. package/payload/server/public/assets/{chunk-XPW4576I-Con3TXqt.js → chunk-XPW4576I-HgXQ2k9h.js} +1 -1
  97. package/payload/server/public/assets/{chunk-YZCP3GAM-Dx8BHGWf.js → chunk-YZCP3GAM-C7oTyCnw.js} +1 -1
  98. package/payload/server/public/assets/{chunk-ZZ45TVLE-Dp4Q5Y-f.js → chunk-ZZ45TVLE-CufWa7QL.js} +1 -1
  99. package/payload/server/public/assets/classDiagram-6PBFFD2Q-QOU4HzJJ.js +1 -0
  100. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DcOUai3Z.js +1 -0
  101. package/payload/server/public/assets/clone-CHh05KN-.js +1 -0
  102. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-pZiCv69E.js → cose-bilkent-S5V4N54A-BM3yEbF-.js} +1 -1
  103. package/payload/server/public/assets/{dagre-CLqhEgbL.js → dagre-C7WHNZO8.js} +1 -1
  104. package/payload/server/public/assets/{dagre-KV5264BT-BCxE8iyk.js → dagre-KV5264BT-bcZx3l06.js} +1 -1
  105. package/payload/server/public/assets/data-BcoBY39U.js +1 -0
  106. package/payload/server/public/assets/{diagram-5BDNPKRD-slUEdZzz.js → diagram-5BDNPKRD-B7VotaMF.js} +1 -1
  107. package/payload/server/public/assets/{diagram-G4DWMVQ6-DPcraMfu.js → diagram-G4DWMVQ6-CWWvEsFx.js} +1 -1
  108. package/payload/server/public/assets/{diagram-MMDJMWI5-DR6luhGK.js → diagram-MMDJMWI5-DYHVkTYJ.js} +1 -1
  109. package/payload/server/public/assets/{diagram-TYMM5635-Jap1B4wA.js → diagram-TYMM5635-CHeB6Ama.js} +1 -1
  110. package/payload/server/public/assets/{dist-Dbh7HrZX.js → dist-CjjtmoWL.js} +1 -1
  111. package/payload/server/public/assets/{erDiagram-SMLLAGMA-DJKUs2hO.js → erDiagram-SMLLAGMA-C9gog8QP.js} +1 -1
  112. package/payload/server/public/assets/{flatten-Cl1Bc3dR.js → flatten-QcJDm7yK.js} +1 -1
  113. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C8W-ZZ9W.js → flowDiagram-DWJPFMVM-B2O9lKTh.js} +1 -1
  114. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DYCX4Xu2.js → ganttDiagram-T4ZO3ILL-DEa4AwbR.js} +1 -1
  115. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BC-u4jgy.js +1 -0
  116. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CZu_fpgS.js → gitGraphDiagram-UUTBAWPF-BjXPQpBL.js} +1 -1
  117. package/payload/server/public/assets/{graph-D29p1FJH.js → graph-C7Hye_vp.js} +2 -2
  118. package/payload/server/public/assets/{graph-labels-DF3QVHkH.js → graph-labels-YYgGsEVd.js} +1 -1
  119. package/payload/server/public/assets/{graphlib-Bdp7TA4y.js → graphlib-CBevn2DP.js} +1 -1
  120. package/payload/server/public/assets/info-OMHHGYJF-DPUetTz-.js +1 -0
  121. package/payload/server/public/assets/infoDiagram-42DDH7IO-q2dl09-M.js +2 -0
  122. package/payload/server/public/assets/{isEmpty-D1pGOD1J.js → isEmpty-BO6BAEn7.js} +1 -1
  123. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B7KfIX6z.js → ishikawaDiagram-UXIWVN3A-CPLfpvqv.js} +1 -1
  124. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CSDwBfhF.js → journeyDiagram-VCZTEJTY-CTHe8MiD.js} +1 -1
  125. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CWzcEKTr.js → kanban-definition-6JOO6SKY-Bm9h1O3Y.js} +1 -1
  126. package/payload/server/public/assets/{line-BNQSlbYn.js → line-C31b0rtY.js} +1 -1
  127. package/payload/server/public/assets/{linear-BN6kGN93.js → linear-Cfm_8_pU.js} +1 -1
  128. package/payload/server/public/assets/{mermaid-parser.core-CcFhkElq.js → mermaid-parser.core-B3tGwOcE.js} +2 -2
  129. package/payload/server/public/assets/{mermaid.core-BsIeJ7Cc.js → mermaid.core-BM3s85ZW.js} +3 -3
  130. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CQVzj6D_.js → mindmap-definition-QFDTVHPH-CaGv_mIB.js} +1 -1
  131. package/payload/server/public/assets/operator-WsXhcbBF.js +1 -0
  132. package/payload/server/public/assets/{ordinal-CBZeH4Yp.js → ordinal-jLCwuvYg.js} +1 -1
  133. package/payload/server/public/assets/packet-4T2RLAQJ-BcfR-ZwA.js +1 -0
  134. package/payload/server/public/assets/page-BhHTnqv4.js +1 -0
  135. package/payload/server/public/assets/pie-ZZUOXDRM-BiKgZdNB.js +1 -0
  136. package/payload/server/public/assets/{pieDiagram-DEJITSTG-DnrQ9fyn.js → pieDiagram-DEJITSTG-BhAXps4u.js} +1 -1
  137. package/payload/server/public/assets/public-ViXjC_dA.js +6 -0
  138. package/payload/server/public/assets/public-next-BKECyMz2.js +1 -0
  139. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BQWlCyWi.js → quadrantDiagram-34T5L4WZ-BWtTdNs8.js} +1 -1
  140. package/payload/server/public/assets/radar-PYXPWWZC-nvCjiW_J.js +1 -0
  141. package/payload/server/public/assets/{reduce-PuPlFPRX.js → reduce-Dmi_NdVH.js} +1 -1
  142. package/payload/server/public/assets/{requirementDiagram-MS252O5E-Du_vZhU1.js → requirementDiagram-MS252O5E-CWU0qCcP.js} +1 -1
  143. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js → sankeyDiagram-XADWPNL6-DYvutQld.js} +1 -1
  144. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CS8GVol8.js → sequenceDiagram-FGHM5R23-Cir0hBWS.js} +1 -1
  145. package/payload/server/public/assets/{src-BoaldmnP.js → src-CwB968DO.js} +1 -1
  146. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Bv1NW2F1.js → stateDiagram-FHFEXIEX-Be-h8YSS.js} +1 -1
  147. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CAnmjSj7.js +1 -0
  148. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ClGYAsr0.js → timeline-definition-GMOUNBTQ-C3C4Wuyk.js} +1 -1
  149. package/payload/server/public/assets/treeView-SZITEDCU-BinXCVyM.js +1 -0
  150. package/payload/server/public/assets/treemap-W4RFUUIX-CSmh20Ze.js +1 -0
  151. package/payload/server/public/assets/{useSelectionMode-ghXuZicl.js → useSelectionMode-CG_Iel5F.js} +1 -1
  152. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C2wTcxQT.js → vennDiagram-DHZGUBPP-mDclw0Sa.js} +1 -1
  153. package/payload/server/public/assets/wardley-RL74JXVD-BiCmRKWx.js +1 -0
  154. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D86-ivEx.js → wardleyDiagram-NUSXRM2D-mvk-YA9g.js} +1 -1
  155. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Ba5WAN8P.js → xychartDiagram-5P7HB3ND-9M7k1hmD.js} +1 -1
  156. package/payload/server/public/browser.html +8 -8
  157. package/payload/server/public/chat.html +11 -11
  158. package/payload/server/public/data.html +7 -7
  159. package/payload/server/public/graph.html +10 -10
  160. package/payload/server/public/index.html +10 -10
  161. package/payload/server/public/operator.html +13 -13
  162. package/payload/server/public/public-next.html +24 -0
  163. package/payload/server/public/public.html +9 -8
  164. package/payload/server/server.js +4450 -3781
  165. package/dist/__tests__/onboarding-state-readback.test.js +0 -61
  166. package/dist/__tests__/rss-sampler-installer.test.js +0 -27
  167. package/dist/onboarding-readback.js +0 -27
  168. package/payload/server/public/assets/AdminLoginScreens-BsC-EwAn.js +0 -1
  169. package/payload/server/public/assets/AdminShell-CiKKN22G.js +0 -1
  170. package/payload/server/public/assets/admin-DSwmdCKp.js +0 -1
  171. package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +0 -1
  172. package/payload/server/public/assets/brand-C001cin3.css +0 -1
  173. package/payload/server/public/assets/browser-BKR1eJJb.js +0 -1
  174. package/payload/server/public/assets/channel-BgQLJanG.js +0 -1
  175. package/payload/server/public/assets/chat-DZXNRiy-.js +0 -1
  176. package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +0 -1
  177. package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +0 -1
  178. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +0 -1
  179. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +0 -1
  180. package/payload/server/public/assets/clone-DnNHGhNe.js +0 -1
  181. package/payload/server/public/assets/data-CuVmW1WN.js +0 -1
  182. package/payload/server/public/assets/file-download-4_hQmMwU.js +0 -1
  183. package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +0 -1
  184. package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +0 -1
  185. package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +0 -2
  186. package/payload/server/public/assets/operator-CQRaBNN7.js +0 -1
  187. package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +0 -1
  188. package/payload/server/public/assets/page-Dz2F3QtB.js +0 -1
  189. package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +0 -1
  190. package/payload/server/public/assets/public-B7BQwWpP.js +0 -6
  191. package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +0 -1
  192. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +0 -1
  193. package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +0 -1
  194. package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +0 -1
  195. package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +0 -1
  196. /package/payload/server/public/assets/{file-download-qc_xy7Az.css → OperatorConversations-qc_xy7Az.css} +0 -0
  197. /package/payload/server/public/assets/{_baseFor-brRjpUOX.js → _baseFor-D8P3gUw3.js} +0 -0
  198. /package/payload/server/public/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
  199. /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
  200. /package/payload/server/public/assets/{cytoscape.esm-TvRJ2tGX.js → cytoscape.esm-mZ4wTuB7.js} +0 -0
  201. /package/payload/server/public/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
  202. /package/payload/server/public/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
  203. /package/payload/server/public/assets/{katex-RxgSu_dy.js → katex-DaHGEgm7.js} +0 -0
  204. /package/payload/server/public/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
  205. /package/payload/server/public/assets/{preload-helper-CQ36nxok.js → preload-helper-TKOBYGYD.js} +0 -0
  206. /package/payload/server/public/assets/{rough.esm-6CnTHTkH.js → rough.esm-JX0wREDd.js} +0 -0
@@ -2756,23 +2756,9 @@ function websockifyLog(event, fields = {}) {
2756
2756
  console.error(`[websockify] ${formatKv({ event, ...fields })}`);
2757
2757
  }
2758
2758
 
2759
- // app/lib/password-strength.ts
2760
- function validatePasswordStrength(password) {
2761
- return [
2762
- { key: "length", label: "At least 8 characters", met: password.length >= 8 },
2763
- { key: "number", label: "Contains a number", met: /\d/.test(password) },
2764
- { key: "special", label: "Contains a special character", met: /[^A-Za-z0-9]/.test(password) },
2765
- { key: "whitespace", label: "No spaces", met: password.length > 0 && !/\s/.test(password) }
2766
- ];
2767
- }
2768
- function isPasswordValid(password) {
2769
- return validatePasswordStrength(password).every((r) => r.met);
2770
- }
2771
-
2772
- // app/lib/remote-auth.ts
2773
- import { scrypt, randomBytes, timingSafeEqual, createHmac } from "crypto";
2774
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
2775
- import { dirname } from "path";
2759
+ // ../lib/admin-access-password/src/index.ts
2760
+ import { scrypt, randomBytes, timingSafeEqual } from "crypto";
2761
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, renameSync, unlinkSync } from "fs";
2776
2762
  var SCRYPT_N = 16384;
2777
2763
  var SCRYPT_R = 8;
2778
2764
  var SCRYPT_P = 1;
@@ -2785,56 +2771,170 @@ function scryptAsync(password, salt) {
2785
2771
  });
2786
2772
  });
2787
2773
  }
2788
- async function hashPassword(password) {
2774
+ async function hashAccessPassword(password) {
2789
2775
  const salt = randomBytes(32);
2790
2776
  const hash = await scryptAsync(password, salt);
2791
2777
  return `${salt.toString("hex")}:${hash.toString("hex")}`;
2792
2778
  }
2793
- async function verifyPassword(password, stored) {
2794
- const colonIndex = stored.indexOf(":");
2795
- if (colonIndex === -1) return { ok: false, why: "bad-hash-format", hashBytes: 0 };
2796
- const saltHex = stored.slice(0, colonIndex);
2797
- const hashHex = stored.slice(colonIndex + 1);
2798
- if (!saltHex || !hashHex) return { ok: false, why: "bad-hash-format", hashBytes: 0 };
2799
- const salt = Buffer.from(saltHex, "hex");
2800
- const storedHash = Buffer.from(hashHex, "hex");
2801
- if (storedHash.length !== SCRYPT_KEYLEN) {
2802
- return { ok: false, why: "hash-length", hashBytes: storedHash.length };
2803
- }
2779
+ async function matchesHash(password, stored) {
2780
+ const colon = stored.indexOf(":");
2781
+ if (colon === -1) return false;
2782
+ const salt = Buffer.from(stored.slice(0, colon), "hex");
2783
+ const storedHash = Buffer.from(stored.slice(colon + 1), "hex");
2784
+ if (storedHash.length !== SCRYPT_KEYLEN) return false;
2804
2785
  let computed;
2805
2786
  try {
2806
2787
  computed = await scryptAsync(password, salt);
2807
2788
  } catch {
2808
- return { ok: false, why: "scrypt-throw", hashBytes: storedHash.length };
2809
- }
2810
- if (timingSafeEqual(computed, storedHash)) {
2811
- return { ok: true, hashBytes: storedHash.length };
2789
+ return false;
2812
2790
  }
2813
- return { ok: false, why: "password-mismatch", hashBytes: storedHash.length };
2791
+ return timingSafeEqual(computed, storedHash);
2814
2792
  }
2815
- function isRemoteAuthConfigured() {
2816
- if (!existsSync2(REMOTE_PASSWORD_FILE)) return false;
2817
- const content = readFileSync2(REMOTE_PASSWORD_FILE, "utf-8").trim();
2818
- return content.length > 0 && content.includes(":");
2793
+ function readUsers(usersFile) {
2794
+ if (!existsSync2(usersFile)) return [];
2795
+ const raw2 = readFileSync2(usersFile, "utf-8").trim();
2796
+ if (!raw2) return [];
2797
+ const parsed = JSON.parse(raw2);
2798
+ if (!Array.isArray(parsed)) throw new Error("users.json is not an array");
2799
+ return parsed;
2800
+ }
2801
+ function writeUsersAtomic(usersFile, users) {
2802
+ const tmp = `${usersFile}.tmp-${process.pid}`;
2803
+ writeFileSync(tmp, JSON.stringify(users, null, 2) + "\n", { mode: 384 });
2804
+ renameSync(tmp, usersFile);
2805
+ }
2806
+ async function setAccessPassword(userId, password, usersFile) {
2807
+ const users = readUsers(usersFile);
2808
+ const idx = users.findIndex((u) => u.userId === userId);
2809
+ if (idx === -1) throw new Error(`no users.json record for userId=${userId}`);
2810
+ users[idx] = { ...users[idx], accessHash: await hashAccessPassword(password) };
2811
+ writeUsersAtomic(usersFile, users);
2819
2812
  }
2820
- function readPasswordHash() {
2813
+ async function verifyAccessPassword(password, usersFile) {
2814
+ let users;
2821
2815
  try {
2822
- if (!existsSync2(REMOTE_PASSWORD_FILE)) return null;
2823
- const content = readFileSync2(REMOTE_PASSWORD_FILE, "utf-8").trim();
2824
- if (!content || !content.includes(":")) return null;
2825
- return content;
2816
+ users = readUsers(usersFile);
2826
2817
  } catch {
2827
2818
  return null;
2828
2819
  }
2820
+ for (const u of users) {
2821
+ if (typeof u.accessHash === "string" && await matchesHash(password, u.accessHash)) {
2822
+ return u.userId;
2823
+ }
2824
+ }
2825
+ return null;
2826
+ }
2827
+ async function accessPasswordCollides(password, usersFile, excludeUserId) {
2828
+ let users;
2829
+ try {
2830
+ users = readUsers(usersFile);
2831
+ } catch {
2832
+ return false;
2833
+ }
2834
+ for (const u of users) {
2835
+ if (u.userId === excludeUserId) continue;
2836
+ if (typeof u.accessHash === "string" && await matchesHash(password, u.accessHash)) {
2837
+ return true;
2838
+ }
2839
+ }
2840
+ return false;
2841
+ }
2842
+ function anyAccessPasswordConfigured(usersFile) {
2843
+ let users;
2844
+ try {
2845
+ users = readUsers(usersFile);
2846
+ } catch {
2847
+ return false;
2848
+ }
2849
+ return users.some((u) => typeof u.accessHash === "string" && u.accessHash.length > 0);
2850
+ }
2851
+ function accessStoreUnreadable(usersFile) {
2852
+ if (!existsSync2(usersFile)) return false;
2853
+ try {
2854
+ readUsers(usersFile);
2855
+ return false;
2856
+ } catch {
2857
+ return true;
2858
+ }
2859
+ }
2860
+ function migrateLegacyRemotePassword(usersFile, legacyFile, ownerUserId) {
2861
+ if (!existsSync2(legacyFile)) return "noop-no-legacy";
2862
+ const legacy = readFileSync2(legacyFile, "utf-8").trim();
2863
+ const users = readUsers(usersFile);
2864
+ const idx = users.findIndex((u) => u.userId === ownerUserId);
2865
+ if (idx === -1) return "noop-no-owner";
2866
+ const existing = users[idx].accessHash;
2867
+ if (typeof existing === "string" && existing.length > 0) {
2868
+ unlinkSync(legacyFile);
2869
+ return "noop-owner-has-hash";
2870
+ }
2871
+ if (!legacy.includes(":")) {
2872
+ unlinkSync(legacyFile);
2873
+ return "noop-no-legacy";
2874
+ }
2875
+ users[idx] = { ...users[idx], accessHash: legacy };
2876
+ writeUsersAtomic(usersFile, users);
2877
+ unlinkSync(legacyFile);
2878
+ return "migrated";
2879
+ }
2880
+ function readLegacyRemoteHash(legacyFile) {
2881
+ if (!existsSync2(legacyFile)) return null;
2882
+ const raw2 = readFileSync2(legacyFile, "utf-8").trim();
2883
+ return raw2.includes(":") ? raw2 : null;
2884
+ }
2885
+
2886
+ // app/lib/password-strength.ts
2887
+ function validatePasswordStrength(password) {
2888
+ return [
2889
+ { key: "length", label: "At least 8 characters", met: password.length >= 8 },
2890
+ { key: "number", label: "Contains a number", met: /\d/.test(password) },
2891
+ { key: "special", label: "Contains a special character", met: /[^A-Za-z0-9]/.test(password) },
2892
+ { key: "whitespace", label: "No spaces", met: password.length > 0 && !/\s/.test(password) }
2893
+ ];
2894
+ }
2895
+ function isPasswordValid(password) {
2896
+ return validatePasswordStrength(password).every((r) => r.met);
2897
+ }
2898
+
2899
+ // app/lib/remote-auth.ts
2900
+ import { scrypt as scrypt2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2, createHmac } from "crypto";
2901
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
2902
+ import { dirname } from "path";
2903
+ var SCRYPT_N2 = 16384;
2904
+ var SCRYPT_R2 = 8;
2905
+ var SCRYPT_P2 = 1;
2906
+ var SCRYPT_KEYLEN2 = 64;
2907
+ function scryptAsync2(password, salt) {
2908
+ return new Promise((resolve7, reject) => {
2909
+ scrypt2(password, salt, SCRYPT_KEYLEN2, { N: SCRYPT_N2, r: SCRYPT_R2, p: SCRYPT_P2 }, (err, key) => {
2910
+ if (err) reject(err);
2911
+ else resolve7(key);
2912
+ });
2913
+ });
2914
+ }
2915
+ async function hashPassword(password) {
2916
+ const salt = randomBytes2(32);
2917
+ const hash = await scryptAsync2(password, salt);
2918
+ return `${salt.toString("hex")}:${hash.toString("hex")}`;
2919
+ }
2920
+ function isRemoteAuthConfigured() {
2921
+ if (anyAccessPasswordConfigured(USERS_FILE)) return true;
2922
+ if (accessStoreUnreadable(USERS_FILE)) return true;
2923
+ return readLegacyRemoteHash(REMOTE_PASSWORD_FILE) !== null;
2829
2924
  }
2830
2925
  async function setRemotePassword(password) {
2831
2926
  const hash = await hashPassword(password);
2832
- writeFileSync(REMOTE_PASSWORD_FILE, hash, "utf-8");
2927
+ writeFileSync2(REMOTE_PASSWORD_FILE, hash, "utf-8");
2833
2928
  }
2834
2929
  async function verifyRemotePassword(password) {
2835
- const stored = readPasswordHash();
2836
- if (!stored) return { ok: false, why: "no-password-file", hashBytes: 0 };
2837
- return verifyPassword(password, stored);
2930
+ const matchedUserId = await verifyAccessPassword(password, USERS_FILE);
2931
+ if (matchedUserId) return { ok: true, hashBytes: SCRYPT_KEYLEN2, userId: matchedUserId };
2932
+ const legacy = readLegacyRemoteHash(REMOTE_PASSWORD_FILE);
2933
+ if (legacy && await matchesHash(password, legacy)) {
2934
+ return { ok: true, hashBytes: SCRYPT_KEYLEN2, userId: null };
2935
+ }
2936
+ const configured = anyAccessPasswordConfigured(USERS_FILE) || legacy !== null;
2937
+ return { ok: false, why: configured ? "password-mismatch" : "no-password-file", hashBytes: 0 };
2838
2938
  }
2839
2939
  var SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
2840
2940
  var TOKEN_PREFIX = "v1.";
@@ -2844,20 +2944,20 @@ var cachedSecret = null;
2844
2944
  function getSecret() {
2845
2945
  if (cachedSecret) return cachedSecret;
2846
2946
  try {
2847
- const hex2 = readFileSync2(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
2947
+ const hex2 = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
2848
2948
  if (hex2.length === SECRET_BYTES * 2) {
2849
2949
  cachedSecret = Buffer.from(hex2, "hex");
2850
2950
  return cachedSecret;
2851
2951
  }
2852
2952
  } catch {
2853
2953
  }
2854
- const fresh = randomBytes(SECRET_BYTES).toString("hex");
2954
+ const fresh = randomBytes2(SECRET_BYTES).toString("hex");
2855
2955
  try {
2856
2956
  mkdirSync2(dirname(REMOTE_SESSION_SECRET_FILE), { recursive: true, mode: 448 });
2857
- writeFileSync(REMOTE_SESSION_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
2957
+ writeFileSync2(REMOTE_SESSION_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
2858
2958
  } catch {
2859
2959
  }
2860
- const hex = readFileSync2(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
2960
+ const hex = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
2861
2961
  cachedSecret = Buffer.from(hex, "hex");
2862
2962
  return cachedSecret;
2863
2963
  }
@@ -2872,7 +2972,7 @@ function signPayload(payloadJson, secret) {
2872
2972
  return base64urlEncode(createHmac("sha256", secret).update(payloadJson).digest());
2873
2973
  }
2874
2974
  function createRemoteSession(opts = {}) {
2875
- const payload = { c: opts.now ?? Date.now(), n: randomBytes(NONCE_BYTES).toString("hex") };
2975
+ const payload = { c: opts.now ?? Date.now(), n: randomBytes2(NONCE_BYTES).toString("hex") };
2876
2976
  const payloadJson = JSON.stringify(payload);
2877
2977
  const payloadB64 = base64urlEncode(Buffer.from(payloadJson, "utf-8"));
2878
2978
  const sig = signPayload(payloadJson, getSecret());
@@ -2895,7 +2995,7 @@ function parseToken(token) {
2895
2995
  const expected = signPayload(payloadJson, getSecret());
2896
2996
  const expectedBuf = Buffer.from(expected, "utf-8");
2897
2997
  const provBuf = Buffer.from(sigB64, "utf-8");
2898
- const signatureValid = expectedBuf.length === provBuf.length && timingSafeEqual(expectedBuf, provBuf);
2998
+ const signatureValid = expectedBuf.length === provBuf.length && timingSafeEqual2(expectedBuf, provBuf);
2899
2999
  let payload;
2900
3000
  try {
2901
3001
  payload = JSON.parse(payloadJson);
@@ -3442,6 +3542,10 @@ var SYSTEM_PATH_SLUGS = ["public", "public-chat", "chat", "graph", "data", "brow
3442
3542
  var PUBLIC_ALLOWED_PREFIXES = [
3443
3543
  "/api/session",
3444
3544
  "/api/chat",
3545
+ // Task 873 — the detooled public surface's visitor-authed reader (pointer +
3546
+ // server-filtered SSE stream). Reached by the visitor browser on the public
3547
+ // host; authenticated by the __access_session grant inside the route.
3548
+ "/api/public-reader/",
3445
3549
  "/api/access/",
3446
3550
  "/api/health",
3447
3551
  "/api/group/",
@@ -3473,13 +3577,13 @@ function classifyHost(host, operatorDomains2, isPublicHost) {
3473
3577
  import { watchFile } from "fs";
3474
3578
 
3475
3579
  // app/lib/operator-domains.ts
3476
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3580
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3477
3581
  import { dirname as dirname2, resolve as resolve3 } from "path";
3478
3582
  var OPERATOR_DOMAINS_PATH = resolve3(MAXY_DIR, "operator-domains.json");
3479
3583
  function loadOperatorDomains() {
3480
3584
  if (!existsSync3(OPERATOR_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
3481
3585
  try {
3482
- const parsed = JSON.parse(readFileSync3(OPERATOR_DOMAINS_PATH, "utf-8"));
3586
+ const parsed = JSON.parse(readFileSync4(OPERATOR_DOMAINS_PATH, "utf-8"));
3483
3587
  if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
3484
3588
  return new Set(parsed.filter((h) => typeof h === "string"));
3485
3589
  } catch {
@@ -3506,11 +3610,11 @@ function getOperatorDomains() {
3506
3610
 
3507
3611
  // app/lib/claude-agent/account.ts
3508
3612
  import { resolve as resolve4 } from "path";
3509
- import { readFileSync as readFileSync5, readdirSync, existsSync as existsSync5, statSync } from "fs";
3613
+ import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, statSync } from "fs";
3510
3614
 
3511
3615
  // ../lib/brand-templating/src/index.ts
3512
3616
  import { join as join2 } from "path";
3513
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
3617
+ import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
3514
3618
  var PLACEHOLDER = "{{productName}}";
3515
3619
  var cachedProductName = null;
3516
3620
  function brandJsonPath() {
@@ -3530,7 +3634,7 @@ function getBrandProductName() {
3530
3634
  }
3531
3635
  let parsed;
3532
3636
  try {
3533
- parsed = JSON.parse(readFileSync4(path, "utf-8"));
3637
+ parsed = JSON.parse(readFileSync5(path, "utf-8"));
3534
3638
  } catch (err) {
3535
3639
  throw new Error(
3536
3640
  `[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`
@@ -3594,7 +3698,7 @@ function listValidAccounts() {
3594
3698
  }
3595
3699
  let config;
3596
3700
  try {
3597
- config = JSON.parse(readFileSync5(configPath, "utf-8"));
3701
+ config = JSON.parse(readFileSync6(configPath, "utf-8"));
3598
3702
  } catch {
3599
3703
  console.error(
3600
3704
  `[platform] accounts-state CORRUPT-JSON id=${entry.name} \u2014 account.json failed to parse; treating as stub`
@@ -3610,7 +3714,7 @@ function resolveAccount() {
3610
3714
  let usersJsonUserId = null;
3611
3715
  if (existsSync5(USERS_FILE)) {
3612
3716
  try {
3613
- const raw2 = readFileSync5(USERS_FILE, "utf-8").trim();
3717
+ const raw2 = readFileSync6(USERS_FILE, "utf-8").trim();
3614
3718
  if (raw2) {
3615
3719
  const users = JSON.parse(raw2);
3616
3720
  if (users.length > 0) {
@@ -3626,7 +3730,7 @@ function resolveAccount() {
3626
3730
  if (!entry.isDirectory()) continue;
3627
3731
  const configPath = resolve4(ACCOUNTS_DIR, entry.name, "account.json");
3628
3732
  if (!existsSync5(configPath)) continue;
3629
- const raw2 = readFileSync5(configPath, "utf-8");
3733
+ const raw2 = readFileSync6(configPath, "utf-8");
3630
3734
  let config;
3631
3735
  try {
3632
3736
  config = JSON.parse(raw2);
@@ -3661,7 +3765,7 @@ function resolveAccount() {
3661
3765
  function readAgentFile(accountDir, agentName, filename) {
3662
3766
  const filePath = resolve4(accountDir, "agents", agentName, filename);
3663
3767
  if (!existsSync5(filePath)) return null;
3664
- const raw2 = readFileSync5(filePath, "utf-8");
3768
+ const raw2 = readFileSync6(filePath, "utf-8");
3665
3769
  if (filename.endsWith(".md")) {
3666
3770
  return substituteBrandPlaceholders(raw2, filePath);
3667
3771
  }
@@ -3690,7 +3794,7 @@ function resolveDefaultAgentSlug(accountDir) {
3690
3794
  }
3691
3795
  let config;
3692
3796
  try {
3693
- config = JSON.parse(readFileSync5(configPath, "utf-8"));
3797
+ config = JSON.parse(readFileSync6(configPath, "utf-8"));
3694
3798
  } catch (err) {
3695
3799
  console.error("[agent-resolve] failed to read account.json:", err);
3696
3800
  return null;
@@ -3765,14 +3869,14 @@ function resolveAgentConfig(accountDir, agentName) {
3765
3869
  const knowledgeMtime = statSync(knowledgePath).mtimeMs;
3766
3870
  const summaryMtime = statSync(summaryPath).mtimeMs;
3767
3871
  if (summaryMtime >= knowledgeMtime) {
3768
- knowledge = readFileSync5(summaryPath, "utf-8");
3872
+ knowledge = readFileSync6(summaryPath, "utf-8");
3769
3873
  } else {
3770
3874
  console.warn(`[agent-config] ${agentName}: KNOWLEDGE-SUMMARY.md is stale (KNOWLEDGE.md is newer) \u2014 using full knowledge`);
3771
- knowledge = readFileSync5(knowledgePath, "utf-8");
3875
+ knowledge = readFileSync6(knowledgePath, "utf-8");
3772
3876
  }
3773
3877
  knowledgeBaked = true;
3774
3878
  } else if (hasKnowledge) {
3775
- knowledge = readFileSync5(knowledgePath, "utf-8");
3879
+ knowledge = readFileSync6(knowledgePath, "utf-8");
3776
3880
  knowledgeBaked = true;
3777
3881
  }
3778
3882
  let budget = null;
@@ -3808,7 +3912,7 @@ function resolveUserAccounts(userId) {
3808
3912
  if (!existsSync5(configPath)) continue;
3809
3913
  let config;
3810
3914
  try {
3811
- config = JSON.parse(readFileSync5(configPath, "utf-8"));
3915
+ config = JSON.parse(readFileSync6(configPath, "utf-8"));
3812
3916
  } catch {
3813
3917
  console.error(`[session] account.json corrupt at ${configPath} \u2014 skipping`);
3814
3918
  continue;
@@ -3893,8 +3997,8 @@ function getSessionKeyBySessionId(_sessionId) {
3893
3997
  // app/lib/claude-agent/plugin-manifest.ts
3894
3998
  import { resolve as resolve5, join as join3 } from "path";
3895
3999
  import {
3896
- readFileSync as readFileSync6,
3897
- writeFileSync as writeFileSync3,
4000
+ readFileSync as readFileSync7,
4001
+ writeFileSync as writeFileSync4,
3898
4002
  readdirSync as readdirSync2,
3899
4003
  existsSync as existsSync6,
3900
4004
  statSync as statSync2,
@@ -3915,7 +4019,7 @@ function readBundleSubPlugins(bundlePath) {
3915
4019
  if (!existsSync6(bundlePath)) return [];
3916
4020
  let raw2;
3917
4021
  try {
3918
- raw2 = readFileSync6(bundlePath, "utf-8");
4022
+ raw2 = readFileSync7(bundlePath, "utf-8");
3919
4023
  } catch {
3920
4024
  return [];
3921
4025
  }
@@ -3988,8 +4092,8 @@ function reapDuplicateFlatPremiumSubs(bundles, stagingRoot, pluginsDir) {
3988
4092
  const flatDir = resolve5(pluginsDir, sub);
3989
4093
  const flatManifest = resolve5(flatDir, "PLUGIN.md");
3990
4094
  if (!existsSync6(premiumManifest) || !existsSync6(flatManifest)) continue;
3991
- const premiumSha = createHash2("sha256").update(readFileSync6(premiumManifest)).digest("hex");
3992
- const flatSha = createHash2("sha256").update(readFileSync6(flatManifest)).digest("hex");
4095
+ const premiumSha = createHash2("sha256").update(readFileSync7(premiumManifest)).digest("hex");
4096
+ const flatSha = createHash2("sha256").update(readFileSync7(flatManifest)).digest("hex");
3993
4097
  if (isBundle) {
3994
4098
  if (premiumSha === flatSha) {
3995
4099
  try {
@@ -4051,10 +4155,10 @@ function reconcileEnabledPlugins(accountDir, config, accountId) {
4051
4155
  const merged = [...currentSet];
4052
4156
  const configPath = resolve5(accountDir, "account.json");
4053
4157
  try {
4054
- const raw2 = readFileSync6(configPath, "utf-8");
4158
+ const raw2 = readFileSync7(configPath, "utf-8");
4055
4159
  const parsed = JSON.parse(raw2);
4056
4160
  parsed.enabledPlugins = merged;
4057
- writeFileSync3(configPath, JSON.stringify(parsed, null, 2) + "\n");
4161
+ writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
4058
4162
  config.enabledPlugins = merged;
4059
4163
  } catch (err) {
4060
4164
  console.error(`${TAG} enabled-stamp write failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -4082,10 +4186,10 @@ function cleanupLeakedPremiumSubs(accountDir, config, accountId) {
4082
4186
  if (removed.length === 0) return;
4083
4187
  const configPath = resolve5(accountDir, "account.json");
4084
4188
  try {
4085
- const raw2 = readFileSync6(configPath, "utf-8");
4189
+ const raw2 = readFileSync7(configPath, "utf-8");
4086
4190
  const parsed = JSON.parse(raw2);
4087
4191
  parsed.enabledPlugins = kept;
4088
- writeFileSync3(configPath, JSON.stringify(parsed, null, 2) + "\n");
4192
+ writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
4089
4193
  config.enabledPlugins = kept;
4090
4194
  console.log(`${TAG} cleanup accountId=${accountId ?? "unknown"} removed=[${removed.join(",")}]`);
4091
4195
  } catch (err) {
@@ -4133,7 +4237,7 @@ function requirePortEnv(envName, options = {}) {
4133
4237
  // app/lib/neo4j-store.ts
4134
4238
  import neo4j from "neo4j-driver";
4135
4239
  import { randomUUID } from "crypto";
4136
- import { readFileSync as readFileSync7, readdirSync as readdirSync3, existsSync as existsSync7, openSync, readSync, closeSync, statSync as statSync3 } from "fs";
4240
+ import { readFileSync as readFileSync8, readdirSync as readdirSync3, existsSync as existsSync7, openSync, readSync, closeSync, statSync as statSync3 } from "fs";
4137
4241
  import { resolve as resolve6 } from "path";
4138
4242
  var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
4139
4243
  var driver = null;
@@ -4141,7 +4245,7 @@ function readPassword() {
4141
4245
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
4142
4246
  const passwordFile = resolve6(PLATFORM_ROOT3, "config/.neo4j-password");
4143
4247
  try {
4144
- return readFileSync7(passwordFile, "utf-8").trim();
4248
+ return readFileSync8(passwordFile, "utf-8").trim();
4145
4249
  } catch {
4146
4250
  throw new Error(
4147
4251
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -5190,7 +5294,7 @@ function loadEnabledPluginProfileKeys(accountId) {
5190
5294
  if (!existsSync7(accountFile)) return {};
5191
5295
  let enabled;
5192
5296
  try {
5193
- const raw2 = readFileSync7(accountFile, "utf-8");
5297
+ const raw2 = readFileSync8(accountFile, "utf-8");
5194
5298
  const parsed = JSON.parse(raw2);
5195
5299
  enabled = Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : [];
5196
5300
  } catch (err) {
@@ -5205,7 +5309,7 @@ function loadEnabledPluginProfileKeys(accountId) {
5205
5309
  if (!existsSync7(manifestPath)) continue;
5206
5310
  let manifest;
5207
5311
  try {
5208
- manifest = readFileSync7(manifestPath, "utf-8");
5312
+ manifest = readFileSync8(manifestPath, "utf-8");
5209
5313
  } catch {
5210
5314
  continue;
5211
5315
  }
@@ -5461,11 +5565,11 @@ async function projectAgent(accountId, accountDir, slug) {
5461
5565
  );
5462
5566
  return;
5463
5567
  }
5464
- config = JSON.parse(readFileSync7(configPath, "utf-8"));
5568
+ config = JSON.parse(readFileSync8(configPath, "utf-8"));
5465
5569
  for (const { filename, role } of AGENT_FILE_ROLES) {
5466
5570
  const filePath = resolve6(agentDir, filename);
5467
5571
  if (!existsSync7(filePath)) continue;
5468
- const body = readFileSync7(filePath, "utf-8");
5572
+ const body = readFileSync8(filePath, "utf-8");
5469
5573
  presentRoles.push({ role, body, edge: ROLE_TO_EDGE[role] });
5470
5574
  }
5471
5575
  } catch (err) {
@@ -5726,6 +5830,7 @@ export {
5726
5830
  LID_MAP_FILE,
5727
5831
  LOG_DIR,
5728
5832
  BIN_DIR,
5833
+ REMOTE_PASSWORD_FILE,
5729
5834
  INSTALL_OWNER_FILE,
5730
5835
  VISITOR_TOKEN_SECRET_FILE,
5731
5836
  CLAUDE_CREDENTIALS_FILE,
@@ -5734,6 +5839,9 @@ export {
5734
5839
  sanitizeClientCorrId,
5735
5840
  httpLog,
5736
5841
  websockifyLog,
5842
+ setAccessPassword,
5843
+ accessPasswordCollides,
5844
+ migrateLegacyRemotePassword,
5737
5845
  validatePasswordStrength,
5738
5846
  isPasswordValid,
5739
5847
  isRemoteAuthConfigured,
@@ -16,7 +16,7 @@ import {
16
16
  sanitizeClientCorrId,
17
17
  vncLog,
18
18
  websockifyLog
19
- } from "./chunk-4QFPGAUZ.js";
19
+ } from "./chunk-J6WDAWFJ.js";
20
20
  import "./chunk-PFF6I7KP.js";
21
21
 
22
22
  // server/edge.ts
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-CAM3fms7.js";import{o as t,u as n}from"./brand-C7kj0USi.js";import{c as r,d as i,l as a,u as o}from"./audio-attachment-mime-DOBET-W1.js";import{r as s}from"./useSelectionMode-CG_Iel5F.js";var c=e(n(),1);function l(){let[e,t]=(0,c.useState)(null),[n,s]=(0,c.useState)(null),[l,u]=(0,c.useState)(`loading`),[d,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(null),[h,g]=(0,c.useState)(null),[_,v]=(0,c.useState)(!1),[y,b]=(0,c.useState)(null),x=(0,c.useMemo)(()=>r(),[]),S=(0,c.useMemo)(()=>a(),[]),[C,w]=(0,c.useState)(null),T=(0,c.useRef)(x||``),E=(0,c.useRef)(null),D=(0,c.useRef)(null),O=(0,c.useRef)(!1),k=(0,c.useRef)(null),[A,j]=(0,c.useState)(`request-link`),[M,N]=(0,c.useState)(null),P=(0,c.useRef)(null),F=(0,c.useRef)(null);(0,c.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(F.current=e)}catch{}},[]);let I=(0,c.useCallback)(e=>{E.current=e,t(e);try{sessionStorage.setItem(`maxy_session`,e)}catch{}u(`chat`)},[]),L=(0,c.useCallback)(()=>{E.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}t(null),u(`auth-required`),j(`request-link`)},[]),R=(0,c.useCallback)(async e=>{j(`verifying`);try{let t=T.current,n=await fetch(`/api/access/verify-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:e,agentSlug:t})});if(window.history.replaceState({},``,window.location.pathname),n.ok){let e=await n.json().catch(()=>({}));return e?.displayName&&N({displayName:e.displayName,contactValue:``,expiresAt:null,status:`active`}),!0}return j(`verify-failed`),!1}catch{return j(`verify-failed`),!1}},[]),z=(0,c.useCallback)(async()=>{if(E.current)return E.current;if(D.current)return D.current;let e=(async()=>{try{let e=F.current,n=await fetch(`/api/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_id:o(),...x?{agent:x}:{},...S?{group_slug:S}:{},...e?{session_key:e}:{}})});if(!n.ok){let e=await n.json().catch(()=>({error:``}));return i&&console.error(`[session] POST /api/session failed: ${n.status} ${n.statusText}`,e),n.status===404?s(e.error||`Agent not found`):n.status===503&&s(e.error||`Service unavailable`),null}let r=await n.json();if(r.auth_required){r.agent_id&&(T.current=r.agent_id),f(r.displayName||``),r.agentImage&&m(r.agentImage),r.agentImageShape&&g(r.agentImageShape),r.showAgentName&&v(r.showAgentName),r.branding&&b(r.branding),u(`auth-required`);let e=new URLSearchParams(window.location.search).get(`token`);return e?await R(e)&&window.location.reload():j(`request-link`),null}E.current=r.session_key,t(r.session_key),r.displayName&&f(r.displayName),r.agentImage&&m(r.agentImage),r.agentImageShape&&g(r.agentImageShape),r.showAgentName&&v(r.showAgentName),r.branding&&b(r.branding),u(`chat`),r.resumed&&r.messages&&(O.current=!0,k.current=r.messages),r.group&&w({groupSlug:r.groupSlug,groupName:r.groupName,participants:r.participants??[]});try{sessionStorage.setItem(`maxy_session`,r.session_key)}catch{}return r.session_key}catch(e){return i&&console.error(`[session] fetch /api/session threw:`,e),s(`Unable to connect. Please check your connection and try again.`),null}finally{D.current=null}})();return D.current=e,e},[x,S,R]);return{sessionId:e,cacheKeyRef:E,sessionError:n,pageState:l,setPageState:u,agentDisplayName:d,agentImage:p,agentImageShape:h,showAgentName:_,agentSlug:x,branding:y,resolvedSlugRef:T,ensureSession:z,startNewSession:(0,c.useCallback)(async()=>{E.current=null,D.current=null,F.current=null,O.current=!1,k.current=null,t(null),s(null);try{sessionStorage.removeItem(`maxy_session`)}catch{}await z()},[z]),enterChat:I,enterGate:L,resumedRef:O,resumeMessagesRef:k,gateState:A,setGateState:j,grantInfo:M,setGrantInfo:N,gateCacheKeyRef:P,groupContext:C,groupSlug:S}}var u=t();function d({gateState:e,setGateState:t,grantInfo:n,resolvedSlugRef:r}){let[i,a]=(0,c.useState)(``),[o,l]=(0,c.useState)(!1),[d,f]=(0,c.useState)(null);async function p(e){e.preventDefault();let n=i.trim().toLowerCase();if(!n){f(`Enter the email you were invited on.`);return}l(!0),f(null);try{let e=await fetch(`/api/access/request-magic-link`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contactValue:n,agentSlug:r.current})});if(e.status===429){f((await e.json().catch(()=>({})))?.error||`Too many requests. Try again later.`);return}t(`request-sent`)}catch{f(`Could not reach the server. Check your connection and try again.`)}finally{l(!1)}}return(0,u.jsxs)(`div`,{className:`access-gate`,children:[e===`verifying`&&(0,u.jsxs)(`div`,{className:`access-gate-message`,children:[(0,u.jsx)(`h2`,{children:`Verifying your link…`}),(0,u.jsx)(`p`,{children:`This takes a moment.`})]}),e===`verify-failed`&&(0,u.jsxs)(`div`,{className:`access-gate-message`,children:[(0,u.jsx)(`h2`,{children:`That link did not work`}),(0,u.jsx)(`p`,{children:`It may have expired, already been used, or been for a different agent. You can request a fresh one below.`}),(0,u.jsx)(s,{onClick:()=>{t(`request-link`),f(null)},children:`Request a new link`})]}),e===`request-link`&&(0,u.jsxs)(`form`,{className:`access-gate-form`,onSubmit:p,children:[(0,u.jsx)(`h2`,{children:n?.displayName?`Welcome back, ${n.displayName}`:`Sign in`}),(0,u.jsx)(`p`,{children:`Enter the email you were invited on and we will send you a fresh link.`}),(0,u.jsx)(`label`,{htmlFor:`access-email`,children:`Email`}),(0,u.jsx)(`input`,{id:`access-email`,type:`email`,inputMode:`email`,autoComplete:`email`,value:i,onChange:e=>a(e.target.value),disabled:o}),d&&(0,u.jsx)(`p`,{className:`access-gate-error`,children:d}),(0,u.jsx)(s,{type:`submit`,disabled:o||!i.trim(),children:o?`Sending…`:`Send me a link`})]}),e===`request-sent`&&(0,u.jsxs)(`div`,{className:`access-gate-message`,children:[(0,u.jsx)(`h2`,{children:`Check your email`}),(0,u.jsx)(`p`,{children:`If that address is on the invite list, a fresh link is on the way. It expires in 15 minutes.`}),(0,u.jsx)(s,{onClick:()=>{t(`request-link`),a(``),f(null)},children:`Try a different email`})]})]})}export{l as n,d as t};
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-CAM3fms7.js";import{a as t,o as n,t as r,u as i}from"./brand-C7kj0USi.js";import{S as a,g as o}from"./OperatorConversations-BIHiyyxU.js";import{s}from"./AdminShell-DkoQSsqo.js";import{r as c}from"./useSelectionMode-CG_Iel5F.js";import{t as l}from"./Checkbox-DMA1hVhn.js";new Set(`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,audio/ogg,audio/opus,audio/mp4,audio/mpeg,audio/webm,audio/wav,.opus,.ogg,.m4a,.mp3,.wav,.webm`.split(`,`).filter(e=>!e.startsWith(`.`)));function u(e){switch(e){case`expanded`:return!0;case`collapsed`:return!1;default:return}}var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(i(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[r,i]=(0,m.useState)(``),[o,c]=(0,m.useState)(``),[l,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=u(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let a=await r.json();if(a.accounts&&!a.session_key){console.log(`[admin] account picker shown: userId=${a.userId} accountCount=${a.accounts.length}`),B(a.accounts),n(`account-picker`);return}D(a.session_key),R(a.sessionId??null),j(a.businessName),N(a.role??null),F(a.userName===void 0?null:a.userName),L(a.avatar??null);let o=u(a.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,a.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=o.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let a=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:a,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await Z(a);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,o]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(r)},[r]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await s())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return n(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}i(``),h(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:o,setOperatorName:c,pinError:l,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(r,e)},[r]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!r){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:r})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}i(``),h(``),n(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[r])}}var g=n();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function v(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function y(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`}),(0,g.jsx)(c,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function b(e){let{accounts:n,loading:i,error:a,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:i,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),i&&(0,g.jsx)(o,{className:`account-picker-spinner`,size:16})]},e.accountId))}),a&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:a})]})})}function x(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,pinError:s,setPinError:l,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}h(!1)}async function v(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),i(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),l(``)}return n||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,g.jsx)(`button`,{onClick:y,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,g.jsx)(x,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};