@rubytech/create-maxy-code 0.1.298 → 0.1.300
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/plugins/cloudflare/references/manual-setup.md +51 -3
- package/payload/platform/plugins/cloudflare/references/reset-guide.md +19 -1
- package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +16 -3
- package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
- package/payload/server/{chunk-7H4KMTMC.js → chunk-JHSF5VPE.js} +171 -95
- package/payload/server/maxy-edge.js +19 -1
- package/payload/server/public/assets/AdminShell-BFdBxg4P.js +1 -0
- package/payload/server/public/assets/{Checkbox-CVPUf_7I.js → Checkbox-BZ1XbA1t.js} +1 -1
- package/payload/server/public/assets/{Transcript-FYmq-mL1.js → Transcript-CaVix6W0.js} +1 -1
- package/payload/server/public/assets/admin-BK7xIr3o.js +1 -0
- package/payload/server/public/assets/{arc-DmR-LPIx.js → arc-DxSm8tli.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-IVt2X8Dk.js → architectureDiagram-Q4EWVU46-7JSAh0vL.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-CFyc3gpD.js +30 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CQDngnsc.js → blockDiagram-DXYQGD6D-DLoVmHKD.js} +1 -1
- package/payload/server/public/assets/{browser-D_hZgtfv.js → browser-ClnGUKp-.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-BjV_YA-L.js → c4Diagram-AHTNJAMY-Nv1G0o9P.js} +1 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +1 -0
- package/payload/server/public/assets/chat-ZTAhSoJV.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BYqpHDvA.js → chunk-2KRD3SAO-BpqPMhoA.js} +1 -1
- package/payload/server/public/assets/chunk-336JU56O-DgXHlVU_.js +2 -0
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-BeDVr5Tb.js → chunk-4BX2VUAB-nwyZSZH8.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-BImQYhPF.js → chunk-4TB4RGXK-Tfxz9LHX.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-DB18cH4S.js → chunk-55IACEB6-6FMJQGXG.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DrDSHQZv.js → chunk-5FUZZQ4R-g2FgZF3D.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-CKX_LIok.js → chunk-5PVQY5BW-DtLwXsPH.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-Ca9KwdQm.js → chunk-67CJDMHE-K91CP5ZU.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BDpzHOmv.js → chunk-7N4EOEYR-BGpCQhqK.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-DXo9fZho.js → chunk-AA7GKIK3-jkDbInck.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-CTqmM6qI.js → chunk-BSJP7CBP-mDosdzGs.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-NufEId2j.js → chunk-CIAEETIT-DhBxewpQ.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-D1zHB217.js → chunk-EDXVE4YY-B7c-9Emg.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-SFpdtszU.js → chunk-ENJZ2VHE-Cqhhncox.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-_4wtKsfc.js → chunk-FMBD7UC4-BpDq6wj1.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-565zaYb3.js → chunk-FOC6F5B3-Ds02-ktu.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-cYdq7RKF.js → chunk-ICPOFSXX-BTX5POFr.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-CTZnA5fq.js → chunk-K5T4RW27-Du1PXXBU.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-CeuKp7uR.js → chunk-KGLVRYIC-siasOAf8.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-DXkzlh3_.js → chunk-LIHQZDEY-xf1rbZtf.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DcZUCmgM.js → chunk-ORNJ4GCN-DeTLQ_LD.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-B7JLCext.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-DWCeFwem.js → chunk-U2HBQHQK-CXmFUKgn.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DGnHsoJ3.js → chunk-X2U36JSP-Bj8-8Wkz.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-CnU6DVpC.js → chunk-XPW4576I-Con3TXqt.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-sg4lGGJV.js → chunk-YZCP3GAM-Dx8BHGWf.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-DtUoGmKE.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-C04wkJr7.js → cose-bilkent-S5V4N54A-pZiCv69E.js} +1 -1
- package/payload/server/public/assets/{dagre-Dfj_jbTe.js → dagre-CLqhEgbL.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-Bd1VlhUJ.js → dagre-KV5264BT-BCxE8iyk.js} +1 -1
- package/payload/server/public/assets/{data-DkbQI40a.js → data-DDjeQQ7e.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-Dqqyk8GE.js → diagram-5BDNPKRD-slUEdZzz.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-Xk3WKR_U.js → diagram-G4DWMVQ6-DPcraMfu.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CAdGL9U7.js → diagram-MMDJMWI5-DR6luhGK.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-DY1iYQVY.js → diagram-TYMM5635-Jap1B4wA.js} +1 -1
- package/payload/server/public/assets/{dist-Pgmncqde.js → dist-Dbh7HrZX.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-BJ5HYKeb.js → erDiagram-SMLLAGMA-DJKUs2hO.js} +1 -1
- package/payload/server/public/assets/{file-download-BYJN3Kgm.js → file-download-DBMW0BNz.js} +1 -1
- package/payload/server/public/assets/{flatten-DeFkSYLU.js → flatten-Cl1Bc3dR.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B-q6x5Q_.js → flowDiagram-DWJPFMVM-C8W-ZZ9W.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DbjwY_bG.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-C3bLrOmb.js → gitGraphDiagram-UUTBAWPF-CZu_fpgS.js} +1 -1
- package/payload/server/public/assets/{graph-DmikPM4A.js → graph-CR74qec3.js} +1 -1
- package/payload/server/public/assets/{graph-labels-CtG6ckdG.js → graph-labels-1Uz0ZBRd.js} +1 -1
- package/payload/server/public/assets/{graphlib-BlOjhixq.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-Bn-Se8yT.js → isEmpty-D1pGOD1J.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B_DzwK8l.js → ishikawaDiagram-UXIWVN3A-B7KfIX6z.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-COzTF-qc.js → journeyDiagram-VCZTEJTY-CSDwBfhF.js} +1 -1
- package/payload/server/public/assets/{jsx-runtime-BjFkEGXb.css → jsx-runtime-BqGVUT1h.css} +1 -1
- package/payload/server/public/assets/{jsx-runtime-UQ0Z6nwN.js → jsx-runtime-D3JkFIbi.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-C2cOIZU6.js → kanban-definition-6JOO6SKY-CWzcEKTr.js} +1 -1
- package/payload/server/public/assets/{line-Bwa6aUYZ.js → line-BNQSlbYn.js} +1 -1
- package/payload/server/public/assets/{linear-CgbkJiu6.js → linear-BN6kGN93.js} +1 -1
- package/payload/server/public/assets/mermaid-parser.core-CcFhkElq.js +4 -0
- package/payload/server/public/assets/mermaid.core-BsIeJ7Cc.js +11 -0
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-bu0QLO17.js → mindmap-definition-QFDTVHPH-CQVzj6D_.js} +1 -1
- package/payload/server/public/assets/operator-QP_z97s8.js +1 -0
- package/payload/server/public/assets/{ordinal-C-EimP2j.js → ordinal-CBZeH4Yp.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +1 -0
- package/payload/server/public/assets/page-CLijftr1.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DQUe6W2Z.js → pieDiagram-DEJITSTG-DnrQ9fyn.js} +1 -1
- package/payload/server/public/assets/preload-helper-CQ36nxok.js +1 -0
- package/payload/server/public/assets/public-W-HholkU.js +6 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-ChhcwVRA.js → quadrantDiagram-34T5L4WZ-BQWlCyWi.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +1 -0
- package/payload/server/public/assets/{reduce-B0wq8DtH.js → reduce-PuPlFPRX.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-DwQXqTA9.js → requirementDiagram-MS252O5E-Du_vZhU1.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-zYqdptBM.js → sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-x2g84gb4.js → sequenceDiagram-FGHM5R23-CS8GVol8.js} +1 -1
- package/payload/server/public/assets/{src-CozP7LCe.js → src-BoaldmnP.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CeUrqs2P.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-CL-c9XN5.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-C1_ky4B6.js → useSelectionMode-geYq13zs.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-By2HBDYr.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-iahvFvIS.js → wardleyDiagram-NUSXRM2D-D86-ivEx.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-33qqdRhI.js → xychartDiagram-5P7HB3ND-Ba5WAN8P.js} +1 -1
- package/payload/server/public/browser.html +7 -7
- package/payload/server/public/chat.html +10 -9
- package/payload/server/public/data.html +6 -6
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +11 -10
- package/payload/server/public/operator.html +24 -0
- package/payload/server/public/public.html +8 -7
- package/payload/server/server.js +392 -330
- package/payload/server/public/assets/AdminShell-BnhxfX97.js +0 -1
- package/payload/server/public/assets/admin-CF8K3hqE.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-CjF2k79a.js +0 -1
- package/payload/server/public/assets/audio-attachment-mime-DaInZ9sa.js +0 -1
- package/payload/server/public/assets/channel-gFnUr8f4.js +0 -1
- package/payload/server/public/assets/chat-COcrNTJi.js +0 -1
- package/payload/server/public/assets/chunk-336JU56O-B0yBhSVq.js +0 -2
- package/payload/server/public/assets/chunk-426QAEUC-BCmWl6vi.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CBWmDBHe.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-C_wlfUTz.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Ltv5s3OY.js +0 -1
- package/payload/server/public/assets/clone-D0XoXc_v.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DsUTwRUb.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-BV9FyUXQ.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-BpaHbiXO.js +0 -2
- package/payload/server/public/assets/mermaid-parser.core-BFAF0BAk.js +0 -4
- package/payload/server/public/assets/mermaid.core-CMOXmawT.js +0 -11
- package/payload/server/public/assets/packet-4T2RLAQJ-SXjQ83Vr.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-q7TXebDD.js +0 -1
- package/payload/server/public/assets/public-CSEIGhb4.js +0 -35
- package/payload/server/public/assets/radar-PYXPWWZC-CXKUHVMS.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B27DBP9X.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWuFgUeJ.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-gKO4rbgo.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-hDEw8pJN.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BV-TyLWt.js → _baseFor-brRjpUOX.js} +0 -0
- /package/payload/server/public/assets/{array-lqrvkwy7.js → array-BGFCBI0e.js} +0 -0
- /package/payload/server/public/assets/{chunk-CWOGyPgy.js → chunk-Pqm5yXtL.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-SmEOayFS.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-Dl3Sud5K.js → defaultLocale-CRZydyG6.js} +0 -0
- /package/payload/server/public/assets/{init-BukMwkmL.js → init-B8gtcn7T.js} +0 -0
- /package/payload/server/public/assets/{katex-jl-BtNZi.js → katex-RxgSu_dy.js} +0 -0
- /package/payload/server/public/assets/{admin-CWMpccrR.css → page-CWMpccrR.css} +0 -0
- /package/payload/server/public/assets/{path-DPTRcLku.js → path-DZF-JdEe.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-VLpapkIG.js → rough.esm-6CnTHTkH.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
ACCOUNTS_DIR,
|
|
4
|
+
AGENT_SLUG_PATTERN,
|
|
4
5
|
BIN_DIR,
|
|
5
6
|
BRAND_NAME,
|
|
6
7
|
CDP_PORT,
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
LOG_DIR,
|
|
16
17
|
MAXY_DIR,
|
|
17
18
|
PLATFORM_ROOT,
|
|
19
|
+
PUBLIC_ALLOWED_EXACT,
|
|
20
|
+
PUBLIC_ALLOWED_PREFIXES,
|
|
18
21
|
RFB_PORT,
|
|
19
22
|
SYSTEM_PATH_SLUGS,
|
|
20
23
|
USERS_FILE,
|
|
@@ -26,6 +29,7 @@ import {
|
|
|
26
29
|
canAccessAdmin,
|
|
27
30
|
checkGroupMembership,
|
|
28
31
|
checkRateLimit,
|
|
32
|
+
classifyHost,
|
|
29
33
|
cleanupLeakedPremiumSubs,
|
|
30
34
|
clearRateLimit,
|
|
31
35
|
clientIpMiddleware,
|
|
@@ -45,6 +49,7 @@ import {
|
|
|
45
49
|
getConversationClaudeSessionIds,
|
|
46
50
|
getDefaultAccountId,
|
|
47
51
|
getGroupParticipants,
|
|
52
|
+
getOperatorDomains,
|
|
48
53
|
getRecentMessages,
|
|
49
54
|
getRoleForSession,
|
|
50
55
|
getSession,
|
|
@@ -55,7 +60,9 @@ import {
|
|
|
55
60
|
getUserTimezone,
|
|
56
61
|
httpLog,
|
|
57
62
|
isActiveAgentSlug,
|
|
63
|
+
isOperatorHost,
|
|
58
64
|
isPasswordValid,
|
|
65
|
+
isPublicPathAllowed,
|
|
59
66
|
isRemoteAuthConfigured,
|
|
60
67
|
linkConversationTranscript,
|
|
61
68
|
listAdminSessions,
|
|
@@ -97,7 +104,7 @@ import {
|
|
|
97
104
|
vncLog,
|
|
98
105
|
walkPremiumBundles,
|
|
99
106
|
writeAdminUserAndPerson
|
|
100
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-JHSF5VPE.js";
|
|
101
108
|
import {
|
|
102
109
|
__commonJS,
|
|
103
110
|
__toESM
|
|
@@ -1214,35 +1221,21 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1214
1221
|
};
|
|
1215
1222
|
|
|
1216
1223
|
// server/index.ts
|
|
1217
|
-
import { readFileSync as readFileSync26, existsSync as
|
|
1218
|
-
import { resolve as
|
|
1224
|
+
import { readFileSync as readFileSync26, existsSync as existsSync27, watchFile } from "fs";
|
|
1225
|
+
import { resolve as resolve29, join as join22, basename as basename8 } from "path";
|
|
1219
1226
|
import { homedir as homedir3 } from "os";
|
|
1220
1227
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1221
1228
|
|
|
1222
|
-
//
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
"/
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
"/api/telegram/",
|
|
1233
|
-
"/assets/",
|
|
1234
|
-
"/brand/",
|
|
1235
|
-
"/agent-assets/",
|
|
1236
|
-
"/generated/",
|
|
1237
|
-
"/g/",
|
|
1238
|
-
"/sites/"
|
|
1239
|
-
];
|
|
1240
|
-
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico", "/brand-defaults.css"];
|
|
1241
|
-
function isPublicPathAllowed(path2) {
|
|
1242
|
-
if (path2 === "/") return true;
|
|
1243
|
-
if (PUBLIC_ALLOWED_EXACT.includes(path2)) return true;
|
|
1244
|
-
if (PUBLIC_ALLOWED_PREFIXES.some((prefix) => path2.startsWith(prefix))) return true;
|
|
1245
|
-
return AGENT_SLUG_PATTERN.test(path2);
|
|
1229
|
+
// server/webchat-descriptor.ts
|
|
1230
|
+
import { resolve, join as join2 } from "path";
|
|
1231
|
+
function webchatGatewayUrl() {
|
|
1232
|
+
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
1233
|
+
}
|
|
1234
|
+
function webchatServerPath() {
|
|
1235
|
+
return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve(process.env.MAXY_PLATFORM_ROOT ?? join2(__dirname, ".."), "services/webchat-channel/dist/server.js");
|
|
1236
|
+
}
|
|
1237
|
+
function webchatChannelDescriptor(key) {
|
|
1238
|
+
return { key, gatewayUrl: webchatGatewayUrl(), serverPath: webchatServerPath() };
|
|
1246
1239
|
}
|
|
1247
1240
|
|
|
1248
1241
|
// app/lib/claude-auth.ts
|
|
@@ -1794,7 +1787,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1794
1787
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1795
1788
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1796
1789
|
const timer2 = new Promise(
|
|
1797
|
-
(
|
|
1790
|
+
(resolve30) => setTimeout(() => resolve30("timeout"), timeoutMs)
|
|
1798
1791
|
);
|
|
1799
1792
|
const result = await Promise.race([
|
|
1800
1793
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1922,11 +1915,11 @@ async function createWaSocket(opts) {
|
|
|
1922
1915
|
return sock;
|
|
1923
1916
|
}
|
|
1924
1917
|
async function waitForConnection(sock) {
|
|
1925
|
-
return new Promise((
|
|
1918
|
+
return new Promise((resolve30, reject) => {
|
|
1926
1919
|
const handler = (update) => {
|
|
1927
1920
|
if (update.connection === "open") {
|
|
1928
1921
|
sock.ev.off("connection.update", handler);
|
|
1929
|
-
|
|
1922
|
+
resolve30();
|
|
1930
1923
|
}
|
|
1931
1924
|
if (update.connection === "close") {
|
|
1932
1925
|
sock.ev.off("connection.update", handler);
|
|
@@ -2040,14 +2033,14 @@ ${inspected}`;
|
|
|
2040
2033
|
return inspect2(err, INSPECT_OPTS2);
|
|
2041
2034
|
}
|
|
2042
2035
|
function withTimeout(label, promise, timeoutMs) {
|
|
2043
|
-
return new Promise((
|
|
2036
|
+
return new Promise((resolve30, reject) => {
|
|
2044
2037
|
const timer2 = setTimeout(() => {
|
|
2045
2038
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2046
2039
|
}, timeoutMs);
|
|
2047
2040
|
promise.then(
|
|
2048
2041
|
(value) => {
|
|
2049
2042
|
clearTimeout(timer2);
|
|
2050
|
-
|
|
2043
|
+
resolve30(value);
|
|
2051
2044
|
},
|
|
2052
2045
|
(err) => {
|
|
2053
2046
|
clearTimeout(timer2);
|
|
@@ -2646,8 +2639,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2646
2639
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2647
2640
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2648
2641
|
let release;
|
|
2649
|
-
const mine = new Promise((
|
|
2650
|
-
release =
|
|
2642
|
+
const mine = new Promise((resolve30) => {
|
|
2643
|
+
release = resolve30;
|
|
2651
2644
|
});
|
|
2652
2645
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2653
2646
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -2833,7 +2826,7 @@ async function ensureWhatsAppConversation(input) {
|
|
|
2833
2826
|
|
|
2834
2827
|
// ../lib/account-enumeration/src/index.ts
|
|
2835
2828
|
import { readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
2836
|
-
import { resolve } from "path";
|
|
2829
|
+
import { resolve as resolve2 } from "path";
|
|
2837
2830
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2838
2831
|
var cache = /* @__PURE__ */ new Map();
|
|
2839
2832
|
function enumerateValidAccountIds(accountsDir) {
|
|
@@ -2852,7 +2845,7 @@ function enumerateValidAccountIds(accountsDir) {
|
|
|
2852
2845
|
const valid = [];
|
|
2853
2846
|
for (const name of names) {
|
|
2854
2847
|
if (!UUID_RE.test(name)) continue;
|
|
2855
|
-
const configPath2 =
|
|
2848
|
+
const configPath2 = resolve2(accountsDir, name, "account.json");
|
|
2856
2849
|
try {
|
|
2857
2850
|
JSON.parse(readFileSync3(configPath2, "utf-8"));
|
|
2858
2851
|
valid.push(name);
|
|
@@ -2871,7 +2864,7 @@ function getAccountsDirFromEnv() {
|
|
|
2871
2864
|
"[graph-write] MAXY_PLATFORM_ROOT not set \u2014 cannot enforce accountId gate. Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly."
|
|
2872
2865
|
);
|
|
2873
2866
|
}
|
|
2874
|
-
return
|
|
2867
|
+
return resolve2(root, "..", "data/accounts");
|
|
2875
2868
|
}
|
|
2876
2869
|
function validateAccountIdEnv(envValue, diskIds) {
|
|
2877
2870
|
if (!envValue) {
|
|
@@ -2910,7 +2903,7 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
|
|
|
2910
2903
|
// app/lib/whatsapp/inbound/media.ts
|
|
2911
2904
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2912
2905
|
import { writeFile, mkdir } from "fs/promises";
|
|
2913
|
-
import { join as
|
|
2906
|
+
import { join as join3 } from "path";
|
|
2914
2907
|
import {
|
|
2915
2908
|
downloadMediaMessage,
|
|
2916
2909
|
downloadContentFromMessage,
|
|
@@ -2996,7 +2989,7 @@ async function downloadInboundMedia(msg, sock, opts) {
|
|
|
2996
2989
|
await mkdir(MEDIA_DIR, { recursive: true });
|
|
2997
2990
|
const ext = mimeToExt(mimetype ?? "application/octet-stream");
|
|
2998
2991
|
const filename = `${randomUUID2()}.${ext}`;
|
|
2999
|
-
const filePath =
|
|
2992
|
+
const filePath = join3(MEDIA_DIR, filename);
|
|
3000
2993
|
await writeFile(filePath, buffer);
|
|
3001
2994
|
const sizeKB = (buffer.length / 1024).toFixed(0);
|
|
3002
2995
|
console.error(`${TAG9} media downloaded type=${mimetype ?? "unknown"} size=${sizeKB}KB path=${filePath}`);
|
|
@@ -3727,11 +3720,11 @@ async function connectWithReconnect(conn) {
|
|
|
3727
3720
|
console.error(
|
|
3728
3721
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3729
3722
|
);
|
|
3730
|
-
await new Promise((
|
|
3731
|
-
const timer2 = setTimeout(
|
|
3723
|
+
await new Promise((resolve30) => {
|
|
3724
|
+
const timer2 = setTimeout(resolve30, delay);
|
|
3732
3725
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3733
3726
|
clearTimeout(timer2);
|
|
3734
|
-
|
|
3727
|
+
resolve30();
|
|
3735
3728
|
}, { once: true });
|
|
3736
3729
|
});
|
|
3737
3730
|
}
|
|
@@ -3739,16 +3732,16 @@ async function connectWithReconnect(conn) {
|
|
|
3739
3732
|
}
|
|
3740
3733
|
}
|
|
3741
3734
|
function waitForDisconnectEvent(conn) {
|
|
3742
|
-
return new Promise((
|
|
3735
|
+
return new Promise((resolve30) => {
|
|
3743
3736
|
if (!conn.sock) {
|
|
3744
|
-
|
|
3737
|
+
resolve30();
|
|
3745
3738
|
return;
|
|
3746
3739
|
}
|
|
3747
3740
|
const sock = conn.sock;
|
|
3748
3741
|
const handler = (update) => {
|
|
3749
3742
|
if (update.connection === "close") {
|
|
3750
3743
|
sock.ev.off("connection.update", handler);
|
|
3751
|
-
|
|
3744
|
+
resolve30();
|
|
3752
3745
|
}
|
|
3753
3746
|
};
|
|
3754
3747
|
sock.ev.on("connection.update", handler);
|
|
@@ -4008,8 +4001,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4008
4001
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4009
4002
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4010
4003
|
let resolvePending;
|
|
4011
|
-
const sttPending = new Promise((
|
|
4012
|
-
resolvePending =
|
|
4004
|
+
const sttPending = new Promise((resolve30) => {
|
|
4005
|
+
resolvePending = resolve30;
|
|
4013
4006
|
});
|
|
4014
4007
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4015
4008
|
try {
|
|
@@ -4106,9 +4099,9 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4106
4099
|
import { spawnSync, execFileSync } from "child_process";
|
|
4107
4100
|
import { createConnection } from "net";
|
|
4108
4101
|
import { mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
4109
|
-
import { resolve as
|
|
4110
|
-
var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
4111
|
-
var VNC_SCRIPT =
|
|
4102
|
+
import { resolve as resolve3 } from "path";
|
|
4103
|
+
var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "..");
|
|
4104
|
+
var VNC_SCRIPT = resolve3(PLATFORM_ROOT2, "scripts/vnc.sh");
|
|
4112
4105
|
var displayMode = process.env.DISPLAY_MODE ?? "virtual";
|
|
4113
4106
|
if (displayMode === "native") {
|
|
4114
4107
|
console.log(`[vnc] DISPLAY_MODE=native \u2014 local requests use desktop display, remote requests use VNC`);
|
|
@@ -4221,7 +4214,7 @@ function ensureLogDir() {
|
|
|
4221
4214
|
mkdirSync(LOG_DIR, { recursive: true });
|
|
4222
4215
|
}
|
|
4223
4216
|
function logPath(name) {
|
|
4224
|
-
return
|
|
4217
|
+
return resolve3(LOG_DIR, `${name}.log`);
|
|
4225
4218
|
}
|
|
4226
4219
|
async function ensureVnc() {
|
|
4227
4220
|
const up = await waitForPort(RFB_PORT, 1e3);
|
|
@@ -4300,7 +4293,7 @@ function killChromium() {
|
|
|
4300
4293
|
}
|
|
4301
4294
|
function writeChromiumWrapper() {
|
|
4302
4295
|
mkdirSync(BIN_DIR, { recursive: true });
|
|
4303
|
-
const wrapperPath =
|
|
4296
|
+
const wrapperPath = resolve3(BIN_DIR, "chromium");
|
|
4304
4297
|
writeFileSync3(wrapperPath, `#!/bin/bash
|
|
4305
4298
|
LOG="${LOG_DIR}/chromium.log"
|
|
4306
4299
|
echo "==== [$(date)] chromium wrapper ====" >> "$LOG"
|
|
@@ -4400,20 +4393,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4400
4393
|
|
|
4401
4394
|
// server/routes/health.ts
|
|
4402
4395
|
function checkPort(port2, timeoutMs = 500) {
|
|
4403
|
-
return new Promise((
|
|
4396
|
+
return new Promise((resolve30) => {
|
|
4404
4397
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4405
4398
|
socket.setTimeout(timeoutMs);
|
|
4406
4399
|
socket.once("connect", () => {
|
|
4407
4400
|
socket.destroy();
|
|
4408
|
-
|
|
4401
|
+
resolve30(true);
|
|
4409
4402
|
});
|
|
4410
4403
|
socket.once("error", () => {
|
|
4411
4404
|
socket.destroy();
|
|
4412
|
-
|
|
4405
|
+
resolve30(false);
|
|
4413
4406
|
});
|
|
4414
4407
|
socket.once("timeout", () => {
|
|
4415
4408
|
socket.destroy();
|
|
4416
|
-
|
|
4409
|
+
resolve30(false);
|
|
4417
4410
|
});
|
|
4418
4411
|
});
|
|
4419
4412
|
}
|
|
@@ -4483,9 +4476,9 @@ var health_default = app;
|
|
|
4483
4476
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4484
4477
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
4485
4478
|
import { realpathSync } from "fs";
|
|
4486
|
-
import { resolve as
|
|
4487
|
-
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ??
|
|
4488
|
-
var ATTACHMENTS_ROOT =
|
|
4479
|
+
import { resolve as resolve4, extname } from "path";
|
|
4480
|
+
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "../platform");
|
|
4481
|
+
var ATTACHMENTS_ROOT = resolve4(PLATFORM_ROOT3, "..", "data/uploads");
|
|
4489
4482
|
var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
4490
4483
|
"image/jpeg",
|
|
4491
4484
|
"image/png",
|
|
@@ -4512,11 +4505,11 @@ function assertSupportedMime(mimeType) {
|
|
|
4512
4505
|
}
|
|
4513
4506
|
async function writeAttachment(scope, filename, mimeType, sizeBytes, buffer) {
|
|
4514
4507
|
const attachmentId = randomUUID3();
|
|
4515
|
-
const dir =
|
|
4508
|
+
const dir = resolve4(ATTACHMENTS_ROOT, scope, attachmentId);
|
|
4516
4509
|
await mkdir2(dir, { recursive: true });
|
|
4517
4510
|
const ext = extname(filename) || "";
|
|
4518
|
-
const storagePath =
|
|
4519
|
-
const metaPath =
|
|
4511
|
+
const storagePath = resolve4(dir, `${attachmentId}${ext}`);
|
|
4512
|
+
const metaPath = resolve4(dir, `${attachmentId}.meta.json`);
|
|
4520
4513
|
const meta = {
|
|
4521
4514
|
attachmentId,
|
|
4522
4515
|
scope,
|
|
@@ -4590,11 +4583,11 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
4590
4583
|
`Component artefact exceeds the 50 MB limit (${(buffer.byteLength / 1024 / 1024).toFixed(1)} MB).`
|
|
4591
4584
|
);
|
|
4592
4585
|
}
|
|
4593
|
-
const dir =
|
|
4586
|
+
const dir = resolve4(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
4594
4587
|
await mkdir2(dir, { recursive: true });
|
|
4595
4588
|
const ext = extname(filename) || (mimeType === "text/html" ? ".html" : ".md");
|
|
4596
|
-
const storagePath =
|
|
4597
|
-
const metaPath =
|
|
4589
|
+
const storagePath = resolve4(dir, `${attachmentId}${ext}`);
|
|
4590
|
+
const metaPath = resolve4(dir, `${attachmentId}.meta.json`);
|
|
4598
4591
|
const meta = {
|
|
4599
4592
|
attachmentId,
|
|
4600
4593
|
scope: accountId,
|
|
@@ -4611,7 +4604,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
4611
4604
|
// app/lib/stt/voice-note.ts
|
|
4612
4605
|
import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
|
|
4613
4606
|
import { tmpdir } from "os";
|
|
4614
|
-
import { join as
|
|
4607
|
+
import { join as join4 } from "path";
|
|
4615
4608
|
var TAG14 = "[voice]";
|
|
4616
4609
|
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
4617
4610
|
"audio/ogg",
|
|
@@ -4655,9 +4648,9 @@ async function transcribeVoiceNote(file, source) {
|
|
|
4655
4648
|
let tempDir;
|
|
4656
4649
|
let tempPath;
|
|
4657
4650
|
try {
|
|
4658
|
-
tempDir = await mkdtemp(
|
|
4651
|
+
tempDir = await mkdtemp(join4(tmpdir(), "voice-"));
|
|
4659
4652
|
const ext = audioExtension(mimeType);
|
|
4660
|
-
tempPath =
|
|
4653
|
+
tempPath = join4(tempDir, `recording${ext}`);
|
|
4661
4654
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
4662
4655
|
await writeFile3(tempPath, buffer);
|
|
4663
4656
|
} catch (err) {
|
|
@@ -4698,7 +4691,7 @@ async function transcribeVoiceNote(file, source) {
|
|
|
4698
4691
|
}
|
|
4699
4692
|
|
|
4700
4693
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
4701
|
-
import { resolve as
|
|
4694
|
+
import { resolve as resolve6 } from "path";
|
|
4702
4695
|
|
|
4703
4696
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
4704
4697
|
function managerBase() {
|
|
@@ -5150,7 +5143,7 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
5150
5143
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
5151
5144
|
import { realpathSync as realpathSync2 } from "fs";
|
|
5152
5145
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
5153
|
-
import { resolve as
|
|
5146
|
+
import { resolve as resolve5, basename } from "path";
|
|
5154
5147
|
var TAG16 = "[whatsapp:outbound]";
|
|
5155
5148
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
5156
5149
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -5181,7 +5174,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
5181
5174
|
if (!maxyAccountId || !platformRoot2) {
|
|
5182
5175
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
5183
5176
|
}
|
|
5184
|
-
const accountDir =
|
|
5177
|
+
const accountDir = resolve5(platformRoot2, "..", "data/accounts", maxyAccountId);
|
|
5185
5178
|
let resolvedPath;
|
|
5186
5179
|
try {
|
|
5187
5180
|
resolvedPath = realpathSync2(filePath);
|
|
@@ -5388,7 +5381,7 @@ async function ensureEntry(input) {
|
|
|
5388
5381
|
});
|
|
5389
5382
|
} else {
|
|
5390
5383
|
console.error(`${tag} route role=${input.role} target=public-spawn senderId=${input.senderId}`);
|
|
5391
|
-
const attachmentDir =
|
|
5384
|
+
const attachmentDir = resolve6(ATTACHMENTS_ROOT, "public", input.senderId);
|
|
5392
5385
|
spawned = await managerSpawn({
|
|
5393
5386
|
senderId: input.senderId,
|
|
5394
5387
|
role: input.role,
|
|
@@ -5520,12 +5513,12 @@ async function dispatchOnce(input) {
|
|
|
5520
5513
|
});
|
|
5521
5514
|
if (!entry) return { error: "spawn-failed" };
|
|
5522
5515
|
entry.lastInboundAt = Date.now();
|
|
5523
|
-
let
|
|
5516
|
+
let resolve30;
|
|
5524
5517
|
const turnPromise = new Promise((r) => {
|
|
5525
|
-
|
|
5518
|
+
resolve30 = r;
|
|
5526
5519
|
});
|
|
5527
5520
|
const listener = (text) => {
|
|
5528
|
-
|
|
5521
|
+
resolve30(text);
|
|
5529
5522
|
};
|
|
5530
5523
|
entry.subscribers.add(listener);
|
|
5531
5524
|
const writeAtMs = Date.now();
|
|
@@ -5895,7 +5888,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5895
5888
|
var chat_default = app2;
|
|
5896
5889
|
|
|
5897
5890
|
// server/routes/whatsapp.ts
|
|
5898
|
-
import { join as
|
|
5891
|
+
import { join as join7, resolve as resolve8 } from "path";
|
|
5899
5892
|
import { readdirSync as readdirSync3, readFileSync as readFileSync7, existsSync as existsSync5 } from "fs";
|
|
5900
5893
|
|
|
5901
5894
|
// app/lib/whatsapp/login.ts
|
|
@@ -5903,10 +5896,10 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
5903
5896
|
|
|
5904
5897
|
// app/lib/whatsapp/config-persist.ts
|
|
5905
5898
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
5906
|
-
import { resolve as
|
|
5899
|
+
import { resolve as resolve7, join as join5 } from "path";
|
|
5907
5900
|
var TAG18 = "[whatsapp:config]";
|
|
5908
5901
|
function configPath(accountDir) {
|
|
5909
|
-
return
|
|
5902
|
+
return resolve7(accountDir, "account.json");
|
|
5910
5903
|
}
|
|
5911
5904
|
function readConfig(accountDir) {
|
|
5912
5905
|
const path2 = configPath(accountDir);
|
|
@@ -6055,7 +6048,7 @@ function setPublicAgent(accountDir, slug) {
|
|
|
6055
6048
|
if (!trimmed) {
|
|
6056
6049
|
return { ok: false, error: "Agent slug cannot be empty." };
|
|
6057
6050
|
}
|
|
6058
|
-
const agentConfigPath =
|
|
6051
|
+
const agentConfigPath = join5(accountDir, "agents", trimmed, "config.json");
|
|
6059
6052
|
if (!existsSync4(agentConfigPath)) {
|
|
6060
6053
|
return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
|
|
6061
6054
|
}
|
|
@@ -6313,8 +6306,8 @@ async function startLogin(opts) {
|
|
|
6313
6306
|
await clearAuth(authDir);
|
|
6314
6307
|
let resolveCode = null;
|
|
6315
6308
|
let rejectCode = null;
|
|
6316
|
-
const codePromise = new Promise((
|
|
6317
|
-
resolveCode =
|
|
6309
|
+
const codePromise = new Promise((resolve30, reject) => {
|
|
6310
|
+
resolveCode = resolve30;
|
|
6318
6311
|
rejectCode = reject;
|
|
6319
6312
|
});
|
|
6320
6313
|
const codeTimer = setTimeout(
|
|
@@ -6546,11 +6539,11 @@ function serializeWhatsAppSchema() {
|
|
|
6546
6539
|
|
|
6547
6540
|
// app/lib/whatsapp/status-reconcile.ts
|
|
6548
6541
|
import { readdirSync as readdirSync2 } from "fs";
|
|
6549
|
-
import { join as
|
|
6542
|
+
import { join as join6 } from "path";
|
|
6550
6543
|
var TAG20 = "[whatsapp:reconcile]";
|
|
6551
6544
|
function listCredsAccountIds(credsRoot) {
|
|
6552
6545
|
try {
|
|
6553
|
-
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(
|
|
6546
|
+
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join6(credsRoot, e.name))).map((e) => e.name);
|
|
6554
6547
|
} catch {
|
|
6555
6548
|
return [];
|
|
6556
6549
|
}
|
|
@@ -6565,7 +6558,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6565
6558
|
const entries = [];
|
|
6566
6559
|
for (const accountId of listCredsAccountIds(credsRoot)) {
|
|
6567
6560
|
if (liveAccountIds.has(accountId)) continue;
|
|
6568
|
-
const authDir =
|
|
6561
|
+
const authDir = join6(credsRoot, accountId);
|
|
6569
6562
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
6570
6563
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
6571
6564
|
console.error(
|
|
@@ -6592,7 +6585,7 @@ app3.get("/status", (c) => {
|
|
|
6592
6585
|
try {
|
|
6593
6586
|
const live = getStatus();
|
|
6594
6587
|
const liveIds = new Set(live.map((a) => a.accountId));
|
|
6595
|
-
const credsRoot =
|
|
6588
|
+
const credsRoot = join7(MAXY_DIR, "credentials", "whatsapp");
|
|
6596
6589
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6597
6590
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
|
|
6598
6591
|
const accounts = [...live, ...reconciled];
|
|
@@ -6613,7 +6606,7 @@ app3.post("/login/start", async (c) => {
|
|
|
6613
6606
|
if (!phone) {
|
|
6614
6607
|
return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
|
|
6615
6608
|
}
|
|
6616
|
-
const authDir =
|
|
6609
|
+
const authDir = join7(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
6617
6610
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6618
6611
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
6619
6612
|
console.error(`${TAG21} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
@@ -6711,14 +6704,14 @@ app3.post("/config", async (c) => {
|
|
|
6711
6704
|
return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
|
|
6712
6705
|
}
|
|
6713
6706
|
case "list-public-agents": {
|
|
6714
|
-
const agentsDir =
|
|
6707
|
+
const agentsDir = resolve8(account.accountDir, "agents");
|
|
6715
6708
|
const agents = [];
|
|
6716
6709
|
if (existsSync5(agentsDir)) {
|
|
6717
6710
|
try {
|
|
6718
6711
|
const entries = readdirSync3(agentsDir, { withFileTypes: true });
|
|
6719
6712
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
6720
6713
|
if (!entry.isDirectory() || entry.name === "admin") continue;
|
|
6721
|
-
const configPath2 =
|
|
6714
|
+
const configPath2 = resolve8(agentsDir, entry.name, "config.json");
|
|
6722
6715
|
if (!existsSync5(configPath2)) continue;
|
|
6723
6716
|
try {
|
|
6724
6717
|
const config = JSON.parse(readFileSync7(configPath2, "utf-8"));
|
|
@@ -6991,11 +6984,11 @@ var whatsapp_default = app3;
|
|
|
6991
6984
|
|
|
6992
6985
|
// server/routes/whatsapp-reader.ts
|
|
6993
6986
|
import { readFileSync as readFileSync10, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync6 } from "fs";
|
|
6994
|
-
import { basename as basename2, dirname, join as
|
|
6987
|
+
import { basename as basename2, dirname, join as join10, resolve as resolve10, sep as sep2 } from "path";
|
|
6995
6988
|
|
|
6996
6989
|
// server/routes/admin/sidebar-sessions.ts
|
|
6997
6990
|
import { readdirSync as readdirSync4, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
6998
|
-
import { join as
|
|
6991
|
+
import { join as join8, resolve as resolve9 } from "path";
|
|
6999
6992
|
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;
|
|
7000
6993
|
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7001
6994
|
var PUBLIC_ROLE = "public";
|
|
@@ -7014,7 +7007,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
7014
7007
|
throw err;
|
|
7015
7008
|
}
|
|
7016
7009
|
for (const slug of slugs) {
|
|
7017
|
-
const slugDir =
|
|
7010
|
+
const slugDir = join8(projectsRoot, slug);
|
|
7018
7011
|
let entries;
|
|
7019
7012
|
try {
|
|
7020
7013
|
entries = readdirSync4(slugDir, { withFileTypes: true });
|
|
@@ -7025,9 +7018,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
7025
7018
|
}
|
|
7026
7019
|
for (const entry of entries) {
|
|
7027
7020
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
7028
|
-
out.push({ path:
|
|
7021
|
+
out.push({ path: join8(slugDir, entry.name), isSubagent: false, archived: false });
|
|
7029
7022
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
7030
|
-
const subDir =
|
|
7023
|
+
const subDir = join8(slugDir, entry.name);
|
|
7031
7024
|
let subEntries;
|
|
7032
7025
|
try {
|
|
7033
7026
|
subEntries = readdirSync4(subDir, { withFileTypes: true });
|
|
@@ -7038,11 +7031,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
7038
7031
|
}
|
|
7039
7032
|
for (const sub of subEntries) {
|
|
7040
7033
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
7041
|
-
out.push({ path:
|
|
7034
|
+
out.push({ path: join8(subDir, sub.name), isSubagent: true, archived: false });
|
|
7042
7035
|
}
|
|
7043
7036
|
}
|
|
7044
7037
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
7045
|
-
const archiveDir =
|
|
7038
|
+
const archiveDir = join8(slugDir, entry.name);
|
|
7046
7039
|
let archiveEntries;
|
|
7047
7040
|
try {
|
|
7048
7041
|
archiveEntries = readdirSync4(archiveDir, { withFileTypes: true });
|
|
@@ -7053,7 +7046,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
7053
7046
|
}
|
|
7054
7047
|
for (const arc of archiveEntries) {
|
|
7055
7048
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
7056
|
-
out.push({ path:
|
|
7049
|
+
out.push({ path: join8(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
7057
7050
|
}
|
|
7058
7051
|
}
|
|
7059
7052
|
}
|
|
@@ -7086,7 +7079,7 @@ async function fetchLiveSessions() {
|
|
|
7086
7079
|
function loadUserTitles(accountDir) {
|
|
7087
7080
|
const out = /* @__PURE__ */ new Map();
|
|
7088
7081
|
if (!accountDir) return out;
|
|
7089
|
-
const path2 =
|
|
7082
|
+
const path2 = join8(accountDir, "session-titles.json");
|
|
7090
7083
|
let raw;
|
|
7091
7084
|
try {
|
|
7092
7085
|
raw = readFileSync8(path2, "utf8");
|
|
@@ -7183,10 +7176,10 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7183
7176
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
7184
7177
|
return c.json({ sessions: [], accountId });
|
|
7185
7178
|
}
|
|
7186
|
-
const projectsRoot =
|
|
7179
|
+
const projectsRoot = join8(configDir2, "projects");
|
|
7187
7180
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
7188
7181
|
const liveSessions = await fetchLiveSessions();
|
|
7189
|
-
const accountDir = accountId ?
|
|
7182
|
+
const accountDir = accountId ? resolve9(ACCOUNTS_DIR, accountId) : null;
|
|
7190
7183
|
const userTitles = loadUserTitles(accountDir);
|
|
7191
7184
|
const rows = [];
|
|
7192
7185
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -7217,7 +7210,7 @@ app4.get("/", requireAdminSession, async (c) => {
|
|
|
7217
7210
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
7218
7211
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
7219
7212
|
titleSourceCounts[resolved.source] += 1;
|
|
7220
|
-
const metaPath =
|
|
7213
|
+
const metaPath = join8(projectDir, `${sessionId}.meta.json`);
|
|
7221
7214
|
const { bridgeIds, role, channel } = readSidecarMeta(metaPath);
|
|
7222
7215
|
const resumable = !(role === PUBLIC_ROLE && channel === WEBCHAT_CHANNEL);
|
|
7223
7216
|
rows.push({
|
|
@@ -7264,7 +7257,7 @@ function selectAdminChannelSessions(rows) {
|
|
|
7264
7257
|
// app/lib/admin-identity/pin-validator.ts
|
|
7265
7258
|
import { createHash as createHash2 } from "crypto";
|
|
7266
7259
|
import { existsSync as existsSync6, readFileSync as readFileSync9, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
7267
|
-
import { join as
|
|
7260
|
+
import { join as join9 } from "path";
|
|
7268
7261
|
function hashPin(pin) {
|
|
7269
7262
|
return createHash2("sha256").update(pin).digest("hex");
|
|
7270
7263
|
}
|
|
@@ -7298,13 +7291,13 @@ function scanForOrphanedAccountAdmins(users, accountsDir) {
|
|
|
7298
7291
|
}
|
|
7299
7292
|
for (const entry of entries) {
|
|
7300
7293
|
if (entry.startsWith(".")) continue;
|
|
7301
|
-
const accountDir =
|
|
7294
|
+
const accountDir = join9(accountsDir, entry);
|
|
7302
7295
|
try {
|
|
7303
7296
|
if (!statSync3(accountDir).isDirectory()) continue;
|
|
7304
7297
|
} catch {
|
|
7305
7298
|
continue;
|
|
7306
7299
|
}
|
|
7307
|
-
const accountJsonPath =
|
|
7300
|
+
const accountJsonPath = join9(accountDir, "account.json");
|
|
7308
7301
|
if (!existsSync6(accountJsonPath)) continue;
|
|
7309
7302
|
try {
|
|
7310
7303
|
const config = JSON.parse(readFileSync9(accountJsonPath, "utf-8"));
|
|
@@ -7484,13 +7477,13 @@ var app5 = new Hono();
|
|
|
7484
7477
|
app5.get("/conversations", requireAdminSession, async (c) => {
|
|
7485
7478
|
const cfg = claudeConfigDir();
|
|
7486
7479
|
if (!cfg) return c.json({ conversations: [] });
|
|
7487
|
-
const projectsRoot =
|
|
7480
|
+
const projectsRoot = join10(cfg, "projects");
|
|
7488
7481
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7489
7482
|
const rows = [];
|
|
7490
7483
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7491
7484
|
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7492
7485
|
const projectDir = dirname(path2);
|
|
7493
|
-
const meta = readSidecarMeta(
|
|
7486
|
+
const meta = readSidecarMeta(join10(projectDir, `${sessionId}.meta.json`));
|
|
7494
7487
|
if (meta.role !== "admin" || meta.channel !== "whatsapp" && meta.channel !== "telegram") continue;
|
|
7495
7488
|
let body = "";
|
|
7496
7489
|
try {
|
|
@@ -7577,11 +7570,11 @@ app5.get("/stream", requireAdminSession, (c) => {
|
|
|
7577
7570
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7578
7571
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7579
7572
|
const cfg = claudeConfigDir();
|
|
7580
|
-
const projectsRoot = cfg ?
|
|
7573
|
+
const projectsRoot = cfg ? resolve10(join10(cfg, "projects")) : null;
|
|
7581
7574
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7582
7575
|
return c.json({ error: "bad session reference" }, 400);
|
|
7583
7576
|
}
|
|
7584
|
-
const jsonlPath =
|
|
7577
|
+
const jsonlPath = resolve10(join10(projectDir, `${sessionId}.jsonl`));
|
|
7585
7578
|
if (!jsonlPath.startsWith(projectsRoot + sep2)) {
|
|
7586
7579
|
return c.json({ error: "bad session reference" }, 400);
|
|
7587
7580
|
}
|
|
@@ -7668,7 +7661,7 @@ var DIRECTIVE_NAME_RE = /^\d+-\d+\.txt$/;
|
|
|
7668
7661
|
function directiveStoreDir(sessionId) {
|
|
7669
7662
|
const account = resolveAccount();
|
|
7670
7663
|
if (!account) return null;
|
|
7671
|
-
return
|
|
7664
|
+
return resolve10(account.accountDir, "logs", "prompt-optimiser-directives", sessionId);
|
|
7672
7665
|
}
|
|
7673
7666
|
app5.get("/directives", requireAdminSession, (c) => {
|
|
7674
7667
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
@@ -7687,7 +7680,7 @@ app5.get("/directives", requireAdminSession, (c) => {
|
|
|
7687
7680
|
const pid = Number(pidPart);
|
|
7688
7681
|
let len = 0;
|
|
7689
7682
|
try {
|
|
7690
|
-
len = statSync4(
|
|
7683
|
+
len = statSync4(join10(dir, name)).size;
|
|
7691
7684
|
} catch {
|
|
7692
7685
|
}
|
|
7693
7686
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -7702,7 +7695,7 @@ app5.get("/directive", requireAdminSession, (c) => {
|
|
|
7702
7695
|
}
|
|
7703
7696
|
const dir = directiveStoreDir(sessionId);
|
|
7704
7697
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
7705
|
-
const path2 =
|
|
7698
|
+
const path2 = resolve10(join10(dir, name));
|
|
7706
7699
|
if (!path2.startsWith(dir + sep2)) return c.json({ error: "bad reference" }, 400);
|
|
7707
7700
|
let body;
|
|
7708
7701
|
try {
|
|
@@ -7716,22 +7709,34 @@ var whatsapp_reader_default = app5;
|
|
|
7716
7709
|
|
|
7717
7710
|
// server/routes/webchat.ts
|
|
7718
7711
|
import { basename as basename3, dirname as dirname2 } from "path";
|
|
7719
|
-
import { join as
|
|
7720
|
-
import { readFileSync as readFileSync11, renameSync, writeFileSync as writeFileSync5 } from "fs";
|
|
7712
|
+
import { join as join11 } from "path";
|
|
7713
|
+
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync11, renameSync, writeFileSync as writeFileSync5 } from "fs";
|
|
7721
7714
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
7722
7715
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7723
7716
|
function locateSession(sessionId) {
|
|
7724
7717
|
const cfg = claudeConfigDir();
|
|
7725
7718
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7726
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7719
|
+
for (const { path: path2 } of enumerateJsonls(join11(cfg, "projects"))) {
|
|
7727
7720
|
if (basename3(path2) === `${sessionId}.jsonl`) {
|
|
7728
7721
|
const dir = dirname2(path2);
|
|
7729
|
-
const meta = readSidecarMeta(
|
|
7722
|
+
const meta = readSidecarMeta(join11(dir, `${sessionId}.meta.json`));
|
|
7730
7723
|
return { projectDir: dir, channel: meta.channel };
|
|
7731
7724
|
}
|
|
7732
7725
|
}
|
|
7733
7726
|
return { projectDir: null, channel: null };
|
|
7734
7727
|
}
|
|
7728
|
+
function sessionSidecarExists(sessionId) {
|
|
7729
|
+
const cfg = claudeConfigDir();
|
|
7730
|
+
if (!cfg) return false;
|
|
7731
|
+
const projectsRoot = join11(cfg, "projects");
|
|
7732
|
+
let slugs;
|
|
7733
|
+
try {
|
|
7734
|
+
slugs = readdirSync7(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
7735
|
+
} catch {
|
|
7736
|
+
return false;
|
|
7737
|
+
}
|
|
7738
|
+
return slugs.some((slug) => existsSync8(join11(projectsRoot, slug, `${sessionId}.meta.json`)));
|
|
7739
|
+
}
|
|
7735
7740
|
function conflictingBinding(channel) {
|
|
7736
7741
|
return channel !== null && channel !== "webchat" ? channel : null;
|
|
7737
7742
|
}
|
|
@@ -7958,7 +7963,7 @@ ${note}` : note;
|
|
|
7958
7963
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
7959
7964
|
return c.json({ error: "account unresolved" }, 503);
|
|
7960
7965
|
}
|
|
7961
|
-
const accountJsonPath =
|
|
7966
|
+
const accountJsonPath = join11(account.accountDir, "account.json");
|
|
7962
7967
|
try {
|
|
7963
7968
|
const parsed = JSON.parse(readFileSync11(accountJsonPath, "utf8"));
|
|
7964
7969
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -7991,14 +7996,15 @@ ${note}` : note;
|
|
|
7991
7996
|
return c.json({ error: "invalid session id" }, 400);
|
|
7992
7997
|
}
|
|
7993
7998
|
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
7999
|
+
const known = projectDir2 !== null || sessionSidecarExists(target);
|
|
7994
8000
|
const indicators2 = await fetchComposerIndicators(target);
|
|
7995
|
-
return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), ...indicators2 });
|
|
8001
|
+
return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), known, ...indicators2 });
|
|
7996
8002
|
}
|
|
7997
8003
|
const sessionId = adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
7998
8004
|
const cfg = claudeConfigDir();
|
|
7999
8005
|
let projectDir = null;
|
|
8000
8006
|
if (cfg) {
|
|
8001
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8007
|
+
for (const { path: path2 } of enumerateJsonls(join11(cfg, "projects"))) {
|
|
8002
8008
|
if (basename3(path2) === `${sessionId}.jsonl`) {
|
|
8003
8009
|
projectDir = dirname2(path2);
|
|
8004
8010
|
break;
|
|
@@ -8012,11 +8018,11 @@ ${note}` : note;
|
|
|
8012
8018
|
}
|
|
8013
8019
|
|
|
8014
8020
|
// server/routes/webchat-greeting.ts
|
|
8015
|
-
import { resolve as
|
|
8021
|
+
import { resolve as resolve11 } from "path";
|
|
8016
8022
|
|
|
8017
8023
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8018
|
-
import { existsSync as
|
|
8019
|
-
import { join as
|
|
8024
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12, readdirSync as readdirSync8 } from "fs";
|
|
8025
|
+
import { join as join12 } from "path";
|
|
8020
8026
|
function field(fm, name) {
|
|
8021
8027
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8022
8028
|
if (!m) return null;
|
|
@@ -8027,15 +8033,15 @@ function field(fm, name) {
|
|
|
8027
8033
|
return value || null;
|
|
8028
8034
|
}
|
|
8029
8035
|
function readSpecialistRoster(specialistsDir) {
|
|
8030
|
-
if (!
|
|
8031
|
-
const entries =
|
|
8036
|
+
if (!existsSync9(specialistsDir)) return { specialists: [], skipped: [] };
|
|
8037
|
+
const entries = readdirSync8(specialistsDir);
|
|
8032
8038
|
const specialists = [];
|
|
8033
8039
|
const skipped = [];
|
|
8034
8040
|
for (const file of entries.sort()) {
|
|
8035
8041
|
if (!file.endsWith(".md")) continue;
|
|
8036
8042
|
let raw;
|
|
8037
8043
|
try {
|
|
8038
|
-
raw = readFileSync12(
|
|
8044
|
+
raw = readFileSync12(join12(specialistsDir, file), "utf-8");
|
|
8039
8045
|
} catch (err) {
|
|
8040
8046
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8041
8047
|
continue;
|
|
@@ -8117,7 +8123,7 @@ app6.get("/", requireAdminSession, async (c) => {
|
|
|
8117
8123
|
let specialists = [];
|
|
8118
8124
|
try {
|
|
8119
8125
|
const roster = readSpecialistRoster(
|
|
8120
|
-
|
|
8126
|
+
resolve11(ACCOUNTS_DIR, accountId, "specialists", "agents")
|
|
8121
8127
|
);
|
|
8122
8128
|
specialists = roster.specialists;
|
|
8123
8129
|
for (const s of roster.skipped) {
|
|
@@ -8152,8 +8158,8 @@ var webchat_greeting_default = app6;
|
|
|
8152
8158
|
|
|
8153
8159
|
// server/routes/telegram.ts
|
|
8154
8160
|
import { homedir } from "os";
|
|
8155
|
-
import { resolve as
|
|
8156
|
-
import { existsSync as
|
|
8161
|
+
import { resolve as resolve12, join as join13 } from "path";
|
|
8162
|
+
import { existsSync as existsSync10, readFileSync as readFileSync13 } from "fs";
|
|
8157
8163
|
|
|
8158
8164
|
// app/lib/telegram/access-control.ts
|
|
8159
8165
|
function checkTelegramAccess(params) {
|
|
@@ -8203,9 +8209,9 @@ function routeTelegramUpdate(input) {
|
|
|
8203
8209
|
var TAG22 = "[telegram-inbound]";
|
|
8204
8210
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
8205
8211
|
function configDirName() {
|
|
8206
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
8207
|
-
const brandPath =
|
|
8208
|
-
if (
|
|
8212
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve12(process.cwd(), "..");
|
|
8213
|
+
const brandPath = join13(platformRoot2, "config", "brand.json");
|
|
8214
|
+
if (existsSync10(brandPath)) {
|
|
8209
8215
|
try {
|
|
8210
8216
|
return JSON.parse(readFileSync13(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
8211
8217
|
} catch {
|
|
@@ -8215,7 +8221,7 @@ function configDirName() {
|
|
|
8215
8221
|
}
|
|
8216
8222
|
function secretPath(botType) {
|
|
8217
8223
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
8218
|
-
return
|
|
8224
|
+
return resolve12(homedir(), configDirName(), filename);
|
|
8219
8225
|
}
|
|
8220
8226
|
async function sendTelegram(botToken, chatId, text) {
|
|
8221
8227
|
try {
|
|
@@ -8239,7 +8245,7 @@ app7.post("/", async (c) => {
|
|
|
8239
8245
|
return c.json({ ok: false }, 400);
|
|
8240
8246
|
}
|
|
8241
8247
|
const sp = secretPath(botType);
|
|
8242
|
-
if (!
|
|
8248
|
+
if (!existsSync10(sp)) {
|
|
8243
8249
|
console.error(`${TAG22} op=reject reason=no-secret-file botType=${botType}`);
|
|
8244
8250
|
return c.json({ ok: false }, 401);
|
|
8245
8251
|
}
|
|
@@ -8306,12 +8312,12 @@ var telegram_default = app7;
|
|
|
8306
8312
|
|
|
8307
8313
|
// server/routes/onboarding.ts
|
|
8308
8314
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
8309
|
-
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync7, writeSync, existsSync as
|
|
8315
|
+
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync7, writeSync, existsSync as existsSync12, readFileSync as readFileSync15, unlinkSync } from "fs";
|
|
8310
8316
|
import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
8311
8317
|
|
|
8312
8318
|
// ../lib/admins-write/src/index.ts
|
|
8313
|
-
import { existsSync as
|
|
8314
|
-
import { dirname as dirname3, join as
|
|
8319
|
+
import { existsSync as existsSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync6, renameSync as renameSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
|
|
8320
|
+
import { dirname as dirname3, join as join14 } from "path";
|
|
8315
8321
|
function logLine(input, result) {
|
|
8316
8322
|
const userIdShort = input.userId.slice(0, 8);
|
|
8317
8323
|
console.error(
|
|
@@ -8328,7 +8334,7 @@ function writeAdminEntry(input) {
|
|
|
8328
8334
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
8329
8335
|
try {
|
|
8330
8336
|
let users = [];
|
|
8331
|
-
if (
|
|
8337
|
+
if (existsSync11(input.usersFile)) {
|
|
8332
8338
|
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8333
8339
|
if (raw) {
|
|
8334
8340
|
const parsed = JSON.parse(raw);
|
|
@@ -8353,8 +8359,8 @@ function writeAdminEntry(input) {
|
|
|
8353
8359
|
return result;
|
|
8354
8360
|
}
|
|
8355
8361
|
try {
|
|
8356
|
-
const accountJsonPath =
|
|
8357
|
-
if (!
|
|
8362
|
+
const accountJsonPath = join14(input.accountDir, "account.json");
|
|
8363
|
+
if (!existsSync11(accountJsonPath)) {
|
|
8358
8364
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
8359
8365
|
}
|
|
8360
8366
|
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
@@ -8381,7 +8387,7 @@ function checkAdminAuthInvariant(input) {
|
|
|
8381
8387
|
usersWithoutAccount: []
|
|
8382
8388
|
};
|
|
8383
8389
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
8384
|
-
if (
|
|
8390
|
+
if (existsSync11(input.usersFile)) {
|
|
8385
8391
|
try {
|
|
8386
8392
|
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8387
8393
|
if (raw) {
|
|
@@ -8396,10 +8402,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
8396
8402
|
}
|
|
8397
8403
|
}
|
|
8398
8404
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
8399
|
-
if (
|
|
8405
|
+
if (existsSync11(input.accountsDir)) {
|
|
8400
8406
|
let entries;
|
|
8401
8407
|
try {
|
|
8402
|
-
entries =
|
|
8408
|
+
entries = readdirSync9(input.accountsDir);
|
|
8403
8409
|
} catch (err) {
|
|
8404
8410
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8405
8411
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -8408,14 +8414,14 @@ function checkAdminAuthInvariant(input) {
|
|
|
8408
8414
|
}
|
|
8409
8415
|
for (const entry of entries) {
|
|
8410
8416
|
if (entry.startsWith(".")) continue;
|
|
8411
|
-
const accountDir =
|
|
8417
|
+
const accountDir = join14(input.accountsDir, entry);
|
|
8412
8418
|
try {
|
|
8413
8419
|
if (!statSync5(accountDir).isDirectory()) continue;
|
|
8414
8420
|
} catch {
|
|
8415
8421
|
continue;
|
|
8416
8422
|
}
|
|
8417
|
-
const accountJsonPath =
|
|
8418
|
-
if (!
|
|
8423
|
+
const accountJsonPath = join14(accountDir, "account.json");
|
|
8424
|
+
if (!existsSync11(accountJsonPath)) continue;
|
|
8419
8425
|
let admins = [];
|
|
8420
8426
|
try {
|
|
8421
8427
|
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
@@ -8458,7 +8464,7 @@ function hashPin2(pin) {
|
|
|
8458
8464
|
return createHash3("sha256").update(pin).digest("hex");
|
|
8459
8465
|
}
|
|
8460
8466
|
function readUsersFile2() {
|
|
8461
|
-
if (!
|
|
8467
|
+
if (!existsSync12(USERS_FILE)) return null;
|
|
8462
8468
|
const raw = readFileSync15(USERS_FILE, "utf-8").trim();
|
|
8463
8469
|
if (!raw) return [];
|
|
8464
8470
|
return JSON.parse(raw);
|
|
@@ -8512,7 +8518,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
8512
8518
|
} catch (err) {
|
|
8513
8519
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
8514
8520
|
}
|
|
8515
|
-
const credentialsPresent =
|
|
8521
|
+
const credentialsPresent = existsSync12(CLAUDE_CREDENTIALS_FILE);
|
|
8516
8522
|
const ranMs = Date.now() - start;
|
|
8517
8523
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
8518
8524
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -8619,7 +8625,7 @@ app8.post("/set-pin", async (c) => {
|
|
|
8619
8625
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
8620
8626
|
if (process.platform === "linux") {
|
|
8621
8627
|
let installOwner = null;
|
|
8622
|
-
if (
|
|
8628
|
+
if (existsSync12(INSTALL_OWNER_FILE)) {
|
|
8623
8629
|
try {
|
|
8624
8630
|
const raw = readFileSync15(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
8625
8631
|
if (raw.length > 0) installOwner = raw;
|
|
@@ -8702,9 +8708,9 @@ app8.delete("/set-pin", async (c) => {
|
|
|
8702
8708
|
var onboarding_default = app8;
|
|
8703
8709
|
|
|
8704
8710
|
// server/routes/client-error.ts
|
|
8705
|
-
import { appendFileSync, existsSync as
|
|
8706
|
-
import { join as
|
|
8707
|
-
var CLIENT_ERRORS_LOG =
|
|
8711
|
+
import { appendFileSync, existsSync as existsSync13, renameSync as renameSync3, statSync as statSync6 } from "fs";
|
|
8712
|
+
import { join as join15 } from "path";
|
|
8713
|
+
var CLIENT_ERRORS_LOG = join15(LOG_DIR, "client-errors.log");
|
|
8708
8714
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
8709
8715
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
8710
8716
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -8747,7 +8753,7 @@ function stackHead(stack) {
|
|
|
8747
8753
|
}
|
|
8748
8754
|
function rotateIfNeeded() {
|
|
8749
8755
|
try {
|
|
8750
|
-
if (!
|
|
8756
|
+
if (!existsSync13(CLIENT_ERRORS_LOG)) return;
|
|
8751
8757
|
const stats = statSync6(CLIENT_ERRORS_LOG);
|
|
8752
8758
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
8753
8759
|
renameSync3(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
@@ -9029,18 +9035,18 @@ app10.post("/", async (c) => {
|
|
|
9029
9035
|
var session_default = app10;
|
|
9030
9036
|
|
|
9031
9037
|
// server/routes/admin/logs.ts
|
|
9032
|
-
import { existsSync as
|
|
9033
|
-
import { resolve as
|
|
9038
|
+
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync16, statSync as statSync7 } from "fs";
|
|
9039
|
+
import { resolve as resolve13, basename as basename4 } from "path";
|
|
9034
9040
|
|
|
9035
9041
|
// app/lib/logs-read-resolve.ts
|
|
9036
|
-
import { existsSync as
|
|
9037
|
-
import { join as
|
|
9042
|
+
import { existsSync as existsSync14 } from "fs";
|
|
9043
|
+
import { join as join16 } from "path";
|
|
9038
9044
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9039
9045
|
const tried = [filename];
|
|
9040
9046
|
const hits = [];
|
|
9041
9047
|
for (const dir of logDirs) {
|
|
9042
|
-
const fullPath =
|
|
9043
|
-
if (
|
|
9048
|
+
const fullPath = join16(dir, filename);
|
|
9049
|
+
if (existsSync14(fullPath)) {
|
|
9044
9050
|
hits.push({ path: fullPath, dir });
|
|
9045
9051
|
}
|
|
9046
9052
|
}
|
|
@@ -9057,7 +9063,7 @@ app11.get("/", async (c) => {
|
|
|
9057
9063
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
9058
9064
|
const download = c.req.query("download") === "1";
|
|
9059
9065
|
const account = resolveAccount();
|
|
9060
|
-
const accountLogDir = account ?
|
|
9066
|
+
const accountLogDir = account ? resolve13(account.accountDir, "logs") : null;
|
|
9061
9067
|
const logDirs = [];
|
|
9062
9068
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
9063
9069
|
logDirs.push(LOG_DIR);
|
|
@@ -9065,7 +9071,7 @@ app11.get("/", async (c) => {
|
|
|
9065
9071
|
const safe = basename4(fileParam);
|
|
9066
9072
|
const searched = [];
|
|
9067
9073
|
for (const dir of logDirs) {
|
|
9068
|
-
const filePath =
|
|
9074
|
+
const filePath = resolve13(dir, safe);
|
|
9069
9075
|
searched.push(filePath);
|
|
9070
9076
|
try {
|
|
9071
9077
|
const buffer = readFileSync16(filePath);
|
|
@@ -9168,19 +9174,19 @@ app11.get("/", async (c) => {
|
|
|
9168
9174
|
const seen = /* @__PURE__ */ new Set();
|
|
9169
9175
|
const logs = {};
|
|
9170
9176
|
for (const dir of logDirs) {
|
|
9171
|
-
if (!
|
|
9177
|
+
if (!existsSync15(dir)) continue;
|
|
9172
9178
|
let files;
|
|
9173
9179
|
try {
|
|
9174
|
-
files =
|
|
9180
|
+
files = readdirSync10(dir).filter((f) => f.endsWith(".log"));
|
|
9175
9181
|
} catch (err) {
|
|
9176
9182
|
const reason = err instanceof Error ? err.message : String(err);
|
|
9177
9183
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
9178
9184
|
continue;
|
|
9179
9185
|
}
|
|
9180
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(
|
|
9186
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve13(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
9181
9187
|
seen.add(name);
|
|
9182
9188
|
try {
|
|
9183
|
-
const content = readFileSync16(
|
|
9189
|
+
const content = readFileSync16(resolve13(dir, name));
|
|
9184
9190
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
9185
9191
|
logs[name] = tail.trim() || "(empty)";
|
|
9186
9192
|
} catch (err) {
|
|
@@ -9219,8 +9225,8 @@ var claude_info_default = app12;
|
|
|
9219
9225
|
|
|
9220
9226
|
// server/routes/admin/attachment.ts
|
|
9221
9227
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
9222
|
-
import { existsSync as
|
|
9223
|
-
import { resolve as
|
|
9228
|
+
import { existsSync as existsSync16 } from "fs";
|
|
9229
|
+
import { resolve as resolve14 } from "path";
|
|
9224
9230
|
var app13 = new Hono();
|
|
9225
9231
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
9226
9232
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -9232,12 +9238,12 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9232
9238
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
9233
9239
|
return new Response("Not found", { status: 404 });
|
|
9234
9240
|
}
|
|
9235
|
-
const dir =
|
|
9236
|
-
if (!
|
|
9241
|
+
const dir = resolve14(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
9242
|
+
if (!existsSync16(dir)) {
|
|
9237
9243
|
return new Response("Not found", { status: 404 });
|
|
9238
9244
|
}
|
|
9239
|
-
const metaPath =
|
|
9240
|
-
if (!
|
|
9245
|
+
const metaPath = resolve14(dir, `${attachmentId}.meta.json`);
|
|
9246
|
+
if (!existsSync16(metaPath)) {
|
|
9241
9247
|
return new Response("Not found", { status: 404 });
|
|
9242
9248
|
}
|
|
9243
9249
|
let meta;
|
|
@@ -9251,7 +9257,7 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9251
9257
|
if (!dataFile) {
|
|
9252
9258
|
return new Response("Not found", { status: 404 });
|
|
9253
9259
|
}
|
|
9254
|
-
const filePath =
|
|
9260
|
+
const filePath = resolve14(dir, dataFile);
|
|
9255
9261
|
const buffer = await readFile2(filePath);
|
|
9256
9262
|
return new Response(new Uint8Array(buffer), {
|
|
9257
9263
|
headers: {
|
|
@@ -9264,22 +9270,22 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9264
9270
|
var attachment_default = app13;
|
|
9265
9271
|
|
|
9266
9272
|
// server/routes/admin/agents.ts
|
|
9267
|
-
import { resolve as
|
|
9268
|
-
import { readdirSync as
|
|
9273
|
+
import { resolve as resolve15 } from "path";
|
|
9274
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync17, existsSync as existsSync17, rmSync } from "fs";
|
|
9269
9275
|
var app14 = new Hono();
|
|
9270
9276
|
app14.get("/", (c) => {
|
|
9271
9277
|
const account = resolveAccount();
|
|
9272
9278
|
if (!account) return c.json({ agents: [] });
|
|
9273
|
-
const agentsDir =
|
|
9274
|
-
if (!
|
|
9279
|
+
const agentsDir = resolve15(account.accountDir, "agents");
|
|
9280
|
+
if (!existsSync17(agentsDir)) return c.json({ agents: [] });
|
|
9275
9281
|
const agents = [];
|
|
9276
9282
|
try {
|
|
9277
|
-
const entries =
|
|
9283
|
+
const entries = readdirSync11(agentsDir, { withFileTypes: true });
|
|
9278
9284
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
9279
9285
|
if (!entry.isDirectory()) continue;
|
|
9280
9286
|
if (entry.name === "admin") continue;
|
|
9281
|
-
const configPath2 =
|
|
9282
|
-
if (!
|
|
9287
|
+
const configPath2 = resolve15(agentsDir, entry.name, "config.json");
|
|
9288
|
+
if (!existsSync17(configPath2)) continue;
|
|
9283
9289
|
try {
|
|
9284
9290
|
const config = JSON.parse(readFileSync17(configPath2, "utf-8"));
|
|
9285
9291
|
agents.push({
|
|
@@ -9307,8 +9313,8 @@ app14.delete("/:slug", async (c) => {
|
|
|
9307
9313
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9308
9314
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9309
9315
|
}
|
|
9310
|
-
const agentDir =
|
|
9311
|
-
if (!
|
|
9316
|
+
const agentDir = resolve15(account.accountDir, "agents", slug);
|
|
9317
|
+
if (!existsSync17(agentDir)) {
|
|
9312
9318
|
return c.json({ error: "Agent not found" }, 404);
|
|
9313
9319
|
}
|
|
9314
9320
|
try {
|
|
@@ -9337,8 +9343,8 @@ app14.post("/:slug/project", async (c) => {
|
|
|
9337
9343
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9338
9344
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9339
9345
|
}
|
|
9340
|
-
const agentDir =
|
|
9341
|
-
if (!
|
|
9346
|
+
const agentDir = resolve15(account.accountDir, "agents", slug);
|
|
9347
|
+
if (!existsSync17(agentDir)) {
|
|
9342
9348
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9343
9349
|
}
|
|
9344
9350
|
try {
|
|
@@ -9354,7 +9360,7 @@ var agents_default = app14;
|
|
|
9354
9360
|
// server/routes/admin/sessions.ts
|
|
9355
9361
|
import crypto2 from "crypto";
|
|
9356
9362
|
import { resolve as resolvePath } from "path";
|
|
9357
|
-
import { existsSync as
|
|
9363
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync3, createWriteStream } from "fs";
|
|
9358
9364
|
|
|
9359
9365
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
9360
9366
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -9514,7 +9520,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
9514
9520
|
let reason = null;
|
|
9515
9521
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
9516
9522
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
9517
|
-
else if (!
|
|
9523
|
+
else if (!existsSync18(a.storagePath)) reason = "missing-file";
|
|
9518
9524
|
if (reason) {
|
|
9519
9525
|
invalid++;
|
|
9520
9526
|
try {
|
|
@@ -10040,8 +10046,8 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10040
10046
|
var sessions_default = app15;
|
|
10041
10047
|
|
|
10042
10048
|
// app/lib/claude-agent/spawn-context.ts
|
|
10043
|
-
import { existsSync as
|
|
10044
|
-
import { dirname as dirname4, resolve as
|
|
10049
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, readdirSync as readdirSync12, statSync as statSync8 } from "fs";
|
|
10050
|
+
import { dirname as dirname4, resolve as resolve16, join as join17 } from "path";
|
|
10045
10051
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10046
10052
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10047
10053
|
try {
|
|
@@ -10070,12 +10076,12 @@ function frontmatterField(manifest, field2) {
|
|
|
10070
10076
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10071
10077
|
const out = /* @__PURE__ */ new Map();
|
|
10072
10078
|
const candidates = [
|
|
10073
|
-
|
|
10074
|
-
|
|
10079
|
+
join17(pluginDir, "mcp/dist/index.js"),
|
|
10080
|
+
join17(pluginDir, "mcp/src/index.ts")
|
|
10075
10081
|
];
|
|
10076
10082
|
let raw = null;
|
|
10077
10083
|
for (const path2 of candidates) {
|
|
10078
|
-
if (!
|
|
10084
|
+
if (!existsSync19(path2)) continue;
|
|
10079
10085
|
try {
|
|
10080
10086
|
raw = readFileSync18(path2, "utf-8");
|
|
10081
10087
|
break;
|
|
@@ -10126,24 +10132,24 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
10126
10132
|
}
|
|
10127
10133
|
function listPluginDirs() {
|
|
10128
10134
|
const out = /* @__PURE__ */ new Map();
|
|
10129
|
-
const platformPlugins =
|
|
10130
|
-
if (
|
|
10131
|
-
for (const name of
|
|
10132
|
-
const dir =
|
|
10135
|
+
const platformPlugins = resolve16(PLATFORM_ROOT, "plugins");
|
|
10136
|
+
if (existsSync19(platformPlugins)) {
|
|
10137
|
+
for (const name of readdirSync12(platformPlugins)) {
|
|
10138
|
+
const dir = join17(platformPlugins, name);
|
|
10133
10139
|
try {
|
|
10134
10140
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
10135
10141
|
} catch {
|
|
10136
10142
|
}
|
|
10137
10143
|
}
|
|
10138
10144
|
}
|
|
10139
|
-
const premiumRoot =
|
|
10140
|
-
if (
|
|
10141
|
-
for (const bundle of
|
|
10142
|
-
const bundlePlugins =
|
|
10143
|
-
if (!
|
|
10145
|
+
const premiumRoot = resolve16(dirname4(PLATFORM_ROOT), "premium-plugins");
|
|
10146
|
+
if (existsSync19(premiumRoot)) {
|
|
10147
|
+
for (const bundle of readdirSync12(premiumRoot)) {
|
|
10148
|
+
const bundlePlugins = join17(premiumRoot, bundle, "plugins");
|
|
10149
|
+
if (!existsSync19(bundlePlugins)) continue;
|
|
10144
10150
|
try {
|
|
10145
|
-
for (const name of
|
|
10146
|
-
const dir =
|
|
10151
|
+
for (const name of readdirSync12(bundlePlugins)) {
|
|
10152
|
+
const dir = join17(bundlePlugins, name);
|
|
10147
10153
|
try {
|
|
10148
10154
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
10149
10155
|
} catch {
|
|
@@ -10156,8 +10162,8 @@ function listPluginDirs() {
|
|
|
10156
10162
|
return out;
|
|
10157
10163
|
}
|
|
10158
10164
|
function readEnabledPlugins(accountId) {
|
|
10159
|
-
const accountFile =
|
|
10160
|
-
if (!
|
|
10165
|
+
const accountFile = resolve16(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10166
|
+
if (!existsSync19(accountFile)) return /* @__PURE__ */ new Set();
|
|
10161
10167
|
try {
|
|
10162
10168
|
const parsed = JSON.parse(readFileSync18(accountFile, "utf-8"));
|
|
10163
10169
|
return new Set(
|
|
@@ -10168,7 +10174,7 @@ function readEnabledPlugins(accountId) {
|
|
|
10168
10174
|
}
|
|
10169
10175
|
}
|
|
10170
10176
|
function readFrontmatter(path2) {
|
|
10171
|
-
if (!
|
|
10177
|
+
if (!existsSync19(path2)) return null;
|
|
10172
10178
|
let raw;
|
|
10173
10179
|
try {
|
|
10174
10180
|
raw = readFileSync18(path2, "utf-8");
|
|
@@ -10186,7 +10192,7 @@ function computeActivePlugins(accountId) {
|
|
|
10186
10192
|
for (const name of Array.from(enabled).sort()) {
|
|
10187
10193
|
const dir = pluginDirs.get(name);
|
|
10188
10194
|
if (!dir) continue;
|
|
10189
|
-
const fm = readFrontmatter(
|
|
10195
|
+
const fm = readFrontmatter(join17(dir, "PLUGIN.md"));
|
|
10190
10196
|
if (!fm) continue;
|
|
10191
10197
|
const description = frontmatterField(`---
|
|
10192
10198
|
${fm}
|
|
@@ -10203,7 +10209,7 @@ ${fm}
|
|
|
10203
10209
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
10204
10210
|
);
|
|
10205
10211
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
10206
|
-
const hasSource =
|
|
10212
|
+
const hasSource = existsSync19(join17(dir, "mcp/dist/index.js")) || existsSync19(join17(dir, "mcp/src/index.ts"));
|
|
10207
10213
|
if (hasSource) {
|
|
10208
10214
|
console.warn(
|
|
10209
10215
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -10213,7 +10219,7 @@ ${fm}
|
|
|
10213
10219
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
10214
10220
|
const skills = [];
|
|
10215
10221
|
for (const relPath of skillPaths) {
|
|
10216
|
-
const skillPath =
|
|
10222
|
+
const skillPath = join17(dir, relPath);
|
|
10217
10223
|
const skillFm = readFrontmatter(skillPath);
|
|
10218
10224
|
if (!skillFm) continue;
|
|
10219
10225
|
const skillName = frontmatterField(`---
|
|
@@ -10229,11 +10235,11 @@ ${skillFm}
|
|
|
10229
10235
|
return out;
|
|
10230
10236
|
}
|
|
10231
10237
|
function computeSpecialistDomains(accountId) {
|
|
10232
|
-
const specialistsDir =
|
|
10233
|
-
if (!
|
|
10238
|
+
const specialistsDir = resolve16(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10239
|
+
if (!existsSync19(specialistsDir)) return [];
|
|
10234
10240
|
let entries;
|
|
10235
10241
|
try {
|
|
10236
|
-
entries =
|
|
10242
|
+
entries = readdirSync12(specialistsDir);
|
|
10237
10243
|
} catch {
|
|
10238
10244
|
return [];
|
|
10239
10245
|
}
|
|
@@ -10257,7 +10263,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
10257
10263
|
const out = [];
|
|
10258
10264
|
for (const file of entries.sort()) {
|
|
10259
10265
|
if (!file.endsWith(".md")) continue;
|
|
10260
|
-
const fm = readFrontmatter(
|
|
10266
|
+
const fm = readFrontmatter(join17(specialistsDir, file));
|
|
10261
10267
|
if (!fm) continue;
|
|
10262
10268
|
const wrapped = `---
|
|
10263
10269
|
${fm}
|
|
@@ -10275,8 +10281,8 @@ ${fm}
|
|
|
10275
10281
|
return out;
|
|
10276
10282
|
}
|
|
10277
10283
|
function computeDormantPlugins(accountId) {
|
|
10278
|
-
const accountFile =
|
|
10279
|
-
if (!
|
|
10284
|
+
const accountFile = resolve16(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10285
|
+
if (!existsSync19(accountFile)) return [];
|
|
10280
10286
|
let enabled;
|
|
10281
10287
|
try {
|
|
10282
10288
|
const raw = readFileSync18(accountFile, "utf-8");
|
|
@@ -10290,19 +10296,19 @@ function computeDormantPlugins(accountId) {
|
|
|
10290
10296
|
);
|
|
10291
10297
|
return [];
|
|
10292
10298
|
}
|
|
10293
|
-
const pluginsDir =
|
|
10294
|
-
if (!
|
|
10299
|
+
const pluginsDir = resolve16(PLATFORM_ROOT, "plugins");
|
|
10300
|
+
if (!existsSync19(pluginsDir)) return [];
|
|
10295
10301
|
let entries;
|
|
10296
10302
|
try {
|
|
10297
|
-
entries =
|
|
10303
|
+
entries = readdirSync12(pluginsDir);
|
|
10298
10304
|
} catch {
|
|
10299
10305
|
return [];
|
|
10300
10306
|
}
|
|
10301
10307
|
const out = [];
|
|
10302
10308
|
for (const name of entries) {
|
|
10303
10309
|
if (enabled.has(name)) continue;
|
|
10304
|
-
const manifestPath =
|
|
10305
|
-
if (!
|
|
10310
|
+
const manifestPath = resolve16(pluginsDir, name, "PLUGIN.md");
|
|
10311
|
+
if (!existsSync19(manifestPath)) continue;
|
|
10306
10312
|
let manifest;
|
|
10307
10313
|
try {
|
|
10308
10314
|
manifest = readFileSync18(manifestPath, "utf-8");
|
|
@@ -10319,11 +10325,11 @@ function computeDormantPlugins(accountId) {
|
|
|
10319
10325
|
}
|
|
10320
10326
|
|
|
10321
10327
|
// server/routes/admin/claude-sessions.ts
|
|
10322
|
-
import { existsSync as
|
|
10323
|
-
import { resolve as
|
|
10328
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
|
|
10329
|
+
import { resolve as resolve17 } from "path";
|
|
10324
10330
|
function readTunnelState(brandConfigDir) {
|
|
10325
10331
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10326
|
-
if (!
|
|
10332
|
+
if (!existsSync20(statePath)) return null;
|
|
10327
10333
|
try {
|
|
10328
10334
|
const parsed = JSON.parse(readFileSync19(statePath, "utf-8"));
|
|
10329
10335
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
@@ -10336,10 +10342,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10336
10342
|
}
|
|
10337
10343
|
}
|
|
10338
10344
|
function resolveTunnelUrl() {
|
|
10339
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
10345
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
10340
10346
|
let brand;
|
|
10341
10347
|
try {
|
|
10342
|
-
brand = JSON.parse(readFileSync19(
|
|
10348
|
+
brand = JSON.parse(readFileSync19(resolve17(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10343
10349
|
} catch {
|
|
10344
10350
|
return null;
|
|
10345
10351
|
}
|
|
@@ -10584,15 +10590,15 @@ var events_default = app18;
|
|
|
10584
10590
|
import { createReadStream as createReadStream2 } from "fs";
|
|
10585
10591
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
10586
10592
|
import { realpathSync as realpathSync4 } from "fs";
|
|
10587
|
-
import { basename as basename6, dirname as dirname5, join as
|
|
10593
|
+
import { basename as basename6, dirname as dirname5, join as join19, resolve as resolve20, sep as sep5 } from "path";
|
|
10588
10594
|
import { Readable as Readable2 } from "stream";
|
|
10589
10595
|
|
|
10590
10596
|
// app/lib/data-path.ts
|
|
10591
10597
|
import { realpathSync as realpathSync3 } from "fs";
|
|
10592
|
-
import { resolve as
|
|
10593
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
10594
|
-
var DATA_ROOT =
|
|
10595
|
-
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ?
|
|
10598
|
+
import { resolve as resolve18, normalize, sep as sep3, relative } from "path";
|
|
10599
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "../platform");
|
|
10600
|
+
var DATA_ROOT = resolve18(PLATFORM_ROOT5, "..", "data");
|
|
10601
|
+
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve18(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
10596
10602
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
10597
10603
|
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;
|
|
10598
10604
|
function crossesForeignAccountPartition(relPath, accountId) {
|
|
@@ -10605,7 +10611,7 @@ function crossesForeignAccountPartition(relPath, accountId) {
|
|
|
10605
10611
|
}
|
|
10606
10612
|
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
10607
10613
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
10608
|
-
const absolute =
|
|
10614
|
+
const absolute = resolve18(rootAbs, cleaned);
|
|
10609
10615
|
let rootReal;
|
|
10610
10616
|
try {
|
|
10611
10617
|
rootReal = realpathSync3(rootAbs);
|
|
@@ -10964,7 +10970,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10964
10970
|
|
|
10965
10971
|
// app/lib/file-index.ts
|
|
10966
10972
|
import * as fsp from "fs/promises";
|
|
10967
|
-
import { resolve as
|
|
10973
|
+
import { resolve as resolve19, relative as relative2, join as join18, basename as basename5, extname as extname2, sep as sep4 } from "path";
|
|
10968
10974
|
import { tmpdir as tmpdir2 } from "os";
|
|
10969
10975
|
import { execFile as execFile2 } from "child_process";
|
|
10970
10976
|
import { promisify as promisify2 } from "util";
|
|
@@ -11035,7 +11041,7 @@ async function extractPdf(absolute) {
|
|
|
11035
11041
|
return stdout.trim();
|
|
11036
11042
|
}
|
|
11037
11043
|
async function ocrPdf(absolute) {
|
|
11038
|
-
const outPdf =
|
|
11044
|
+
const outPdf = join18(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11039
11045
|
try {
|
|
11040
11046
|
await execFileAsync2(
|
|
11041
11047
|
"ocrmypdf",
|
|
@@ -11097,7 +11103,7 @@ async function readDisplayName(absolute) {
|
|
|
11097
11103
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11098
11104
|
if (base === `${stem}.meta.json`) return null;
|
|
11099
11105
|
try {
|
|
11100
|
-
const raw = await fsp.readFile(
|
|
11106
|
+
const raw = await fsp.readFile(join18(dir, `${stem}.meta.json`), "utf-8");
|
|
11101
11107
|
const meta = JSON.parse(raw);
|
|
11102
11108
|
const dn = meta.displayName ?? meta.filename;
|
|
11103
11109
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11117,7 +11123,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11117
11123
|
let clean = true;
|
|
11118
11124
|
for (const entry of entries) {
|
|
11119
11125
|
if (entry.isSymbolicLink()) continue;
|
|
11120
|
-
const abs =
|
|
11126
|
+
const abs = join18(root, entry.name);
|
|
11121
11127
|
if (entry.isDirectory()) {
|
|
11122
11128
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11123
11129
|
if (!sub.clean) clean = false;
|
|
@@ -11272,8 +11278,8 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
11272
11278
|
return withSession(opts, async (session) => {
|
|
11273
11279
|
const walked = [];
|
|
11274
11280
|
const subtreeRoots = [
|
|
11275
|
-
|
|
11276
|
-
|
|
11281
|
+
resolve19(dataRoot, "uploads", accountId),
|
|
11282
|
+
resolve19(dataRoot, "accounts", accountId)
|
|
11277
11283
|
];
|
|
11278
11284
|
let clean = true;
|
|
11279
11285
|
for (const root of subtreeRoots) {
|
|
@@ -11354,7 +11360,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
11354
11360
|
async function indexFile(accountId, relativePath, opts) {
|
|
11355
11361
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
11356
11362
|
const embed2 = opts?.embed ?? embed;
|
|
11357
|
-
const absolute =
|
|
11363
|
+
const absolute = resolve19(dataRoot, relativePath);
|
|
11358
11364
|
await withSession(opts, async (session) => {
|
|
11359
11365
|
const st = await fsp.stat(absolute);
|
|
11360
11366
|
const wf = {
|
|
@@ -11388,7 +11394,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
11388
11394
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11389
11395
|
async function readMeta(absDir, baseName) {
|
|
11390
11396
|
try {
|
|
11391
|
-
const raw = await readFile4(
|
|
11397
|
+
const raw = await readFile4(join19(absDir, `${baseName}.meta.json`), "utf8");
|
|
11392
11398
|
const parsed = JSON.parse(raw);
|
|
11393
11399
|
if (typeof parsed?.filename === "string") {
|
|
11394
11400
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11399,7 +11405,7 @@ async function readMeta(absDir, baseName) {
|
|
|
11399
11405
|
}
|
|
11400
11406
|
async function readAccountNames() {
|
|
11401
11407
|
const map = /* @__PURE__ */ new Map();
|
|
11402
|
-
const accountsDir =
|
|
11408
|
+
const accountsDir = resolve20(DATA_ROOT, "accounts");
|
|
11403
11409
|
let names;
|
|
11404
11410
|
try {
|
|
11405
11411
|
names = await readdir3(accountsDir);
|
|
@@ -11408,7 +11414,7 @@ async function readAccountNames() {
|
|
|
11408
11414
|
}
|
|
11409
11415
|
for (const name of names) {
|
|
11410
11416
|
if (!UUID_RE3.test(name)) continue;
|
|
11411
|
-
const configPath2 =
|
|
11417
|
+
const configPath2 = resolve20(accountsDir, name, "account.json");
|
|
11412
11418
|
try {
|
|
11413
11419
|
const raw = await readFile4(configPath2, "utf8");
|
|
11414
11420
|
const parsed = JSON.parse(raw);
|
|
@@ -11426,7 +11432,7 @@ async function readAccountNames() {
|
|
|
11426
11432
|
}
|
|
11427
11433
|
async function enrich(absolute, entry, accountNames) {
|
|
11428
11434
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
11429
|
-
const meta = await readMeta(
|
|
11435
|
+
const meta = await readMeta(join19(absolute, entry.name), entry.name);
|
|
11430
11436
|
if (meta?.filename) {
|
|
11431
11437
|
entry.displayName = meta.filename;
|
|
11432
11438
|
entry.mimeType = meta.mimeType;
|
|
@@ -11524,7 +11530,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11524
11530
|
continue;
|
|
11525
11531
|
}
|
|
11526
11532
|
try {
|
|
11527
|
-
const entryPath =
|
|
11533
|
+
const entryPath = join19(absolute, name);
|
|
11528
11534
|
const s = await stat4(entryPath);
|
|
11529
11535
|
entries.push({
|
|
11530
11536
|
name,
|
|
@@ -11649,8 +11655,8 @@ app19.post("/upload", requireAdminSession, async (c) => {
|
|
|
11649
11655
|
}
|
|
11650
11656
|
const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
|
|
11651
11657
|
const finalName = `${Date.now()}-${safeName}`;
|
|
11652
|
-
const destDir =
|
|
11653
|
-
const destPath =
|
|
11658
|
+
const destDir = resolve20(DATA_ROOT, "uploads", accountId);
|
|
11659
|
+
const destPath = resolve20(destDir, finalName);
|
|
11654
11660
|
try {
|
|
11655
11661
|
await mkdir3(destDir, { recursive: true });
|
|
11656
11662
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
@@ -11715,7 +11721,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
11715
11721
|
}
|
|
11716
11722
|
const dot = base.lastIndexOf(".");
|
|
11717
11723
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11718
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
11724
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join19(dirname5(absolute), `${stem}.meta.json`) : null;
|
|
11719
11725
|
await unlink2(absolute);
|
|
11720
11726
|
if (sidecarPath) {
|
|
11721
11727
|
try {
|
|
@@ -13764,8 +13770,8 @@ var graph_default_view_default = app25;
|
|
|
13764
13770
|
|
|
13765
13771
|
// server/routes/admin/sidebar-artefacts.ts
|
|
13766
13772
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
13767
|
-
import { resolve as
|
|
13768
|
-
import { existsSync as
|
|
13773
|
+
import { resolve as resolve21, relative as relative3, isAbsolute, sep as sep6, basename as basename7 } from "path";
|
|
13774
|
+
import { existsSync as existsSync21 } from "fs";
|
|
13769
13775
|
var LIMIT = 50;
|
|
13770
13776
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
13771
13777
|
function toDataRootRelPath(absPath) {
|
|
@@ -13784,7 +13790,7 @@ app26.get("/", requireAdminSession, async (c) => {
|
|
|
13784
13790
|
if (accountFiles === null) {
|
|
13785
13791
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
13786
13792
|
}
|
|
13787
|
-
const accountDir =
|
|
13793
|
+
const accountDir = resolve21(ACCOUNTS_DIR, accountId);
|
|
13788
13794
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
13789
13795
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
13790
13796
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -13835,8 +13841,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
13835
13841
|
async function fetchAgentTemplateRows(accountDir) {
|
|
13836
13842
|
const rows = [];
|
|
13837
13843
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
13838
|
-
const overridePath =
|
|
13839
|
-
const bundledPath =
|
|
13844
|
+
const overridePath = resolve21(accountDir, "agents", "admin", filename);
|
|
13845
|
+
const bundledPath = resolve21(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
13840
13846
|
const labelStem = filename.replace(/\.md$/, "");
|
|
13841
13847
|
const row = await readAgentTemplateRow({
|
|
13842
13848
|
id: `agent-template:admin:${filename}`,
|
|
@@ -13849,12 +13855,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13849
13855
|
});
|
|
13850
13856
|
if (row) rows.push(row);
|
|
13851
13857
|
}
|
|
13852
|
-
const overrideDir =
|
|
13853
|
-
const bundledDir =
|
|
13858
|
+
const overrideDir = resolve21(accountDir, "specialists", "agents");
|
|
13859
|
+
const bundledDir = resolve21(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
13854
13860
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
13855
13861
|
for (const filename of specialistNames) {
|
|
13856
|
-
const overridePath =
|
|
13857
|
-
const bundledPath =
|
|
13862
|
+
const overridePath = resolve21(overrideDir, filename);
|
|
13863
|
+
const bundledPath = resolve21(bundledDir, filename);
|
|
13858
13864
|
const row = await readAgentTemplateRow({
|
|
13859
13865
|
id: `agent-template:specialist:${filename}`,
|
|
13860
13866
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -13871,7 +13877,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13871
13877
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
13872
13878
|
const names = /* @__PURE__ */ new Set();
|
|
13873
13879
|
for (const dir of [overrideDir, bundledDir]) {
|
|
13874
|
-
if (!
|
|
13880
|
+
if (!existsSync21(dir)) continue;
|
|
13875
13881
|
try {
|
|
13876
13882
|
const entries = await readdir4(dir);
|
|
13877
13883
|
for (const entry of entries) {
|
|
@@ -13886,7 +13892,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
13886
13892
|
}
|
|
13887
13893
|
async function readAgentTemplateRow(inp) {
|
|
13888
13894
|
let chosenPath = null;
|
|
13889
|
-
if (
|
|
13895
|
+
if (existsSync21(inp.overridePath)) {
|
|
13890
13896
|
try {
|
|
13891
13897
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
13892
13898
|
chosenPath = inp.overridePath;
|
|
@@ -13897,7 +13903,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
13897
13903
|
);
|
|
13898
13904
|
return null;
|
|
13899
13905
|
}
|
|
13900
|
-
} else if (
|
|
13906
|
+
} else if (existsSync21(inp.bundledPath)) {
|
|
13901
13907
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
13902
13908
|
console.error(
|
|
13903
13909
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -14062,6 +14068,36 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
14062
14068
|
var session_archive_default = app29;
|
|
14063
14069
|
|
|
14064
14070
|
// server/routes/admin/session-rc-spawn.ts
|
|
14071
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
14072
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID9) {
|
|
14073
|
+
const operator = isOperatorHost(host, operatorDomains);
|
|
14074
|
+
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
14075
|
+
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
14076
|
+
const webchatBind = resumeId === void 0 || operator;
|
|
14077
|
+
const kind = resumeId === void 0 ? "new" : "resume";
|
|
14078
|
+
const origin = operator ? "operator" : "admin";
|
|
14079
|
+
const payload = {};
|
|
14080
|
+
let sessionId;
|
|
14081
|
+
if (webchatBind) {
|
|
14082
|
+
sessionId = resumeId ?? mintId();
|
|
14083
|
+
const key = `session:${sessionId}`;
|
|
14084
|
+
payload.sessionId = sessionId;
|
|
14085
|
+
payload.role = "admin";
|
|
14086
|
+
payload.channel = "webchat";
|
|
14087
|
+
payload.senderId = key;
|
|
14088
|
+
payload.webchatChannel = webchatChannelDescriptor(key);
|
|
14089
|
+
if (name) payload.name = name;
|
|
14090
|
+
} else {
|
|
14091
|
+
sessionId = resumeId;
|
|
14092
|
+
payload.sessionId = resumeId;
|
|
14093
|
+
if (name) payload.name = name;
|
|
14094
|
+
}
|
|
14095
|
+
return { webchatBind, origin, kind, sessionId, payload };
|
|
14096
|
+
}
|
|
14097
|
+
function shapeWebchatResponse(sessionId, manager) {
|
|
14098
|
+
const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
|
|
14099
|
+
return { sessionId, outcome, target: `/chat?session=${sessionId}` };
|
|
14100
|
+
}
|
|
14065
14101
|
var app30 = new Hono();
|
|
14066
14102
|
app30.post("/", requireAdminSession, async (c) => {
|
|
14067
14103
|
let body;
|
|
@@ -14070,19 +14106,26 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14070
14106
|
} catch {
|
|
14071
14107
|
body = {};
|
|
14072
14108
|
}
|
|
14073
|
-
const
|
|
14074
|
-
|
|
14075
|
-
|
|
14109
|
+
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14110
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body);
|
|
14111
|
+
const spawnReqId = randomUUID9();
|
|
14112
|
+
console.log(
|
|
14113
|
+
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
14114
|
+
);
|
|
14115
|
+
if (plan.webchatBind) {
|
|
14116
|
+
console.log(`[chat-spawn] op=args spawnReqId=${spawnReqId} webchatChannel=present sessionId=${plan.sessionId}`);
|
|
14117
|
+
}
|
|
14076
14118
|
let res;
|
|
14077
14119
|
try {
|
|
14078
14120
|
res = await fetch(`${managerBase3("session-rc-spawn:wrapper")}/rc-spawn`, {
|
|
14079
14121
|
method: "POST",
|
|
14080
14122
|
headers: { "content-type": "application/json" },
|
|
14081
|
-
body: JSON.stringify(payload)
|
|
14123
|
+
body: JSON.stringify(plan.payload)
|
|
14082
14124
|
});
|
|
14083
14125
|
} catch (err) {
|
|
14084
14126
|
const msg = err instanceof Error ? err.message : String(err);
|
|
14085
14127
|
console.error(`[session-rc-spawn] manager-unreachable err=${msg}`);
|
|
14128
|
+
console.log(`[chat-spawn] op=exit spawnReqId=${spawnReqId} outcome=spawn-failed`);
|
|
14086
14129
|
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
14087
14130
|
}
|
|
14088
14131
|
const text = await res.text();
|
|
@@ -14093,8 +14136,18 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14093
14136
|
}
|
|
14094
14137
|
if (!res.ok) {
|
|
14095
14138
|
console.error(`[session-rc-spawn] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
14139
|
+
console.log(`[chat-spawn] op=exit spawnReqId=${spawnReqId} outcome=spawn-failed`);
|
|
14096
14140
|
return c.json(parsed ?? { error: text }, res.status);
|
|
14097
14141
|
}
|
|
14142
|
+
if (plan.webchatBind) {
|
|
14143
|
+
const target = `/chat?session=${plan.sessionId}`;
|
|
14144
|
+
console.log(
|
|
14145
|
+
`[chat-spawn] op=acquired spawnReqId=${spawnReqId} pid=${parsed?.spawnedPid ?? "none"} sessionId=${plan.sessionId}`
|
|
14146
|
+
);
|
|
14147
|
+
console.log(`[chat-spawn] op=navigate spawnReqId=${spawnReqId} target=${target}`);
|
|
14148
|
+
console.log(`[chat-spawn] op=exit spawnReqId=${spawnReqId} outcome=bound`);
|
|
14149
|
+
return c.json(shapeWebchatResponse(plan.sessionId, parsed));
|
|
14150
|
+
}
|
|
14098
14151
|
return c.json(parsed ?? {});
|
|
14099
14152
|
});
|
|
14100
14153
|
var session_rc_spawn_default = app30;
|
|
@@ -14221,23 +14274,23 @@ app31.get("/", async (c) => {
|
|
|
14221
14274
|
var system_stats_default = app31;
|
|
14222
14275
|
|
|
14223
14276
|
// server/routes/admin/health.ts
|
|
14224
|
-
import { existsSync as
|
|
14225
|
-
import { resolve as
|
|
14226
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14277
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20 } from "fs";
|
|
14278
|
+
import { resolve as resolve22, join as join20 } from "path";
|
|
14279
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
|
|
14227
14280
|
var brandHostname = "maxy";
|
|
14228
|
-
var brandJsonPath =
|
|
14229
|
-
if (
|
|
14281
|
+
var brandJsonPath = join20(PLATFORM_ROOT6, "config", "brand.json");
|
|
14282
|
+
if (existsSync22(brandJsonPath)) {
|
|
14230
14283
|
try {
|
|
14231
14284
|
const brand = JSON.parse(readFileSync20(brandJsonPath, "utf-8"));
|
|
14232
14285
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
14233
14286
|
} catch {
|
|
14234
14287
|
}
|
|
14235
14288
|
}
|
|
14236
|
-
var VERSION_FILE =
|
|
14289
|
+
var VERSION_FILE = resolve22(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
14237
14290
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
14238
14291
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
14239
14292
|
function readVersion() {
|
|
14240
|
-
if (!
|
|
14293
|
+
if (!existsSync22(VERSION_FILE)) return "unknown";
|
|
14241
14294
|
return readFileSync20(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
14242
14295
|
}
|
|
14243
14296
|
async function probeConversationDb() {
|
|
@@ -14289,7 +14342,7 @@ app32.get("/", async (c) => {
|
|
|
14289
14342
|
var health_default2 = app32;
|
|
14290
14343
|
|
|
14291
14344
|
// server/routes/admin/linkedin-ingest.ts
|
|
14292
|
-
import { randomUUID as
|
|
14345
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
14293
14346
|
var TAG25 = "[linkedin-ingest-route]";
|
|
14294
14347
|
var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
14295
14348
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
@@ -14415,7 +14468,7 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
14415
14468
|
);
|
|
14416
14469
|
const initialMessage = buildInitialMessage(envelope);
|
|
14417
14470
|
const spawnStart = Date.now();
|
|
14418
|
-
const sessionId =
|
|
14471
|
+
const sessionId = randomUUID10();
|
|
14419
14472
|
console.log(TAG25 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
14420
14473
|
const spawned = await managerRcSpawn({
|
|
14421
14474
|
sessionId,
|
|
@@ -14781,13 +14834,13 @@ var admin_default = app39;
|
|
|
14781
14834
|
// app/lib/access-gate.ts
|
|
14782
14835
|
import neo4j4 from "neo4j-driver";
|
|
14783
14836
|
import { readFileSync as readFileSync21 } from "fs";
|
|
14784
|
-
import { resolve as
|
|
14785
|
-
import { randomUUID as
|
|
14786
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14837
|
+
import { resolve as resolve23 } from "path";
|
|
14838
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
14839
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
|
|
14787
14840
|
var driver = null;
|
|
14788
14841
|
function readPassword() {
|
|
14789
14842
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
14790
|
-
const passwordFile =
|
|
14843
|
+
const passwordFile = resolve23(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
14791
14844
|
try {
|
|
14792
14845
|
return readFileSync21(passwordFile, "utf-8").trim();
|
|
14793
14846
|
} catch {
|
|
@@ -14965,7 +15018,7 @@ async function consumeMagicTokenAndActivate(grantId) {
|
|
|
14965
15018
|
}
|
|
14966
15019
|
}
|
|
14967
15020
|
async function generateNewMagicToken(grantId) {
|
|
14968
|
-
const token =
|
|
15021
|
+
const token = randomUUID11();
|
|
14969
15022
|
const session = getSession3();
|
|
14970
15023
|
try {
|
|
14971
15024
|
const result = await session.run(
|
|
@@ -15077,9 +15130,9 @@ var verify_token_default = app40;
|
|
|
15077
15130
|
|
|
15078
15131
|
// app/lib/access-email.ts
|
|
15079
15132
|
import { spawn as spawn2 } from "child_process";
|
|
15080
|
-
import { resolve as
|
|
15081
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
15082
|
-
var SEND_SCRIPT =
|
|
15133
|
+
import { resolve as resolve24 } from "path";
|
|
15134
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15135
|
+
var SEND_SCRIPT = resolve24(
|
|
15083
15136
|
PLATFORM_ROOT8,
|
|
15084
15137
|
"plugins",
|
|
15085
15138
|
"email",
|
|
@@ -15221,8 +15274,8 @@ app42.route("/request-magic-link", request_magic_link_default);
|
|
|
15221
15274
|
var access_default = app42;
|
|
15222
15275
|
|
|
15223
15276
|
// server/routes/sites.ts
|
|
15224
|
-
import { existsSync as
|
|
15225
|
-
import { resolve as
|
|
15277
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
|
|
15278
|
+
import { resolve as resolve25 } from "path";
|
|
15226
15279
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
15227
15280
|
var MIME = {
|
|
15228
15281
|
".html": "text/html; charset=utf-8",
|
|
@@ -15279,15 +15332,15 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
15279
15332
|
}
|
|
15280
15333
|
segments.push(seg);
|
|
15281
15334
|
}
|
|
15282
|
-
const rootDir =
|
|
15283
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
15335
|
+
const rootDir = resolve25(account.accountDir, "sites");
|
|
15336
|
+
let filePath = segments.length === 0 ? rootDir : resolve25(rootDir, ...segments);
|
|
15284
15337
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
15285
15338
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15286
15339
|
return c.text("Forbidden", 403);
|
|
15287
15340
|
}
|
|
15288
15341
|
let stat7;
|
|
15289
15342
|
try {
|
|
15290
|
-
stat7 =
|
|
15343
|
+
stat7 = existsSync23(filePath) ? statSync9(filePath) : null;
|
|
15291
15344
|
} catch {
|
|
15292
15345
|
stat7 = null;
|
|
15293
15346
|
}
|
|
@@ -15300,13 +15353,13 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
15300
15353
|
return c.redirect(target, 301);
|
|
15301
15354
|
}
|
|
15302
15355
|
if (stat7?.isDirectory()) {
|
|
15303
|
-
filePath =
|
|
15356
|
+
filePath = resolve25(filePath, "index.html");
|
|
15304
15357
|
}
|
|
15305
15358
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
15306
15359
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15307
15360
|
return c.text("Forbidden", 403);
|
|
15308
15361
|
}
|
|
15309
|
-
if (!
|
|
15362
|
+
if (!existsSync23(filePath)) {
|
|
15310
15363
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
15311
15364
|
return c.text("Not found", 404);
|
|
15312
15365
|
}
|
|
@@ -15437,8 +15490,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
15437
15490
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
15438
15491
|
|
|
15439
15492
|
// app/lib/brand-config.ts
|
|
15440
|
-
import { existsSync as
|
|
15441
|
-
import { join as
|
|
15493
|
+
import { existsSync as existsSync24, readFileSync as readFileSync24 } from "fs";
|
|
15494
|
+
import { join as join21 } from "path";
|
|
15442
15495
|
var cached2 = null;
|
|
15443
15496
|
var cachedAttempted = false;
|
|
15444
15497
|
function readBrandConfig() {
|
|
@@ -15446,8 +15499,8 @@ function readBrandConfig() {
|
|
|
15446
15499
|
cachedAttempted = true;
|
|
15447
15500
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
15448
15501
|
if (!platformRoot2) return null;
|
|
15449
|
-
const brandPath =
|
|
15450
|
-
if (!
|
|
15502
|
+
const brandPath = join21(platformRoot2, "config", "brand.json");
|
|
15503
|
+
if (!existsSync24(brandPath)) return null;
|
|
15451
15504
|
try {
|
|
15452
15505
|
cached2 = JSON.parse(readFileSync24(brandPath, "utf-8"));
|
|
15453
15506
|
return cached2;
|
|
@@ -15937,14 +15990,14 @@ async function writeEvent(opts) {
|
|
|
15937
15990
|
var visitor_event_default = app46;
|
|
15938
15991
|
|
|
15939
15992
|
// server/routes/session.ts
|
|
15940
|
-
import { resolve as
|
|
15941
|
-
import { existsSync as
|
|
15993
|
+
import { resolve as resolve26 } from "path";
|
|
15994
|
+
import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
15942
15995
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15943
15996
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
15944
15997
|
try {
|
|
15945
|
-
const cacheDir =
|
|
15998
|
+
const cacheDir = resolve26(MAXY_DIR, "branding-cache", accountId);
|
|
15946
15999
|
mkdirSync5(cacheDir, { recursive: true });
|
|
15947
|
-
writeFileSync9(
|
|
16000
|
+
writeFileSync9(resolve26(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
15948
16001
|
} catch (err) {
|
|
15949
16002
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
15950
16003
|
}
|
|
@@ -16032,8 +16085,8 @@ app47.post("/", async (c) => {
|
|
|
16032
16085
|
}
|
|
16033
16086
|
let agentConfig = null;
|
|
16034
16087
|
if (account) {
|
|
16035
|
-
const agentDir =
|
|
16036
|
-
if (!
|
|
16088
|
+
const agentDir = resolve26(account.accountDir, "agents", agentSlug);
|
|
16089
|
+
if (!existsSync25(agentDir) || !existsSync25(resolve26(agentDir, "config.json"))) {
|
|
16037
16090
|
return c.json({ error: "Agent not found" }, 404);
|
|
16038
16091
|
}
|
|
16039
16092
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -16313,7 +16366,7 @@ function startGraphHealthTimer() {
|
|
|
16313
16366
|
|
|
16314
16367
|
// app/lib/file-watcher.ts
|
|
16315
16368
|
import * as fsp2 from "fs/promises";
|
|
16316
|
-
import { resolve as
|
|
16369
|
+
import { resolve as resolve27, sep as sep7 } from "path";
|
|
16317
16370
|
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;
|
|
16318
16371
|
var DEFAULT_COALESCE_MS = 500;
|
|
16319
16372
|
var ROOTS = ["uploads", "accounts"];
|
|
@@ -16332,7 +16385,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16332
16385
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
16333
16386
|
for (const r of ROOTS) {
|
|
16334
16387
|
try {
|
|
16335
|
-
await fsp2.mkdir(
|
|
16388
|
+
await fsp2.mkdir(resolve27(dataRoot, r), { recursive: true });
|
|
16336
16389
|
} catch (err) {
|
|
16337
16390
|
console.error(
|
|
16338
16391
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -16353,7 +16406,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16353
16406
|
timers.set(relativePath, t);
|
|
16354
16407
|
}
|
|
16355
16408
|
async function runHook(relativePath, accountId) {
|
|
16356
|
-
const absolute =
|
|
16409
|
+
const absolute = resolve27(dataRoot, relativePath);
|
|
16357
16410
|
let exists = false;
|
|
16358
16411
|
try {
|
|
16359
16412
|
const st = await fsp2.stat(absolute);
|
|
@@ -16377,7 +16430,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16377
16430
|
}
|
|
16378
16431
|
}
|
|
16379
16432
|
async function watchRoot(rootName) {
|
|
16380
|
-
const absRoot =
|
|
16433
|
+
const absRoot = resolve27(dataRoot, rootName);
|
|
16381
16434
|
try {
|
|
16382
16435
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
16383
16436
|
for await (const event of iter) {
|
|
@@ -17271,8 +17324,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
17271
17324
|
|
|
17272
17325
|
// ../lib/entitlement/src/index.ts
|
|
17273
17326
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
17274
|
-
import { existsSync as
|
|
17275
|
-
import { resolve as
|
|
17327
|
+
import { existsSync as existsSync26, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
|
|
17328
|
+
import { resolve as resolve28 } from "path";
|
|
17276
17329
|
|
|
17277
17330
|
// ../lib/entitlement/src/canonicalize.ts
|
|
17278
17331
|
function canonicalize(value) {
|
|
@@ -17307,7 +17360,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
17307
17360
|
var GRACE_DAYS = 7;
|
|
17308
17361
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
17309
17362
|
function pubkeyPath(brand) {
|
|
17310
|
-
return
|
|
17363
|
+
return resolve28(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
17311
17364
|
}
|
|
17312
17365
|
var memo = null;
|
|
17313
17366
|
function memoKey(mtimeMs, account) {
|
|
@@ -17319,8 +17372,8 @@ function resolveEntitlement(brand, account) {
|
|
|
17319
17372
|
if (brand.commercialMode !== true) {
|
|
17320
17373
|
return logResolved(implicitTrust(account), null);
|
|
17321
17374
|
}
|
|
17322
|
-
const entitlementPath =
|
|
17323
|
-
if (!
|
|
17375
|
+
const entitlementPath = resolve28(brand.configDir, "entitlement.json");
|
|
17376
|
+
if (!existsSync26(entitlementPath)) {
|
|
17324
17377
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
17325
17378
|
}
|
|
17326
17379
|
const stat7 = statSync10(entitlementPath);
|
|
@@ -17510,12 +17563,12 @@ function clientFrom(c) {
|
|
|
17510
17563
|
);
|
|
17511
17564
|
}
|
|
17512
17565
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
17513
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
17566
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join22(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
17514
17567
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
17515
|
-
if (BRAND_JSON_PATH && !
|
|
17568
|
+
if (BRAND_JSON_PATH && !existsSync27(BRAND_JSON_PATH)) {
|
|
17516
17569
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
17517
17570
|
}
|
|
17518
|
-
if (BRAND_JSON_PATH &&
|
|
17571
|
+
if (BRAND_JSON_PATH && existsSync27(BRAND_JSON_PATH)) {
|
|
17519
17572
|
try {
|
|
17520
17573
|
const parsed = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
17521
17574
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -17536,10 +17589,10 @@ var brandLoginOpts = {
|
|
|
17536
17589
|
bodyFont: BRAND.defaultFonts?.body,
|
|
17537
17590
|
logoContainsName: !!BRAND.logoContainsName
|
|
17538
17591
|
};
|
|
17539
|
-
var ALIAS_DOMAINS_PATH =
|
|
17592
|
+
var ALIAS_DOMAINS_PATH = join22(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
17540
17593
|
function loadAliasDomains() {
|
|
17541
17594
|
try {
|
|
17542
|
-
if (!
|
|
17595
|
+
if (!existsSync27(ALIAS_DOMAINS_PATH)) return null;
|
|
17543
17596
|
const parsed = JSON.parse(readFileSync26(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
17544
17597
|
if (!Array.isArray(parsed)) {
|
|
17545
17598
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -17568,7 +17621,7 @@ var app48 = new Hono();
|
|
|
17568
17621
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
17569
17622
|
var waGateway = new WaGateway({
|
|
17570
17623
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17571
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
17624
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve29(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
17572
17625
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
17573
17626
|
// account + path validation here and funnel through the shared send core.
|
|
17574
17627
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -17584,7 +17637,7 @@ var waGateway = new WaGateway({
|
|
|
17584
17637
|
caption,
|
|
17585
17638
|
accountId,
|
|
17586
17639
|
maxyAccountId,
|
|
17587
|
-
platformRoot:
|
|
17640
|
+
platformRoot: resolve29(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, ".."))
|
|
17588
17641
|
});
|
|
17589
17642
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
17590
17643
|
},
|
|
@@ -17623,8 +17676,8 @@ var waGateway = new WaGateway({
|
|
|
17623
17676
|
app48.route("/", waGateway.routes());
|
|
17624
17677
|
waGateway.startSweeper();
|
|
17625
17678
|
var webchatGateway = new WebchatGateway({
|
|
17626
|
-
gatewayUrl:
|
|
17627
|
-
serverPath:
|
|
17679
|
+
gatewayUrl: webchatGatewayUrl(),
|
|
17680
|
+
serverPath: webchatServerPath(),
|
|
17628
17681
|
ensureChannelSession: async ({ accountId, key, role, gatewayUrl, serverPath, sessionId }) => {
|
|
17629
17682
|
if (role !== "admin") {
|
|
17630
17683
|
console.error(`[webchat:inbound] op=spawn-refused key=${key} role=${role} reason=public-path-not-wired`);
|
|
@@ -17676,7 +17729,7 @@ app48.use("*", async (c, next) => {
|
|
|
17676
17729
|
});
|
|
17677
17730
|
app48.use("*", async (c, next) => {
|
|
17678
17731
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
17679
|
-
if (!isPublicHost(host)) {
|
|
17732
|
+
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
17680
17733
|
await next();
|
|
17681
17734
|
return;
|
|
17682
17735
|
}
|
|
@@ -17908,7 +17961,10 @@ app48.use("*", async (c, next) => {
|
|
|
17908
17961
|
remoteAddress: rawRemote,
|
|
17909
17962
|
xForwardedFor: rawXff,
|
|
17910
17963
|
cookieHeader: c.req.header("cookie"),
|
|
17911
|
-
|
|
17964
|
+
// Task 829 — operator-wins: an operator host is admin-gated, so it must not
|
|
17965
|
+
// be classified public here (which would bypass the admin gate). A host in
|
|
17966
|
+
// both operator-domains.json and alias-domains.json stays admin-gated.
|
|
17967
|
+
isPublicHost: (h) => !isOperatorHost(h, getOperatorDomains()) && isPublicHost(h)
|
|
17912
17968
|
});
|
|
17913
17969
|
if (decision.allow) {
|
|
17914
17970
|
await next();
|
|
@@ -17965,13 +18021,13 @@ app48.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
17965
18021
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
17966
18022
|
return c.text("Not found", 404);
|
|
17967
18023
|
}
|
|
17968
|
-
const filePath =
|
|
17969
|
-
const expectedDir =
|
|
18024
|
+
const filePath = resolve29(account.accountDir, "agents", slug, "assets", filename);
|
|
18025
|
+
const expectedDir = resolve29(account.accountDir, "agents", slug, "assets");
|
|
17970
18026
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
17971
18027
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
17972
18028
|
return c.text("Forbidden", 403);
|
|
17973
18029
|
}
|
|
17974
|
-
if (!
|
|
18030
|
+
if (!existsSync27(filePath)) {
|
|
17975
18031
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
17976
18032
|
return c.text("Not found", 404);
|
|
17977
18033
|
}
|
|
@@ -17995,13 +18051,13 @@ app48.get("/generated/:filename", (c) => {
|
|
|
17995
18051
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
17996
18052
|
return c.text("Not found", 404);
|
|
17997
18053
|
}
|
|
17998
|
-
const filePath =
|
|
17999
|
-
const expectedDir =
|
|
18054
|
+
const filePath = resolve29(account.accountDir, "generated", filename);
|
|
18055
|
+
const expectedDir = resolve29(account.accountDir, "generated");
|
|
18000
18056
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
18001
18057
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
18002
18058
|
return c.text("Forbidden", 403);
|
|
18003
18059
|
}
|
|
18004
|
-
if (!
|
|
18060
|
+
if (!existsSync27(filePath)) {
|
|
18005
18061
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
18006
18062
|
return c.text("Not found", 404);
|
|
18007
18063
|
}
|
|
@@ -18021,7 +18077,7 @@ app48.route("/v", visitor_consent_default);
|
|
|
18021
18077
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
18022
18078
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
18023
18079
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
18024
|
-
if (BRAND_JSON_PATH &&
|
|
18080
|
+
if (BRAND_JSON_PATH && existsSync27(BRAND_JSON_PATH)) {
|
|
18025
18081
|
try {
|
|
18026
18082
|
const fullBrand = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
18027
18083
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -18040,8 +18096,8 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
18040
18096
|
function readInstalledVersion() {
|
|
18041
18097
|
try {
|
|
18042
18098
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
18043
|
-
const versionFile =
|
|
18044
|
-
if (!
|
|
18099
|
+
const versionFile = join22(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
18100
|
+
if (!existsSync27(versionFile)) return "unknown";
|
|
18045
18101
|
const content = readFileSync26(versionFile, "utf-8").trim();
|
|
18046
18102
|
return content || "unknown";
|
|
18047
18103
|
} catch {
|
|
@@ -18083,7 +18139,7 @@ var clientErrorReporterScript = `<script>
|
|
|
18083
18139
|
function cachedHtml(file) {
|
|
18084
18140
|
let html = htmlCache.get(file);
|
|
18085
18141
|
if (!html) {
|
|
18086
|
-
html = readFileSync26(
|
|
18142
|
+
html = readFileSync26(resolve29(process.cwd(), "public", file), "utf-8");
|
|
18087
18143
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
18088
18144
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
18089
18145
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -18099,12 +18155,12 @@ ${clientErrorReporterScript}
|
|
|
18099
18155
|
}
|
|
18100
18156
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
18101
18157
|
function loadBrandingCache(agentSlug) {
|
|
18102
|
-
const configDir2 =
|
|
18158
|
+
const configDir2 = join22(homedir3(), BRAND.configDir);
|
|
18103
18159
|
try {
|
|
18104
18160
|
const accountId = getDefaultAccountId();
|
|
18105
18161
|
if (!accountId) return null;
|
|
18106
|
-
const cachePath =
|
|
18107
|
-
if (!
|
|
18162
|
+
const cachePath = join22(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
18163
|
+
if (!existsSync27(cachePath)) return null;
|
|
18108
18164
|
return JSON.parse(readFileSync26(cachePath, "utf-8"));
|
|
18109
18165
|
} catch {
|
|
18110
18166
|
return null;
|
|
@@ -18150,7 +18206,12 @@ function agentUnavailableHtml() {
|
|
|
18150
18206
|
}
|
|
18151
18207
|
app48.get("/", (c) => {
|
|
18152
18208
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
18153
|
-
|
|
18209
|
+
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
18210
|
+
if (klass === "operator") {
|
|
18211
|
+
console.log(`[host-class] host=${host} class=operator served=operator.html`);
|
|
18212
|
+
return c.html(cachedHtml("operator.html"));
|
|
18213
|
+
}
|
|
18214
|
+
if (klass === "public") {
|
|
18154
18215
|
const defaultSlug = resolveDefaultSlug();
|
|
18155
18216
|
if (!defaultSlug) {
|
|
18156
18217
|
console.error("[public-root] op=no-default");
|
|
@@ -18162,6 +18223,7 @@ app48.get("/", (c) => {
|
|
|
18162
18223
|
console.error(`[public-root] op=serve-default slug=${defaultSlug}`);
|
|
18163
18224
|
return c.html(brandedPublicHtml(defaultSlug));
|
|
18164
18225
|
}
|
|
18226
|
+
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
18165
18227
|
return c.html(cachedHtml("index.html"));
|
|
18166
18228
|
});
|
|
18167
18229
|
app48.get("/public", (c) => {
|
|
@@ -18193,7 +18255,7 @@ app48.use("/vnc-popout.html", logViewerFetch);
|
|
|
18193
18255
|
app48.get("/vnc-popout.html", (c) => {
|
|
18194
18256
|
let html = htmlCache.get("vnc-popout.html");
|
|
18195
18257
|
if (!html) {
|
|
18196
|
-
html = readFileSync26(
|
|
18258
|
+
html = readFileSync26(resolve29(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
18197
18259
|
const name = escapeHtml(BRAND.productName);
|
|
18198
18260
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
18199
18261
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -18229,7 +18291,7 @@ app48.get("/g/:slug", (c) => {
|
|
|
18229
18291
|
});
|
|
18230
18292
|
app48.get("/graph", (c) => {
|
|
18231
18293
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
18232
|
-
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
18294
|
+
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
18233
18295
|
return c.html(cachedHtml("graph.html"));
|
|
18234
18296
|
});
|
|
18235
18297
|
app48.get("/chat", (c) => {
|
|
@@ -18244,7 +18306,7 @@ app48.get("/data", (c) => {
|
|
|
18244
18306
|
});
|
|
18245
18307
|
app48.get("/browser", (c) => {
|
|
18246
18308
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
18247
|
-
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
18309
|
+
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
18248
18310
|
return c.html(cachedHtml("browser.html"));
|
|
18249
18311
|
});
|
|
18250
18312
|
app48.get("/:slug", async (c, next) => {
|
|
@@ -18349,7 +18411,7 @@ try {
|
|
|
18349
18411
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
18350
18412
|
async function runAdminUserReconcileTick() {
|
|
18351
18413
|
try {
|
|
18352
|
-
if (!
|
|
18414
|
+
if (!existsSync27(USERS_FILE)) {
|
|
18353
18415
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
18354
18416
|
return;
|
|
18355
18417
|
}
|
|
@@ -18463,7 +18525,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
18463
18525
|
}
|
|
18464
18526
|
init({
|
|
18465
18527
|
configDir: configDirForWhatsApp,
|
|
18466
|
-
platformRoot:
|
|
18528
|
+
platformRoot: resolve29(process.env.MAXY_PLATFORM_ROOT ?? join22(__dirname, "..")),
|
|
18467
18529
|
accountConfig: bootAccountConfig,
|
|
18468
18530
|
onMessage: async (msg) => {
|
|
18469
18531
|
if (msg.isOwnerMirror) {
|