@rubytech/create-maxy-code 0.1.294 → 0.1.295
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/admin/skills/platform-architecture/SKILL.md +22 -4
- package/payload/platform/plugins/docs/references/admin-ui.md +19 -2
- package/payload/platform/plugins/docs/references/platform.md +2 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +23 -3
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +14 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +7 -4
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +7 -4
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts +3 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js +28 -0
- package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js.map +1 -0
- package/payload/platform/templates/specialists/agents/data-manager.md +27 -0
- package/payload/server/public/assets/AdminShell-DDieHnzi.js +1 -0
- package/payload/server/public/assets/{Checkbox-DxOCnNT7.js → Checkbox-DTrIyIFP.js} +1 -1
- package/payload/server/public/assets/{Transcript-BIhFafaZ.js → Transcript-C3aDVJ-n.js} +1 -1
- package/payload/server/public/assets/{admin-CGjBmQRF.js → admin-DVdyV-Q6.js} +1 -1
- package/payload/server/public/assets/{arc-CL2g6wtE.js → arc-DmR-LPIx.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-CjF2k79a.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-B6pI_4kf.js → architectureDiagram-Q4EWVU46-DR9W0q1P.js} +1 -1
- package/payload/server/public/assets/audio-attachment-mime-DGEfApkA.js +1 -0
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-OTjX8onE.js → blockDiagram-DXYQGD6D-C3uwaI7p.js} +1 -1
- package/payload/server/public/assets/{browser-Bf0v--kb.js → browser-DrJReVEG.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-d3BJbhwh.js → c4Diagram-AHTNJAMY-C8hmUDdd.js} +1 -1
- package/payload/server/public/assets/channel-drVqp11B.js +1 -0
- package/payload/server/public/assets/chat-DeEYwIKE.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-CjdgBkCI.js → chunk-2KRD3SAO-BYqpHDvA.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-77Kuo1_M.js → chunk-336JU56O-BRCubMCb.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-BNINkVsL.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-CJ-bacvW.js → chunk-4BX2VUAB-BeDVr5Tb.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-C7oTm4E0.js → chunk-4TB4RGXK-DSMj_AZh.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BGVu8gHm.js → chunk-55IACEB6-DB18cH4S.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-BBHRG4DD.js → chunk-5FUZZQ4R-6DNGaUkf.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-BbxYk0vN.js → chunk-5PVQY5BW-DPhkkS4p.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-DCXRVLld.js → chunk-67CJDMHE-Ca9KwdQm.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-Cb8gnv2L.js → chunk-7N4EOEYR-BDpzHOmv.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-BDKd8RHS.js → chunk-AA7GKIK3-DXo9fZho.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-C-a5U7hf.js → chunk-BSJP7CBP-CTqmM6qI.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-C2s4AWWp.js → chunk-CIAEETIT-NufEId2j.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-C_NxZc3q.js → chunk-EDXVE4YY-BjWSqn7_.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-CP-iwXd0.js → chunk-ENJZ2VHE-BX1ZnU4A.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-Cb04mvB7.js → chunk-FMBD7UC4-_4wtKsfc.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-B1tHdg5H.js → chunk-FOC6F5B3-565zaYb3.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BlGsRet_.js → chunk-ICPOFSXX-DvYSWH7x.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-I1-reqf9.js → chunk-K5T4RW27-CTZnA5fq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-Dz5VoWZh.js → chunk-KGLVRYIC-CeuKp7uR.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-CJVhgo59.js → chunk-LIHQZDEY-DXkzlh3_.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-B236VjaQ.js → chunk-ORNJ4GCN-DcZUCmgM.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-CqSmIaQf.js → chunk-OYMX7WX6-7_m3mEOK.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CBWmDBHe.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CeMKC3D0.js → chunk-U2HBQHQK-Bl1a895I.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DK30THxZ.js → chunk-X2U36JSP-WkSpBPYx.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-DVW18Ukl.js → chunk-XPW4576I-CnU6DVpC.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DxfWX7Ap.js → chunk-YZCP3GAM-DpWRmPUo.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-BEQSVm39.js → chunk-ZZ45TVLE-D9Dgmeso.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-Dplkw_pj.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-sJXv1Ihp.js +1 -0
- package/payload/server/public/assets/clone-Q_B6oO0c.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BcEd1xsZ.js → cose-bilkent-S5V4N54A-C04wkJr7.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BBzAnJNh.js → dagre-KV5264BT-DPq3dcLH.js} +1 -1
- package/payload/server/public/assets/{dagre-Ch3nCevh.js → dagre-PrVfCcSt.js} +1 -1
- package/payload/server/public/assets/data-CYyR2m_B.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-BG13t9mu.js → diagram-5BDNPKRD-DoszElKb.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DYh2zRvB.js → diagram-G4DWMVQ6-BRuqosix.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-CNMjDPoP.js → diagram-MMDJMWI5-CpigG1d_.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BAb8gFOW.js → diagram-TYMM5635-BS0eYiq9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-Dy4ADi6A.js → erDiagram-SMLLAGMA-VEQyXCFl.js} +1 -1
- package/payload/server/public/assets/file-download-C3pBZjt9.js +1 -0
- package/payload/server/public/assets/{flatten-E2Sr0FeD.js → flatten-DeFkSYLU.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-DSMf9IO0.js → flowDiagram-DWJPFMVM-2NYMfqHX.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DRj0wip6.js → ganttDiagram-T4ZO3ILL-AAAa2sqE.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DsUTwRUb.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-D5s87wIr.js → gitGraphDiagram-UUTBAWPF-d8NUAIz5.js} +1 -1
- package/payload/server/public/assets/graph-Bx9_2qbJ.js +51 -0
- package/payload/server/public/assets/{graph-labels-DsXyfwKP.js → graph-labels-Cc1nU1_f.js} +1 -1
- package/payload/server/public/assets/{graphlib-DBueCu-j.js → graphlib-DUlqr2mr.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-BV9FyUXQ.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-D4dh4-0g.js +2 -0
- package/payload/server/public/assets/{isEmpty-CLz-UprQ.js → isEmpty-Bn-Se8yT.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BoMwv4cD.js → ishikawaDiagram-UXIWVN3A-DPTmm2IE.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-BkKxK7iC.js → journeyDiagram-VCZTEJTY-B85vjqkE.js} +1 -1
- package/payload/server/public/assets/jsx-runtime-D3PZpOAF.css +1 -0
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BSrkzXlb.js → kanban-definition-6JOO6SKY-C2Lfb5Xh.js} +1 -1
- package/payload/server/public/assets/{line-CMDTDopn.js → line-CODKFpwO.js} +1 -1
- package/payload/server/public/assets/{linear-CKifLODy.js → linear-CgbkJiu6.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CEH6m0Lv.js → mermaid-parser.core-DYdFZnXH.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-DyAGyaJG.js → mermaid.core-Bamjzahu.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DLZa0d69.js → mindmap-definition-QFDTVHPH-CLK90bKJ.js} +1 -1
- package/payload/server/public/assets/{ordinal-5RtyPJVt.js → ordinal-C-EimP2j.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-SXjQ83Vr.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-q7TXebDD.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-zTOJvniq.js → pieDiagram-DEJITSTG-DEsnxhqP.js} +1 -1
- package/payload/server/public/assets/public-BFMu-jux.js +35 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CHzDGI4U.js → quadrantDiagram-34T5L4WZ-uIP9V2jZ.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CXKUHVMS.js +1 -0
- package/payload/server/public/assets/{reduce-B3Mw_0s1.js → reduce-B0wq8DtH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CrrYBRTT.js → requirementDiagram-MS252O5E-CVS6t5tv.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-EEi77dbS.js → sankeyDiagram-XADWPNL6-BIsmtyZA.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BNeO1Hdg.js → sequenceDiagram-FGHM5R23-Cu8TfQiW.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-9Zyf6fFj.js → stateDiagram-FHFEXIEX-ax4vYGft.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BRv1By5g.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DRCVn4rg.js → timeline-definition-GMOUNBTQ-3l7ojkMA.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWuFgUeJ.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-gKO4rbgo.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-CVoG6qb0.js → useSelectionMode-C_EBRd2k.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CNaA1Bcg.js → vennDiagram-DHZGUBPP-C_sv0qMD.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-hDEw8pJN.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-9BoBW3Oo.js → wardleyDiagram-NUSXRM2D-C7u4IHMB.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-CAXyPTsj.js → xychartDiagram-5P7HB3ND-A-uLXr1a.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -9
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -9
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +558 -275
- package/payload/server/public/assets/AdminShell-t3IuI7JZ.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-DLCnSHk9.js +0 -1
- package/payload/server/public/assets/channel-BEqls8-f.js +0 -1
- package/payload/server/public/assets/chat-DJ3nvES3.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-TEFdhIy5.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CcHV2DdO.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CtuzQYGd.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CnyF9bus.js +0 -1
- package/payload/server/public/assets/clone-HKYySpjZ.js +0 -1
- package/payload/server/public/assets/data-BNqGUTEs.js +0 -1
- package/payload/server/public/assets/file-download-BUeQHzJD.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DOHzO_KB.js +0 -1
- package/payload/server/public/assets/graph-C4FX88ML.js +0 -51
- package/payload/server/public/assets/info-OMHHGYJF-CgstATO5.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO--6bwMJZM.js +0 -2
- package/payload/server/public/assets/jsx-runtime-61OZ_8PV.css +0 -1
- package/payload/server/public/assets/mic-BXINsrwF.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BRSJpaWt.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-B5VBvTzX.js +0 -1
- package/payload/server/public/assets/public-Cya9ie76.js +0 -35
- package/payload/server/public/assets/radar-PYXPWWZC-CWBqEfap.js +0 -1
- package/payload/server/public/assets/sliders-horizontal-CUmlgKbR.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-PeqMIgxs.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-D8zjIvCq.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-DQW69zQK.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-CDTm6Cdu.js +0 -1
- /package/payload/server/public/assets/{_baseFor-DVaNaTfF.js → _baseFor-BV-TyLWt.js} +0 -0
- /package/payload/server/public/assets/{array-8_H1156C.js → array-lqrvkwy7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-h10p_6j-.js → cytoscape.esm-SmEOayFS.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-pD7tFa1r.js → defaultLocale-Dl3Sud5K.js} +0 -0
- /package/payload/server/public/assets/{dist-DHQbMi0P.js → dist-Pgmncqde.js} +0 -0
- /package/payload/server/public/assets/{init-CwJ4b81e.js → init-BukMwkmL.js} +0 -0
- /package/payload/server/public/assets/{jsx-runtime-GpAtq6d8.js → jsx-runtime-5auA0FEj.js} +0 -0
- /package/payload/server/public/assets/{katex-DJPjIBAI.js → katex-jl-BtNZi.js} +0 -0
- /package/payload/server/public/assets/{path-CK8wrAxY.js → path-DPTRcLku.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-Dwml_la6.js → rough.esm-VLpapkIG.js} +0 -0
- /package/payload/server/public/assets/{src-CglFLxOI.js → src-CozP7LCe.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1214,8 +1214,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1214
1214
|
};
|
|
1215
1215
|
|
|
1216
1216
|
// server/index.ts
|
|
1217
|
-
import { readFileSync as
|
|
1218
|
-
import { resolve as
|
|
1217
|
+
import { readFileSync as readFileSync26, existsSync as existsSync26, watchFile } from "fs";
|
|
1218
|
+
import { resolve as resolve28, join as join21, basename as basename8 } from "path";
|
|
1219
1219
|
import { homedir as homedir3 } from "os";
|
|
1220
1220
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1221
1221
|
|
|
@@ -1794,7 +1794,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1794
1794
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1795
1795
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1796
1796
|
const timer2 = new Promise(
|
|
1797
|
-
(
|
|
1797
|
+
(resolve29) => setTimeout(() => resolve29("timeout"), timeoutMs)
|
|
1798
1798
|
);
|
|
1799
1799
|
const result = await Promise.race([
|
|
1800
1800
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1922,11 +1922,11 @@ async function createWaSocket(opts) {
|
|
|
1922
1922
|
return sock;
|
|
1923
1923
|
}
|
|
1924
1924
|
async function waitForConnection(sock) {
|
|
1925
|
-
return new Promise((
|
|
1925
|
+
return new Promise((resolve29, reject) => {
|
|
1926
1926
|
const handler = (update) => {
|
|
1927
1927
|
if (update.connection === "open") {
|
|
1928
1928
|
sock.ev.off("connection.update", handler);
|
|
1929
|
-
|
|
1929
|
+
resolve29();
|
|
1930
1930
|
}
|
|
1931
1931
|
if (update.connection === "close") {
|
|
1932
1932
|
sock.ev.off("connection.update", handler);
|
|
@@ -2040,14 +2040,14 @@ ${inspected}`;
|
|
|
2040
2040
|
return inspect2(err, INSPECT_OPTS2);
|
|
2041
2041
|
}
|
|
2042
2042
|
function withTimeout(label, promise, timeoutMs) {
|
|
2043
|
-
return new Promise((
|
|
2043
|
+
return new Promise((resolve29, reject) => {
|
|
2044
2044
|
const timer2 = setTimeout(() => {
|
|
2045
2045
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2046
2046
|
}, timeoutMs);
|
|
2047
2047
|
promise.then(
|
|
2048
2048
|
(value) => {
|
|
2049
2049
|
clearTimeout(timer2);
|
|
2050
|
-
|
|
2050
|
+
resolve29(value);
|
|
2051
2051
|
},
|
|
2052
2052
|
(err) => {
|
|
2053
2053
|
clearTimeout(timer2);
|
|
@@ -2646,8 +2646,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2646
2646
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2647
2647
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2648
2648
|
let release;
|
|
2649
|
-
const mine = new Promise((
|
|
2650
|
-
release =
|
|
2649
|
+
const mine = new Promise((resolve29) => {
|
|
2650
|
+
release = resolve29;
|
|
2651
2651
|
});
|
|
2652
2652
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2653
2653
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3727,11 +3727,11 @@ async function connectWithReconnect(conn) {
|
|
|
3727
3727
|
console.error(
|
|
3728
3728
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3729
3729
|
);
|
|
3730
|
-
await new Promise((
|
|
3731
|
-
const timer2 = setTimeout(
|
|
3730
|
+
await new Promise((resolve29) => {
|
|
3731
|
+
const timer2 = setTimeout(resolve29, delay);
|
|
3732
3732
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3733
3733
|
clearTimeout(timer2);
|
|
3734
|
-
|
|
3734
|
+
resolve29();
|
|
3735
3735
|
}, { once: true });
|
|
3736
3736
|
});
|
|
3737
3737
|
}
|
|
@@ -3739,16 +3739,16 @@ async function connectWithReconnect(conn) {
|
|
|
3739
3739
|
}
|
|
3740
3740
|
}
|
|
3741
3741
|
function waitForDisconnectEvent(conn) {
|
|
3742
|
-
return new Promise((
|
|
3742
|
+
return new Promise((resolve29) => {
|
|
3743
3743
|
if (!conn.sock) {
|
|
3744
|
-
|
|
3744
|
+
resolve29();
|
|
3745
3745
|
return;
|
|
3746
3746
|
}
|
|
3747
3747
|
const sock = conn.sock;
|
|
3748
3748
|
const handler = (update) => {
|
|
3749
3749
|
if (update.connection === "close") {
|
|
3750
3750
|
sock.ev.off("connection.update", handler);
|
|
3751
|
-
|
|
3751
|
+
resolve29();
|
|
3752
3752
|
}
|
|
3753
3753
|
};
|
|
3754
3754
|
sock.ev.on("connection.update", handler);
|
|
@@ -4008,8 +4008,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4008
4008
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4009
4009
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4010
4010
|
let resolvePending;
|
|
4011
|
-
const sttPending = new Promise((
|
|
4012
|
-
resolvePending =
|
|
4011
|
+
const sttPending = new Promise((resolve29) => {
|
|
4012
|
+
resolvePending = resolve29;
|
|
4013
4013
|
});
|
|
4014
4014
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4015
4015
|
try {
|
|
@@ -4400,20 +4400,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4400
4400
|
|
|
4401
4401
|
// server/routes/health.ts
|
|
4402
4402
|
function checkPort(port2, timeoutMs = 500) {
|
|
4403
|
-
return new Promise((
|
|
4403
|
+
return new Promise((resolve29) => {
|
|
4404
4404
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4405
4405
|
socket.setTimeout(timeoutMs);
|
|
4406
4406
|
socket.once("connect", () => {
|
|
4407
4407
|
socket.destroy();
|
|
4408
|
-
|
|
4408
|
+
resolve29(true);
|
|
4409
4409
|
});
|
|
4410
4410
|
socket.once("error", () => {
|
|
4411
4411
|
socket.destroy();
|
|
4412
|
-
|
|
4412
|
+
resolve29(false);
|
|
4413
4413
|
});
|
|
4414
4414
|
socket.once("timeout", () => {
|
|
4415
4415
|
socket.destroy();
|
|
4416
|
-
|
|
4416
|
+
resolve29(false);
|
|
4417
4417
|
});
|
|
4418
4418
|
});
|
|
4419
4419
|
}
|
|
@@ -4529,6 +4529,16 @@ async function writeAttachment(scope, filename, mimeType, sizeBytes, buffer) {
|
|
|
4529
4529
|
await writeFile2(metaPath, JSON.stringify(meta, null, 2));
|
|
4530
4530
|
return { attachmentId, filename, storagePath, metaPath, mimeType, sizeBytes };
|
|
4531
4531
|
}
|
|
4532
|
+
async function storeAttachment(accountId, file) {
|
|
4533
|
+
assertSupportedMime(file.type);
|
|
4534
|
+
if (file.size > MAX_FILE_SIZE_BYTES) {
|
|
4535
|
+
throw new Error(
|
|
4536
|
+
`File "${file.name}" exceeds the 50 MB limit (${(file.size / 1024 / 1024).toFixed(1)} MB).`
|
|
4537
|
+
);
|
|
4538
|
+
}
|
|
4539
|
+
const buffer = Buffer.from(await file.arrayBuffer());
|
|
4540
|
+
return writeAttachment(accountId, file.name, file.type, file.size, buffer);
|
|
4541
|
+
}
|
|
4532
4542
|
async function storePublicAttachment(sessionId, file, buffer) {
|
|
4533
4543
|
assertSupportedMime(file.type);
|
|
4534
4544
|
if (file.size > MAX_FILE_SIZE_BYTES) {
|
|
@@ -5510,12 +5520,12 @@ async function dispatchOnce(input) {
|
|
|
5510
5520
|
});
|
|
5511
5521
|
if (!entry) return { error: "spawn-failed" };
|
|
5512
5522
|
entry.lastInboundAt = Date.now();
|
|
5513
|
-
let
|
|
5523
|
+
let resolve29;
|
|
5514
5524
|
const turnPromise = new Promise((r) => {
|
|
5515
|
-
|
|
5525
|
+
resolve29 = r;
|
|
5516
5526
|
});
|
|
5517
5527
|
const listener = (text) => {
|
|
5518
|
-
|
|
5528
|
+
resolve29(text);
|
|
5519
5529
|
};
|
|
5520
5530
|
entry.subscribers.add(listener);
|
|
5521
5531
|
const writeAtMs = Date.now();
|
|
@@ -6301,8 +6311,8 @@ async function startLogin(opts) {
|
|
|
6301
6311
|
await clearAuth(authDir);
|
|
6302
6312
|
let resolveCode = null;
|
|
6303
6313
|
let rejectCode = null;
|
|
6304
|
-
const codePromise = new Promise((
|
|
6305
|
-
resolveCode =
|
|
6314
|
+
const codePromise = new Promise((resolve29, reject) => {
|
|
6315
|
+
resolveCode = resolve29;
|
|
6306
6316
|
rejectCode = reject;
|
|
6307
6317
|
});
|
|
6308
6318
|
const codeTimer = setTimeout(
|
|
@@ -7705,7 +7715,24 @@ var whatsapp_reader_default = app5;
|
|
|
7705
7715
|
// server/routes/webchat.ts
|
|
7706
7716
|
import { basename as basename3, dirname as dirname2 } from "path";
|
|
7707
7717
|
import { join as join10 } from "path";
|
|
7718
|
+
import { readFileSync as readFileSync11, renameSync, writeFileSync as writeFileSync5 } from "fs";
|
|
7708
7719
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
7720
|
+
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;
|
|
7721
|
+
function locateSession(sessionId) {
|
|
7722
|
+
const cfg = claudeConfigDir();
|
|
7723
|
+
if (!cfg) return { projectDir: null, channel: null };
|
|
7724
|
+
for (const { path: path2 } of enumerateJsonls(join10(cfg, "projects"))) {
|
|
7725
|
+
if (basename3(path2) === `${sessionId}.jsonl`) {
|
|
7726
|
+
const dir = dirname2(path2);
|
|
7727
|
+
const meta = readSidecarMeta(join10(dir, `${sessionId}.meta.json`));
|
|
7728
|
+
return { projectDir: dir, channel: meta.channel };
|
|
7729
|
+
}
|
|
7730
|
+
}
|
|
7731
|
+
return { projectDir: null, channel: null };
|
|
7732
|
+
}
|
|
7733
|
+
function conflictingBinding(channel) {
|
|
7734
|
+
return channel !== null && channel !== "webchat" ? channel : null;
|
|
7735
|
+
}
|
|
7709
7736
|
var NO_INDICATORS = {
|
|
7710
7737
|
activity: null,
|
|
7711
7738
|
permissionMode: null,
|
|
@@ -7741,14 +7768,44 @@ async function fetchComposerIndicators(sessionId) {
|
|
|
7741
7768
|
return NO_INDICATORS;
|
|
7742
7769
|
}
|
|
7743
7770
|
}
|
|
7771
|
+
var MODEL_ID_PATTERN = /^claude-[a-z0-9][a-z0-9.-]*(\[1m\])?$/;
|
|
7772
|
+
var EFFORT_LEVELS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh"]);
|
|
7773
|
+
function readLevers() {
|
|
7774
|
+
let account;
|
|
7775
|
+
try {
|
|
7776
|
+
account = resolveAccount();
|
|
7777
|
+
} catch {
|
|
7778
|
+
return { leverModel: null, leverEffort: null };
|
|
7779
|
+
}
|
|
7780
|
+
if (!account) return { leverModel: null, leverEffort: null };
|
|
7781
|
+
const model = account.config.adminModel;
|
|
7782
|
+
const effort = account.config.effort;
|
|
7783
|
+
return {
|
|
7784
|
+
leverModel: typeof model === "string" && MODEL_ID_PATTERN.test(model) ? model : null,
|
|
7785
|
+
leverEffort: typeof effort === "string" && EFFORT_LEVELS.has(effort) ? effort : null
|
|
7786
|
+
};
|
|
7787
|
+
}
|
|
7788
|
+
var REAPPLY_TIMEOUT_MS = 1500;
|
|
7789
|
+
async function reapplyLeversViaManager() {
|
|
7790
|
+
let port2;
|
|
7791
|
+
try {
|
|
7792
|
+
port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "webchat:settings" });
|
|
7793
|
+
} catch {
|
|
7794
|
+
return false;
|
|
7795
|
+
}
|
|
7796
|
+
try {
|
|
7797
|
+
const res = await fetch(`http://127.0.0.1:${port2}/reapply-levers`, {
|
|
7798
|
+
method: "POST",
|
|
7799
|
+
signal: AbortSignal.timeout(REAPPLY_TIMEOUT_MS)
|
|
7800
|
+
});
|
|
7801
|
+
return res.ok;
|
|
7802
|
+
} catch {
|
|
7803
|
+
return false;
|
|
7804
|
+
}
|
|
7805
|
+
}
|
|
7744
7806
|
function createWebchatRoutes(deps) {
|
|
7745
7807
|
const app49 = new Hono();
|
|
7746
7808
|
app49.post("/send", requireAdminSession, async (c) => {
|
|
7747
|
-
const body = await c.req.json().catch(() => null);
|
|
7748
|
-
const text = body?.text;
|
|
7749
|
-
if (typeof text !== "string" || text.length === 0) {
|
|
7750
|
-
return c.json({ error: "text required" }, 400);
|
|
7751
|
-
}
|
|
7752
7809
|
let accountId;
|
|
7753
7810
|
try {
|
|
7754
7811
|
accountId = resolvePlatformAccountId();
|
|
@@ -7757,9 +7814,160 @@ function createWebchatRoutes(deps) {
|
|
|
7757
7814
|
console.error(`[webchat:inbound] op=send-refused reason=account-unresolved detail=${detail}`);
|
|
7758
7815
|
return c.json({ error: "account unresolved" }, 503);
|
|
7759
7816
|
}
|
|
7760
|
-
|
|
7817
|
+
let text;
|
|
7818
|
+
let target;
|
|
7819
|
+
let files = [];
|
|
7820
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
7821
|
+
const isMultipart = contentType.startsWith("multipart/form-data");
|
|
7822
|
+
if (isMultipart) {
|
|
7823
|
+
let formData;
|
|
7824
|
+
try {
|
|
7825
|
+
formData = await c.req.formData();
|
|
7826
|
+
} catch {
|
|
7827
|
+
console.error("[webchat:inbound] op=send-refused kind=multipart reason=invalid-body");
|
|
7828
|
+
return c.json({ error: "invalid multipart body" }, 400);
|
|
7829
|
+
}
|
|
7830
|
+
const typed = formData.get("text");
|
|
7831
|
+
text = typeof typed === "string" ? typed : "";
|
|
7832
|
+
files = formData.getAll("attachments").filter((f) => f instanceof File);
|
|
7833
|
+
const rawTarget = formData.get("session");
|
|
7834
|
+
if (rawTarget !== null) {
|
|
7835
|
+
if (typeof rawTarget !== "string" || !UUID_PATTERN.test(rawTarget)) {
|
|
7836
|
+
return c.json({ error: "invalid session id" }, 400);
|
|
7837
|
+
}
|
|
7838
|
+
target = rawTarget;
|
|
7839
|
+
}
|
|
7840
|
+
} else {
|
|
7841
|
+
const body = await c.req.json().catch(() => null);
|
|
7842
|
+
const typed = body?.text;
|
|
7843
|
+
if (typeof typed !== "string" || typed.length === 0) {
|
|
7844
|
+
return c.json({ error: "text required" }, 400);
|
|
7845
|
+
}
|
|
7846
|
+
text = typed;
|
|
7847
|
+
const rawTarget = body?.session;
|
|
7848
|
+
if (rawTarget !== void 0) {
|
|
7849
|
+
if (typeof rawTarget !== "string" || !UUID_PATTERN.test(rawTarget)) {
|
|
7850
|
+
return c.json({ error: "invalid session id" }, 400);
|
|
7851
|
+
}
|
|
7852
|
+
target = rawTarget;
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
let deliveryKey = WEBCHAT_ADMIN_KEY;
|
|
7856
|
+
let deliverySessionId;
|
|
7857
|
+
if (target !== void 0) {
|
|
7858
|
+
const { projectDir, channel } = locateSession(target);
|
|
7859
|
+
if (projectDir === null) {
|
|
7860
|
+
return c.json({ error: "session not found" }, 404);
|
|
7861
|
+
}
|
|
7862
|
+
const binding = conflictingBinding(channel);
|
|
7863
|
+
if (binding !== null) {
|
|
7864
|
+
console.error(`[webchat:inbound] op=send-refused key=session:${target.slice(0, 8)} reason=channel-conflict binding=${binding}`);
|
|
7865
|
+
return c.json({ error: "channel-conflict", binding }, 409);
|
|
7866
|
+
}
|
|
7867
|
+
deliveryKey = `session:${target}`;
|
|
7868
|
+
deliverySessionId = target;
|
|
7869
|
+
}
|
|
7870
|
+
if (isMultipart) {
|
|
7871
|
+
const kind = files.some((f) => isAudioMime(f.type)) ? "voice" : "files";
|
|
7872
|
+
if (files.length > MAX_FILES_PER_MESSAGE) {
|
|
7873
|
+
console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=too-many-files count=${files.length}`);
|
|
7874
|
+
return c.json({ error: `Maximum ${MAX_FILES_PER_MESSAGE} files per message.` }, 422);
|
|
7875
|
+
}
|
|
7876
|
+
const audioFile = files.find((f) => isAudioMime(f.type));
|
|
7877
|
+
const regularFiles = files.filter((f) => !isAudioMime(f.type));
|
|
7878
|
+
if (audioFile) {
|
|
7879
|
+
if (audioFile.size > MAX_FILE_SIZE_BYTES) {
|
|
7880
|
+
console.error(`[webchat:inbound] op=send-refused kind=voice reason=oversize bytes=${audioFile.size}`);
|
|
7881
|
+
return c.json({ error: "Recording too long. Try a shorter voice note." }, 422);
|
|
7882
|
+
}
|
|
7883
|
+
const result = await transcribeVoiceNote(audioFile, "admin");
|
|
7884
|
+
if (!result.ok) {
|
|
7885
|
+
console.error(`[webchat:inbound] op=send-refused kind=voice reason=stt-failed detail=${result.error}`);
|
|
7886
|
+
return c.json({ error: result.error }, 422);
|
|
7887
|
+
}
|
|
7888
|
+
text = result.result.text;
|
|
7889
|
+
}
|
|
7890
|
+
for (const file of regularFiles) {
|
|
7891
|
+
try {
|
|
7892
|
+
assertSupportedMime(file.type);
|
|
7893
|
+
if (file.size > MAX_FILE_SIZE_BYTES) {
|
|
7894
|
+
throw new Error(`File "${file.name}" exceeds the 50 MB limit (${(file.size / 1024 / 1024).toFixed(1)} MB).`);
|
|
7895
|
+
}
|
|
7896
|
+
} catch (err) {
|
|
7897
|
+
const detail = err instanceof Error ? err.message : "invalid file";
|
|
7898
|
+
console.error(`[webchat:inbound] op=send-refused kind=files reason=file-rejected detail=${detail}`);
|
|
7899
|
+
return c.json({ error: detail }, 422);
|
|
7900
|
+
}
|
|
7901
|
+
}
|
|
7902
|
+
const stored = [];
|
|
7903
|
+
try {
|
|
7904
|
+
for (const file of regularFiles) {
|
|
7905
|
+
stored.push(await storeAttachment(accountId, file));
|
|
7906
|
+
}
|
|
7907
|
+
} catch (err) {
|
|
7908
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7909
|
+
console.error(`[webchat:inbound] op=send-refused kind=files reason=store-failed detail=${detail}`);
|
|
7910
|
+
return c.json({ error: "failed to store attachment" }, 500);
|
|
7911
|
+
}
|
|
7912
|
+
if (stored.length > 0) {
|
|
7913
|
+
const listing = stored.map((s) => `${s.filename} (${s.storagePath})`).join(", ");
|
|
7914
|
+
const note = `[The operator uploaded ${stored.length} file(s): ${listing}]`;
|
|
7915
|
+
text = text.length > 0 ? `${text}
|
|
7916
|
+
|
|
7917
|
+
${note}` : note;
|
|
7918
|
+
}
|
|
7919
|
+
if (text.length === 0) {
|
|
7920
|
+
console.error(`[webchat:inbound] op=send-refused kind=${kind} reason=empty-text`);
|
|
7921
|
+
return c.json({ error: "text required" }, 400);
|
|
7922
|
+
}
|
|
7923
|
+
console.log(`[webchat:inbound] op=send-accepted kind=${kind} files=${stored.length} bytes=${Buffer.byteLength(text, "utf8")}`);
|
|
7924
|
+
}
|
|
7925
|
+
if (deliverySessionId !== void 0) {
|
|
7926
|
+
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text, sessionId: deliverySessionId });
|
|
7927
|
+
} else {
|
|
7928
|
+
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text });
|
|
7929
|
+
}
|
|
7761
7930
|
return c.json({ ok: true });
|
|
7762
7931
|
});
|
|
7932
|
+
app49.post("/settings", requireAdminSession, async (c) => {
|
|
7933
|
+
const body = await c.req.json().catch(() => null);
|
|
7934
|
+
const op = body?.op;
|
|
7935
|
+
const value = body?.value;
|
|
7936
|
+
if (op !== "model" && op !== "effort") {
|
|
7937
|
+
console.error(`[webchat:settings] op=${String(op)} outcome=refused reason=unknown-op`);
|
|
7938
|
+
return c.json({ error: "op must be model or effort" }, 400);
|
|
7939
|
+
}
|
|
7940
|
+
if (typeof value !== "string" || op === "model" && !MODEL_ID_PATTERN.test(value) || op === "effort" && !EFFORT_LEVELS.has(value)) {
|
|
7941
|
+
console.error(`[webchat:settings] op=${op} outcome=refused value=${JSON.stringify(value)} reason=invalid-value`);
|
|
7942
|
+
return c.json({ error: `invalid ${op} value` }, 400);
|
|
7943
|
+
}
|
|
7944
|
+
let account;
|
|
7945
|
+
try {
|
|
7946
|
+
account = resolveAccount();
|
|
7947
|
+
} catch {
|
|
7948
|
+
account = null;
|
|
7949
|
+
}
|
|
7950
|
+
if (!account) {
|
|
7951
|
+
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
7952
|
+
return c.json({ error: "account unresolved" }, 503);
|
|
7953
|
+
}
|
|
7954
|
+
const accountJsonPath = join10(account.accountDir, "account.json");
|
|
7955
|
+
try {
|
|
7956
|
+
const parsed = JSON.parse(readFileSync11(accountJsonPath, "utf8"));
|
|
7957
|
+
if (op === "model") parsed.adminModel = value;
|
|
7958
|
+
else parsed.effort = value;
|
|
7959
|
+
const tmp = `${accountJsonPath}.${process.pid}.tmp`;
|
|
7960
|
+
writeFileSync5(tmp, JSON.stringify(parsed, null, 2), "utf8");
|
|
7961
|
+
renameSync(tmp, accountJsonPath);
|
|
7962
|
+
} catch (err) {
|
|
7963
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7964
|
+
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=write-failed detail=${detail}`);
|
|
7965
|
+
return c.json({ error: "persist failed" }, 500);
|
|
7966
|
+
}
|
|
7967
|
+
const settingsApplied = await reapplyLeversViaManager();
|
|
7968
|
+
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
7969
|
+
return c.json({ ok: true, settingsApplied });
|
|
7970
|
+
});
|
|
7763
7971
|
app49.get("/session", requireAdminSession, async (c) => {
|
|
7764
7972
|
let accountId;
|
|
7765
7973
|
try {
|
|
@@ -7769,6 +7977,15 @@ function createWebchatRoutes(deps) {
|
|
|
7769
7977
|
console.error(`[webchat:inbound] op=session-refused reason=account-unresolved detail=${detail}`);
|
|
7770
7978
|
return c.json({ error: "account unresolved" }, 503);
|
|
7771
7979
|
}
|
|
7980
|
+
const target = c.req.query("session");
|
|
7981
|
+
if (target !== void 0) {
|
|
7982
|
+
if (!UUID_PATTERN.test(target)) {
|
|
7983
|
+
return c.json({ error: "invalid session id" }, 400);
|
|
7984
|
+
}
|
|
7985
|
+
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
7986
|
+
const indicators2 = await fetchComposerIndicators(target);
|
|
7987
|
+
return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), ...indicators2 });
|
|
7988
|
+
}
|
|
7772
7989
|
const sessionId = adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
7773
7990
|
const cfg = claudeConfigDir();
|
|
7774
7991
|
let projectDir = null;
|
|
@@ -7781,11 +7998,56 @@ function createWebchatRoutes(deps) {
|
|
|
7781
7998
|
}
|
|
7782
7999
|
}
|
|
7783
8000
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
7784
|
-
return c.json({ sessionId, projectDir, ...indicators });
|
|
8001
|
+
return c.json({ sessionId, projectDir, ...indicators, ...readLevers() });
|
|
7785
8002
|
});
|
|
7786
8003
|
return app49;
|
|
7787
8004
|
}
|
|
7788
8005
|
|
|
8006
|
+
// server/routes/webchat-greeting.ts
|
|
8007
|
+
import { resolve as resolve10 } from "path";
|
|
8008
|
+
|
|
8009
|
+
// app/lib/claude-agent/specialist-roster.ts
|
|
8010
|
+
import { existsSync as existsSync8, readFileSync as readFileSync12, readdirSync as readdirSync7 } from "fs";
|
|
8011
|
+
import { join as join11 } from "path";
|
|
8012
|
+
function field(fm, name) {
|
|
8013
|
+
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8014
|
+
if (!m) return null;
|
|
8015
|
+
let value = m[1].trim();
|
|
8016
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
8017
|
+
value = value.slice(1, -1);
|
|
8018
|
+
}
|
|
8019
|
+
return value || null;
|
|
8020
|
+
}
|
|
8021
|
+
function readSpecialistRoster(specialistsDir) {
|
|
8022
|
+
if (!existsSync8(specialistsDir)) return { specialists: [], skipped: [] };
|
|
8023
|
+
const entries = readdirSync7(specialistsDir);
|
|
8024
|
+
const specialists = [];
|
|
8025
|
+
const skipped = [];
|
|
8026
|
+
for (const file of entries.sort()) {
|
|
8027
|
+
if (!file.endsWith(".md")) continue;
|
|
8028
|
+
let raw;
|
|
8029
|
+
try {
|
|
8030
|
+
raw = readFileSync12(join11(specialistsDir, file), "utf-8");
|
|
8031
|
+
} catch (err) {
|
|
8032
|
+
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8033
|
+
continue;
|
|
8034
|
+
}
|
|
8035
|
+
const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
8036
|
+
if (!fm) {
|
|
8037
|
+
skipped.push({ file, reason: "no-frontmatter" });
|
|
8038
|
+
continue;
|
|
8039
|
+
}
|
|
8040
|
+
const name = field(fm[1], "name");
|
|
8041
|
+
if (!name) {
|
|
8042
|
+
skipped.push({ file, reason: "missing-name" });
|
|
8043
|
+
continue;
|
|
8044
|
+
}
|
|
8045
|
+
const summary = field(fm[1], "summary") ?? field(fm[1], "description") ?? "";
|
|
8046
|
+
specialists.push({ name, summary });
|
|
8047
|
+
}
|
|
8048
|
+
return { specialists, skipped };
|
|
8049
|
+
}
|
|
8050
|
+
|
|
7789
8051
|
// server/routes/webchat-greeting.ts
|
|
7790
8052
|
var OUTSTANDING_TASK_STATUSES = ["pending", "active", "running"];
|
|
7791
8053
|
var UPCOMING_EVENT_STATUSES = ["scheduled", "due"];
|
|
@@ -7844,10 +8106,25 @@ app6.get("/", requireAdminSession, async (c) => {
|
|
|
7844
8106
|
return { events: events2, tasks: tasks2 };
|
|
7845
8107
|
}
|
|
7846
8108
|
);
|
|
8109
|
+
let specialists = [];
|
|
8110
|
+
try {
|
|
8111
|
+
const roster = readSpecialistRoster(
|
|
8112
|
+
resolve10(ACCOUNTS_DIR, accountId, "specialists", "agents")
|
|
8113
|
+
);
|
|
8114
|
+
specialists = roster.specialists;
|
|
8115
|
+
for (const s of roster.skipped) {
|
|
8116
|
+
console.warn(
|
|
8117
|
+
`[webchat:greeting] op=specialist-skipped file=${s.file} reason=${s.reason}`
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
8120
|
+
} catch (err) {
|
|
8121
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
8122
|
+
console.error(`[webchat:greeting] op=specialists-read-failed reason=${detail}`);
|
|
8123
|
+
}
|
|
7847
8124
|
console.log(
|
|
7848
|
-
`[webchat:greeting] op=read account=${accountId.slice(0, 8)} events=${events.length} tasks=${tasks.total} ms=${Date.now() - started}`
|
|
8125
|
+
`[webchat:greeting] op=read account=${accountId.slice(0, 8)} events=${events.length} tasks=${tasks.total} specialists=${specialists.length} ms=${Date.now() - started}`
|
|
7849
8126
|
);
|
|
7850
|
-
return c.json({ ok: true, events, tasks });
|
|
8127
|
+
return c.json({ ok: true, events, tasks, specialists });
|
|
7851
8128
|
} catch (err) {
|
|
7852
8129
|
const detail = err instanceof Error ? err.message : String(err);
|
|
7853
8130
|
console.error(`[webchat:greeting] op=read-failed reason=${detail}`);
|
|
@@ -7867,8 +8144,8 @@ var webchat_greeting_default = app6;
|
|
|
7867
8144
|
|
|
7868
8145
|
// server/routes/telegram.ts
|
|
7869
8146
|
import { homedir } from "os";
|
|
7870
|
-
import { resolve as
|
|
7871
|
-
import { existsSync as
|
|
8147
|
+
import { resolve as resolve11, join as join12 } from "path";
|
|
8148
|
+
import { existsSync as existsSync9, readFileSync as readFileSync13 } from "fs";
|
|
7872
8149
|
|
|
7873
8150
|
// app/lib/telegram/access-control.ts
|
|
7874
8151
|
function checkTelegramAccess(params) {
|
|
@@ -7918,11 +8195,11 @@ function routeTelegramUpdate(input) {
|
|
|
7918
8195
|
var TAG22 = "[telegram-inbound]";
|
|
7919
8196
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
7920
8197
|
function configDirName() {
|
|
7921
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
7922
|
-
const brandPath =
|
|
7923
|
-
if (
|
|
8198
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve11(process.cwd(), "..");
|
|
8199
|
+
const brandPath = join12(platformRoot2, "config", "brand.json");
|
|
8200
|
+
if (existsSync9(brandPath)) {
|
|
7924
8201
|
try {
|
|
7925
|
-
return JSON.parse(
|
|
8202
|
+
return JSON.parse(readFileSync13(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
7926
8203
|
} catch {
|
|
7927
8204
|
}
|
|
7928
8205
|
}
|
|
@@ -7930,7 +8207,7 @@ function configDirName() {
|
|
|
7930
8207
|
}
|
|
7931
8208
|
function secretPath(botType) {
|
|
7932
8209
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
7933
|
-
return
|
|
8210
|
+
return resolve11(homedir(), configDirName(), filename);
|
|
7934
8211
|
}
|
|
7935
8212
|
async function sendTelegram(botToken, chatId, text) {
|
|
7936
8213
|
try {
|
|
@@ -7954,11 +8231,11 @@ app7.post("/", async (c) => {
|
|
|
7954
8231
|
return c.json({ ok: false }, 400);
|
|
7955
8232
|
}
|
|
7956
8233
|
const sp = secretPath(botType);
|
|
7957
|
-
if (!
|
|
8234
|
+
if (!existsSync9(sp)) {
|
|
7958
8235
|
console.error(`${TAG22} op=reject reason=no-secret-file botType=${botType}`);
|
|
7959
8236
|
return c.json({ ok: false }, 401);
|
|
7960
8237
|
}
|
|
7961
|
-
const expected =
|
|
8238
|
+
const expected = readFileSync13(sp, "utf-8").trim();
|
|
7962
8239
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
7963
8240
|
if (got !== expected) {
|
|
7964
8241
|
console.error(`${TAG22} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -8021,12 +8298,12 @@ var telegram_default = app7;
|
|
|
8021
8298
|
|
|
8022
8299
|
// server/routes/onboarding.ts
|
|
8023
8300
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
8024
|
-
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as
|
|
8301
|
+
import { openSync as openSync2, closeSync as closeSync2, writeFileSync as writeFileSync7, writeSync, existsSync as existsSync11, readFileSync as readFileSync15, unlinkSync } from "fs";
|
|
8025
8302
|
import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
8026
8303
|
|
|
8027
8304
|
// ../lib/admins-write/src/index.ts
|
|
8028
|
-
import { existsSync as
|
|
8029
|
-
import { dirname as dirname3, join as
|
|
8305
|
+
import { existsSync as existsSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync6, renameSync as renameSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync8, statSync as statSync5 } from "fs";
|
|
8306
|
+
import { dirname as dirname3, join as join13 } from "path";
|
|
8030
8307
|
function logLine(input, result) {
|
|
8031
8308
|
const userIdShort = input.userId.slice(0, 8);
|
|
8032
8309
|
console.error(
|
|
@@ -8036,15 +8313,15 @@ function logLine(input, result) {
|
|
|
8036
8313
|
function writeFileAtomic(filePath, contents, mode) {
|
|
8037
8314
|
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
8038
8315
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
8039
|
-
|
|
8040
|
-
|
|
8316
|
+
writeFileSync6(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
8317
|
+
renameSync2(tempPath, filePath);
|
|
8041
8318
|
}
|
|
8042
8319
|
function writeAdminEntry(input) {
|
|
8043
8320
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
8044
8321
|
try {
|
|
8045
8322
|
let users = [];
|
|
8046
|
-
if (
|
|
8047
|
-
const raw =
|
|
8323
|
+
if (existsSync10(input.usersFile)) {
|
|
8324
|
+
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8048
8325
|
if (raw) {
|
|
8049
8326
|
const parsed = JSON.parse(raw);
|
|
8050
8327
|
if (!Array.isArray(parsed)) {
|
|
@@ -8068,11 +8345,11 @@ function writeAdminEntry(input) {
|
|
|
8068
8345
|
return result;
|
|
8069
8346
|
}
|
|
8070
8347
|
try {
|
|
8071
|
-
const accountJsonPath =
|
|
8072
|
-
if (!
|
|
8348
|
+
const accountJsonPath = join13(input.accountDir, "account.json");
|
|
8349
|
+
if (!existsSync10(accountJsonPath)) {
|
|
8073
8350
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
8074
8351
|
}
|
|
8075
|
-
const config = JSON.parse(
|
|
8352
|
+
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
8076
8353
|
const admins = config.admins ?? [];
|
|
8077
8354
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
8078
8355
|
result.accountJsonResult = "noop";
|
|
@@ -8096,9 +8373,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
8096
8373
|
usersWithoutAccount: []
|
|
8097
8374
|
};
|
|
8098
8375
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
8099
|
-
if (
|
|
8376
|
+
if (existsSync10(input.usersFile)) {
|
|
8100
8377
|
try {
|
|
8101
|
-
const raw =
|
|
8378
|
+
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8102
8379
|
if (raw) {
|
|
8103
8380
|
const users = JSON.parse(raw);
|
|
8104
8381
|
for (const u of users) {
|
|
@@ -8111,10 +8388,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
8111
8388
|
}
|
|
8112
8389
|
}
|
|
8113
8390
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
8114
|
-
if (
|
|
8391
|
+
if (existsSync10(input.accountsDir)) {
|
|
8115
8392
|
let entries;
|
|
8116
8393
|
try {
|
|
8117
|
-
entries =
|
|
8394
|
+
entries = readdirSync8(input.accountsDir);
|
|
8118
8395
|
} catch (err) {
|
|
8119
8396
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8120
8397
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -8123,17 +8400,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
8123
8400
|
}
|
|
8124
8401
|
for (const entry of entries) {
|
|
8125
8402
|
if (entry.startsWith(".")) continue;
|
|
8126
|
-
const accountDir =
|
|
8403
|
+
const accountDir = join13(input.accountsDir, entry);
|
|
8127
8404
|
try {
|
|
8128
8405
|
if (!statSync5(accountDir).isDirectory()) continue;
|
|
8129
8406
|
} catch {
|
|
8130
8407
|
continue;
|
|
8131
8408
|
}
|
|
8132
|
-
const accountJsonPath =
|
|
8133
|
-
if (!
|
|
8409
|
+
const accountJsonPath = join13(accountDir, "account.json");
|
|
8410
|
+
if (!existsSync10(accountJsonPath)) continue;
|
|
8134
8411
|
let admins = [];
|
|
8135
8412
|
try {
|
|
8136
|
-
const config = JSON.parse(
|
|
8413
|
+
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
8137
8414
|
admins = config.admins ?? [];
|
|
8138
8415
|
} catch (err) {
|
|
8139
8416
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -8173,8 +8450,8 @@ function hashPin2(pin) {
|
|
|
8173
8450
|
return createHash3("sha256").update(pin).digest("hex");
|
|
8174
8451
|
}
|
|
8175
8452
|
function readUsersFile2() {
|
|
8176
|
-
if (!
|
|
8177
|
-
const raw =
|
|
8453
|
+
if (!existsSync11(USERS_FILE)) return null;
|
|
8454
|
+
const raw = readFileSync15(USERS_FILE, "utf-8").trim();
|
|
8178
8455
|
if (!raw) return [];
|
|
8179
8456
|
return JSON.parse(raw);
|
|
8180
8457
|
}
|
|
@@ -8227,7 +8504,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
8227
8504
|
} catch (err) {
|
|
8228
8505
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
8229
8506
|
}
|
|
8230
|
-
const credentialsPresent =
|
|
8507
|
+
const credentialsPresent = existsSync11(CLAUDE_CREDENTIALS_FILE);
|
|
8231
8508
|
const ranMs = Date.now() - start;
|
|
8232
8509
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
8233
8510
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -8245,7 +8522,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
8245
8522
|
return c.json({ launched: cdpReady });
|
|
8246
8523
|
}
|
|
8247
8524
|
ensureLogDir();
|
|
8248
|
-
|
|
8525
|
+
writeFileSync7(logPath("claude-auth"), "");
|
|
8249
8526
|
const claudeAuthLogFd = openSync2(logPath("claude-auth"), "a");
|
|
8250
8527
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
8251
8528
|
if (process.platform === "darwin") {
|
|
@@ -8334,9 +8611,9 @@ app8.post("/set-pin", async (c) => {
|
|
|
8334
8611
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
8335
8612
|
if (process.platform === "linux") {
|
|
8336
8613
|
let installOwner = null;
|
|
8337
|
-
if (
|
|
8614
|
+
if (existsSync11(INSTALL_OWNER_FILE)) {
|
|
8338
8615
|
try {
|
|
8339
|
-
const raw =
|
|
8616
|
+
const raw = readFileSync15(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
8340
8617
|
if (raw.length > 0) installOwner = raw;
|
|
8341
8618
|
} catch (err) {
|
|
8342
8619
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -8409,7 +8686,7 @@ app8.delete("/set-pin", async (c) => {
|
|
|
8409
8686
|
unlinkSync(USERS_FILE);
|
|
8410
8687
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${matchedUser.userId.slice(0, 8)}\u2026`);
|
|
8411
8688
|
} else {
|
|
8412
|
-
|
|
8689
|
+
writeFileSync7(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
8413
8690
|
console.log(`[set-pin] removed entry from users.json: userId=${matchedUser.userId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
8414
8691
|
}
|
|
8415
8692
|
return c.json({ ok: true });
|
|
@@ -8417,9 +8694,9 @@ app8.delete("/set-pin", async (c) => {
|
|
|
8417
8694
|
var onboarding_default = app8;
|
|
8418
8695
|
|
|
8419
8696
|
// server/routes/client-error.ts
|
|
8420
|
-
import { appendFileSync, existsSync as
|
|
8421
|
-
import { join as
|
|
8422
|
-
var CLIENT_ERRORS_LOG =
|
|
8697
|
+
import { appendFileSync, existsSync as existsSync12, renameSync as renameSync3, statSync as statSync6 } from "fs";
|
|
8698
|
+
import { join as join14 } from "path";
|
|
8699
|
+
var CLIENT_ERRORS_LOG = join14(LOG_DIR, "client-errors.log");
|
|
8423
8700
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
8424
8701
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
8425
8702
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -8462,10 +8739,10 @@ function stackHead(stack) {
|
|
|
8462
8739
|
}
|
|
8463
8740
|
function rotateIfNeeded() {
|
|
8464
8741
|
try {
|
|
8465
|
-
if (!
|
|
8742
|
+
if (!existsSync12(CLIENT_ERRORS_LOG)) return;
|
|
8466
8743
|
const stats = statSync6(CLIENT_ERRORS_LOG);
|
|
8467
8744
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
8468
|
-
|
|
8745
|
+
renameSync3(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
8469
8746
|
} catch (err) {
|
|
8470
8747
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8471
8748
|
}
|
|
@@ -8744,18 +9021,18 @@ app10.post("/", async (c) => {
|
|
|
8744
9021
|
var session_default = app10;
|
|
8745
9022
|
|
|
8746
9023
|
// server/routes/admin/logs.ts
|
|
8747
|
-
import { existsSync as
|
|
8748
|
-
import { resolve as
|
|
9024
|
+
import { existsSync as existsSync14, readdirSync as readdirSync9, readFileSync as readFileSync16, statSync as statSync7 } from "fs";
|
|
9025
|
+
import { resolve as resolve12, basename as basename4 } from "path";
|
|
8749
9026
|
|
|
8750
9027
|
// app/lib/logs-read-resolve.ts
|
|
8751
|
-
import { existsSync as
|
|
8752
|
-
import { join as
|
|
9028
|
+
import { existsSync as existsSync13 } from "fs";
|
|
9029
|
+
import { join as join15 } from "path";
|
|
8753
9030
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
8754
9031
|
const tried = [filename];
|
|
8755
9032
|
const hits = [];
|
|
8756
9033
|
for (const dir of logDirs) {
|
|
8757
|
-
const fullPath =
|
|
8758
|
-
if (
|
|
9034
|
+
const fullPath = join15(dir, filename);
|
|
9035
|
+
if (existsSync13(fullPath)) {
|
|
8759
9036
|
hits.push({ path: fullPath, dir });
|
|
8760
9037
|
}
|
|
8761
9038
|
}
|
|
@@ -8772,7 +9049,7 @@ app11.get("/", async (c) => {
|
|
|
8772
9049
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
8773
9050
|
const download = c.req.query("download") === "1";
|
|
8774
9051
|
const account = resolveAccount();
|
|
8775
|
-
const accountLogDir = account ?
|
|
9052
|
+
const accountLogDir = account ? resolve12(account.accountDir, "logs") : null;
|
|
8776
9053
|
const logDirs = [];
|
|
8777
9054
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
8778
9055
|
logDirs.push(LOG_DIR);
|
|
@@ -8780,10 +9057,10 @@ app11.get("/", async (c) => {
|
|
|
8780
9057
|
const safe = basename4(fileParam);
|
|
8781
9058
|
const searched = [];
|
|
8782
9059
|
for (const dir of logDirs) {
|
|
8783
|
-
const filePath =
|
|
9060
|
+
const filePath = resolve12(dir, safe);
|
|
8784
9061
|
searched.push(filePath);
|
|
8785
9062
|
try {
|
|
8786
|
-
const buffer =
|
|
9063
|
+
const buffer = readFileSync16(filePath);
|
|
8787
9064
|
const onDiskBytes = statSync7(filePath).size;
|
|
8788
9065
|
const headers = {
|
|
8789
9066
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -8848,7 +9125,7 @@ app11.get("/", async (c) => {
|
|
|
8848
9125
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
8849
9126
|
try {
|
|
8850
9127
|
const filename = basename4(hit.path);
|
|
8851
|
-
const buffer =
|
|
9128
|
+
const buffer = readFileSync16(hit.path);
|
|
8852
9129
|
const onDiskBytes = statSync7(hit.path).size;
|
|
8853
9130
|
const headers = {
|
|
8854
9131
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -8883,19 +9160,19 @@ app11.get("/", async (c) => {
|
|
|
8883
9160
|
const seen = /* @__PURE__ */ new Set();
|
|
8884
9161
|
const logs = {};
|
|
8885
9162
|
for (const dir of logDirs) {
|
|
8886
|
-
if (!
|
|
9163
|
+
if (!existsSync14(dir)) continue;
|
|
8887
9164
|
let files;
|
|
8888
9165
|
try {
|
|
8889
|
-
files =
|
|
9166
|
+
files = readdirSync9(dir).filter((f) => f.endsWith(".log"));
|
|
8890
9167
|
} catch (err) {
|
|
8891
9168
|
const reason = err instanceof Error ? err.message : String(err);
|
|
8892
9169
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
8893
9170
|
continue;
|
|
8894
9171
|
}
|
|
8895
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(
|
|
9172
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve12(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
8896
9173
|
seen.add(name);
|
|
8897
9174
|
try {
|
|
8898
|
-
const content =
|
|
9175
|
+
const content = readFileSync16(resolve12(dir, name));
|
|
8899
9176
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
8900
9177
|
logs[name] = tail.trim() || "(empty)";
|
|
8901
9178
|
} catch (err) {
|
|
@@ -8934,8 +9211,8 @@ var claude_info_default = app12;
|
|
|
8934
9211
|
|
|
8935
9212
|
// server/routes/admin/attachment.ts
|
|
8936
9213
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
8937
|
-
import { existsSync as
|
|
8938
|
-
import { resolve as
|
|
9214
|
+
import { existsSync as existsSync15 } from "fs";
|
|
9215
|
+
import { resolve as resolve13 } from "path";
|
|
8939
9216
|
var app13 = new Hono();
|
|
8940
9217
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
8941
9218
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -8947,12 +9224,12 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8947
9224
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
8948
9225
|
return new Response("Not found", { status: 404 });
|
|
8949
9226
|
}
|
|
8950
|
-
const dir =
|
|
8951
|
-
if (!
|
|
9227
|
+
const dir = resolve13(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
9228
|
+
if (!existsSync15(dir)) {
|
|
8952
9229
|
return new Response("Not found", { status: 404 });
|
|
8953
9230
|
}
|
|
8954
|
-
const metaPath =
|
|
8955
|
-
if (!
|
|
9231
|
+
const metaPath = resolve13(dir, `${attachmentId}.meta.json`);
|
|
9232
|
+
if (!existsSync15(metaPath)) {
|
|
8956
9233
|
return new Response("Not found", { status: 404 });
|
|
8957
9234
|
}
|
|
8958
9235
|
let meta;
|
|
@@ -8966,7 +9243,7 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8966
9243
|
if (!dataFile) {
|
|
8967
9244
|
return new Response("Not found", { status: 404 });
|
|
8968
9245
|
}
|
|
8969
|
-
const filePath =
|
|
9246
|
+
const filePath = resolve13(dir, dataFile);
|
|
8970
9247
|
const buffer = await readFile2(filePath);
|
|
8971
9248
|
return new Response(new Uint8Array(buffer), {
|
|
8972
9249
|
headers: {
|
|
@@ -8979,24 +9256,24 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8979
9256
|
var attachment_default = app13;
|
|
8980
9257
|
|
|
8981
9258
|
// server/routes/admin/agents.ts
|
|
8982
|
-
import { resolve as
|
|
8983
|
-
import { readdirSync as
|
|
9259
|
+
import { resolve as resolve14 } from "path";
|
|
9260
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync17, existsSync as existsSync16, rmSync } from "fs";
|
|
8984
9261
|
var app14 = new Hono();
|
|
8985
9262
|
app14.get("/", (c) => {
|
|
8986
9263
|
const account = resolveAccount();
|
|
8987
9264
|
if (!account) return c.json({ agents: [] });
|
|
8988
|
-
const agentsDir =
|
|
8989
|
-
if (!
|
|
9265
|
+
const agentsDir = resolve14(account.accountDir, "agents");
|
|
9266
|
+
if (!existsSync16(agentsDir)) return c.json({ agents: [] });
|
|
8990
9267
|
const agents = [];
|
|
8991
9268
|
try {
|
|
8992
|
-
const entries =
|
|
9269
|
+
const entries = readdirSync10(agentsDir, { withFileTypes: true });
|
|
8993
9270
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
8994
9271
|
if (!entry.isDirectory()) continue;
|
|
8995
9272
|
if (entry.name === "admin") continue;
|
|
8996
|
-
const configPath2 =
|
|
8997
|
-
if (!
|
|
9273
|
+
const configPath2 = resolve14(agentsDir, entry.name, "config.json");
|
|
9274
|
+
if (!existsSync16(configPath2)) continue;
|
|
8998
9275
|
try {
|
|
8999
|
-
const config = JSON.parse(
|
|
9276
|
+
const config = JSON.parse(readFileSync17(configPath2, "utf-8"));
|
|
9000
9277
|
agents.push({
|
|
9001
9278
|
slug: entry.name,
|
|
9002
9279
|
displayName: config.displayName ?? entry.name,
|
|
@@ -9022,8 +9299,8 @@ app14.delete("/:slug", async (c) => {
|
|
|
9022
9299
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9023
9300
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9024
9301
|
}
|
|
9025
|
-
const agentDir =
|
|
9026
|
-
if (!
|
|
9302
|
+
const agentDir = resolve14(account.accountDir, "agents", slug);
|
|
9303
|
+
if (!existsSync16(agentDir)) {
|
|
9027
9304
|
return c.json({ error: "Agent not found" }, 404);
|
|
9028
9305
|
}
|
|
9029
9306
|
try {
|
|
@@ -9052,8 +9329,8 @@ app14.post("/:slug/project", async (c) => {
|
|
|
9052
9329
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9053
9330
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9054
9331
|
}
|
|
9055
|
-
const agentDir =
|
|
9056
|
-
if (!
|
|
9332
|
+
const agentDir = resolve14(account.accountDir, "agents", slug);
|
|
9333
|
+
if (!existsSync16(agentDir)) {
|
|
9057
9334
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9058
9335
|
}
|
|
9059
9336
|
try {
|
|
@@ -9069,7 +9346,7 @@ var agents_default = app14;
|
|
|
9069
9346
|
// server/routes/admin/sessions.ts
|
|
9070
9347
|
import crypto2 from "crypto";
|
|
9071
9348
|
import { resolve as resolvePath } from "path";
|
|
9072
|
-
import { existsSync as
|
|
9349
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync3, createWriteStream } from "fs";
|
|
9073
9350
|
|
|
9074
9351
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
9075
9352
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -9229,7 +9506,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
9229
9506
|
let reason = null;
|
|
9230
9507
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
9231
9508
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
9232
|
-
else if (!
|
|
9509
|
+
else if (!existsSync17(a.storagePath)) reason = "missing-file";
|
|
9233
9510
|
if (reason) {
|
|
9234
9511
|
invalid++;
|
|
9235
9512
|
try {
|
|
@@ -9755,8 +10032,8 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
9755
10032
|
var sessions_default = app15;
|
|
9756
10033
|
|
|
9757
10034
|
// app/lib/claude-agent/spawn-context.ts
|
|
9758
|
-
import { existsSync as
|
|
9759
|
-
import { dirname as dirname4, resolve as
|
|
10035
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync8 } from "fs";
|
|
10036
|
+
import { dirname as dirname4, resolve as resolve15, join as join16 } from "path";
|
|
9760
10037
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
9761
10038
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
9762
10039
|
try {
|
|
@@ -9770,10 +10047,10 @@ async function resolveOwnerProfileBlock(accountId, userId) {
|
|
|
9770
10047
|
return { ok: false, reason: "neo4j-unreachable" };
|
|
9771
10048
|
}
|
|
9772
10049
|
}
|
|
9773
|
-
function frontmatterField(manifest,
|
|
10050
|
+
function frontmatterField(manifest, field2) {
|
|
9774
10051
|
const fm = manifest.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
9775
10052
|
if (!fm) return null;
|
|
9776
|
-
const re = new RegExp(`^${
|
|
10053
|
+
const re = new RegExp(`^${field2}:\\s*(.*?)\\r?$`, "m");
|
|
9777
10054
|
const m = fm[1].match(re);
|
|
9778
10055
|
if (!m) return null;
|
|
9779
10056
|
let value = m[1].trim();
|
|
@@ -9785,14 +10062,14 @@ function frontmatterField(manifest, field) {
|
|
|
9785
10062
|
function extractPluginToolDescriptions(pluginDir) {
|
|
9786
10063
|
const out = /* @__PURE__ */ new Map();
|
|
9787
10064
|
const candidates = [
|
|
9788
|
-
|
|
9789
|
-
|
|
10065
|
+
join16(pluginDir, "mcp/dist/index.js"),
|
|
10066
|
+
join16(pluginDir, "mcp/src/index.ts")
|
|
9790
10067
|
];
|
|
9791
10068
|
let raw = null;
|
|
9792
10069
|
for (const path2 of candidates) {
|
|
9793
|
-
if (!
|
|
10070
|
+
if (!existsSync18(path2)) continue;
|
|
9794
10071
|
try {
|
|
9795
|
-
raw =
|
|
10072
|
+
raw = readFileSync18(path2, "utf-8");
|
|
9796
10073
|
break;
|
|
9797
10074
|
} catch {
|
|
9798
10075
|
}
|
|
@@ -9841,24 +10118,24 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
9841
10118
|
}
|
|
9842
10119
|
function listPluginDirs() {
|
|
9843
10120
|
const out = /* @__PURE__ */ new Map();
|
|
9844
|
-
const platformPlugins =
|
|
9845
|
-
if (
|
|
9846
|
-
for (const name of
|
|
9847
|
-
const dir =
|
|
10121
|
+
const platformPlugins = resolve15(PLATFORM_ROOT, "plugins");
|
|
10122
|
+
if (existsSync18(platformPlugins)) {
|
|
10123
|
+
for (const name of readdirSync11(platformPlugins)) {
|
|
10124
|
+
const dir = join16(platformPlugins, name);
|
|
9848
10125
|
try {
|
|
9849
10126
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
9850
10127
|
} catch {
|
|
9851
10128
|
}
|
|
9852
10129
|
}
|
|
9853
10130
|
}
|
|
9854
|
-
const premiumRoot =
|
|
9855
|
-
if (
|
|
9856
|
-
for (const bundle of
|
|
9857
|
-
const bundlePlugins =
|
|
9858
|
-
if (!
|
|
10131
|
+
const premiumRoot = resolve15(dirname4(PLATFORM_ROOT), "premium-plugins");
|
|
10132
|
+
if (existsSync18(premiumRoot)) {
|
|
10133
|
+
for (const bundle of readdirSync11(premiumRoot)) {
|
|
10134
|
+
const bundlePlugins = join16(premiumRoot, bundle, "plugins");
|
|
10135
|
+
if (!existsSync18(bundlePlugins)) continue;
|
|
9859
10136
|
try {
|
|
9860
|
-
for (const name of
|
|
9861
|
-
const dir =
|
|
10137
|
+
for (const name of readdirSync11(bundlePlugins)) {
|
|
10138
|
+
const dir = join16(bundlePlugins, name);
|
|
9862
10139
|
try {
|
|
9863
10140
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
9864
10141
|
} catch {
|
|
@@ -9871,10 +10148,10 @@ function listPluginDirs() {
|
|
|
9871
10148
|
return out;
|
|
9872
10149
|
}
|
|
9873
10150
|
function readEnabledPlugins(accountId) {
|
|
9874
|
-
const accountFile =
|
|
9875
|
-
if (!
|
|
10151
|
+
const accountFile = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10152
|
+
if (!existsSync18(accountFile)) return /* @__PURE__ */ new Set();
|
|
9876
10153
|
try {
|
|
9877
|
-
const parsed = JSON.parse(
|
|
10154
|
+
const parsed = JSON.parse(readFileSync18(accountFile, "utf-8"));
|
|
9878
10155
|
return new Set(
|
|
9879
10156
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
9880
10157
|
);
|
|
@@ -9883,10 +10160,10 @@ function readEnabledPlugins(accountId) {
|
|
|
9883
10160
|
}
|
|
9884
10161
|
}
|
|
9885
10162
|
function readFrontmatter(path2) {
|
|
9886
|
-
if (!
|
|
10163
|
+
if (!existsSync18(path2)) return null;
|
|
9887
10164
|
let raw;
|
|
9888
10165
|
try {
|
|
9889
|
-
raw =
|
|
10166
|
+
raw = readFileSync18(path2, "utf-8");
|
|
9890
10167
|
} catch {
|
|
9891
10168
|
return null;
|
|
9892
10169
|
}
|
|
@@ -9901,7 +10178,7 @@ function computeActivePlugins(accountId) {
|
|
|
9901
10178
|
for (const name of Array.from(enabled).sort()) {
|
|
9902
10179
|
const dir = pluginDirs.get(name);
|
|
9903
10180
|
if (!dir) continue;
|
|
9904
|
-
const fm = readFrontmatter(
|
|
10181
|
+
const fm = readFrontmatter(join16(dir, "PLUGIN.md"));
|
|
9905
10182
|
if (!fm) continue;
|
|
9906
10183
|
const description = frontmatterField(`---
|
|
9907
10184
|
${fm}
|
|
@@ -9918,7 +10195,7 @@ ${fm}
|
|
|
9918
10195
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
9919
10196
|
);
|
|
9920
10197
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
9921
|
-
const hasSource =
|
|
10198
|
+
const hasSource = existsSync18(join16(dir, "mcp/dist/index.js")) || existsSync18(join16(dir, "mcp/src/index.ts"));
|
|
9922
10199
|
if (hasSource) {
|
|
9923
10200
|
console.warn(
|
|
9924
10201
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -9928,7 +10205,7 @@ ${fm}
|
|
|
9928
10205
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
9929
10206
|
const skills = [];
|
|
9930
10207
|
for (const relPath of skillPaths) {
|
|
9931
|
-
const skillPath =
|
|
10208
|
+
const skillPath = join16(dir, relPath);
|
|
9932
10209
|
const skillFm = readFrontmatter(skillPath);
|
|
9933
10210
|
if (!skillFm) continue;
|
|
9934
10211
|
const skillName = frontmatterField(`---
|
|
@@ -9944,11 +10221,11 @@ ${skillFm}
|
|
|
9944
10221
|
return out;
|
|
9945
10222
|
}
|
|
9946
10223
|
function computeSpecialistDomains(accountId) {
|
|
9947
|
-
const specialistsDir =
|
|
9948
|
-
if (!
|
|
10224
|
+
const specialistsDir = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10225
|
+
if (!existsSync18(specialistsDir)) return [];
|
|
9949
10226
|
let entries;
|
|
9950
10227
|
try {
|
|
9951
|
-
entries =
|
|
10228
|
+
entries = readdirSync11(specialistsDir);
|
|
9952
10229
|
} catch {
|
|
9953
10230
|
return [];
|
|
9954
10231
|
}
|
|
@@ -9972,7 +10249,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
9972
10249
|
const out = [];
|
|
9973
10250
|
for (const file of entries.sort()) {
|
|
9974
10251
|
if (!file.endsWith(".md")) continue;
|
|
9975
|
-
const fm = readFrontmatter(
|
|
10252
|
+
const fm = readFrontmatter(join16(specialistsDir, file));
|
|
9976
10253
|
if (!fm) continue;
|
|
9977
10254
|
const wrapped = `---
|
|
9978
10255
|
${fm}
|
|
@@ -9990,11 +10267,11 @@ ${fm}
|
|
|
9990
10267
|
return out;
|
|
9991
10268
|
}
|
|
9992
10269
|
function computeDormantPlugins(accountId) {
|
|
9993
|
-
const accountFile =
|
|
9994
|
-
if (!
|
|
10270
|
+
const accountFile = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10271
|
+
if (!existsSync18(accountFile)) return [];
|
|
9995
10272
|
let enabled;
|
|
9996
10273
|
try {
|
|
9997
|
-
const raw =
|
|
10274
|
+
const raw = readFileSync18(accountFile, "utf-8");
|
|
9998
10275
|
const parsed = JSON.parse(raw);
|
|
9999
10276
|
enabled = new Set(
|
|
10000
10277
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -10005,22 +10282,22 @@ function computeDormantPlugins(accountId) {
|
|
|
10005
10282
|
);
|
|
10006
10283
|
return [];
|
|
10007
10284
|
}
|
|
10008
|
-
const pluginsDir =
|
|
10009
|
-
if (!
|
|
10285
|
+
const pluginsDir = resolve15(PLATFORM_ROOT, "plugins");
|
|
10286
|
+
if (!existsSync18(pluginsDir)) return [];
|
|
10010
10287
|
let entries;
|
|
10011
10288
|
try {
|
|
10012
|
-
entries =
|
|
10289
|
+
entries = readdirSync11(pluginsDir);
|
|
10013
10290
|
} catch {
|
|
10014
10291
|
return [];
|
|
10015
10292
|
}
|
|
10016
10293
|
const out = [];
|
|
10017
10294
|
for (const name of entries) {
|
|
10018
10295
|
if (enabled.has(name)) continue;
|
|
10019
|
-
const manifestPath =
|
|
10020
|
-
if (!
|
|
10296
|
+
const manifestPath = resolve15(pluginsDir, name, "PLUGIN.md");
|
|
10297
|
+
if (!existsSync18(manifestPath)) continue;
|
|
10021
10298
|
let manifest;
|
|
10022
10299
|
try {
|
|
10023
|
-
manifest =
|
|
10300
|
+
manifest = readFileSync18(manifestPath, "utf-8");
|
|
10024
10301
|
} catch {
|
|
10025
10302
|
continue;
|
|
10026
10303
|
}
|
|
@@ -10034,13 +10311,13 @@ function computeDormantPlugins(accountId) {
|
|
|
10034
10311
|
}
|
|
10035
10312
|
|
|
10036
10313
|
// server/routes/admin/claude-sessions.ts
|
|
10037
|
-
import { existsSync as
|
|
10038
|
-
import { resolve as
|
|
10314
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
|
|
10315
|
+
import { resolve as resolve16 } from "path";
|
|
10039
10316
|
function readTunnelState(brandConfigDir) {
|
|
10040
10317
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10041
|
-
if (!
|
|
10318
|
+
if (!existsSync19(statePath)) return null;
|
|
10042
10319
|
try {
|
|
10043
|
-
const parsed = JSON.parse(
|
|
10320
|
+
const parsed = JSON.parse(readFileSync19(statePath, "utf-8"));
|
|
10044
10321
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
10045
10322
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
10046
10323
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -10051,10 +10328,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10051
10328
|
}
|
|
10052
10329
|
}
|
|
10053
10330
|
function resolveTunnelUrl() {
|
|
10054
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
10331
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve16(process.cwd(), "..");
|
|
10055
10332
|
let brand;
|
|
10056
10333
|
try {
|
|
10057
|
-
brand = JSON.parse(
|
|
10334
|
+
brand = JSON.parse(readFileSync19(resolve16(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10058
10335
|
} catch {
|
|
10059
10336
|
return null;
|
|
10060
10337
|
}
|
|
@@ -10299,15 +10576,15 @@ var events_default = app18;
|
|
|
10299
10576
|
import { createReadStream as createReadStream2 } from "fs";
|
|
10300
10577
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
10301
10578
|
import { realpathSync as realpathSync4 } from "fs";
|
|
10302
|
-
import { basename as basename6, dirname as dirname5, join as
|
|
10579
|
+
import { basename as basename6, dirname as dirname5, join as join18, resolve as resolve19, sep as sep5 } from "path";
|
|
10303
10580
|
import { Readable as Readable2 } from "stream";
|
|
10304
10581
|
|
|
10305
10582
|
// app/lib/data-path.ts
|
|
10306
10583
|
import { realpathSync as realpathSync3 } from "fs";
|
|
10307
|
-
import { resolve as
|
|
10308
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
10309
|
-
var DATA_ROOT =
|
|
10310
|
-
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ?
|
|
10584
|
+
import { resolve as resolve17, normalize, sep as sep3, relative } from "path";
|
|
10585
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "../platform");
|
|
10586
|
+
var DATA_ROOT = resolve17(PLATFORM_ROOT5, "..", "data");
|
|
10587
|
+
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve17(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
10311
10588
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
10312
10589
|
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;
|
|
10313
10590
|
function crossesForeignAccountPartition(relPath, accountId) {
|
|
@@ -10320,7 +10597,7 @@ function crossesForeignAccountPartition(relPath, accountId) {
|
|
|
10320
10597
|
}
|
|
10321
10598
|
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
10322
10599
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
10323
|
-
const absolute =
|
|
10600
|
+
const absolute = resolve17(rootAbs, cleaned);
|
|
10324
10601
|
let rootReal;
|
|
10325
10602
|
try {
|
|
10326
10603
|
rootReal = realpathSync3(rootAbs);
|
|
@@ -10679,7 +10956,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10679
10956
|
|
|
10680
10957
|
// app/lib/file-index.ts
|
|
10681
10958
|
import * as fsp from "fs/promises";
|
|
10682
|
-
import { resolve as
|
|
10959
|
+
import { resolve as resolve18, relative as relative2, join as join17, basename as basename5, extname as extname2, sep as sep4 } from "path";
|
|
10683
10960
|
import { tmpdir as tmpdir2 } from "os";
|
|
10684
10961
|
import { execFile as execFile2 } from "child_process";
|
|
10685
10962
|
import { promisify as promisify2 } from "util";
|
|
@@ -10750,7 +11027,7 @@ async function extractPdf(absolute) {
|
|
|
10750
11027
|
return stdout.trim();
|
|
10751
11028
|
}
|
|
10752
11029
|
async function ocrPdf(absolute) {
|
|
10753
|
-
const outPdf =
|
|
11030
|
+
const outPdf = join17(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
10754
11031
|
try {
|
|
10755
11032
|
await execFileAsync2(
|
|
10756
11033
|
"ocrmypdf",
|
|
@@ -10812,7 +11089,7 @@ async function readDisplayName(absolute) {
|
|
|
10812
11089
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10813
11090
|
if (base === `${stem}.meta.json`) return null;
|
|
10814
11091
|
try {
|
|
10815
|
-
const raw = await fsp.readFile(
|
|
11092
|
+
const raw = await fsp.readFile(join17(dir, `${stem}.meta.json`), "utf-8");
|
|
10816
11093
|
const meta = JSON.parse(raw);
|
|
10817
11094
|
const dn = meta.displayName ?? meta.filename;
|
|
10818
11095
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -10832,7 +11109,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
10832
11109
|
let clean = true;
|
|
10833
11110
|
for (const entry of entries) {
|
|
10834
11111
|
if (entry.isSymbolicLink()) continue;
|
|
10835
|
-
const abs =
|
|
11112
|
+
const abs = join17(root, entry.name);
|
|
10836
11113
|
if (entry.isDirectory()) {
|
|
10837
11114
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
10838
11115
|
if (!sub.clean) clean = false;
|
|
@@ -10987,8 +11264,8 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
10987
11264
|
return withSession(opts, async (session) => {
|
|
10988
11265
|
const walked = [];
|
|
10989
11266
|
const subtreeRoots = [
|
|
10990
|
-
|
|
10991
|
-
|
|
11267
|
+
resolve18(dataRoot, "uploads", accountId),
|
|
11268
|
+
resolve18(dataRoot, "accounts", accountId)
|
|
10992
11269
|
];
|
|
10993
11270
|
let clean = true;
|
|
10994
11271
|
for (const root of subtreeRoots) {
|
|
@@ -11069,7 +11346,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
11069
11346
|
async function indexFile(accountId, relativePath, opts) {
|
|
11070
11347
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
11071
11348
|
const embed2 = opts?.embed ?? embed;
|
|
11072
|
-
const absolute =
|
|
11349
|
+
const absolute = resolve18(dataRoot, relativePath);
|
|
11073
11350
|
await withSession(opts, async (session) => {
|
|
11074
11351
|
const st = await fsp.stat(absolute);
|
|
11075
11352
|
const wf = {
|
|
@@ -11103,7 +11380,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
11103
11380
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11104
11381
|
async function readMeta(absDir, baseName) {
|
|
11105
11382
|
try {
|
|
11106
|
-
const raw = await readFile4(
|
|
11383
|
+
const raw = await readFile4(join18(absDir, `${baseName}.meta.json`), "utf8");
|
|
11107
11384
|
const parsed = JSON.parse(raw);
|
|
11108
11385
|
if (typeof parsed?.filename === "string") {
|
|
11109
11386
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11114,7 +11391,7 @@ async function readMeta(absDir, baseName) {
|
|
|
11114
11391
|
}
|
|
11115
11392
|
async function readAccountNames() {
|
|
11116
11393
|
const map = /* @__PURE__ */ new Map();
|
|
11117
|
-
const accountsDir =
|
|
11394
|
+
const accountsDir = resolve19(DATA_ROOT, "accounts");
|
|
11118
11395
|
let names;
|
|
11119
11396
|
try {
|
|
11120
11397
|
names = await readdir3(accountsDir);
|
|
@@ -11123,7 +11400,7 @@ async function readAccountNames() {
|
|
|
11123
11400
|
}
|
|
11124
11401
|
for (const name of names) {
|
|
11125
11402
|
if (!UUID_RE3.test(name)) continue;
|
|
11126
|
-
const configPath2 =
|
|
11403
|
+
const configPath2 = resolve19(accountsDir, name, "account.json");
|
|
11127
11404
|
try {
|
|
11128
11405
|
const raw = await readFile4(configPath2, "utf8");
|
|
11129
11406
|
const parsed = JSON.parse(raw);
|
|
@@ -11141,7 +11418,7 @@ async function readAccountNames() {
|
|
|
11141
11418
|
}
|
|
11142
11419
|
async function enrich(absolute, entry, accountNames) {
|
|
11143
11420
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
11144
|
-
const meta = await readMeta(
|
|
11421
|
+
const meta = await readMeta(join18(absolute, entry.name), entry.name);
|
|
11145
11422
|
if (meta?.filename) {
|
|
11146
11423
|
entry.displayName = meta.filename;
|
|
11147
11424
|
entry.mimeType = meta.mimeType;
|
|
@@ -11239,7 +11516,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11239
11516
|
continue;
|
|
11240
11517
|
}
|
|
11241
11518
|
try {
|
|
11242
|
-
const entryPath =
|
|
11519
|
+
const entryPath = join18(absolute, name);
|
|
11243
11520
|
const s = await stat4(entryPath);
|
|
11244
11521
|
entries.push({
|
|
11245
11522
|
name,
|
|
@@ -11364,8 +11641,8 @@ app19.post("/upload", requireAdminSession, async (c) => {
|
|
|
11364
11641
|
}
|
|
11365
11642
|
const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
|
|
11366
11643
|
const finalName = `${Date.now()}-${safeName}`;
|
|
11367
|
-
const destDir =
|
|
11368
|
-
const destPath =
|
|
11644
|
+
const destDir = resolve19(DATA_ROOT, "uploads", accountId);
|
|
11645
|
+
const destPath = resolve19(destDir, finalName);
|
|
11369
11646
|
try {
|
|
11370
11647
|
await mkdir3(destDir, { recursive: true });
|
|
11371
11648
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
@@ -11430,7 +11707,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
11430
11707
|
}
|
|
11431
11708
|
const dot = base.lastIndexOf(".");
|
|
11432
11709
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11433
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
11710
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join18(dirname5(absolute), `${stem}.meta.json`) : null;
|
|
11434
11711
|
await unlink2(absolute);
|
|
11435
11712
|
if (sidecarPath) {
|
|
11436
11713
|
try {
|
|
@@ -13479,8 +13756,8 @@ var graph_default_view_default = app25;
|
|
|
13479
13756
|
|
|
13480
13757
|
// server/routes/admin/sidebar-artefacts.ts
|
|
13481
13758
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
13482
|
-
import { resolve as
|
|
13483
|
-
import { existsSync as
|
|
13759
|
+
import { resolve as resolve20, relative as relative3, isAbsolute, sep as sep6, basename as basename7 } from "path";
|
|
13760
|
+
import { existsSync as existsSync20 } from "fs";
|
|
13484
13761
|
var LIMIT = 50;
|
|
13485
13762
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
13486
13763
|
function toDataRootRelPath(absPath) {
|
|
@@ -13499,7 +13776,7 @@ app26.get("/", requireAdminSession, async (c) => {
|
|
|
13499
13776
|
if (accountFiles === null) {
|
|
13500
13777
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
13501
13778
|
}
|
|
13502
|
-
const accountDir =
|
|
13779
|
+
const accountDir = resolve20(ACCOUNTS_DIR, accountId);
|
|
13503
13780
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
13504
13781
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
13505
13782
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -13550,8 +13827,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
13550
13827
|
async function fetchAgentTemplateRows(accountDir) {
|
|
13551
13828
|
const rows = [];
|
|
13552
13829
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
13553
|
-
const overridePath =
|
|
13554
|
-
const bundledPath =
|
|
13830
|
+
const overridePath = resolve20(accountDir, "agents", "admin", filename);
|
|
13831
|
+
const bundledPath = resolve20(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
13555
13832
|
const labelStem = filename.replace(/\.md$/, "");
|
|
13556
13833
|
const row = await readAgentTemplateRow({
|
|
13557
13834
|
id: `agent-template:admin:${filename}`,
|
|
@@ -13564,12 +13841,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13564
13841
|
});
|
|
13565
13842
|
if (row) rows.push(row);
|
|
13566
13843
|
}
|
|
13567
|
-
const overrideDir =
|
|
13568
|
-
const bundledDir =
|
|
13844
|
+
const overrideDir = resolve20(accountDir, "specialists", "agents");
|
|
13845
|
+
const bundledDir = resolve20(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
13569
13846
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
13570
13847
|
for (const filename of specialistNames) {
|
|
13571
|
-
const overridePath =
|
|
13572
|
-
const bundledPath =
|
|
13848
|
+
const overridePath = resolve20(overrideDir, filename);
|
|
13849
|
+
const bundledPath = resolve20(bundledDir, filename);
|
|
13573
13850
|
const row = await readAgentTemplateRow({
|
|
13574
13851
|
id: `agent-template:specialist:${filename}`,
|
|
13575
13852
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -13586,7 +13863,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13586
13863
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
13587
13864
|
const names = /* @__PURE__ */ new Set();
|
|
13588
13865
|
for (const dir of [overrideDir, bundledDir]) {
|
|
13589
|
-
if (!
|
|
13866
|
+
if (!existsSync20(dir)) continue;
|
|
13590
13867
|
try {
|
|
13591
13868
|
const entries = await readdir4(dir);
|
|
13592
13869
|
for (const entry of entries) {
|
|
@@ -13601,7 +13878,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
13601
13878
|
}
|
|
13602
13879
|
async function readAgentTemplateRow(inp) {
|
|
13603
13880
|
let chosenPath = null;
|
|
13604
|
-
if (
|
|
13881
|
+
if (existsSync20(inp.overridePath)) {
|
|
13605
13882
|
try {
|
|
13606
13883
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
13607
13884
|
chosenPath = inp.overridePath;
|
|
@@ -13612,7 +13889,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
13612
13889
|
);
|
|
13613
13890
|
return null;
|
|
13614
13891
|
}
|
|
13615
|
-
} else if (
|
|
13892
|
+
} else if (existsSync20(inp.bundledPath)) {
|
|
13616
13893
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
13617
13894
|
console.error(
|
|
13618
13895
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -13936,24 +14213,24 @@ app31.get("/", async (c) => {
|
|
|
13936
14213
|
var system_stats_default = app31;
|
|
13937
14214
|
|
|
13938
14215
|
// server/routes/admin/health.ts
|
|
13939
|
-
import { existsSync as
|
|
13940
|
-
import { resolve as
|
|
13941
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14216
|
+
import { existsSync as existsSync21, readFileSync as readFileSync20 } from "fs";
|
|
14217
|
+
import { resolve as resolve21, join as join19 } from "path";
|
|
14218
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
13942
14219
|
var brandHostname = "maxy";
|
|
13943
|
-
var brandJsonPath =
|
|
13944
|
-
if (
|
|
14220
|
+
var brandJsonPath = join19(PLATFORM_ROOT6, "config", "brand.json");
|
|
14221
|
+
if (existsSync21(brandJsonPath)) {
|
|
13945
14222
|
try {
|
|
13946
|
-
const brand = JSON.parse(
|
|
14223
|
+
const brand = JSON.parse(readFileSync20(brandJsonPath, "utf-8"));
|
|
13947
14224
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
13948
14225
|
} catch {
|
|
13949
14226
|
}
|
|
13950
14227
|
}
|
|
13951
|
-
var VERSION_FILE =
|
|
14228
|
+
var VERSION_FILE = resolve21(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
13952
14229
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
13953
14230
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
13954
14231
|
function readVersion() {
|
|
13955
|
-
if (!
|
|
13956
|
-
return
|
|
14232
|
+
if (!existsSync21(VERSION_FILE)) return "unknown";
|
|
14233
|
+
return readFileSync20(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
13957
14234
|
}
|
|
13958
14235
|
async function probeConversationDb() {
|
|
13959
14236
|
let session;
|
|
@@ -14495,16 +14772,16 @@ var admin_default = app39;
|
|
|
14495
14772
|
|
|
14496
14773
|
// app/lib/access-gate.ts
|
|
14497
14774
|
import neo4j4 from "neo4j-driver";
|
|
14498
|
-
import { readFileSync as
|
|
14499
|
-
import { resolve as
|
|
14775
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
14776
|
+
import { resolve as resolve22 } from "path";
|
|
14500
14777
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
14501
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14778
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
|
|
14502
14779
|
var driver = null;
|
|
14503
14780
|
function readPassword() {
|
|
14504
14781
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
14505
|
-
const passwordFile =
|
|
14782
|
+
const passwordFile = resolve22(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
14506
14783
|
try {
|
|
14507
|
-
return
|
|
14784
|
+
return readFileSync21(passwordFile, "utf-8").trim();
|
|
14508
14785
|
} catch {
|
|
14509
14786
|
throw new Error(
|
|
14510
14787
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -14792,9 +15069,9 @@ var verify_token_default = app40;
|
|
|
14792
15069
|
|
|
14793
15070
|
// app/lib/access-email.ts
|
|
14794
15071
|
import { spawn as spawn2 } from "child_process";
|
|
14795
|
-
import { resolve as
|
|
14796
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14797
|
-
var SEND_SCRIPT =
|
|
15072
|
+
import { resolve as resolve23 } from "path";
|
|
15073
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
|
|
15074
|
+
var SEND_SCRIPT = resolve23(
|
|
14798
15075
|
PLATFORM_ROOT8,
|
|
14799
15076
|
"plugins",
|
|
14800
15077
|
"email",
|
|
@@ -14936,8 +15213,8 @@ app42.route("/request-magic-link", request_magic_link_default);
|
|
|
14936
15213
|
var access_default = app42;
|
|
14937
15214
|
|
|
14938
15215
|
// server/routes/sites.ts
|
|
14939
|
-
import { existsSync as
|
|
14940
|
-
import { resolve as
|
|
15216
|
+
import { existsSync as existsSync22, readFileSync as readFileSync22, realpathSync as realpathSync5, statSync as statSync9 } from "fs";
|
|
15217
|
+
import { resolve as resolve24 } from "path";
|
|
14941
15218
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14942
15219
|
var MIME = {
|
|
14943
15220
|
".html": "text/html; charset=utf-8",
|
|
@@ -14994,15 +15271,15 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
14994
15271
|
}
|
|
14995
15272
|
segments.push(seg);
|
|
14996
15273
|
}
|
|
14997
|
-
const rootDir =
|
|
14998
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
15274
|
+
const rootDir = resolve24(account.accountDir, "sites");
|
|
15275
|
+
let filePath = segments.length === 0 ? rootDir : resolve24(rootDir, ...segments);
|
|
14999
15276
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
15000
15277
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15001
15278
|
return c.text("Forbidden", 403);
|
|
15002
15279
|
}
|
|
15003
15280
|
let stat7;
|
|
15004
15281
|
try {
|
|
15005
|
-
stat7 =
|
|
15282
|
+
stat7 = existsSync22(filePath) ? statSync9(filePath) : null;
|
|
15006
15283
|
} catch {
|
|
15007
15284
|
stat7 = null;
|
|
15008
15285
|
}
|
|
@@ -15015,13 +15292,13 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
15015
15292
|
return c.redirect(target, 301);
|
|
15016
15293
|
}
|
|
15017
15294
|
if (stat7?.isDirectory()) {
|
|
15018
|
-
filePath =
|
|
15295
|
+
filePath = resolve24(filePath, "index.html");
|
|
15019
15296
|
}
|
|
15020
15297
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
15021
15298
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15022
15299
|
return c.text("Forbidden", 403);
|
|
15023
15300
|
}
|
|
15024
|
-
if (!
|
|
15301
|
+
if (!existsSync22(filePath)) {
|
|
15025
15302
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
15026
15303
|
return c.text("Not found", 404);
|
|
15027
15304
|
}
|
|
@@ -15040,7 +15317,7 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
15040
15317
|
}
|
|
15041
15318
|
let body;
|
|
15042
15319
|
try {
|
|
15043
|
-
body =
|
|
15320
|
+
body = readFileSync22(realPath);
|
|
15044
15321
|
} catch (err) {
|
|
15045
15322
|
const code = err?.code;
|
|
15046
15323
|
if (code === "EISDIR") {
|
|
@@ -15076,7 +15353,7 @@ var sites_default = app43;
|
|
|
15076
15353
|
|
|
15077
15354
|
// app/lib/visitor-token.ts
|
|
15078
15355
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
15079
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
15356
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync23, writeFileSync as writeFileSync8 } from "fs";
|
|
15080
15357
|
import { dirname as dirname6 } from "path";
|
|
15081
15358
|
var TOKEN_PREFIX = "v1.";
|
|
15082
15359
|
var SECRET_BYTES = 32;
|
|
@@ -15085,7 +15362,7 @@ var cachedSecret = null;
|
|
|
15085
15362
|
function getSecret() {
|
|
15086
15363
|
if (cachedSecret) return cachedSecret;
|
|
15087
15364
|
try {
|
|
15088
|
-
const hex2 =
|
|
15365
|
+
const hex2 = readFileSync23(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
15089
15366
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
15090
15367
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
15091
15368
|
return cachedSecret;
|
|
@@ -15095,11 +15372,11 @@ function getSecret() {
|
|
|
15095
15372
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
15096
15373
|
try {
|
|
15097
15374
|
mkdirSync4(dirname6(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
15098
|
-
|
|
15375
|
+
writeFileSync8(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
15099
15376
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
15100
15377
|
} catch {
|
|
15101
15378
|
}
|
|
15102
|
-
const hex =
|
|
15379
|
+
const hex = readFileSync23(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
15103
15380
|
cachedSecret = Buffer.from(hex, "hex");
|
|
15104
15381
|
return cachedSecret;
|
|
15105
15382
|
}
|
|
@@ -15152,8 +15429,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
15152
15429
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
15153
15430
|
|
|
15154
15431
|
// app/lib/brand-config.ts
|
|
15155
|
-
import { existsSync as
|
|
15156
|
-
import { join as
|
|
15432
|
+
import { existsSync as existsSync23, readFileSync as readFileSync24 } from "fs";
|
|
15433
|
+
import { join as join20 } from "path";
|
|
15157
15434
|
var cached2 = null;
|
|
15158
15435
|
var cachedAttempted = false;
|
|
15159
15436
|
function readBrandConfig() {
|
|
@@ -15161,10 +15438,10 @@ function readBrandConfig() {
|
|
|
15161
15438
|
cachedAttempted = true;
|
|
15162
15439
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
15163
15440
|
if (!platformRoot2) return null;
|
|
15164
|
-
const brandPath =
|
|
15165
|
-
if (!
|
|
15441
|
+
const brandPath = join20(platformRoot2, "config", "brand.json");
|
|
15442
|
+
if (!existsSync23(brandPath)) return null;
|
|
15166
15443
|
try {
|
|
15167
|
-
cached2 = JSON.parse(
|
|
15444
|
+
cached2 = JSON.parse(readFileSync24(brandPath, "utf-8"));
|
|
15168
15445
|
return cached2;
|
|
15169
15446
|
} catch {
|
|
15170
15447
|
return null;
|
|
@@ -15652,14 +15929,14 @@ async function writeEvent(opts) {
|
|
|
15652
15929
|
var visitor_event_default = app46;
|
|
15653
15930
|
|
|
15654
15931
|
// server/routes/session.ts
|
|
15655
|
-
import { resolve as
|
|
15656
|
-
import { existsSync as
|
|
15932
|
+
import { resolve as resolve25 } from "path";
|
|
15933
|
+
import { existsSync as existsSync24, writeFileSync as writeFileSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
15657
15934
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
15658
15935
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
15659
15936
|
try {
|
|
15660
|
-
const cacheDir =
|
|
15937
|
+
const cacheDir = resolve25(MAXY_DIR, "branding-cache", accountId);
|
|
15661
15938
|
mkdirSync5(cacheDir, { recursive: true });
|
|
15662
|
-
|
|
15939
|
+
writeFileSync9(resolve25(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
15663
15940
|
} catch (err) {
|
|
15664
15941
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
15665
15942
|
}
|
|
@@ -15747,8 +16024,8 @@ app47.post("/", async (c) => {
|
|
|
15747
16024
|
}
|
|
15748
16025
|
let agentConfig = null;
|
|
15749
16026
|
if (account) {
|
|
15750
|
-
const agentDir =
|
|
15751
|
-
if (!
|
|
16027
|
+
const agentDir = resolve25(account.accountDir, "agents", agentSlug);
|
|
16028
|
+
if (!existsSync24(agentDir) || !existsSync24(resolve25(agentDir, "config.json"))) {
|
|
15752
16029
|
return c.json({ error: "Agent not found" }, 404);
|
|
15753
16030
|
}
|
|
15754
16031
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -16028,7 +16305,7 @@ function startGraphHealthTimer() {
|
|
|
16028
16305
|
|
|
16029
16306
|
// app/lib/file-watcher.ts
|
|
16030
16307
|
import * as fsp2 from "fs/promises";
|
|
16031
|
-
import { resolve as
|
|
16308
|
+
import { resolve as resolve26, sep as sep7 } from "path";
|
|
16032
16309
|
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;
|
|
16033
16310
|
var DEFAULT_COALESCE_MS = 500;
|
|
16034
16311
|
var ROOTS = ["uploads", "accounts"];
|
|
@@ -16047,7 +16324,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16047
16324
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
16048
16325
|
for (const r of ROOTS) {
|
|
16049
16326
|
try {
|
|
16050
|
-
await fsp2.mkdir(
|
|
16327
|
+
await fsp2.mkdir(resolve26(dataRoot, r), { recursive: true });
|
|
16051
16328
|
} catch (err) {
|
|
16052
16329
|
console.error(
|
|
16053
16330
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -16068,7 +16345,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16068
16345
|
timers.set(relativePath, t);
|
|
16069
16346
|
}
|
|
16070
16347
|
async function runHook(relativePath, accountId) {
|
|
16071
|
-
const absolute =
|
|
16348
|
+
const absolute = resolve26(dataRoot, relativePath);
|
|
16072
16349
|
let exists = false;
|
|
16073
16350
|
try {
|
|
16074
16351
|
const st = await fsp2.stat(absolute);
|
|
@@ -16092,7 +16369,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16092
16369
|
}
|
|
16093
16370
|
}
|
|
16094
16371
|
async function watchRoot(rootName) {
|
|
16095
|
-
const absRoot =
|
|
16372
|
+
const absRoot = resolve26(dataRoot, rootName);
|
|
16096
16373
|
try {
|
|
16097
16374
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
16098
16375
|
for await (const event of iter) {
|
|
@@ -16781,6 +17058,9 @@ function createWebchatChannelRoutes(deps) {
|
|
|
16781
17058
|
var QUEUED_THRESHOLD_MS2 = 3e4;
|
|
16782
17059
|
var ACK_THRESHOLD_MS2 = 3e4;
|
|
16783
17060
|
var SWEEP_INTERVAL_MS2 = 15e3;
|
|
17061
|
+
function keyDisplay(key) {
|
|
17062
|
+
return key.startsWith("session:") ? key.slice(0, "session:".length + 8) : key.slice(0, 8);
|
|
17063
|
+
}
|
|
16784
17064
|
var WebchatGateway = class {
|
|
16785
17065
|
constructor(deps) {
|
|
16786
17066
|
this.deps = deps;
|
|
@@ -16843,7 +17123,7 @@ var WebchatGateway = class {
|
|
|
16843
17123
|
);
|
|
16844
17124
|
if (willDeliverNow) this.lastDeliveredAt.set(input.key, Date.now());
|
|
16845
17125
|
console.error(
|
|
16846
|
-
`[webchat:inbound] op=received key=${input.key
|
|
17126
|
+
`[webchat:inbound] op=received key=${keyDisplay(input.key)} role=${input.role} bytes=${bytes} delivery=${willDeliverNow ? "immediate" : "queued"}`
|
|
16847
17127
|
);
|
|
16848
17128
|
if (!hadSubscriber && !this.spawning.has(input.key)) {
|
|
16849
17129
|
this.spawning.add(input.key);
|
|
@@ -16854,7 +17134,10 @@ var WebchatGateway = class {
|
|
|
16854
17134
|
key: input.key,
|
|
16855
17135
|
role: input.role,
|
|
16856
17136
|
gatewayUrl: this.deps.gatewayUrl,
|
|
16857
|
-
serverPath: this.deps.serverPath
|
|
17137
|
+
serverPath: this.deps.serverPath,
|
|
17138
|
+
// Task 800 — only present on a session-targeted launch, so the
|
|
17139
|
+
// default-path call shape stays byte-identical.
|
|
17140
|
+
...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {}
|
|
16858
17141
|
});
|
|
16859
17142
|
} finally {
|
|
16860
17143
|
this.spawning.delete(input.key);
|
|
@@ -16980,8 +17263,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
16980
17263
|
|
|
16981
17264
|
// ../lib/entitlement/src/index.ts
|
|
16982
17265
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
16983
|
-
import { existsSync as
|
|
16984
|
-
import { resolve as
|
|
17266
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
|
|
17267
|
+
import { resolve as resolve27 } from "path";
|
|
16985
17268
|
|
|
16986
17269
|
// ../lib/entitlement/src/canonicalize.ts
|
|
16987
17270
|
function canonicalize(value) {
|
|
@@ -17016,7 +17299,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
17016
17299
|
var GRACE_DAYS = 7;
|
|
17017
17300
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
17018
17301
|
function pubkeyPath(brand) {
|
|
17019
|
-
return
|
|
17302
|
+
return resolve27(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
17020
17303
|
}
|
|
17021
17304
|
var memo = null;
|
|
17022
17305
|
function memoKey(mtimeMs, account) {
|
|
@@ -17028,8 +17311,8 @@ function resolveEntitlement(brand, account) {
|
|
|
17028
17311
|
if (brand.commercialMode !== true) {
|
|
17029
17312
|
return logResolved(implicitTrust(account), null);
|
|
17030
17313
|
}
|
|
17031
|
-
const entitlementPath =
|
|
17032
|
-
if (!
|
|
17314
|
+
const entitlementPath = resolve27(brand.configDir, "entitlement.json");
|
|
17315
|
+
if (!existsSync25(entitlementPath)) {
|
|
17033
17316
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
17034
17317
|
}
|
|
17035
17318
|
const stat7 = statSync10(entitlementPath);
|
|
@@ -17044,7 +17327,7 @@ function resolveEntitlement(brand, account) {
|
|
|
17044
17327
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
17045
17328
|
let pubkeyPem;
|
|
17046
17329
|
try {
|
|
17047
|
-
pubkeyPem =
|
|
17330
|
+
pubkeyPem = readFileSync25(pubkeyPath(brand), "utf-8");
|
|
17048
17331
|
} catch (err) {
|
|
17049
17332
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
17050
17333
|
reason: "pubkey-missing"
|
|
@@ -17058,7 +17341,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
17058
17341
|
}
|
|
17059
17342
|
let envelope;
|
|
17060
17343
|
try {
|
|
17061
|
-
envelope = JSON.parse(
|
|
17344
|
+
envelope = JSON.parse(readFileSync25(entitlementPath, "utf-8"));
|
|
17062
17345
|
} catch {
|
|
17063
17346
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
17064
17347
|
}
|
|
@@ -17219,14 +17502,14 @@ function clientFrom(c) {
|
|
|
17219
17502
|
);
|
|
17220
17503
|
}
|
|
17221
17504
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
17222
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
17505
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join21(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
17223
17506
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
17224
|
-
if (BRAND_JSON_PATH && !
|
|
17507
|
+
if (BRAND_JSON_PATH && !existsSync26(BRAND_JSON_PATH)) {
|
|
17225
17508
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
17226
17509
|
}
|
|
17227
|
-
if (BRAND_JSON_PATH &&
|
|
17510
|
+
if (BRAND_JSON_PATH && existsSync26(BRAND_JSON_PATH)) {
|
|
17228
17511
|
try {
|
|
17229
|
-
const parsed = JSON.parse(
|
|
17512
|
+
const parsed = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
17230
17513
|
BRAND = { ...BRAND, ...parsed };
|
|
17231
17514
|
} catch (err) {
|
|
17232
17515
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -17245,11 +17528,11 @@ var brandLoginOpts = {
|
|
|
17245
17528
|
bodyFont: BRAND.defaultFonts?.body,
|
|
17246
17529
|
logoContainsName: !!BRAND.logoContainsName
|
|
17247
17530
|
};
|
|
17248
|
-
var ALIAS_DOMAINS_PATH =
|
|
17531
|
+
var ALIAS_DOMAINS_PATH = join21(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
17249
17532
|
function loadAliasDomains() {
|
|
17250
17533
|
try {
|
|
17251
|
-
if (!
|
|
17252
|
-
const parsed = JSON.parse(
|
|
17534
|
+
if (!existsSync26(ALIAS_DOMAINS_PATH)) return null;
|
|
17535
|
+
const parsed = JSON.parse(readFileSync26(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
17253
17536
|
if (!Array.isArray(parsed)) {
|
|
17254
17537
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
17255
17538
|
return null;
|
|
@@ -17277,7 +17560,7 @@ var app48 = new Hono();
|
|
|
17277
17560
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
17278
17561
|
var waGateway = new WaGateway({
|
|
17279
17562
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17280
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
17563
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
17281
17564
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
17282
17565
|
// account + path validation here and funnel through the shared send core.
|
|
17283
17566
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -17293,7 +17576,7 @@ var waGateway = new WaGateway({
|
|
|
17293
17576
|
caption,
|
|
17294
17577
|
accountId,
|
|
17295
17578
|
maxyAccountId,
|
|
17296
|
-
platformRoot:
|
|
17579
|
+
platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, ".."))
|
|
17297
17580
|
});
|
|
17298
17581
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
17299
17582
|
},
|
|
@@ -17333,14 +17616,14 @@ app48.route("/", waGateway.routes());
|
|
|
17333
17616
|
waGateway.startSweeper();
|
|
17334
17617
|
var webchatGateway = new WebchatGateway({
|
|
17335
17618
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17336
|
-
serverPath: process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ??
|
|
17337
|
-
ensureChannelSession: async ({ accountId, key, role, gatewayUrl, serverPath }) => {
|
|
17619
|
+
serverPath: process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, ".."), "services/webchat-channel/dist/server.js"),
|
|
17620
|
+
ensureChannelSession: async ({ accountId, key, role, gatewayUrl, serverPath, sessionId }) => {
|
|
17338
17621
|
if (role !== "admin") {
|
|
17339
17622
|
console.error(`[webchat:inbound] op=spawn-refused key=${key} role=${role} reason=public-path-not-wired`);
|
|
17340
17623
|
return;
|
|
17341
17624
|
}
|
|
17342
17625
|
const result = await managerRcSpawn({
|
|
17343
|
-
sessionId: adminSessionIdFor(accountId, key),
|
|
17626
|
+
sessionId: sessionId ?? adminSessionIdFor(accountId, key),
|
|
17344
17627
|
role: "admin",
|
|
17345
17628
|
channel: "webchat",
|
|
17346
17629
|
senderId: key,
|
|
@@ -17674,20 +17957,20 @@ app48.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
17674
17957
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
17675
17958
|
return c.text("Not found", 404);
|
|
17676
17959
|
}
|
|
17677
|
-
const filePath =
|
|
17678
|
-
const expectedDir =
|
|
17960
|
+
const filePath = resolve28(account.accountDir, "agents", slug, "assets", filename);
|
|
17961
|
+
const expectedDir = resolve28(account.accountDir, "agents", slug, "assets");
|
|
17679
17962
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
17680
17963
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
17681
17964
|
return c.text("Forbidden", 403);
|
|
17682
17965
|
}
|
|
17683
|
-
if (!
|
|
17966
|
+
if (!existsSync26(filePath)) {
|
|
17684
17967
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
17685
17968
|
return c.text("Not found", 404);
|
|
17686
17969
|
}
|
|
17687
17970
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
17688
17971
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
17689
17972
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
17690
|
-
const body =
|
|
17973
|
+
const body = readFileSync26(filePath);
|
|
17691
17974
|
return c.body(body, 200, {
|
|
17692
17975
|
"Content-Type": contentType,
|
|
17693
17976
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -17704,20 +17987,20 @@ app48.get("/generated/:filename", (c) => {
|
|
|
17704
17987
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
17705
17988
|
return c.text("Not found", 404);
|
|
17706
17989
|
}
|
|
17707
|
-
const filePath =
|
|
17708
|
-
const expectedDir =
|
|
17990
|
+
const filePath = resolve28(account.accountDir, "generated", filename);
|
|
17991
|
+
const expectedDir = resolve28(account.accountDir, "generated");
|
|
17709
17992
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
17710
17993
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
17711
17994
|
return c.text("Forbidden", 403);
|
|
17712
17995
|
}
|
|
17713
|
-
if (!
|
|
17996
|
+
if (!existsSync26(filePath)) {
|
|
17714
17997
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
17715
17998
|
return c.text("Not found", 404);
|
|
17716
17999
|
}
|
|
17717
18000
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
17718
18001
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
17719
18002
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
17720
|
-
const body =
|
|
18003
|
+
const body = readFileSync26(filePath);
|
|
17721
18004
|
return c.body(body, 200, {
|
|
17722
18005
|
"Content-Type": contentType,
|
|
17723
18006
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -17730,9 +18013,9 @@ app48.route("/v", visitor_consent_default);
|
|
|
17730
18013
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
17731
18014
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
17732
18015
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
17733
|
-
if (BRAND_JSON_PATH &&
|
|
18016
|
+
if (BRAND_JSON_PATH && existsSync26(BRAND_JSON_PATH)) {
|
|
17734
18017
|
try {
|
|
17735
|
-
const fullBrand = JSON.parse(
|
|
18018
|
+
const fullBrand = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
17736
18019
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
17737
18020
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
17738
18021
|
} catch {
|
|
@@ -17749,9 +18032,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
17749
18032
|
function readInstalledVersion() {
|
|
17750
18033
|
try {
|
|
17751
18034
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
17752
|
-
const versionFile =
|
|
17753
|
-
if (!
|
|
17754
|
-
const content =
|
|
18035
|
+
const versionFile = join21(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
18036
|
+
if (!existsSync26(versionFile)) return "unknown";
|
|
18037
|
+
const content = readFileSync26(versionFile, "utf-8").trim();
|
|
17755
18038
|
return content || "unknown";
|
|
17756
18039
|
} catch {
|
|
17757
18040
|
return "unknown";
|
|
@@ -17792,7 +18075,7 @@ var clientErrorReporterScript = `<script>
|
|
|
17792
18075
|
function cachedHtml(file) {
|
|
17793
18076
|
let html = htmlCache.get(file);
|
|
17794
18077
|
if (!html) {
|
|
17795
|
-
html =
|
|
18078
|
+
html = readFileSync26(resolve28(process.cwd(), "public", file), "utf-8");
|
|
17796
18079
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
17797
18080
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
17798
18081
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -17808,13 +18091,13 @@ ${clientErrorReporterScript}
|
|
|
17808
18091
|
}
|
|
17809
18092
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
17810
18093
|
function loadBrandingCache(agentSlug) {
|
|
17811
|
-
const configDir2 =
|
|
18094
|
+
const configDir2 = join21(homedir3(), BRAND.configDir);
|
|
17812
18095
|
try {
|
|
17813
18096
|
const accountId = getDefaultAccountId();
|
|
17814
18097
|
if (!accountId) return null;
|
|
17815
|
-
const cachePath =
|
|
17816
|
-
if (!
|
|
17817
|
-
return JSON.parse(
|
|
18098
|
+
const cachePath = join21(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
18099
|
+
if (!existsSync26(cachePath)) return null;
|
|
18100
|
+
return JSON.parse(readFileSync26(cachePath, "utf-8"));
|
|
17818
18101
|
} catch {
|
|
17819
18102
|
return null;
|
|
17820
18103
|
}
|
|
@@ -17902,7 +18185,7 @@ app48.use("/vnc-popout.html", logViewerFetch);
|
|
|
17902
18185
|
app48.get("/vnc-popout.html", (c) => {
|
|
17903
18186
|
let html = htmlCache.get("vnc-popout.html");
|
|
17904
18187
|
if (!html) {
|
|
17905
|
-
html =
|
|
18188
|
+
html = readFileSync26(resolve28(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
17906
18189
|
const name = escapeHtml(BRAND.productName);
|
|
17907
18190
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
17908
18191
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -18058,11 +18341,11 @@ try {
|
|
|
18058
18341
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
18059
18342
|
async function runAdminUserReconcileTick() {
|
|
18060
18343
|
try {
|
|
18061
|
-
if (!
|
|
18344
|
+
if (!existsSync26(USERS_FILE)) {
|
|
18062
18345
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
18063
18346
|
return;
|
|
18064
18347
|
}
|
|
18065
|
-
const usersRaw =
|
|
18348
|
+
const usersRaw = readFileSync26(USERS_FILE, "utf-8").trim();
|
|
18066
18349
|
if (!usersRaw) {
|
|
18067
18350
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
18068
18351
|
return;
|
|
@@ -18172,7 +18455,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
18172
18455
|
}
|
|
18173
18456
|
init({
|
|
18174
18457
|
configDir: configDirForWhatsApp,
|
|
18175
|
-
platformRoot:
|
|
18458
|
+
platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, "..")),
|
|
18176
18459
|
accountConfig: bootAccountConfig,
|
|
18177
18460
|
onMessage: async (msg) => {
|
|
18178
18461
|
if (msg.isOwnerMirror) {
|