@rubytech/create-maxy-code 0.1.306 → 0.1.307
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.
- package/package.json +1 -1
- package/payload/platform/lib/models/dist/index.d.ts +0 -1
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +2 -5
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +1 -4
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +33 -12
- package/payload/platform/plugins/docs/references/admin-ui.md +32 -11
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +14 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +13 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +18 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/server.js +34 -10
- package/payload/platform/services/whatsapp-channel/dist/server.js.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +9 -0
- package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/targets.js +13 -0
- package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
- package/payload/platform/templates/account.json +1 -1
- package/payload/server/{chunk-TUY3RB5G.js → chunk-4QFPGAUZ.js} +27 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AdminLoginScreens-BsC-EwAn.js +1 -0
- package/payload/server/public/assets/AdminShell-CiKKN22G.js +1 -0
- package/payload/server/public/assets/Checkbox-DoPOlZTV.js +1 -0
- package/payload/server/public/assets/admin-DSwmdCKp.js +1 -0
- package/payload/server/public/assets/{arc-BrTRjBIM.js → arc-DxSm8tli.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-DJ9on7sZ.js → architectureDiagram-Q4EWVU46-7JSAh0vL.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-j2VvxEtx.js → audio-attachment-mime-BA10IzqQ.js} +4 -4
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CIcyQn0q.js → blockDiagram-DXYQGD6D-DLoVmHKD.js} +1 -1
- package/payload/server/public/assets/brand-BaRMO3mZ.js +9 -0
- package/payload/server/public/assets/{jsx-runtime-DZkld3Wk.css → brand-C001cin3.css} +1 -1
- package/payload/server/public/assets/browser-BKR1eJJb.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Dt5dh_GR.js → c4Diagram-AHTNJAMY-Nv1G0o9P.js} +1 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +1 -0
- package/payload/server/public/assets/chat-DZXNRiy-.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BUq3MqUy.js → chunk-2KRD3SAO-BpqPMhoA.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-CUzJH5Qt.js → chunk-336JU56O-DgXHlVU_.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-B4JUc3UA.js → chunk-4BX2VUAB-nwyZSZH8.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-HRO9fIIs.js → chunk-4TB4RGXK-Tfxz9LHX.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-MZdrLBuw.js → chunk-55IACEB6-6FMJQGXG.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-XcAN5zlM.js → chunk-5FUZZQ4R-g2FgZF3D.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-PQ1GEsxo.js → chunk-5PVQY5BW-DtLwXsPH.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BVvCaqGd.js → chunk-67CJDMHE-K91CP5ZU.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BlBbZdpM.js → chunk-7N4EOEYR-BGpCQhqK.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-Ct-PgkGa.js → chunk-AA7GKIK3-jkDbInck.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-DZRRfCSz.js → chunk-BSJP7CBP-mDosdzGs.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-BoGEJiXe.js → chunk-CIAEETIT-DhBxewpQ.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DiSmN31f.js → chunk-EDXVE4YY-B7c-9Emg.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-uhhokIvs.js → chunk-ENJZ2VHE-Cqhhncox.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CfCx5WI7.js → chunk-FMBD7UC4-BpDq6wj1.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-Dj9E9gTu.js → chunk-FOC6F5B3-Ds02-ktu.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-DcBs_FNy.js → chunk-ICPOFSXX-BTX5POFr.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-7-VefyJD.js → chunk-K5T4RW27-Du1PXXBU.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-CqgTEVxm.js → chunk-KGLVRYIC-siasOAf8.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-C0gzDXha.js → chunk-LIHQZDEY-xf1rbZtf.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-JXz23R1H.js → chunk-ORNJ4GCN-DeTLQ_LD.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C2snCNq9.js → chunk-OYMX7WX6-DQ7_oVJn.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CXCU7M-M.js → chunk-U2HBQHQK-CXmFUKgn.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-CEdcSb28.js → chunk-X2U36JSP-Bj8-8Wkz.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Cckc75YS.js → chunk-XPW4576I-Con3TXqt.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-4nN8AO7H.js → chunk-YZCP3GAM-Dx8BHGWf.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-DcoBc8-7.js → chunk-ZZ45TVLE-Dp4Q5Y-f.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +1 -0
- package/payload/server/public/assets/clone-DnNHGhNe.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BFFro_t9.js → cose-bilkent-S5V4N54A-pZiCv69E.js} +1 -1
- package/payload/server/public/assets/{dagre-CN5to_JM.js → dagre-CLqhEgbL.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-WYrPwDg0.js → dagre-KV5264BT-BCxE8iyk.js} +1 -1
- package/payload/server/public/assets/data-CuVmW1WN.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-Dz2CiboN.js → diagram-5BDNPKRD-slUEdZzz.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-r8h3Ip9O.js → diagram-G4DWMVQ6-DPcraMfu.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CECcpGtr.js → diagram-MMDJMWI5-DR6luhGK.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CHOcAyIP.js → diagram-TYMM5635-Jap1B4wA.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-YIqKdPbS.js → erDiagram-SMLLAGMA-DJKUs2hO.js} +1 -1
- package/payload/server/public/assets/file-download-4_hQmMwU.js +1 -0
- package/payload/server/public/assets/{flatten-DhYYI_lo.js → flatten-Cl1Bc3dR.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DaEvQWpj.js → flowDiagram-DWJPFMVM-C8W-ZZ9W.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-x1hClEOB.js → ganttDiagram-T4ZO3ILL-DYCX4Xu2.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-C-sZsh6Z.js → gitGraphDiagram-UUTBAWPF-CZu_fpgS.js} +1 -1
- package/payload/server/public/assets/{graph-Uaa5heM5.js → graph-D29p1FJH.js} +3 -3
- package/payload/server/public/assets/graph-labels-DF3QVHkH.js +1 -0
- package/payload/server/public/assets/{graphlib-CNkAqm2w.js → graphlib-Bdp7TA4y.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +2 -0
- package/payload/server/public/assets/{isEmpty-DGhq_DBP.js → isEmpty-D1pGOD1J.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-wHE-RwzZ.js → ishikawaDiagram-UXIWVN3A-B7KfIX6z.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DQB6iThz.js → journeyDiagram-VCZTEJTY-CSDwBfhF.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Ck08vXSA.js → kanban-definition-6JOO6SKY-CWzcEKTr.js} +1 -1
- package/payload/server/public/assets/{line-Cdc2FBEU.js → line-BNQSlbYn.js} +1 -1
- package/payload/server/public/assets/{linear-DhtUm5H7.js → linear-BN6kGN93.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CSYulPIL.js → mermaid-parser.core-CcFhkElq.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-CP-hOmMh.js → mermaid.core-BsIeJ7Cc.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-GxlkvV1Z.js → mindmap-definition-QFDTVHPH-CQVzj6D_.js} +1 -1
- package/payload/server/public/assets/operator-CQRaBNN7.js +1 -0
- package/payload/server/public/assets/{ordinal-CibZU3PM.js → ordinal-CBZeH4Yp.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +1 -0
- package/payload/server/public/assets/page-Dz2F3QtB.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-Di6kWh9c.js → pieDiagram-DEJITSTG-DnrQ9fyn.js} +1 -1
- package/payload/server/public/assets/{public-DBXfM02B.js → public-B7BQwWpP.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-iNHC5bkO.js → quadrantDiagram-34T5L4WZ-BQWlCyWi.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +1 -0
- package/payload/server/public/assets/{reduce-Da0RBva0.js → reduce-PuPlFPRX.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-BBlLREXo.js → requirementDiagram-MS252O5E-Du_vZhU1.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-qyDkP-Ca.js → sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-C0MJuS0m.js → sequenceDiagram-FGHM5R23-CS8GVol8.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-aHTrlosa.js → stateDiagram-FHFEXIEX-Bv1NW2F1.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BlRZIxEp.js → timeline-definition-GMOUNBTQ-ClGYAsr0.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +1 -0
- package/payload/server/public/assets/useSelectionMode-ghXuZicl.js +5 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-s76adysx.js → vennDiagram-DHZGUBPP-C2wTcxQT.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-xC8t2QGW.js → wardleyDiagram-NUSXRM2D-D86-ivEx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DRcHg-Wj.js → xychartDiagram-5P7HB3ND-Ba5WAN8P.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +9 -10
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +8 -9
- package/payload/server/public/operator.html +11 -12
- package/payload/server/public/public.html +7 -7
- package/payload/server/server.js +470 -221
- package/payload/server/public/assets/AdminLoginScreens-Cw882rmm.js +0 -1
- package/payload/server/public/assets/AdminShell-DpWl1uoY.js +0 -1
- package/payload/server/public/assets/Checkbox-DAWZItdK.js +0 -1
- package/payload/server/public/assets/Transcript-DbK2YA3K.js +0 -1
- package/payload/server/public/assets/admin-nQRdn79w.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DqQB3T6j.js +0 -1
- package/payload/server/public/assets/browser-CHWZDCXt.js +0 -1
- package/payload/server/public/assets/channel-NZeJdLVK.js +0 -1
- package/payload/server/public/assets/chat-BBK6ulFy.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-DFKX5l0L.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-BWCCN0AM.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DPlCQCX2.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CqkQq74h.js +0 -1
- package/payload/server/public/assets/clone-CSykdD1A.js +0 -1
- package/payload/server/public/assets/data-33mdnHv8.js +0 -1
- package/payload/server/public/assets/file-download-P_qlMCg5.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-V7Tx7_eY.js +0 -1
- package/payload/server/public/assets/graph-labels-rG63rHvl.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-D3DqVPGn.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-B_O-R0vN.js +0 -2
- package/payload/server/public/assets/jsx-runtime-sFVKdwlP.js +0 -9
- package/payload/server/public/assets/operator-CiDwt5I9.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BY7mgCTQ.js +0 -1
- package/payload/server/public/assets/page-BvkaS_tu.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-B9f6jN54.js +0 -1
- package/payload/server/public/assets/radar-PYXPWWZC-BKS8JOUe.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-V2vo4BjY.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-bIKzyIdw.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-CQycQ4H9.js +0 -1
- package/payload/server/public/assets/useSelectionMode-Dky-Stnf.js +0 -5
- package/payload/server/public/assets/wardley-RL74JXVD-COr9o-nG.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BFYpZGkN.js → _baseFor-brRjpUOX.js} +0 -0
- /package/payload/server/public/assets/{array-CYkMkqnU.js → array-BGFCBI0e.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-DqlHsaog.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-Beh6XjaL.js → defaultLocale-CRZydyG6.js} +0 -0
- /package/payload/server/public/assets/{dist-t9p-NJH2.js → dist-Dbh7HrZX.js} +0 -0
- /package/payload/server/public/assets/{init-Rr1s_RiX.js → init-B8gtcn7T.js} +0 -0
- /package/payload/server/public/assets/{katex-pVJiI_rc.js → katex-RxgSu_dy.js} +0 -0
- /package/payload/server/public/assets/{path-BAQ3hXlG.js → path-DZF-JdEe.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-B_l5jfgx.js → preload-helper-CQ36nxok.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-nHaDi0Kw.js → rough.esm-6CnTHTkH.js} +0 -0
- /package/payload/server/public/assets/{src-DuPQVw-H.js → src-BoaldmnP.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
listAdminSessions,
|
|
70
70
|
listValidAccounts,
|
|
71
71
|
loadAdminUserName,
|
|
72
|
+
loadPersonNameByElementId,
|
|
72
73
|
loadUserProfile,
|
|
73
74
|
loadWhatsappSenderName,
|
|
74
75
|
persistMessage,
|
|
@@ -105,7 +106,7 @@ import {
|
|
|
105
106
|
vncLog,
|
|
106
107
|
walkPremiumBundles,
|
|
107
108
|
writeAdminUserAndPerson
|
|
108
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-4QFPGAUZ.js";
|
|
109
110
|
import {
|
|
110
111
|
__commonJS,
|
|
111
112
|
__toESM
|
|
@@ -1223,7 +1224,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1223
1224
|
|
|
1224
1225
|
// server/index.ts
|
|
1225
1226
|
import { readFileSync as readFileSync26, existsSync as existsSync27, watchFile } from "fs";
|
|
1226
|
-
import { resolve as
|
|
1227
|
+
import { resolve as resolve30, join as join22, basename as basename8 } from "path";
|
|
1227
1228
|
import { homedir as homedir3 } from "os";
|
|
1228
1229
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1229
1230
|
|
|
@@ -1871,7 +1872,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1871
1872
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1872
1873
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1873
1874
|
const timer2 = new Promise(
|
|
1874
|
-
(
|
|
1875
|
+
(resolve31) => setTimeout(() => resolve31("timeout"), timeoutMs)
|
|
1875
1876
|
);
|
|
1876
1877
|
const result = await Promise.race([
|
|
1877
1878
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1999,11 +2000,11 @@ async function createWaSocket(opts) {
|
|
|
1999
2000
|
return sock;
|
|
2000
2001
|
}
|
|
2001
2002
|
async function waitForConnection(sock) {
|
|
2002
|
-
return new Promise((
|
|
2003
|
+
return new Promise((resolve31, reject) => {
|
|
2003
2004
|
const handler = (update) => {
|
|
2004
2005
|
if (update.connection === "open") {
|
|
2005
2006
|
sock.ev.off("connection.update", handler);
|
|
2006
|
-
|
|
2007
|
+
resolve31();
|
|
2007
2008
|
}
|
|
2008
2009
|
if (update.connection === "close") {
|
|
2009
2010
|
sock.ev.off("connection.update", handler);
|
|
@@ -2117,14 +2118,14 @@ ${inspected}`;
|
|
|
2117
2118
|
return inspect2(err, INSPECT_OPTS2);
|
|
2118
2119
|
}
|
|
2119
2120
|
function withTimeout(label, promise, timeoutMs) {
|
|
2120
|
-
return new Promise((
|
|
2121
|
+
return new Promise((resolve31, reject) => {
|
|
2121
2122
|
const timer2 = setTimeout(() => {
|
|
2122
2123
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2123
2124
|
}, timeoutMs);
|
|
2124
2125
|
promise.then(
|
|
2125
2126
|
(value) => {
|
|
2126
2127
|
clearTimeout(timer2);
|
|
2127
|
-
|
|
2128
|
+
resolve31(value);
|
|
2128
2129
|
},
|
|
2129
2130
|
(err) => {
|
|
2130
2131
|
clearTimeout(timer2);
|
|
@@ -3008,8 +3009,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3008
3009
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3009
3010
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3010
3011
|
let release;
|
|
3011
|
-
const mine = new Promise((
|
|
3012
|
-
release =
|
|
3012
|
+
const mine = new Promise((resolve31) => {
|
|
3013
|
+
release = resolve31;
|
|
3013
3014
|
});
|
|
3014
3015
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3015
3016
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -4089,11 +4090,11 @@ async function connectWithReconnect(conn) {
|
|
|
4089
4090
|
console.error(
|
|
4090
4091
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
4091
4092
|
);
|
|
4092
|
-
await new Promise((
|
|
4093
|
-
const timer2 = setTimeout(
|
|
4093
|
+
await new Promise((resolve31) => {
|
|
4094
|
+
const timer2 = setTimeout(resolve31, delay);
|
|
4094
4095
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
4095
4096
|
clearTimeout(timer2);
|
|
4096
|
-
|
|
4097
|
+
resolve31();
|
|
4097
4098
|
}, { once: true });
|
|
4098
4099
|
});
|
|
4099
4100
|
}
|
|
@@ -4101,16 +4102,16 @@ async function connectWithReconnect(conn) {
|
|
|
4101
4102
|
}
|
|
4102
4103
|
}
|
|
4103
4104
|
function waitForDisconnectEvent(conn) {
|
|
4104
|
-
return new Promise((
|
|
4105
|
+
return new Promise((resolve31) => {
|
|
4105
4106
|
if (!conn.sock) {
|
|
4106
|
-
|
|
4107
|
+
resolve31();
|
|
4107
4108
|
return;
|
|
4108
4109
|
}
|
|
4109
4110
|
const sock = conn.sock;
|
|
4110
4111
|
const handler = (update) => {
|
|
4111
4112
|
if (update.connection === "close") {
|
|
4112
4113
|
sock.ev.off("connection.update", handler);
|
|
4113
|
-
|
|
4114
|
+
resolve31();
|
|
4114
4115
|
}
|
|
4115
4116
|
};
|
|
4116
4117
|
sock.ev.on("connection.update", handler);
|
|
@@ -4370,8 +4371,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4370
4371
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4371
4372
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4372
4373
|
let resolvePending;
|
|
4373
|
-
const sttPending = new Promise((
|
|
4374
|
-
resolvePending =
|
|
4374
|
+
const sttPending = new Promise((resolve31) => {
|
|
4375
|
+
resolvePending = resolve31;
|
|
4375
4376
|
});
|
|
4376
4377
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4377
4378
|
try {
|
|
@@ -4765,20 +4766,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4765
4766
|
|
|
4766
4767
|
// server/routes/health.ts
|
|
4767
4768
|
function checkPort(port2, timeoutMs = 500) {
|
|
4768
|
-
return new Promise((
|
|
4769
|
+
return new Promise((resolve31) => {
|
|
4769
4770
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4770
4771
|
socket.setTimeout(timeoutMs);
|
|
4771
4772
|
socket.once("connect", () => {
|
|
4772
4773
|
socket.destroy();
|
|
4773
|
-
|
|
4774
|
+
resolve31(true);
|
|
4774
4775
|
});
|
|
4775
4776
|
socket.once("error", () => {
|
|
4776
4777
|
socket.destroy();
|
|
4777
|
-
|
|
4778
|
+
resolve31(false);
|
|
4778
4779
|
});
|
|
4779
4780
|
socket.once("timeout", () => {
|
|
4780
4781
|
socket.destroy();
|
|
4781
|
-
|
|
4782
|
+
resolve31(false);
|
|
4782
4783
|
});
|
|
4783
4784
|
});
|
|
4784
4785
|
}
|
|
@@ -4847,10 +4848,75 @@ var health_default = app;
|
|
|
4847
4848
|
// app/lib/attachments.ts
|
|
4848
4849
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
4849
4850
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
4851
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
4852
|
+
import { resolve as resolve6, extname } from "path";
|
|
4853
|
+
|
|
4854
|
+
// app/lib/data-path.ts
|
|
4850
4855
|
import { realpathSync } from "fs";
|
|
4851
|
-
import { resolve as resolve5,
|
|
4856
|
+
import { resolve as resolve5, normalize, sep as sep2, relative } from "path";
|
|
4852
4857
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "../platform");
|
|
4853
|
-
var
|
|
4858
|
+
var DATA_ROOT = resolve5(PLATFORM_ROOT4, "..", "data");
|
|
4859
|
+
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve5(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
4860
|
+
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["accounts"]);
|
|
4861
|
+
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4862
|
+
function crossesForeignAccountPartition(relPath, accountId) {
|
|
4863
|
+
const segs = relPath.split("/").filter(Boolean);
|
|
4864
|
+
if (segs.length < 2) return false;
|
|
4865
|
+
if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
|
|
4866
|
+
const owner = segs[1];
|
|
4867
|
+
if (!ACCOUNT_UUID_RE.test(owner)) return false;
|
|
4868
|
+
return owner !== accountId;
|
|
4869
|
+
}
|
|
4870
|
+
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
4871
|
+
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
4872
|
+
const absolute = resolve5(rootAbs, cleaned);
|
|
4873
|
+
let rootReal;
|
|
4874
|
+
try {
|
|
4875
|
+
rootReal = realpathSync(rootAbs);
|
|
4876
|
+
} catch (err) {
|
|
4877
|
+
return {
|
|
4878
|
+
ok: false,
|
|
4879
|
+
status: 500,
|
|
4880
|
+
error: `${rootLabel} not accessible: ${err instanceof Error ? err.message : String(err)}`
|
|
4881
|
+
};
|
|
4882
|
+
}
|
|
4883
|
+
let resolvedReal;
|
|
4884
|
+
try {
|
|
4885
|
+
resolvedReal = realpathSync(absolute);
|
|
4886
|
+
} catch (err) {
|
|
4887
|
+
const code = err.code;
|
|
4888
|
+
if (code === "ENOENT") {
|
|
4889
|
+
if (absolute !== rootReal && !absolute.startsWith(rootReal + sep2)) {
|
|
4890
|
+
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
|
|
4891
|
+
}
|
|
4892
|
+
return { ok: false, status: 404, error: "Not found" };
|
|
4893
|
+
}
|
|
4894
|
+
return {
|
|
4895
|
+
ok: false,
|
|
4896
|
+
status: 500,
|
|
4897
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4898
|
+
};
|
|
4899
|
+
}
|
|
4900
|
+
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep2)) {
|
|
4901
|
+
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
|
|
4902
|
+
}
|
|
4903
|
+
const relPath = relative(rootReal, resolvedReal) || ".";
|
|
4904
|
+
return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath };
|
|
4905
|
+
}
|
|
4906
|
+
function resolveDataPath(raw) {
|
|
4907
|
+
return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
|
|
4908
|
+
}
|
|
4909
|
+
function resolveClaudeUploadsPath(raw) {
|
|
4910
|
+
if (!CLAUDE_UPLOADS_ROOT) {
|
|
4911
|
+
return { ok: false, status: 404, error: "Not found" };
|
|
4912
|
+
}
|
|
4913
|
+
return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
|
|
4914
|
+
}
|
|
4915
|
+
|
|
4916
|
+
// app/lib/attachments.ts
|
|
4917
|
+
function uploadsDirFor(accountId, subPath, attachmentId) {
|
|
4918
|
+
return subPath ? resolve6(DATA_ROOT, "accounts", accountId, "uploads", subPath, attachmentId) : resolve6(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
4919
|
+
}
|
|
4854
4920
|
var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
4855
4921
|
"image/jpeg",
|
|
4856
4922
|
"image/png",
|
|
@@ -4875,16 +4941,16 @@ function assertSupportedMime(mimeType) {
|
|
|
4875
4941
|
);
|
|
4876
4942
|
}
|
|
4877
4943
|
}
|
|
4878
|
-
async function writeAttachment(
|
|
4944
|
+
async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes, buffer) {
|
|
4879
4945
|
const attachmentId = randomUUID4();
|
|
4880
|
-
const dir =
|
|
4946
|
+
const dir = uploadsDirFor(accountId, subPath, attachmentId);
|
|
4881
4947
|
await mkdir2(dir, { recursive: true });
|
|
4882
4948
|
const ext = extname(filename) || "";
|
|
4883
|
-
const storagePath =
|
|
4884
|
-
const metaPath =
|
|
4949
|
+
const storagePath = resolve6(dir, `${attachmentId}${ext}`);
|
|
4950
|
+
const metaPath = resolve6(dir, `${attachmentId}.meta.json`);
|
|
4885
4951
|
const meta = {
|
|
4886
4952
|
attachmentId,
|
|
4887
|
-
scope,
|
|
4953
|
+
scope: subPath || accountId,
|
|
4888
4954
|
filename,
|
|
4889
4955
|
mimeType,
|
|
4890
4956
|
sizeBytes,
|
|
@@ -4902,16 +4968,16 @@ async function storeAttachment(accountId, file) {
|
|
|
4902
4968
|
);
|
|
4903
4969
|
}
|
|
4904
4970
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
4905
|
-
return writeAttachment(accountId, file.name, file.type, file.size, buffer);
|
|
4971
|
+
return writeAttachment(accountId, "", file.name, file.type, file.size, buffer);
|
|
4906
4972
|
}
|
|
4907
|
-
async function storePublicAttachment(sessionId, file, buffer) {
|
|
4973
|
+
async function storePublicAttachment(accountId, sessionId, file, buffer) {
|
|
4908
4974
|
assertSupportedMime(file.type);
|
|
4909
4975
|
if (file.size > MAX_FILE_SIZE_BYTES) {
|
|
4910
4976
|
throw new Error(
|
|
4911
4977
|
`File "${file.name}" exceeds the 50 MB limit (${(file.size / 1024 / 1024).toFixed(1)} MB).`
|
|
4912
4978
|
);
|
|
4913
4979
|
}
|
|
4914
|
-
return writeAttachment(`public/${sessionId}`, file.name, file.type, file.size, buffer);
|
|
4980
|
+
return writeAttachment(accountId, `public/${sessionId}`, file.name, file.type, file.size, buffer);
|
|
4915
4981
|
}
|
|
4916
4982
|
var MIME_BY_EXT = {
|
|
4917
4983
|
".pdf": "application/pdf",
|
|
@@ -4941,8 +5007,8 @@ function detectMimeType(filePath) {
|
|
|
4941
5007
|
return MIME_BY_EXT[ext] ?? "application/octet-stream";
|
|
4942
5008
|
}
|
|
4943
5009
|
function validateFilePathInAccount(filePath, accountDir) {
|
|
4944
|
-
const resolved =
|
|
4945
|
-
const accountResolved =
|
|
5010
|
+
const resolved = realpathSync2(filePath);
|
|
5011
|
+
const accountResolved = realpathSync2(accountDir);
|
|
4946
5012
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
4947
5013
|
throw new Error(`File path is outside the account directory`);
|
|
4948
5014
|
}
|
|
@@ -4955,11 +5021,11 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
4955
5021
|
`Component artefact exceeds the 50 MB limit (${(buffer.byteLength / 1024 / 1024).toFixed(1)} MB).`
|
|
4956
5022
|
);
|
|
4957
5023
|
}
|
|
4958
|
-
const dir =
|
|
5024
|
+
const dir = uploadsDirFor(accountId, "", attachmentId);
|
|
4959
5025
|
await mkdir2(dir, { recursive: true });
|
|
4960
5026
|
const ext = extname(filename) || (mimeType === "text/html" ? ".html" : ".md");
|
|
4961
|
-
const storagePath =
|
|
4962
|
-
const metaPath =
|
|
5027
|
+
const storagePath = resolve6(dir, `${attachmentId}${ext}`);
|
|
5028
|
+
const metaPath = resolve6(dir, `${attachmentId}.meta.json`);
|
|
4963
5029
|
const meta = {
|
|
4964
5030
|
attachmentId,
|
|
4965
5031
|
scope: accountId,
|
|
@@ -5063,7 +5129,7 @@ async function transcribeVoiceNote(file, source) {
|
|
|
5063
5129
|
}
|
|
5064
5130
|
|
|
5065
5131
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
5066
|
-
import { resolve as
|
|
5132
|
+
import { resolve as resolve8 } from "path";
|
|
5067
5133
|
|
|
5068
5134
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
5069
5135
|
function managerBase() {
|
|
@@ -5514,9 +5580,9 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
5514
5580
|
}
|
|
5515
5581
|
|
|
5516
5582
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
5517
|
-
import { realpathSync as
|
|
5583
|
+
import { realpathSync as realpathSync3 } from "fs";
|
|
5518
5584
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
5519
|
-
import { resolve as
|
|
5585
|
+
import { resolve as resolve7, basename } from "path";
|
|
5520
5586
|
var TAG16 = "[whatsapp:outbound]";
|
|
5521
5587
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
5522
5588
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -5547,11 +5613,11 @@ async function sendWhatsAppDocument(input) {
|
|
|
5547
5613
|
if (!maxyAccountId || !platformRoot2) {
|
|
5548
5614
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
5549
5615
|
}
|
|
5550
|
-
const accountDir =
|
|
5616
|
+
const accountDir = resolve7(platformRoot2, "..", "data/accounts", maxyAccountId);
|
|
5551
5617
|
let resolvedPath;
|
|
5552
5618
|
try {
|
|
5553
|
-
resolvedPath =
|
|
5554
|
-
const accountResolved =
|
|
5619
|
+
resolvedPath = realpathSync3(filePath);
|
|
5620
|
+
const accountResolved = realpathSync3(accountDir);
|
|
5555
5621
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
5556
5622
|
const sanitised = filePath.replace(accountDir, "<account>/");
|
|
5557
5623
|
console.error(`${TAG16} document REJECTED path=${sanitised} reason=outside_account_directory`);
|
|
@@ -5757,7 +5823,7 @@ async function ensureEntry(input) {
|
|
|
5757
5823
|
});
|
|
5758
5824
|
} else {
|
|
5759
5825
|
console.error(`${tag} route role=${input.role} target=public-spawn senderId=${input.senderId}`);
|
|
5760
|
-
const attachmentDir =
|
|
5826
|
+
const attachmentDir = resolve8(DATA_ROOT, "accounts", input.accountId, "uploads", "public", input.senderId);
|
|
5761
5827
|
spawned = await managerSpawn({
|
|
5762
5828
|
senderId: input.senderId,
|
|
5763
5829
|
role: input.role,
|
|
@@ -5889,12 +5955,12 @@ async function dispatchOnce(input) {
|
|
|
5889
5955
|
});
|
|
5890
5956
|
if (!entry) return { error: "spawn-failed" };
|
|
5891
5957
|
entry.lastInboundAt = Date.now();
|
|
5892
|
-
let
|
|
5958
|
+
let resolve31;
|
|
5893
5959
|
const turnPromise = new Promise((r) => {
|
|
5894
|
-
|
|
5960
|
+
resolve31 = r;
|
|
5895
5961
|
});
|
|
5896
5962
|
const listener = (text) => {
|
|
5897
|
-
|
|
5963
|
+
resolve31(text);
|
|
5898
5964
|
};
|
|
5899
5965
|
entry.subscribers.add(listener);
|
|
5900
5966
|
const writeAtMs = Date.now();
|
|
@@ -6043,6 +6109,10 @@ var app2 = new Hono();
|
|
|
6043
6109
|
app2.post("/", async (c) => {
|
|
6044
6110
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
6045
6111
|
const contentType = c.req.header("content-type") ?? "";
|
|
6112
|
+
const account = resolveAccount();
|
|
6113
|
+
if (!account) {
|
|
6114
|
+
return c.json({ error: "No account configured" }, 500);
|
|
6115
|
+
}
|
|
6046
6116
|
let message;
|
|
6047
6117
|
let session_key;
|
|
6048
6118
|
let userTimestamp;
|
|
@@ -6103,7 +6173,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6103
6173
|
const stored = [];
|
|
6104
6174
|
for (const file of regularFiles) {
|
|
6105
6175
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
6106
|
-
const att = await storePublicAttachment(session_key, file, buffer);
|
|
6176
|
+
const att = await storePublicAttachment(account.accountId, session_key, file, buffer);
|
|
6107
6177
|
stored.push({ name: file.name, path: att.storagePath, mime: att.mimeType, sizeBytes: att.sizeBytes });
|
|
6108
6178
|
}
|
|
6109
6179
|
attachmentCount = stored.length;
|
|
@@ -6149,10 +6219,6 @@ ${result.result.text}` : result.result.text;
|
|
|
6149
6219
|
);
|
|
6150
6220
|
const fullMessage = message + uploadNote;
|
|
6151
6221
|
const encoder = new TextEncoder();
|
|
6152
|
-
const account = resolveAccount();
|
|
6153
|
-
if (!account) {
|
|
6154
|
-
return c.json({ error: "No account configured" }, 500);
|
|
6155
|
-
}
|
|
6156
6222
|
let agentSlug;
|
|
6157
6223
|
let resolveSource;
|
|
6158
6224
|
if (requestedSlug) {
|
|
@@ -6264,7 +6330,7 @@ ${result.result.text}` : result.result.text;
|
|
|
6264
6330
|
var chat_default = app2;
|
|
6265
6331
|
|
|
6266
6332
|
// server/routes/whatsapp.ts
|
|
6267
|
-
import { join as join7, resolve as
|
|
6333
|
+
import { join as join7, resolve as resolve10 } from "path";
|
|
6268
6334
|
import { readdirSync as readdirSync3, readFileSync as readFileSync8, existsSync as existsSync5 } from "fs";
|
|
6269
6335
|
|
|
6270
6336
|
// app/lib/whatsapp/login.ts
|
|
@@ -6272,10 +6338,10 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
6272
6338
|
|
|
6273
6339
|
// app/lib/whatsapp/config-persist.ts
|
|
6274
6340
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
6275
|
-
import { resolve as
|
|
6341
|
+
import { resolve as resolve9, join as join5 } from "path";
|
|
6276
6342
|
var TAG18 = "[whatsapp:config]";
|
|
6277
6343
|
function configPath(accountDir) {
|
|
6278
|
-
return
|
|
6344
|
+
return resolve9(accountDir, "account.json");
|
|
6279
6345
|
}
|
|
6280
6346
|
function readConfig(accountDir) {
|
|
6281
6347
|
const path2 = configPath(accountDir);
|
|
@@ -6682,8 +6748,8 @@ async function startLogin(opts) {
|
|
|
6682
6748
|
await clearAuth(authDir);
|
|
6683
6749
|
let resolveCode = null;
|
|
6684
6750
|
let rejectCode = null;
|
|
6685
|
-
const codePromise = new Promise((
|
|
6686
|
-
resolveCode =
|
|
6751
|
+
const codePromise = new Promise((resolve31, reject) => {
|
|
6752
|
+
resolveCode = resolve31;
|
|
6687
6753
|
rejectCode = reject;
|
|
6688
6754
|
});
|
|
6689
6755
|
const codeTimer = setTimeout(
|
|
@@ -7080,14 +7146,14 @@ app3.post("/config", async (c) => {
|
|
|
7080
7146
|
return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
|
|
7081
7147
|
}
|
|
7082
7148
|
case "list-public-agents": {
|
|
7083
|
-
const agentsDir =
|
|
7149
|
+
const agentsDir = resolve10(account.accountDir, "agents");
|
|
7084
7150
|
const agents = [];
|
|
7085
7151
|
if (existsSync5(agentsDir)) {
|
|
7086
7152
|
try {
|
|
7087
7153
|
const entries = readdirSync3(agentsDir, { withFileTypes: true });
|
|
7088
7154
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7089
7155
|
if (!entry.isDirectory() || entry.name === "admin") continue;
|
|
7090
|
-
const configPath2 =
|
|
7156
|
+
const configPath2 = resolve10(agentsDir, entry.name, "config.json");
|
|
7091
7157
|
if (!existsSync5(configPath2)) continue;
|
|
7092
7158
|
try {
|
|
7093
7159
|
const config = JSON.parse(readFileSync8(configPath2, "utf-8"));
|
|
@@ -7360,15 +7426,17 @@ var whatsapp_default = app3;
|
|
|
7360
7426
|
|
|
7361
7427
|
// server/routes/whatsapp-reader.ts
|
|
7362
7428
|
import { readFileSync as readFileSync11, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync6 } from "fs";
|
|
7363
|
-
import { basename as basename2, dirname, join as join10, resolve as
|
|
7429
|
+
import { basename as basename2, dirname, join as join10, resolve as resolve12, sep as sep3 } from "path";
|
|
7364
7430
|
|
|
7365
7431
|
// server/routes/admin/sidebar-sessions.ts
|
|
7366
7432
|
import { readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync2 } from "fs";
|
|
7367
|
-
import { join as join8, resolve as
|
|
7433
|
+
import { join as join8, resolve as resolve11 } from "path";
|
|
7368
7434
|
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;
|
|
7369
7435
|
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7370
7436
|
var PUBLIC_ROLE = "public";
|
|
7437
|
+
var ADMIN_ROLE = "admin";
|
|
7371
7438
|
var WEBCHAT_CHANNEL = "webchat";
|
|
7439
|
+
var WHATSAPP_CHANNEL = "whatsapp";
|
|
7372
7440
|
var app4 = new Hono();
|
|
7373
7441
|
function claudeConfigDir() {
|
|
7374
7442
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
@@ -7481,7 +7549,7 @@ function loadUserTitles(accountDir) {
|
|
|
7481
7549
|
return out;
|
|
7482
7550
|
}
|
|
7483
7551
|
function readSidecarMeta(metaPath) {
|
|
7484
|
-
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null };
|
|
7552
|
+
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null };
|
|
7485
7553
|
let raw;
|
|
7486
7554
|
try {
|
|
7487
7555
|
raw = readFileSync9(metaPath, "utf8");
|
|
@@ -7502,7 +7570,9 @@ function readSidecarMeta(metaPath) {
|
|
|
7502
7570
|
role: typeof r.role === "string" ? r.role : null,
|
|
7503
7571
|
channel: typeof r.channel === "string" ? r.channel : null,
|
|
7504
7572
|
senderId: typeof r.senderId === "string" ? r.senderId : null,
|
|
7505
|
-
startedAt: typeof r.startedAt === "string" ? r.startedAt : null
|
|
7573
|
+
startedAt: typeof r.startedAt === "string" ? r.startedAt : null,
|
|
7574
|
+
personId: typeof r.personId === "string" ? r.personId : null,
|
|
7575
|
+
adminUserId: typeof r.adminUserId === "string" ? r.adminUserId : null
|
|
7506
7576
|
};
|
|
7507
7577
|
}
|
|
7508
7578
|
function startsWithCliMarker(s) {
|
|
@@ -7512,9 +7582,29 @@ function startsWithCliMarker(s) {
|
|
|
7512
7582
|
function trimToTitle(raw) {
|
|
7513
7583
|
return raw.trim().replace(/\s+/g, " ");
|
|
7514
7584
|
}
|
|
7585
|
+
var CHANNEL_WRAPPER = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
7586
|
+
var SOURCE_ATTR = /\bsource="([^"]+)"/;
|
|
7587
|
+
var CHANNEL_SOURCE_MAP = {
|
|
7588
|
+
whatsapp: "whatsapp",
|
|
7589
|
+
"whatsapp-channel": "whatsapp",
|
|
7590
|
+
webchat: "webchat",
|
|
7591
|
+
"webchat-channel": "webchat"
|
|
7592
|
+
};
|
|
7593
|
+
function stripChannelEnvelope(text) {
|
|
7594
|
+
const m = text.match(CHANNEL_WRAPPER);
|
|
7595
|
+
if (!m) return { inner: text, channel: null };
|
|
7596
|
+
let raw = m[1].match(SOURCE_ATTR)?.[1] ?? "";
|
|
7597
|
+
let inner = m[2];
|
|
7598
|
+
const im = inner.match(CHANNEL_WRAPPER);
|
|
7599
|
+
const innerRaw = im?.[1].match(SOURCE_ATTR)?.[1];
|
|
7600
|
+
if (im && innerRaw) {
|
|
7601
|
+
raw = innerRaw;
|
|
7602
|
+
inner = im[2];
|
|
7603
|
+
}
|
|
7604
|
+
return { inner, channel: CHANNEL_SOURCE_MAP[raw] ?? (raw || null) };
|
|
7605
|
+
}
|
|
7515
7606
|
function resolveTitle(body, sessionId, userTitles) {
|
|
7516
7607
|
const userTitle = userTitles.get(sessionId);
|
|
7517
|
-
if (userTitle) return { title: trimToTitle(userTitle), source: "user" };
|
|
7518
7608
|
let aiTitle = null;
|
|
7519
7609
|
let firstUserMessage = null;
|
|
7520
7610
|
for (const line of body.split("\n")) {
|
|
@@ -7541,9 +7631,12 @@ function resolveTitle(body, sessionId, userTitles) {
|
|
|
7541
7631
|
firstUserMessage = trimmed;
|
|
7542
7632
|
}
|
|
7543
7633
|
}
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
return { title:
|
|
7634
|
+
const stripped = firstUserMessage !== null ? stripChannelEnvelope(firstUserMessage) : { inner: null, channel: null };
|
|
7635
|
+
const channel = stripped.channel;
|
|
7636
|
+
if (userTitle) return { title: trimToTitle(userTitle), source: "user", channel };
|
|
7637
|
+
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai", channel };
|
|
7638
|
+
if (stripped.inner) return { title: trimToTitle(stripped.inner), source: "first-message", channel };
|
|
7639
|
+
return { title: sessionId.slice(0, 8), source: "prefix", channel };
|
|
7547
7640
|
}
|
|
7548
7641
|
app4.get("/", requireAdminSession, async (c) => {
|
|
7549
7642
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
@@ -7555,7 +7648,7 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7555
7648
|
const projectsRoot = join8(configDir2, "projects");
|
|
7556
7649
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
7557
7650
|
const liveSessions = await fetchLiveSessions();
|
|
7558
|
-
const accountDir = accountId ?
|
|
7651
|
+
const accountDir = accountId ? resolve11(ACCOUNTS_DIR, accountId) : null;
|
|
7559
7652
|
const userTitles = loadUserTitles(accountDir);
|
|
7560
7653
|
const rows = [];
|
|
7561
7654
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -7564,6 +7657,8 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7564
7657
|
let nonResumableCount = 0;
|
|
7565
7658
|
let archivedCount = 0;
|
|
7566
7659
|
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
7660
|
+
const personIdBySession = /* @__PURE__ */ new Map();
|
|
7661
|
+
const adminUserIdBySession = /* @__PURE__ */ new Map();
|
|
7567
7662
|
for (const { path: path2, isSubagent, archived } of jsonls) {
|
|
7568
7663
|
const lastSlash = path2.lastIndexOf("/");
|
|
7569
7664
|
const base = path2.slice(lastSlash + 1);
|
|
@@ -7587,8 +7682,12 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7587
7682
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
7588
7683
|
titleSourceCounts[resolved.source] += 1;
|
|
7589
7684
|
const metaPath = join8(projectDir, `${sessionId}.meta.json`);
|
|
7590
|
-
const { bridgeIds, role, channel } = readSidecarMeta(metaPath);
|
|
7591
|
-
const resumable = !(role === PUBLIC_ROLE &&
|
|
7685
|
+
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId } = readSidecarMeta(metaPath);
|
|
7686
|
+
const resumable = !(role === PUBLIC_ROLE && (sidecarChannel === WEBCHAT_CHANNEL || sidecarChannel === WHATSAPP_CHANNEL));
|
|
7687
|
+
if (personId) personIdBySession.set(sessionId, personId);
|
|
7688
|
+
if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
|
|
7689
|
+
adminUserIdBySession.set(sessionId, adminUserId);
|
|
7690
|
+
}
|
|
7592
7691
|
rows.push({
|
|
7593
7692
|
sessionId,
|
|
7594
7693
|
title: resolved.title,
|
|
@@ -7600,30 +7699,59 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7600
7699
|
projectDir,
|
|
7601
7700
|
bridgeIds,
|
|
7602
7701
|
resumable,
|
|
7603
|
-
archived
|
|
7702
|
+
archived,
|
|
7703
|
+
channel: resolved.channel,
|
|
7704
|
+
personName: null
|
|
7604
7705
|
});
|
|
7605
7706
|
if (live) liveCount += 1;
|
|
7606
7707
|
if (isSubagent) subagentCount += 1;
|
|
7607
7708
|
if (!resumable) nonResumableCount += 1;
|
|
7608
7709
|
if (archived) archivedCount += 1;
|
|
7609
7710
|
}
|
|
7711
|
+
let personNameCount = 0;
|
|
7712
|
+
let adminNameCount = 0;
|
|
7713
|
+
if (accountId) {
|
|
7714
|
+
await Promise.all(
|
|
7715
|
+
rows.map(async (row) => {
|
|
7716
|
+
if (row.titleSource !== "first-message" && row.titleSource !== "prefix") return;
|
|
7717
|
+
const pid = personIdBySession.get(row.sessionId);
|
|
7718
|
+
if (pid) {
|
|
7719
|
+
const name = await loadPersonNameByElementId(accountId, pid);
|
|
7720
|
+
if (name) {
|
|
7721
|
+
row.personName = name;
|
|
7722
|
+
personNameCount += 1;
|
|
7723
|
+
}
|
|
7724
|
+
return;
|
|
7725
|
+
}
|
|
7726
|
+
const auid = adminUserIdBySession.get(row.sessionId);
|
|
7727
|
+
if (auid) {
|
|
7728
|
+
const resolved = await loadAdminUserName(accountId, auid);
|
|
7729
|
+
if (resolved.source === "neo4j") {
|
|
7730
|
+
row.personName = resolved.joined;
|
|
7731
|
+
adminNameCount += 1;
|
|
7732
|
+
}
|
|
7733
|
+
}
|
|
7734
|
+
})
|
|
7735
|
+
);
|
|
7736
|
+
}
|
|
7610
7737
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
7611
7738
|
console.log(
|
|
7612
|
-
`[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} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
7739
|
+
`[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"}`
|
|
7613
7740
|
);
|
|
7614
7741
|
return c.json({ sessions: rows, accountId });
|
|
7615
7742
|
});
|
|
7616
7743
|
var sidebar_sessions_default = app4;
|
|
7617
7744
|
|
|
7618
7745
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
7619
|
-
function
|
|
7620
|
-
return rows.filter((r) => r.role === "admin" && (r.channel === "whatsapp" || r.channel === "telegram")).sort((a, b) => b.startedAt.localeCompare(a.startedAt)).map((r) => ({
|
|
7746
|
+
function selectReaderChannelSessions(rows) {
|
|
7747
|
+
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) => ({
|
|
7621
7748
|
sessionId: r.sessionId,
|
|
7622
7749
|
projectDir: r.projectDir,
|
|
7623
7750
|
title: r.title,
|
|
7624
7751
|
senderId: r.senderId,
|
|
7625
7752
|
startedAt: r.startedAt,
|
|
7626
7753
|
channel: r.channel,
|
|
7754
|
+
role: r.role,
|
|
7627
7755
|
operatorName: null,
|
|
7628
7756
|
whatsappName: null,
|
|
7629
7757
|
lastMessageAt: r.lastMessageAt
|
|
@@ -7727,14 +7855,26 @@ function resolveOperatorDisplay(userIdRes, nameRes) {
|
|
|
7727
7855
|
return { name: null, reason: "no-person-name" };
|
|
7728
7856
|
}
|
|
7729
7857
|
|
|
7858
|
+
// app/lib/agent-errors.ts
|
|
7859
|
+
function classifyAgentError(err) {
|
|
7860
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7861
|
+
if (/\b(401|authentication_error|OAuth token has expired)\b/i.test(msg)) return "auth_expired";
|
|
7862
|
+
if (/\b(529|overloaded)\b/i.test(msg)) return "claude_overloaded";
|
|
7863
|
+
if (/\b(404|model_not_found)\b/i.test(msg) || /issue with the selected model|may not have access to it/i.test(msg))
|
|
7864
|
+
return "model_unavailable";
|
|
7865
|
+
if (/\b(500|api_error|internal server error)\b/i.test(msg)) return "claude_down";
|
|
7866
|
+
return "agent_error";
|
|
7867
|
+
}
|
|
7868
|
+
|
|
7730
7869
|
// app/lib/whatsapp-reader/parse-transcript.ts
|
|
7731
7870
|
var WA_REPLY_TOOL = "mcp__whatsapp-channel__reply";
|
|
7732
7871
|
var WA_REPLY_DOCUMENT_TOOL = "mcp__whatsapp-channel__reply-document";
|
|
7733
7872
|
var WEBCHAT_REPLY_TOOL = "mcp__webchat-channel__reply";
|
|
7734
7873
|
var CHANNEL_REPLY_TOOL = "mcp__channel__reply";
|
|
7874
|
+
var CHANNEL_REPLY_DOCUMENT_TOOL = "mcp__channel__reply-document";
|
|
7735
7875
|
var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7736
|
-
var
|
|
7737
|
-
var
|
|
7876
|
+
var CHANNEL_WRAPPER2 = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
7877
|
+
var SOURCE_ATTR2 = /\bsource="([^"]+)"/;
|
|
7738
7878
|
var SOURCE_MAP = {
|
|
7739
7879
|
whatsapp: "whatsapp",
|
|
7740
7880
|
"whatsapp-channel": "whatsapp",
|
|
@@ -7742,13 +7882,13 @@ var SOURCE_MAP = {
|
|
|
7742
7882
|
"webchat-channel": "webchat"
|
|
7743
7883
|
};
|
|
7744
7884
|
function unwrapChannel(text) {
|
|
7745
|
-
const m = text.match(
|
|
7885
|
+
const m = text.match(CHANNEL_WRAPPER2);
|
|
7746
7886
|
if (!m) return { text };
|
|
7747
|
-
let source = SOURCE_MAP[m[1].match(
|
|
7887
|
+
let source = SOURCE_MAP[m[1].match(SOURCE_ATTR2)?.[1] ?? ""];
|
|
7748
7888
|
let inner = m[2];
|
|
7749
|
-
const im = inner.match(
|
|
7889
|
+
const im = inner.match(CHANNEL_WRAPPER2);
|
|
7750
7890
|
if (im) {
|
|
7751
|
-
const innerSource = SOURCE_MAP[im[1].match(
|
|
7891
|
+
const innerSource = SOURCE_MAP[im[1].match(SOURCE_ATTR2)?.[1] ?? ""];
|
|
7752
7892
|
if (innerSource) {
|
|
7753
7893
|
source = innerSource;
|
|
7754
7894
|
inner = im[2];
|
|
@@ -7762,6 +7902,17 @@ function asString(content) {
|
|
|
7762
7902
|
function tsOf(row) {
|
|
7763
7903
|
return typeof row.timestamp === "string" ? row.timestamp : null;
|
|
7764
7904
|
}
|
|
7905
|
+
function joinTextBlocks(content) {
|
|
7906
|
+
if (!Array.isArray(content)) return "";
|
|
7907
|
+
const parts = [];
|
|
7908
|
+
for (const block of content) {
|
|
7909
|
+
if (block && typeof block === "object") {
|
|
7910
|
+
const b = block;
|
|
7911
|
+
if (b.type === "text" && typeof b.text === "string") parts.push(b.text);
|
|
7912
|
+
}
|
|
7913
|
+
}
|
|
7914
|
+
return parts.join("");
|
|
7915
|
+
}
|
|
7765
7916
|
function assistantTurns(content, ts) {
|
|
7766
7917
|
if (!Array.isArray(content)) return [];
|
|
7767
7918
|
const out = [];
|
|
@@ -7773,7 +7924,7 @@ function assistantTurns(content, ts) {
|
|
|
7773
7924
|
} else if (b.type === "tool_use" && (b.name === WA_REPLY_TOOL || b.name === WEBCHAT_REPLY_TOOL || b.name === CHANNEL_REPLY_TOOL)) {
|
|
7774
7925
|
const text = b.input?.text;
|
|
7775
7926
|
out.push({ kind: "agent-reply", text: typeof text === "string" ? text : "", ts });
|
|
7776
|
-
} else if (b.type === "tool_use" && b.name === WA_REPLY_DOCUMENT_TOOL) {
|
|
7927
|
+
} else if (b.type === "tool_use" && (b.name === WA_REPLY_DOCUMENT_TOOL || b.name === CHANNEL_REPLY_DOCUMENT_TOOL)) {
|
|
7777
7928
|
const input = b.input ?? {};
|
|
7778
7929
|
const files = Array.isArray(input.files) ? input.files.filter((f) => typeof f === "string") : [];
|
|
7779
7930
|
const caption = typeof input.caption === "string" ? input.caption : null;
|
|
@@ -7819,6 +7970,14 @@ function parseTranscript(lines) {
|
|
|
7819
7970
|
const ts = tsOf(row);
|
|
7820
7971
|
const msg = row.message;
|
|
7821
7972
|
if (row.type === "assistant") {
|
|
7973
|
+
if (row.isApiErrorMessage === true) {
|
|
7974
|
+
const raw = joinTextBlocks(msg?.content);
|
|
7975
|
+
const status = typeof row.apiErrorStatus === "number" ? String(row.apiErrorStatus) : "";
|
|
7976
|
+
const errorSlug = typeof row.error === "string" ? row.error : "";
|
|
7977
|
+
const code = classifyAgentError(`${status} ${errorSlug} ${raw}`.trim());
|
|
7978
|
+
out.push({ kind: "agent-error", code, raw, ts });
|
|
7979
|
+
continue;
|
|
7980
|
+
}
|
|
7822
7981
|
out.push(...assistantTurns(msg?.content, ts));
|
|
7823
7982
|
continue;
|
|
7824
7983
|
}
|
|
@@ -7882,7 +8041,9 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
7882
8041
|
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7883
8042
|
const projectDir = dirname(path2);
|
|
7884
8043
|
const meta = readSidecarMeta(join10(projectDir, `${sessionId}.meta.json`));
|
|
7885
|
-
|
|
8044
|
+
const isAdminChannel = meta.role === "admin" && (meta.channel === "whatsapp" || meta.channel === "telegram");
|
|
8045
|
+
const isPublicChannel = meta.role === "public" && (meta.channel === "whatsapp" || meta.channel === "webchat");
|
|
8046
|
+
if (!isAdminChannel && !isPublicChannel) continue;
|
|
7886
8047
|
let body = "";
|
|
7887
8048
|
try {
|
|
7888
8049
|
body = readFileSync11(path2, "utf8");
|
|
@@ -7901,7 +8062,7 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
7901
8062
|
lastMessageAt
|
|
7902
8063
|
});
|
|
7903
8064
|
}
|
|
7904
|
-
const selected =
|
|
8065
|
+
const selected = selectReaderChannelSessions(rows);
|
|
7905
8066
|
const account = resolveAccount();
|
|
7906
8067
|
let users = [];
|
|
7907
8068
|
if (account) {
|
|
@@ -7968,12 +8129,12 @@ app5.get("/stream", requireAdminSession, (c) => {
|
|
|
7968
8129
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7969
8130
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7970
8131
|
const cfg = claudeConfigDir();
|
|
7971
|
-
const projectsRoot = cfg ?
|
|
8132
|
+
const projectsRoot = cfg ? resolve12(join10(cfg, "projects")) : null;
|
|
7972
8133
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7973
8134
|
return c.json({ error: "bad session reference" }, 400);
|
|
7974
8135
|
}
|
|
7975
|
-
const jsonlPath =
|
|
7976
|
-
if (!jsonlPath.startsWith(projectsRoot +
|
|
8136
|
+
const jsonlPath = resolve12(join10(projectDir, `${sessionId}.jsonl`));
|
|
8137
|
+
if (!jsonlPath.startsWith(projectsRoot + sep3)) {
|
|
7977
8138
|
return c.json({ error: "bad session reference" }, 400);
|
|
7978
8139
|
}
|
|
7979
8140
|
const encoder = new TextEncoder();
|
|
@@ -8004,6 +8165,9 @@ data: ${JSON.stringify(turn)}
|
|
|
8004
8165
|
let n = 0;
|
|
8005
8166
|
for (const turn of parseTranscript(lines)) {
|
|
8006
8167
|
send(controller, turn, offset);
|
|
8168
|
+
if (turn.kind === "agent-error") {
|
|
8169
|
+
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
8170
|
+
}
|
|
8007
8171
|
n++;
|
|
8008
8172
|
}
|
|
8009
8173
|
if (n > 0) console.log(`[wa-stream] op=drain conn=${connId} turns=${n}`);
|
|
@@ -8017,6 +8181,9 @@ data: ${JSON.stringify(turn)}
|
|
|
8017
8181
|
let n = 0;
|
|
8018
8182
|
for (const turn of parseTranscript(buf.toString("utf8").split("\n"))) {
|
|
8019
8183
|
send(controller, turn, offset);
|
|
8184
|
+
if (turn.kind === "agent-error") {
|
|
8185
|
+
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
8186
|
+
}
|
|
8020
8187
|
n++;
|
|
8021
8188
|
}
|
|
8022
8189
|
console.log(`[wa-stream] op=backlog conn=${connId} turns=${n} bytes=${end}`);
|
|
@@ -8059,7 +8226,7 @@ var DIRECTIVE_NAME_RE = /^\d+-\d+\.txt$/;
|
|
|
8059
8226
|
function directiveStoreDir(sessionId) {
|
|
8060
8227
|
const account = resolveAccount();
|
|
8061
8228
|
if (!account) return null;
|
|
8062
|
-
return
|
|
8229
|
+
return resolve12(account.accountDir, "logs", "prompt-optimiser-directives", sessionId);
|
|
8063
8230
|
}
|
|
8064
8231
|
app5.get("/directives", requireAdminSession, (c) => {
|
|
8065
8232
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
@@ -8093,8 +8260,8 @@ app5.get("/directive", requireAdminSession, (c) => {
|
|
|
8093
8260
|
}
|
|
8094
8261
|
const dir = directiveStoreDir(sessionId);
|
|
8095
8262
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
8096
|
-
const path2 =
|
|
8097
|
-
if (!path2.startsWith(dir +
|
|
8263
|
+
const path2 = resolve12(join10(dir, name));
|
|
8264
|
+
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
8098
8265
|
let body;
|
|
8099
8266
|
try {
|
|
8100
8267
|
body = readFileSync11(path2, "utf8");
|
|
@@ -8430,7 +8597,7 @@ ${note}` : note;
|
|
|
8430
8597
|
}
|
|
8431
8598
|
|
|
8432
8599
|
// server/routes/webchat-greeting.ts
|
|
8433
|
-
import { resolve as
|
|
8600
|
+
import { resolve as resolve13 } from "path";
|
|
8434
8601
|
|
|
8435
8602
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8436
8603
|
import { existsSync as existsSync9, readFileSync as readFileSync13, readdirSync as readdirSync8 } from "fs";
|
|
@@ -8535,7 +8702,7 @@ app6.get("/", requireAdminSession, async (c) => {
|
|
|
8535
8702
|
let specialists = [];
|
|
8536
8703
|
try {
|
|
8537
8704
|
const roster = readSpecialistRoster(
|
|
8538
|
-
|
|
8705
|
+
resolve13(ACCOUNTS_DIR, accountId, "specialists", "agents")
|
|
8539
8706
|
);
|
|
8540
8707
|
specialists = roster.specialists;
|
|
8541
8708
|
for (const s of roster.skipped) {
|
|
@@ -8570,7 +8737,7 @@ var webchat_greeting_default = app6;
|
|
|
8570
8737
|
|
|
8571
8738
|
// server/routes/telegram.ts
|
|
8572
8739
|
import { homedir } from "os";
|
|
8573
|
-
import { resolve as
|
|
8740
|
+
import { resolve as resolve14, join as join13 } from "path";
|
|
8574
8741
|
import { existsSync as existsSync10, readFileSync as readFileSync14 } from "fs";
|
|
8575
8742
|
|
|
8576
8743
|
// app/lib/telegram/access-control.ts
|
|
@@ -8621,7 +8788,7 @@ function routeTelegramUpdate(input) {
|
|
|
8621
8788
|
var TAG22 = "[telegram-inbound]";
|
|
8622
8789
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
8623
8790
|
function configDirName() {
|
|
8624
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
8791
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
8625
8792
|
const brandPath = join13(platformRoot2, "config", "brand.json");
|
|
8626
8793
|
if (existsSync10(brandPath)) {
|
|
8627
8794
|
try {
|
|
@@ -8633,7 +8800,7 @@ function configDirName() {
|
|
|
8633
8800
|
}
|
|
8634
8801
|
function secretPath(botType) {
|
|
8635
8802
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
8636
|
-
return
|
|
8803
|
+
return resolve14(homedir(), configDirName(), filename);
|
|
8637
8804
|
}
|
|
8638
8805
|
async function sendTelegram(botToken, chatId, text) {
|
|
8639
8806
|
try {
|
|
@@ -9448,7 +9615,7 @@ var session_default = app10;
|
|
|
9448
9615
|
|
|
9449
9616
|
// server/routes/admin/logs.ts
|
|
9450
9617
|
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync17, statSync as statSync7 } from "fs";
|
|
9451
|
-
import { resolve as
|
|
9618
|
+
import { resolve as resolve15, basename as basename4 } from "path";
|
|
9452
9619
|
|
|
9453
9620
|
// app/lib/logs-read-resolve.ts
|
|
9454
9621
|
import { existsSync as existsSync14 } from "fs";
|
|
@@ -9475,7 +9642,7 @@ app11.get("/", async (c) => {
|
|
|
9475
9642
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
9476
9643
|
const download = c.req.query("download") === "1";
|
|
9477
9644
|
const account = resolveAccount();
|
|
9478
|
-
const accountLogDir = account ?
|
|
9645
|
+
const accountLogDir = account ? resolve15(account.accountDir, "logs") : null;
|
|
9479
9646
|
const logDirs = [];
|
|
9480
9647
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
9481
9648
|
logDirs.push(LOG_DIR);
|
|
@@ -9483,7 +9650,7 @@ app11.get("/", async (c) => {
|
|
|
9483
9650
|
const safe = basename4(fileParam);
|
|
9484
9651
|
const searched = [];
|
|
9485
9652
|
for (const dir of logDirs) {
|
|
9486
|
-
const filePath =
|
|
9653
|
+
const filePath = resolve15(dir, safe);
|
|
9487
9654
|
searched.push(filePath);
|
|
9488
9655
|
try {
|
|
9489
9656
|
const buffer = readFileSync17(filePath);
|
|
@@ -9595,10 +9762,10 @@ app11.get("/", async (c) => {
|
|
|
9595
9762
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
9596
9763
|
continue;
|
|
9597
9764
|
}
|
|
9598
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(
|
|
9765
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve15(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
9599
9766
|
seen.add(name);
|
|
9600
9767
|
try {
|
|
9601
|
-
const content = readFileSync17(
|
|
9768
|
+
const content = readFileSync17(resolve15(dir, name));
|
|
9602
9769
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
9603
9770
|
logs[name] = tail.trim() || "(empty)";
|
|
9604
9771
|
} catch (err) {
|
|
@@ -9638,7 +9805,7 @@ var claude_info_default = app12;
|
|
|
9638
9805
|
// server/routes/admin/attachment.ts
|
|
9639
9806
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
9640
9807
|
import { existsSync as existsSync16 } from "fs";
|
|
9641
|
-
import { resolve as
|
|
9808
|
+
import { resolve as resolve16 } from "path";
|
|
9642
9809
|
var app13 = new Hono();
|
|
9643
9810
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
9644
9811
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -9650,11 +9817,11 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9650
9817
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
9651
9818
|
return new Response("Not found", { status: 404 });
|
|
9652
9819
|
}
|
|
9653
|
-
const dir =
|
|
9820
|
+
const dir = resolve16(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
9654
9821
|
if (!existsSync16(dir)) {
|
|
9655
9822
|
return new Response("Not found", { status: 404 });
|
|
9656
9823
|
}
|
|
9657
|
-
const metaPath =
|
|
9824
|
+
const metaPath = resolve16(dir, `${attachmentId}.meta.json`);
|
|
9658
9825
|
if (!existsSync16(metaPath)) {
|
|
9659
9826
|
return new Response("Not found", { status: 404 });
|
|
9660
9827
|
}
|
|
@@ -9669,7 +9836,7 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9669
9836
|
if (!dataFile) {
|
|
9670
9837
|
return new Response("Not found", { status: 404 });
|
|
9671
9838
|
}
|
|
9672
|
-
const filePath =
|
|
9839
|
+
const filePath = resolve16(dir, dataFile);
|
|
9673
9840
|
const buffer = await readFile2(filePath);
|
|
9674
9841
|
return new Response(new Uint8Array(buffer), {
|
|
9675
9842
|
headers: {
|
|
@@ -9682,13 +9849,13 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9682
9849
|
var attachment_default = app13;
|
|
9683
9850
|
|
|
9684
9851
|
// server/routes/admin/agents.ts
|
|
9685
|
-
import { resolve as
|
|
9852
|
+
import { resolve as resolve17 } from "path";
|
|
9686
9853
|
import { readdirSync as readdirSync11, readFileSync as readFileSync18, existsSync as existsSync17, rmSync } from "fs";
|
|
9687
9854
|
var app14 = new Hono();
|
|
9688
9855
|
app14.get("/", (c) => {
|
|
9689
9856
|
const account = resolveAccount();
|
|
9690
9857
|
if (!account) return c.json({ agents: [] });
|
|
9691
|
-
const agentsDir =
|
|
9858
|
+
const agentsDir = resolve17(account.accountDir, "agents");
|
|
9692
9859
|
if (!existsSync17(agentsDir)) return c.json({ agents: [] });
|
|
9693
9860
|
const agents = [];
|
|
9694
9861
|
try {
|
|
@@ -9696,7 +9863,7 @@ app14.get("/", (c) => {
|
|
|
9696
9863
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
9697
9864
|
if (!entry.isDirectory()) continue;
|
|
9698
9865
|
if (entry.name === "admin") continue;
|
|
9699
|
-
const configPath2 =
|
|
9866
|
+
const configPath2 = resolve17(agentsDir, entry.name, "config.json");
|
|
9700
9867
|
if (!existsSync17(configPath2)) continue;
|
|
9701
9868
|
try {
|
|
9702
9869
|
const config = JSON.parse(readFileSync18(configPath2, "utf-8"));
|
|
@@ -9725,7 +9892,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
9725
9892
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9726
9893
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9727
9894
|
}
|
|
9728
|
-
const agentDir =
|
|
9895
|
+
const agentDir = resolve17(account.accountDir, "agents", slug);
|
|
9729
9896
|
if (!existsSync17(agentDir)) {
|
|
9730
9897
|
return c.json({ error: "Agent not found" }, 404);
|
|
9731
9898
|
}
|
|
@@ -9755,7 +9922,7 @@ app14.post("/:slug/project", async (c) => {
|
|
|
9755
9922
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9756
9923
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9757
9924
|
}
|
|
9758
|
-
const agentDir =
|
|
9925
|
+
const agentDir = resolve17(account.accountDir, "agents", slug);
|
|
9759
9926
|
if (!existsSync17(agentDir)) {
|
|
9760
9927
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9761
9928
|
}
|
|
@@ -10459,7 +10626,7 @@ var sessions_default = app15;
|
|
|
10459
10626
|
|
|
10460
10627
|
// app/lib/claude-agent/spawn-context.ts
|
|
10461
10628
|
import { existsSync as existsSync19, readFileSync as readFileSync19, readdirSync as readdirSync12, statSync as statSync8 } from "fs";
|
|
10462
|
-
import { dirname as dirname4, resolve as
|
|
10629
|
+
import { dirname as dirname4, resolve as resolve18, join as join17 } from "path";
|
|
10463
10630
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10464
10631
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10465
10632
|
try {
|
|
@@ -10544,7 +10711,7 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
10544
10711
|
}
|
|
10545
10712
|
function listPluginDirs() {
|
|
10546
10713
|
const out = /* @__PURE__ */ new Map();
|
|
10547
|
-
const platformPlugins =
|
|
10714
|
+
const platformPlugins = resolve18(PLATFORM_ROOT, "plugins");
|
|
10548
10715
|
if (existsSync19(platformPlugins)) {
|
|
10549
10716
|
for (const name of readdirSync12(platformPlugins)) {
|
|
10550
10717
|
const dir = join17(platformPlugins, name);
|
|
@@ -10554,7 +10721,7 @@ function listPluginDirs() {
|
|
|
10554
10721
|
}
|
|
10555
10722
|
}
|
|
10556
10723
|
}
|
|
10557
|
-
const premiumRoot =
|
|
10724
|
+
const premiumRoot = resolve18(dirname4(PLATFORM_ROOT), "premium-plugins");
|
|
10558
10725
|
if (existsSync19(premiumRoot)) {
|
|
10559
10726
|
for (const bundle of readdirSync12(premiumRoot)) {
|
|
10560
10727
|
const bundlePlugins = join17(premiumRoot, bundle, "plugins");
|
|
@@ -10574,7 +10741,7 @@ function listPluginDirs() {
|
|
|
10574
10741
|
return out;
|
|
10575
10742
|
}
|
|
10576
10743
|
function readEnabledPlugins(accountId) {
|
|
10577
|
-
const accountFile =
|
|
10744
|
+
const accountFile = resolve18(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10578
10745
|
if (!existsSync19(accountFile)) return /* @__PURE__ */ new Set();
|
|
10579
10746
|
try {
|
|
10580
10747
|
const parsed = JSON.parse(readFileSync19(accountFile, "utf-8"));
|
|
@@ -10647,7 +10814,7 @@ ${skillFm}
|
|
|
10647
10814
|
return out;
|
|
10648
10815
|
}
|
|
10649
10816
|
function computeSpecialistDomains(accountId) {
|
|
10650
|
-
const specialistsDir =
|
|
10817
|
+
const specialistsDir = resolve18(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10651
10818
|
if (!existsSync19(specialistsDir)) return [];
|
|
10652
10819
|
let entries;
|
|
10653
10820
|
try {
|
|
@@ -10693,7 +10860,7 @@ ${fm}
|
|
|
10693
10860
|
return out;
|
|
10694
10861
|
}
|
|
10695
10862
|
function computeDormantPlugins(accountId) {
|
|
10696
|
-
const accountFile =
|
|
10863
|
+
const accountFile = resolve18(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10697
10864
|
if (!existsSync19(accountFile)) return [];
|
|
10698
10865
|
let enabled;
|
|
10699
10866
|
try {
|
|
@@ -10708,7 +10875,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10708
10875
|
);
|
|
10709
10876
|
return [];
|
|
10710
10877
|
}
|
|
10711
|
-
const pluginsDir =
|
|
10878
|
+
const pluginsDir = resolve18(PLATFORM_ROOT, "plugins");
|
|
10712
10879
|
if (!existsSync19(pluginsDir)) return [];
|
|
10713
10880
|
let entries;
|
|
10714
10881
|
try {
|
|
@@ -10719,7 +10886,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10719
10886
|
const out = [];
|
|
10720
10887
|
for (const name of entries) {
|
|
10721
10888
|
if (enabled.has(name)) continue;
|
|
10722
|
-
const manifestPath =
|
|
10889
|
+
const manifestPath = resolve18(pluginsDir, name, "PLUGIN.md");
|
|
10723
10890
|
if (!existsSync19(manifestPath)) continue;
|
|
10724
10891
|
let manifest;
|
|
10725
10892
|
try {
|
|
@@ -10738,7 +10905,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10738
10905
|
|
|
10739
10906
|
// server/routes/admin/claude-sessions.ts
|
|
10740
10907
|
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
10741
|
-
import { resolve as
|
|
10908
|
+
import { resolve as resolve19 } from "path";
|
|
10742
10909
|
function readTunnelState(brandConfigDir) {
|
|
10743
10910
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10744
10911
|
if (!existsSync20(statePath)) return null;
|
|
@@ -10754,10 +10921,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10754
10921
|
}
|
|
10755
10922
|
}
|
|
10756
10923
|
function resolveTunnelUrl() {
|
|
10757
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
10924
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
10758
10925
|
let brand;
|
|
10759
10926
|
try {
|
|
10760
|
-
brand = JSON.parse(readFileSync20(
|
|
10927
|
+
brand = JSON.parse(readFileSync20(resolve19(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10761
10928
|
} catch {
|
|
10762
10929
|
return null;
|
|
10763
10930
|
}
|
|
@@ -11005,68 +11172,6 @@ import { realpathSync as realpathSync4 } from "fs";
|
|
|
11005
11172
|
import { basename as basename6, dirname as dirname5, join as join19, resolve as resolve21, sep as sep5 } from "path";
|
|
11006
11173
|
import { Readable as Readable2 } from "stream";
|
|
11007
11174
|
|
|
11008
|
-
// app/lib/data-path.ts
|
|
11009
|
-
import { realpathSync as realpathSync3 } from "fs";
|
|
11010
|
-
import { resolve as resolve19, normalize, sep as sep3, relative } from "path";
|
|
11011
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "../platform");
|
|
11012
|
-
var DATA_ROOT = resolve19(PLATFORM_ROOT6, "..", "data");
|
|
11013
|
-
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve19(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
11014
|
-
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
11015
|
-
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11016
|
-
function crossesForeignAccountPartition(relPath, accountId) {
|
|
11017
|
-
const segs = relPath.split("/").filter(Boolean);
|
|
11018
|
-
if (segs.length < 2) return false;
|
|
11019
|
-
if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
|
|
11020
|
-
const owner = segs[1];
|
|
11021
|
-
if (!ACCOUNT_UUID_RE.test(owner)) return false;
|
|
11022
|
-
return owner !== accountId;
|
|
11023
|
-
}
|
|
11024
|
-
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
11025
|
-
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
11026
|
-
const absolute = resolve19(rootAbs, cleaned);
|
|
11027
|
-
let rootReal;
|
|
11028
|
-
try {
|
|
11029
|
-
rootReal = realpathSync3(rootAbs);
|
|
11030
|
-
} catch (err) {
|
|
11031
|
-
return {
|
|
11032
|
-
ok: false,
|
|
11033
|
-
status: 500,
|
|
11034
|
-
error: `${rootLabel} not accessible: ${err instanceof Error ? err.message : String(err)}`
|
|
11035
|
-
};
|
|
11036
|
-
}
|
|
11037
|
-
let resolvedReal;
|
|
11038
|
-
try {
|
|
11039
|
-
resolvedReal = realpathSync3(absolute);
|
|
11040
|
-
} catch (err) {
|
|
11041
|
-
const code = err.code;
|
|
11042
|
-
if (code === "ENOENT") {
|
|
11043
|
-
if (absolute !== rootReal && !absolute.startsWith(rootReal + sep3)) {
|
|
11044
|
-
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: absolute };
|
|
11045
|
-
}
|
|
11046
|
-
return { ok: false, status: 404, error: "Not found" };
|
|
11047
|
-
}
|
|
11048
|
-
return {
|
|
11049
|
-
ok: false,
|
|
11050
|
-
status: 500,
|
|
11051
|
-
error: err instanceof Error ? err.message : String(err)
|
|
11052
|
-
};
|
|
11053
|
-
}
|
|
11054
|
-
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep3)) {
|
|
11055
|
-
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
|
|
11056
|
-
}
|
|
11057
|
-
const relPath = relative(rootReal, resolvedReal) || ".";
|
|
11058
|
-
return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath };
|
|
11059
|
-
}
|
|
11060
|
-
function resolveDataPath(raw) {
|
|
11061
|
-
return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
|
|
11062
|
-
}
|
|
11063
|
-
function resolveClaudeUploadsPath(raw) {
|
|
11064
|
-
if (!CLAUDE_UPLOADS_ROOT) {
|
|
11065
|
-
return { ok: false, status: 404, error: "Not found" };
|
|
11066
|
-
}
|
|
11067
|
-
return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
|
|
11068
|
-
}
|
|
11069
|
-
|
|
11070
11175
|
// ../lib/graph-trash/src/index.ts
|
|
11071
11176
|
var UNIQUE_KEYS_BY_LABEL = {
|
|
11072
11177
|
Person: ["email", "telephone"],
|
|
@@ -11304,11 +11409,11 @@ async function restoreNode(params) {
|
|
|
11304
11409
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11305
11410
|
function parseAttachmentPath(relPath) {
|
|
11306
11411
|
const segments = relPath.split("/").filter(Boolean);
|
|
11307
|
-
if (segments.length !==
|
|
11308
|
-
if (segments[0] !== "uploads") return null;
|
|
11412
|
+
if (segments.length !== 5) return null;
|
|
11413
|
+
if (segments[0] !== "accounts" || segments[2] !== "uploads") return null;
|
|
11309
11414
|
const accountId = segments[1];
|
|
11310
|
-
const attachmentId = segments[
|
|
11311
|
-
const filename = segments[
|
|
11415
|
+
const attachmentId = segments[3];
|
|
11416
|
+
const filename = segments[4];
|
|
11312
11417
|
if (!UUID_RE2.test(accountId) || !UUID_RE2.test(attachmentId)) return null;
|
|
11313
11418
|
const dot = filename.lastIndexOf(".");
|
|
11314
11419
|
if (dot === -1) return null;
|
|
@@ -11386,6 +11491,17 @@ import { resolve as resolve20, relative as relative2, join as join18, basename a
|
|
|
11386
11491
|
import { tmpdir as tmpdir2 } from "os";
|
|
11387
11492
|
import { execFile as execFile2 } from "child_process";
|
|
11388
11493
|
import { promisify as promisify2 } from "util";
|
|
11494
|
+
|
|
11495
|
+
// app/lib/migration-state.ts
|
|
11496
|
+
var inProgress = false;
|
|
11497
|
+
function setUploadsMigrationInProgress(value) {
|
|
11498
|
+
inProgress = value;
|
|
11499
|
+
}
|
|
11500
|
+
function uploadsMigrationInProgress() {
|
|
11501
|
+
return inProgress;
|
|
11502
|
+
}
|
|
11503
|
+
|
|
11504
|
+
// app/lib/file-index.ts
|
|
11389
11505
|
var execFileAsync2 = promisify2(execFile2);
|
|
11390
11506
|
var CONTENT_CAP = 1e5;
|
|
11391
11507
|
var OCR_TIMEOUT_MS = 3e4;
|
|
@@ -11690,7 +11806,6 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
11690
11806
|
return withSession(opts, async (session) => {
|
|
11691
11807
|
const walked = [];
|
|
11692
11808
|
const subtreeRoots = [
|
|
11693
|
-
resolve20(dataRoot, "uploads", accountId),
|
|
11694
11809
|
resolve20(dataRoot, "accounts", accountId)
|
|
11695
11810
|
];
|
|
11696
11811
|
let clean = true;
|
|
@@ -11727,7 +11842,9 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
11727
11842
|
}
|
|
11728
11843
|
let pruned = 0;
|
|
11729
11844
|
let cascadeKds = 0, cascadeSections = 0, cascadeChunks = 0;
|
|
11730
|
-
if (clean) {
|
|
11845
|
+
if (clean && uploadsMigrationInProgress()) {
|
|
11846
|
+
console.error(`[file-index] reconcile account=${accountId} prune-skipped reason="uploads-migration-in-progress"`);
|
|
11847
|
+
} else if (clean) {
|
|
11731
11848
|
const foundPaths = walked.map((w) => w.relativePath);
|
|
11732
11849
|
const goneRes = await session.run(
|
|
11733
11850
|
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
@@ -11958,7 +12075,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11958
12075
|
}
|
|
11959
12076
|
const names = await readdir3(absolute);
|
|
11960
12077
|
const segs = relPath.split("/").filter(Boolean);
|
|
11961
|
-
const isAccountParent = segs.length === 1 &&
|
|
12078
|
+
const isAccountParent = segs.length === 1 && segs[0] === "accounts";
|
|
11962
12079
|
const entries = [];
|
|
11963
12080
|
for (const name of names) {
|
|
11964
12081
|
if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
@@ -11967,6 +12084,8 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11967
12084
|
if (isAccountParent && UUID_RE3.test(name) && name !== accountId) {
|
|
11968
12085
|
continue;
|
|
11969
12086
|
}
|
|
12087
|
+
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12088
|
+
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
11970
12089
|
try {
|
|
11971
12090
|
const entryPath = join19(absolute, name);
|
|
11972
12091
|
const s = await stat4(entryPath);
|
|
@@ -11974,10 +12093,11 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11974
12093
|
name,
|
|
11975
12094
|
kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
|
|
11976
12095
|
sizeBytes: s.isDirectory() ? null : s.size,
|
|
11977
|
-
modifiedAt: s.mtime.toISOString()
|
|
12096
|
+
modifiedAt: s.mtime.toISOString(),
|
|
12097
|
+
protected: protectedEntry
|
|
11978
12098
|
});
|
|
11979
12099
|
} catch {
|
|
11980
|
-
entries.push({ name, kind: "other", sizeBytes: null, modifiedAt: (/* @__PURE__ */ new Date(0)).toISOString() });
|
|
12100
|
+
entries.push({ name, kind: "other", sizeBytes: null, modifiedAt: (/* @__PURE__ */ new Date(0)).toISOString(), protected: protectedEntry });
|
|
11981
12101
|
}
|
|
11982
12102
|
}
|
|
11983
12103
|
const accountNames = await readAccountNames();
|
|
@@ -12093,14 +12213,14 @@ app19.post("/upload", requireAdminSession, async (c) => {
|
|
|
12093
12213
|
}
|
|
12094
12214
|
const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
|
|
12095
12215
|
const finalName = `${Date.now()}-${safeName}`;
|
|
12096
|
-
const destDir = resolve21(DATA_ROOT, "
|
|
12216
|
+
const destDir = resolve21(DATA_ROOT, "accounts", accountId, "uploads");
|
|
12097
12217
|
const destPath = resolve21(destDir, finalName);
|
|
12098
12218
|
try {
|
|
12099
12219
|
await mkdir3(destDir, { recursive: true });
|
|
12100
12220
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
12101
12221
|
const destDirReal = realpathSync4(destDir);
|
|
12102
12222
|
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep5)) {
|
|
12103
|
-
console.error(`[data] path-traversal-blocked requested="
|
|
12223
|
+
console.error(`[data] path-traversal-blocked requested="accounts/${accountId}/uploads" resolved="${destDirReal}"`);
|
|
12104
12224
|
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
12105
12225
|
}
|
|
12106
12226
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
@@ -12110,7 +12230,7 @@ app19.post("/upload", requireAdminSession, async (c) => {
|
|
|
12110
12230
|
console.error(`[data] file-upload error filename="${safeName}" err="${message}"`);
|
|
12111
12231
|
return c.json({ error: message }, 500);
|
|
12112
12232
|
}
|
|
12113
|
-
const relativeDest = `
|
|
12233
|
+
const relativeDest = `accounts/${accountId}/uploads/${finalName}`;
|
|
12114
12234
|
console.error(`[data] file-upload filename="${safeName}" size=${file.size} dest="${relativeDest}"`);
|
|
12115
12235
|
void indexFile(accountId, relativeDest).catch((err) => {
|
|
12116
12236
|
console.error(`[data] file-upload index-failed dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
@@ -14245,13 +14365,14 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
14245
14365
|
const result = await session.run(
|
|
14246
14366
|
`MATCH (f:FileArtifact { accountId: $accountId })
|
|
14247
14367
|
WHERE f.relativePath STARTS WITH 'accounts/'
|
|
14368
|
+
AND NOT f.relativePath STARTS WITH $uploadsPrefix
|
|
14248
14369
|
RETURN f.relativePath AS relativePath,
|
|
14249
14370
|
f.displayName AS displayName,
|
|
14250
14371
|
f.mimeType AS mimeType,
|
|
14251
14372
|
f.modifiedAt AS modifiedAt
|
|
14252
14373
|
ORDER BY f.modifiedAt DESC
|
|
14253
14374
|
LIMIT 50`,
|
|
14254
|
-
{ accountId }
|
|
14375
|
+
{ accountId, uploadsPrefix: `accounts/${accountId}/uploads/` }
|
|
14255
14376
|
);
|
|
14256
14377
|
return result.records.map((r) => {
|
|
14257
14378
|
const relativePath = r.get("relativePath");
|
|
@@ -14507,7 +14628,7 @@ var session_archive_default = app29;
|
|
|
14507
14628
|
|
|
14508
14629
|
// server/routes/admin/session-rc-spawn.ts
|
|
14509
14630
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
14510
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10) {
|
|
14631
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, adminUserId) {
|
|
14511
14632
|
const operator = isOperatorHost(host, operatorDomains);
|
|
14512
14633
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
14513
14634
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -14525,6 +14646,7 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10) {
|
|
|
14525
14646
|
payload.senderId = key;
|
|
14526
14647
|
payload.webchatChannel = webchatChannelDescriptor(key);
|
|
14527
14648
|
if (name) payload.name = name;
|
|
14649
|
+
if (adminUserId) payload.adminUserId = adminUserId;
|
|
14528
14650
|
} else {
|
|
14529
14651
|
sessionId = resumeId;
|
|
14530
14652
|
payload.sessionId = resumeId;
|
|
@@ -14545,7 +14667,9 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14545
14667
|
body = {};
|
|
14546
14668
|
}
|
|
14547
14669
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14548
|
-
const
|
|
14670
|
+
const cacheKey = c.get("cacheKey");
|
|
14671
|
+
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
14672
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID10, adminUserId);
|
|
14549
14673
|
const spawnReqId = randomUUID10();
|
|
14550
14674
|
console.log(
|
|
14551
14675
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
@@ -14714,9 +14838,9 @@ var system_stats_default = app31;
|
|
|
14714
14838
|
// server/routes/admin/health.ts
|
|
14715
14839
|
import { existsSync as existsSync22, readFileSync as readFileSync21 } from "fs";
|
|
14716
14840
|
import { resolve as resolve23, join as join20 } from "path";
|
|
14717
|
-
var
|
|
14841
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
|
|
14718
14842
|
var brandHostname = "maxy";
|
|
14719
|
-
var brandJsonPath = join20(
|
|
14843
|
+
var brandJsonPath = join20(PLATFORM_ROOT6, "config", "brand.json");
|
|
14720
14844
|
if (existsSync22(brandJsonPath)) {
|
|
14721
14845
|
try {
|
|
14722
14846
|
const brand = JSON.parse(readFileSync21(brandJsonPath, "utf-8"));
|
|
@@ -14724,7 +14848,7 @@ if (existsSync22(brandJsonPath)) {
|
|
|
14724
14848
|
} catch {
|
|
14725
14849
|
}
|
|
14726
14850
|
}
|
|
14727
|
-
var VERSION_FILE = resolve23(
|
|
14851
|
+
var VERSION_FILE = resolve23(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
14728
14852
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
14729
14853
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
14730
14854
|
function readVersion() {
|
|
@@ -15434,9 +15558,9 @@ var verify_token_default = app41;
|
|
|
15434
15558
|
// app/lib/access-email.ts
|
|
15435
15559
|
import { spawn as spawn2 } from "child_process";
|
|
15436
15560
|
import { resolve as resolve24 } from "path";
|
|
15437
|
-
var
|
|
15561
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15438
15562
|
var SEND_SCRIPT = resolve24(
|
|
15439
|
-
|
|
15563
|
+
PLATFORM_ROOT7,
|
|
15440
15564
|
"plugins",
|
|
15441
15565
|
"email",
|
|
15442
15566
|
"mcp",
|
|
@@ -16672,7 +16796,7 @@ import * as fsp2 from "fs/promises";
|
|
|
16672
16796
|
import { resolve as resolve27, sep as sep7 } from "path";
|
|
16673
16797
|
var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16674
16798
|
var DEFAULT_COALESCE_MS = 500;
|
|
16675
|
-
var ROOTS = ["
|
|
16799
|
+
var ROOTS = ["accounts"];
|
|
16676
16800
|
function _routeEvent(rootName, filename) {
|
|
16677
16801
|
if (!filename) return null;
|
|
16678
16802
|
const segs = filename.split(sep7).filter(Boolean);
|
|
@@ -16770,6 +16894,129 @@ async function startFileWatcher(opts = {}) {
|
|
|
16770
16894
|
return { stop };
|
|
16771
16895
|
}
|
|
16772
16896
|
|
|
16897
|
+
// app/lib/migrate-uploads.ts
|
|
16898
|
+
import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
|
|
16899
|
+
import { dirname as dirname7, relative as relative4, resolve as resolve28 } from "path";
|
|
16900
|
+
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;
|
|
16901
|
+
async function walkFiles(dir) {
|
|
16902
|
+
const out = [];
|
|
16903
|
+
let entries;
|
|
16904
|
+
try {
|
|
16905
|
+
entries = await readdir5(dir, { withFileTypes: true });
|
|
16906
|
+
} catch {
|
|
16907
|
+
return out;
|
|
16908
|
+
}
|
|
16909
|
+
for (const e of entries) {
|
|
16910
|
+
const abs = resolve28(dir, e.name);
|
|
16911
|
+
if (e.isDirectory()) {
|
|
16912
|
+
out.push(...await walkFiles(abs));
|
|
16913
|
+
} else if (e.isFile()) {
|
|
16914
|
+
out.push(abs);
|
|
16915
|
+
}
|
|
16916
|
+
}
|
|
16917
|
+
return out;
|
|
16918
|
+
}
|
|
16919
|
+
function toNumber2(v) {
|
|
16920
|
+
if (v && typeof v.toNumber === "function") {
|
|
16921
|
+
return v.toNumber();
|
|
16922
|
+
}
|
|
16923
|
+
return Number(v ?? 0);
|
|
16924
|
+
}
|
|
16925
|
+
async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
16926
|
+
const files = await walkFiles(srcDir);
|
|
16927
|
+
let moved = 0;
|
|
16928
|
+
for (const oldAbs of files) {
|
|
16929
|
+
const suffix = relative4(srcDir, oldAbs);
|
|
16930
|
+
const newAbs = resolve28(destDir, suffix);
|
|
16931
|
+
await mkdir5(dirname7(newAbs), { recursive: true });
|
|
16932
|
+
await rename(oldAbs, newAbs);
|
|
16933
|
+
moved++;
|
|
16934
|
+
const oldRel = relative4(dataRoot, oldAbs);
|
|
16935
|
+
const newRel = relative4(dataRoot, newAbs);
|
|
16936
|
+
let linked = false;
|
|
16937
|
+
if (accountId && session) {
|
|
16938
|
+
const fa = await session.run(
|
|
16939
|
+
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $oldRel})
|
|
16940
|
+
SET f.relativePath = $newRel RETURN count(f) AS n`,
|
|
16941
|
+
{ accountId, oldRel, newRel }
|
|
16942
|
+
);
|
|
16943
|
+
const kd = await session.run(
|
|
16944
|
+
`MATCH (d:KnowledgeDocument {accountId: $accountId, sourcePath: $oldAbs})
|
|
16945
|
+
SET d.sourcePath = $newAbs RETURN count(d) AS n`,
|
|
16946
|
+
{ accountId, oldAbs, newAbs }
|
|
16947
|
+
);
|
|
16948
|
+
linked = toNumber2(fa.records[0]?.get("n")) + toNumber2(kd.records[0]?.get("n")) > 0;
|
|
16949
|
+
}
|
|
16950
|
+
console.error(`[uploads-migrate] from=${oldRel} to=${newRel} linked=${linked}`);
|
|
16951
|
+
}
|
|
16952
|
+
await rm3(srcDir, { recursive: true, force: true });
|
|
16953
|
+
return moved;
|
|
16954
|
+
}
|
|
16955
|
+
async function migrateUploads(opts = {}) {
|
|
16956
|
+
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
16957
|
+
const oldRoot = resolve28(dataRoot, "uploads");
|
|
16958
|
+
let topEntries;
|
|
16959
|
+
try {
|
|
16960
|
+
topEntries = await readdir5(oldRoot, { withFileTypes: true });
|
|
16961
|
+
} catch (err) {
|
|
16962
|
+
if (err.code === "ENOENT") {
|
|
16963
|
+
return { moved: 0, skipped: 0, removedRoot: false };
|
|
16964
|
+
}
|
|
16965
|
+
throw err;
|
|
16966
|
+
}
|
|
16967
|
+
const installAccountId = opts.installAccountId ?? resolveAccount()?.accountId;
|
|
16968
|
+
const session = opts.session ?? getSession();
|
|
16969
|
+
const ownSession = !opts.session;
|
|
16970
|
+
setUploadsMigrationInProgress(true);
|
|
16971
|
+
let moved = 0;
|
|
16972
|
+
let skipped = 0;
|
|
16973
|
+
try {
|
|
16974
|
+
for (const entry of topEntries) {
|
|
16975
|
+
const name = entry.name;
|
|
16976
|
+
if (ACCOUNT_UUID_RE3.test(name)) {
|
|
16977
|
+
moved += await relocateTree(
|
|
16978
|
+
resolve28(oldRoot, name),
|
|
16979
|
+
resolve28(dataRoot, "accounts", name, "uploads"),
|
|
16980
|
+
dataRoot,
|
|
16981
|
+
name,
|
|
16982
|
+
session
|
|
16983
|
+
);
|
|
16984
|
+
} else if (name === "public") {
|
|
16985
|
+
if (!installAccountId) {
|
|
16986
|
+
console.error(`[uploads-migrate] skip entry="public" reason="no-install-account"`);
|
|
16987
|
+
skipped++;
|
|
16988
|
+
continue;
|
|
16989
|
+
}
|
|
16990
|
+
moved += await relocateTree(
|
|
16991
|
+
resolve28(oldRoot, "public"),
|
|
16992
|
+
resolve28(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
16993
|
+
dataRoot,
|
|
16994
|
+
null,
|
|
16995
|
+
// public uploads carry no graph nodes
|
|
16996
|
+
session
|
|
16997
|
+
);
|
|
16998
|
+
} else {
|
|
16999
|
+
console.error(`[uploads-migrate] skip entry="${name}" reason="not-account-or-public"`);
|
|
17000
|
+
skipped++;
|
|
17001
|
+
}
|
|
17002
|
+
}
|
|
17003
|
+
let removedRoot = false;
|
|
17004
|
+
try {
|
|
17005
|
+
const remaining = await readdir5(oldRoot);
|
|
17006
|
+
if (remaining.length === 0) {
|
|
17007
|
+
await rm3(oldRoot, { recursive: true, force: true });
|
|
17008
|
+
removedRoot = true;
|
|
17009
|
+
}
|
|
17010
|
+
} catch {
|
|
17011
|
+
}
|
|
17012
|
+
console.error(`[uploads-migrate] done moved=${moved} skipped=${skipped} removedRoot=${removedRoot}`);
|
|
17013
|
+
return { moved, skipped, removedRoot };
|
|
17014
|
+
} finally {
|
|
17015
|
+
setUploadsMigrationInProgress(false);
|
|
17016
|
+
if (ownSession) await session.close();
|
|
17017
|
+
}
|
|
17018
|
+
}
|
|
17019
|
+
|
|
16773
17020
|
// app/lib/whatsapp/gateway/inbound-hub.ts
|
|
16774
17021
|
var InboundHub = class {
|
|
16775
17022
|
senders = /* @__PURE__ */ new Map();
|
|
@@ -17681,7 +17928,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
17681
17928
|
// ../lib/entitlement/src/index.ts
|
|
17682
17929
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
17683
17930
|
import { existsSync as existsSync26, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
|
|
17684
|
-
import { resolve as
|
|
17931
|
+
import { resolve as resolve29 } from "path";
|
|
17685
17932
|
|
|
17686
17933
|
// ../lib/entitlement/src/canonicalize.ts
|
|
17687
17934
|
function canonicalize(value) {
|
|
@@ -17716,7 +17963,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
17716
17963
|
var GRACE_DAYS = 7;
|
|
17717
17964
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
17718
17965
|
function pubkeyPath(brand) {
|
|
17719
|
-
return
|
|
17966
|
+
return resolve29(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
17720
17967
|
}
|
|
17721
17968
|
var memo = null;
|
|
17722
17969
|
function memoKey(mtimeMs, account) {
|
|
@@ -17728,7 +17975,7 @@ function resolveEntitlement(brand, account) {
|
|
|
17728
17975
|
if (brand.commercialMode !== true) {
|
|
17729
17976
|
return logResolved(implicitTrust(account), null);
|
|
17730
17977
|
}
|
|
17731
|
-
const entitlementPath =
|
|
17978
|
+
const entitlementPath = resolve29(brand.configDir, "entitlement.json");
|
|
17732
17979
|
if (!existsSync26(entitlementPath)) {
|
|
17733
17980
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
17734
17981
|
}
|
|
@@ -17918,8 +18165,8 @@ function clientFrom(c) {
|
|
|
17918
18165
|
c.req.header("x-forwarded-for")
|
|
17919
18166
|
);
|
|
17920
18167
|
}
|
|
17921
|
-
var
|
|
17922
|
-
var BRAND_JSON_PATH =
|
|
18168
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18169
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join22(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
17923
18170
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
17924
18171
|
if (BRAND_JSON_PATH && !existsSync27(BRAND_JSON_PATH)) {
|
|
17925
18172
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -17977,7 +18224,7 @@ var app49 = new Hono();
|
|
|
17977
18224
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
17978
18225
|
var waGateway = new WaGateway({
|
|
17979
18226
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17980
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
18227
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
17981
18228
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
17982
18229
|
// account + path validation here and funnel through the shared send core.
|
|
17983
18230
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -17993,7 +18240,7 @@ var waGateway = new WaGateway({
|
|
|
17993
18240
|
caption,
|
|
17994
18241
|
accountId,
|
|
17995
18242
|
maxyAccountId,
|
|
17996
|
-
platformRoot:
|
|
18243
|
+
platformRoot: resolve30(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, ".."))
|
|
17997
18244
|
});
|
|
17998
18245
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
17999
18246
|
},
|
|
@@ -18376,8 +18623,8 @@ app49.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
18376
18623
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
18377
18624
|
return c.text("Not found", 404);
|
|
18378
18625
|
}
|
|
18379
|
-
const filePath =
|
|
18380
|
-
const expectedDir =
|
|
18626
|
+
const filePath = resolve30(account.accountDir, "agents", slug, "assets", filename);
|
|
18627
|
+
const expectedDir = resolve30(account.accountDir, "agents", slug, "assets");
|
|
18381
18628
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
18382
18629
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
18383
18630
|
return c.text("Forbidden", 403);
|
|
@@ -18406,8 +18653,8 @@ app49.get("/generated/:filename", (c) => {
|
|
|
18406
18653
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
18407
18654
|
return c.text("Not found", 404);
|
|
18408
18655
|
}
|
|
18409
|
-
const filePath =
|
|
18410
|
-
const expectedDir =
|
|
18656
|
+
const filePath = resolve30(account.accountDir, "generated", filename);
|
|
18657
|
+
const expectedDir = resolve30(account.accountDir, "generated");
|
|
18411
18658
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
18412
18659
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
18413
18660
|
return c.text("Forbidden", 403);
|
|
@@ -18450,19 +18697,19 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
18450
18697
|
})}</script>`;
|
|
18451
18698
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
18452
18699
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
18453
|
-
var brandIconFsPath =
|
|
18700
|
+
var brandIconFsPath = resolve30(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
18454
18701
|
var brandIconExists = existsSync27(brandIconFsPath);
|
|
18455
18702
|
var SW_SOURCE = (() => {
|
|
18456
18703
|
try {
|
|
18457
|
-
return readFileSync26(
|
|
18704
|
+
return readFileSync26(resolve30(process.cwd(), "public", "sw.js"), "utf-8");
|
|
18458
18705
|
} catch {
|
|
18459
18706
|
return null;
|
|
18460
18707
|
}
|
|
18461
18708
|
})();
|
|
18462
18709
|
function readInstalledVersion() {
|
|
18463
18710
|
try {
|
|
18464
|
-
if (!
|
|
18465
|
-
const versionFile = join22(
|
|
18711
|
+
if (!PLATFORM_ROOT8) return "unknown";
|
|
18712
|
+
const versionFile = join22(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
18466
18713
|
if (!existsSync27(versionFile)) return "unknown";
|
|
18467
18714
|
const content = readFileSync26(versionFile, "utf-8").trim();
|
|
18468
18715
|
return content || "unknown";
|
|
@@ -18505,7 +18752,7 @@ var clientErrorReporterScript = `<script>
|
|
|
18505
18752
|
function cachedHtml(file) {
|
|
18506
18753
|
let html = htmlCache.get(file);
|
|
18507
18754
|
if (!html) {
|
|
18508
|
-
html = readFileSync26(
|
|
18755
|
+
html = readFileSync26(resolve30(process.cwd(), "public", file), "utf-8");
|
|
18509
18756
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
18510
18757
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
18511
18758
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -18623,7 +18870,7 @@ app49.use("/vnc-popout.html", logViewerFetch);
|
|
|
18623
18870
|
app49.get("/vnc-popout.html", (c) => {
|
|
18624
18871
|
let html = htmlCache.get("vnc-popout.html");
|
|
18625
18872
|
if (!html) {
|
|
18626
|
-
html = readFileSync26(
|
|
18873
|
+
html = readFileSync26(resolve30(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
18627
18874
|
const name = escapeHtml(BRAND.productName);
|
|
18628
18875
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
18629
18876
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -18849,8 +19096,10 @@ var adminUserReconcileTimer = setInterval(() => {
|
|
|
18849
19096
|
}, ADMINUSER_RECONCILE_INTERVAL_MS);
|
|
18850
19097
|
if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer.unref();
|
|
18851
19098
|
startGraphHealthTimer();
|
|
18852
|
-
void
|
|
18853
|
-
|
|
19099
|
+
void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err="${err instanceof Error ? err.message : String(err)}"`)).finally(() => {
|
|
19100
|
+
void startFileWatcher().catch((err) => {
|
|
19101
|
+
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
19102
|
+
});
|
|
18854
19103
|
});
|
|
18855
19104
|
try {
|
|
18856
19105
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
@@ -18932,7 +19181,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
18932
19181
|
}
|
|
18933
19182
|
init({
|
|
18934
19183
|
configDir: configDirForWhatsApp,
|
|
18935
|
-
platformRoot:
|
|
19184
|
+
platformRoot: resolve30(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, "..")),
|
|
18936
19185
|
accountConfig: bootAccountConfig,
|
|
18937
19186
|
onMessage: async (msg) => {
|
|
18938
19187
|
if (msg.isOwnerMirror) {
|