@rubytech/create-maxy-code 0.1.293 → 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 +28 -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-DTrIyIFP.js +1 -0
- package/payload/server/public/assets/Transcript-C3aDVJ-n.js +1 -0
- package/payload/server/public/assets/admin-DVdyV-Q6.js +1 -0
- package/payload/server/public/assets/{arc-iu3VNUKX.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-un5y1Pav.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-CrT4y-Ve.js → blockDiagram-DXYQGD6D-C3uwaI7p.js} +1 -1
- package/payload/server/public/assets/browser-DrJReVEG.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-BTNlRxRe.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-DjQJDvnb.js → chunk-2KRD3SAO-BYqpHDvA.js} +1 -1
- package/payload/server/public/assets/chunk-336JU56O-BRCubMCb.js +2 -0
- package/payload/server/public/assets/chunk-426QAEUC-BNINkVsL.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-B2BREWGj.js → chunk-4BX2VUAB-BeDVr5Tb.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-CWOel6yZ.js → chunk-4TB4RGXK-DSMj_AZh.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-8_6mlBoL.js → chunk-55IACEB6-DB18cH4S.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-CcBL3hEb.js → chunk-5FUZZQ4R-6DNGaUkf.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DpqQNCTE.js → chunk-5PVQY5BW-DPhkkS4p.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-D-EZpLie.js → chunk-67CJDMHE-Ca9KwdQm.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-C9Ely26O.js → chunk-7N4EOEYR-BDpzHOmv.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-DZZsYrza.js → chunk-AA7GKIK3-DXo9fZho.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-B_1DfG3d.js → chunk-BSJP7CBP-CTqmM6qI.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-Osq5Xgsl.js → chunk-CIAEETIT-NufEId2j.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-ecraT_D1.js → chunk-EDXVE4YY-BjWSqn7_.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-D2_uycym.js → chunk-ENJZ2VHE-BX1ZnU4A.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-CpPyTbk9.js → chunk-FMBD7UC4-_4wtKsfc.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-BBUjlBL-.js → chunk-FOC6F5B3-565zaYb3.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BG-5Z4Qz.js → chunk-ICPOFSXX-DvYSWH7x.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-BQfKdYtk.js → chunk-K5T4RW27-CTZnA5fq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-D1pxYesN.js → chunk-KGLVRYIC-CeuKp7uR.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-CwDi08BU.js → chunk-LIHQZDEY-DXkzlh3_.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-Dy-V9ZFU.js → chunk-ORNJ4GCN-DcZUCmgM.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-Be3df9Kc.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-B1lsc9BA.js → chunk-U2HBQHQK-Bl1a895I.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-lSzO6qYV.js → chunk-X2U36JSP-WkSpBPYx.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-BvIgWKZQ.js → chunk-XPW4576I-CnU6DVpC.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Bb60_vDO.js → chunk-YZCP3GAM-DpWRmPUo.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Bny6wiCL.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-DsO6VRrT.js → cose-bilkent-S5V4N54A-C04wkJr7.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-Bd45zu30.js → dagre-KV5264BT-DPq3dcLH.js} +1 -1
- package/payload/server/public/assets/{dagre-DTQyvF-b.js → dagre-PrVfCcSt.js} +1 -1
- package/payload/server/public/assets/data-CYyR2m_B.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-B3GfgObm.js → diagram-5BDNPKRD-DoszElKb.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-Ccy_YcB0.js → diagram-G4DWMVQ6-BRuqosix.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-uOEKrHYy.js → diagram-MMDJMWI5-CpigG1d_.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BAWSU1wH.js → diagram-TYMM5635-BS0eYiq9.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-C5SNsoHU.js → erDiagram-SMLLAGMA-VEQyXCFl.js} +1 -1
- package/payload/server/public/assets/file-download-C3pBZjt9.js +1 -0
- package/payload/server/public/assets/{flatten-ya0TqRLc.js → flatten-DeFkSYLU.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-eGUNT0jC.js → flowDiagram-DWJPFMVM-2NYMfqHX.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-ChQD_MQS.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-CK5hWyS_.js → gitGraphDiagram-UUTBAWPF-d8NUAIz5.js} +1 -1
- package/payload/server/public/assets/{graph-nPeTW1V_.js → graph-Bx9_2qbJ.js} +3 -3
- package/payload/server/public/assets/graph-labels-Cc1nU1_f.js +1 -0
- package/payload/server/public/assets/{graphlib-DbSkkysa.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-h-wRi_o9.js → isEmpty-Bn-Se8yT.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-DR685OiM.js → ishikawaDiagram-UXIWVN3A-DPTmm2IE.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DYgyVIQE.js → journeyDiagram-VCZTEJTY-B85vjqkE.js} +1 -1
- package/payload/server/public/assets/jsx-runtime-5auA0FEj.js +9 -0
- package/payload/server/public/assets/jsx-runtime-D3PZpOAF.css +1 -0
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-BbOYz3ft.js → kanban-definition-6JOO6SKY-C2Lfb5Xh.js} +1 -1
- package/payload/server/public/assets/{line-BmJuH1ci.js → line-CODKFpwO.js} +1 -1
- package/payload/server/public/assets/{linear-HbmXARXu.js → linear-CgbkJiu6.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-B9dlRmr6.js → mermaid-parser.core-DYdFZnXH.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-CA_tMkuh.js → mermaid.core-Bamjzahu.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DNfGKB3j.js → mindmap-definition-QFDTVHPH-CLK90bKJ.js} +1 -1
- package/payload/server/public/assets/{ordinal-Dwxksj1B.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-4nplxyR3.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-BuRxivWl.js → quadrantDiagram-34T5L4WZ-uIP9V2jZ.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-CXKUHVMS.js +1 -0
- package/payload/server/public/assets/{reduce-BUuWaDl2.js → reduce-B0wq8DtH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CX0JWzZW.js → requirementDiagram-MS252O5E-CVS6t5tv.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BPbfY-tX.js → sankeyDiagram-XADWPNL6-BIsmtyZA.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-BgDVnY5n.js → sequenceDiagram-FGHM5R23-Cu8TfQiW.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-DZzcTY8N.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-LRc4oAIn.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-C_EBRd2k.js +5 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-D285XuiE.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-55WTCJwx.js → wardleyDiagram-NUSXRM2D-C7u4IHMB.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-mBKutlt4.js → xychartDiagram-5P7HB3ND-A-uLXr1a.js} +1 -1
- package/payload/server/public/browser.html +7 -5
- package/payload/server/public/chat.html +9 -6
- package/payload/server/public/data.html +6 -6
- package/payload/server/public/graph.html +9 -7
- package/payload/server/public/index.html +9 -7
- package/payload/server/public/public.html +6 -4
- package/payload/server/server.js +595 -276
- package/payload/server/public/assets/AdminShell-7xqVmEF0.js +0 -1
- package/payload/server/public/assets/Checkbox-xIFPRr-Y.js +0 -1
- package/payload/server/public/assets/Transcript-siyY9S7_.js +0 -1
- package/payload/server/public/assets/admin-DVyRE7og.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-HsK_v-AH.js +0 -1
- package/payload/server/public/assets/browser-CWFHESdi.js +0 -1
- package/payload/server/public/assets/channel-B3X2ELTx.js +0 -1
- package/payload/server/public/assets/chat-CoZ5hSiK.js +0 -1
- package/payload/server/public/assets/chunk-336JU56O-CWAQPaQW.js +0 -2
- package/payload/server/public/assets/chunk-426QAEUC-CYsbwfwG.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CitInsDb.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-B8ZHYEIL.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D7TgEwXH.js +0 -1
- package/payload/server/public/assets/clone-C-K4Yq8V.js +0 -1
- package/payload/server/public/assets/data-Dex0L_hs.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CP3pxYZ8.js +0 -1
- package/payload/server/public/assets/graph-labels-J48HJ3as.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DUz8FRjp.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-CoLeR6OP.js +0 -2
- package/payload/server/public/assets/packet-4T2RLAQJ-C-0PIYwM.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-DUWx5LLr.js +0 -1
- package/payload/server/public/assets/public-C7o23SFC.js +0 -35
- package/payload/server/public/assets/radar-PYXPWWZC-BPW6Hewb.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Bk-yVe98.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CfxoEICI.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-BFC84eoy.js +0 -1
- package/payload/server/public/assets/useSelectionMode-CFisDuuw.js +0 -13
- package/payload/server/public/assets/useSelectionMode-s7AH5v9J.css +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-C-mQV2If.js +0 -1
- /package/payload/server/public/assets/{_baseFor-Dn4GSmI6.js → _baseFor-BV-TyLWt.js} +0 -0
- /package/payload/server/public/assets/{array-DJN9YAVf.js → array-lqrvkwy7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-BcJTl1re.js → cytoscape.esm-SmEOayFS.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-B4F_XsBB.js → defaultLocale-Dl3Sud5K.js} +0 -0
- /package/payload/server/public/assets/{dist-B7zzC2xF.js → dist-Pgmncqde.js} +0 -0
- /package/payload/server/public/assets/{AdminShell-qc_xy7Az.css → file-download-qc_xy7Az.css} +0 -0
- /package/payload/server/public/assets/{init-DX0Y1qU4.js → init-BukMwkmL.js} +0 -0
- /package/payload/server/public/assets/{katex-CjHJ1D7d.js → katex-jl-BtNZi.js} +0 -0
- /package/payload/server/public/assets/{path-7vUsG-o2.js → path-DPTRcLku.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-NLRoWnq-.js → rough.esm-VLpapkIG.js} +0 -0
- /package/payload/server/public/assets/{src-CpjuOYjb.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,15 +7715,97 @@ 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
|
+
}
|
|
7736
|
+
var NO_INDICATORS = {
|
|
7737
|
+
activity: null,
|
|
7738
|
+
permissionMode: null,
|
|
7739
|
+
effectivePermissionMode: null,
|
|
7740
|
+
model: null
|
|
7741
|
+
};
|
|
7742
|
+
var indicatorsErrorLogged = false;
|
|
7743
|
+
var INDICATORS_TIMEOUT_MS = 1500;
|
|
7744
|
+
async function fetchComposerIndicators(sessionId) {
|
|
7745
|
+
let port2;
|
|
7746
|
+
try {
|
|
7747
|
+
port2 = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "webchat:session" });
|
|
7748
|
+
} catch {
|
|
7749
|
+
return NO_INDICATORS;
|
|
7750
|
+
}
|
|
7751
|
+
try {
|
|
7752
|
+
const res = await fetch(`http://127.0.0.1:${port2}/${sessionId}/meta`, {
|
|
7753
|
+
signal: AbortSignal.timeout(INDICATORS_TIMEOUT_MS)
|
|
7754
|
+
});
|
|
7755
|
+
if (!res.ok) return NO_INDICATORS;
|
|
7756
|
+
const body = await res.json();
|
|
7757
|
+
return {
|
|
7758
|
+
activity: typeof body.activity === "string" ? body.activity : null,
|
|
7759
|
+
permissionMode: typeof body.permissionMode === "string" ? body.permissionMode : null,
|
|
7760
|
+
effectivePermissionMode: typeof body.effectivePermissionMode === "string" ? body.effectivePermissionMode : null,
|
|
7761
|
+
model: typeof body.model === "string" ? body.model : null
|
|
7762
|
+
};
|
|
7763
|
+
} catch (err) {
|
|
7764
|
+
if (!indicatorsErrorLogged) {
|
|
7765
|
+
indicatorsErrorLogged = true;
|
|
7766
|
+
console.error(`[webchat:session] indicators-unavailable detail=${err instanceof Error ? err.message : String(err)} (logged once per process)`);
|
|
7767
|
+
}
|
|
7768
|
+
return NO_INDICATORS;
|
|
7769
|
+
}
|
|
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
|
+
}
|
|
7709
7806
|
function createWebchatRoutes(deps) {
|
|
7710
7807
|
const app49 = new Hono();
|
|
7711
7808
|
app49.post("/send", requireAdminSession, async (c) => {
|
|
7712
|
-
const body = await c.req.json().catch(() => null);
|
|
7713
|
-
const text = body?.text;
|
|
7714
|
-
if (typeof text !== "string" || text.length === 0) {
|
|
7715
|
-
return c.json({ error: "text required" }, 400);
|
|
7716
|
-
}
|
|
7717
7809
|
let accountId;
|
|
7718
7810
|
try {
|
|
7719
7811
|
accountId = resolvePlatformAccountId();
|
|
@@ -7722,10 +7814,161 @@ function createWebchatRoutes(deps) {
|
|
|
7722
7814
|
console.error(`[webchat:inbound] op=send-refused reason=account-unresolved detail=${detail}`);
|
|
7723
7815
|
return c.json({ error: "account unresolved" }, 503);
|
|
7724
7816
|
}
|
|
7725
|
-
|
|
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
|
+
}
|
|
7726
7930
|
return c.json({ ok: true });
|
|
7727
7931
|
});
|
|
7728
|
-
app49.
|
|
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
|
+
});
|
|
7971
|
+
app49.get("/session", requireAdminSession, async (c) => {
|
|
7729
7972
|
let accountId;
|
|
7730
7973
|
try {
|
|
7731
7974
|
accountId = resolvePlatformAccountId();
|
|
@@ -7734,6 +7977,15 @@ function createWebchatRoutes(deps) {
|
|
|
7734
7977
|
console.error(`[webchat:inbound] op=session-refused reason=account-unresolved detail=${detail}`);
|
|
7735
7978
|
return c.json({ error: "account unresolved" }, 503);
|
|
7736
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
|
+
}
|
|
7737
7989
|
const sessionId = adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
7738
7990
|
const cfg = claudeConfigDir();
|
|
7739
7991
|
let projectDir = null;
|
|
@@ -7745,11 +7997,57 @@ function createWebchatRoutes(deps) {
|
|
|
7745
7997
|
}
|
|
7746
7998
|
}
|
|
7747
7999
|
}
|
|
7748
|
-
|
|
8000
|
+
const indicators = await fetchComposerIndicators(sessionId);
|
|
8001
|
+
return c.json({ sessionId, projectDir, ...indicators, ...readLevers() });
|
|
7749
8002
|
});
|
|
7750
8003
|
return app49;
|
|
7751
8004
|
}
|
|
7752
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
|
+
|
|
7753
8051
|
// server/routes/webchat-greeting.ts
|
|
7754
8052
|
var OUTSTANDING_TASK_STATUSES = ["pending", "active", "running"];
|
|
7755
8053
|
var UPCOMING_EVENT_STATUSES = ["scheduled", "due"];
|
|
@@ -7808,10 +8106,25 @@ app6.get("/", requireAdminSession, async (c) => {
|
|
|
7808
8106
|
return { events: events2, tasks: tasks2 };
|
|
7809
8107
|
}
|
|
7810
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
|
+
}
|
|
7811
8124
|
console.log(
|
|
7812
|
-
`[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}`
|
|
7813
8126
|
);
|
|
7814
|
-
return c.json({ ok: true, events, tasks });
|
|
8127
|
+
return c.json({ ok: true, events, tasks, specialists });
|
|
7815
8128
|
} catch (err) {
|
|
7816
8129
|
const detail = err instanceof Error ? err.message : String(err);
|
|
7817
8130
|
console.error(`[webchat:greeting] op=read-failed reason=${detail}`);
|
|
@@ -7831,8 +8144,8 @@ var webchat_greeting_default = app6;
|
|
|
7831
8144
|
|
|
7832
8145
|
// server/routes/telegram.ts
|
|
7833
8146
|
import { homedir } from "os";
|
|
7834
|
-
import { resolve as
|
|
7835
|
-
import { existsSync as
|
|
8147
|
+
import { resolve as resolve11, join as join12 } from "path";
|
|
8148
|
+
import { existsSync as existsSync9, readFileSync as readFileSync13 } from "fs";
|
|
7836
8149
|
|
|
7837
8150
|
// app/lib/telegram/access-control.ts
|
|
7838
8151
|
function checkTelegramAccess(params) {
|
|
@@ -7882,11 +8195,11 @@ function routeTelegramUpdate(input) {
|
|
|
7882
8195
|
var TAG22 = "[telegram-inbound]";
|
|
7883
8196
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
7884
8197
|
function configDirName() {
|
|
7885
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
7886
|
-
const brandPath =
|
|
7887
|
-
if (
|
|
8198
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve11(process.cwd(), "..");
|
|
8199
|
+
const brandPath = join12(platformRoot2, "config", "brand.json");
|
|
8200
|
+
if (existsSync9(brandPath)) {
|
|
7888
8201
|
try {
|
|
7889
|
-
return JSON.parse(
|
|
8202
|
+
return JSON.parse(readFileSync13(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
7890
8203
|
} catch {
|
|
7891
8204
|
}
|
|
7892
8205
|
}
|
|
@@ -7894,7 +8207,7 @@ function configDirName() {
|
|
|
7894
8207
|
}
|
|
7895
8208
|
function secretPath(botType) {
|
|
7896
8209
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
7897
|
-
return
|
|
8210
|
+
return resolve11(homedir(), configDirName(), filename);
|
|
7898
8211
|
}
|
|
7899
8212
|
async function sendTelegram(botToken, chatId, text) {
|
|
7900
8213
|
try {
|
|
@@ -7918,11 +8231,11 @@ app7.post("/", async (c) => {
|
|
|
7918
8231
|
return c.json({ ok: false }, 400);
|
|
7919
8232
|
}
|
|
7920
8233
|
const sp = secretPath(botType);
|
|
7921
|
-
if (!
|
|
8234
|
+
if (!existsSync9(sp)) {
|
|
7922
8235
|
console.error(`${TAG22} op=reject reason=no-secret-file botType=${botType}`);
|
|
7923
8236
|
return c.json({ ok: false }, 401);
|
|
7924
8237
|
}
|
|
7925
|
-
const expected =
|
|
8238
|
+
const expected = readFileSync13(sp, "utf-8").trim();
|
|
7926
8239
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
7927
8240
|
if (got !== expected) {
|
|
7928
8241
|
console.error(`${TAG22} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -7985,12 +8298,12 @@ var telegram_default = app7;
|
|
|
7985
8298
|
|
|
7986
8299
|
// server/routes/onboarding.ts
|
|
7987
8300
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
7988
|
-
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";
|
|
7989
8302
|
import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
7990
8303
|
|
|
7991
8304
|
// ../lib/admins-write/src/index.ts
|
|
7992
|
-
import { existsSync as
|
|
7993
|
-
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";
|
|
7994
8307
|
function logLine(input, result) {
|
|
7995
8308
|
const userIdShort = input.userId.slice(0, 8);
|
|
7996
8309
|
console.error(
|
|
@@ -8000,15 +8313,15 @@ function logLine(input, result) {
|
|
|
8000
8313
|
function writeFileAtomic(filePath, contents, mode) {
|
|
8001
8314
|
mkdirSync2(dirname3(filePath), { recursive: true });
|
|
8002
8315
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
8003
|
-
|
|
8004
|
-
|
|
8316
|
+
writeFileSync6(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
8317
|
+
renameSync2(tempPath, filePath);
|
|
8005
8318
|
}
|
|
8006
8319
|
function writeAdminEntry(input) {
|
|
8007
8320
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
8008
8321
|
try {
|
|
8009
8322
|
let users = [];
|
|
8010
|
-
if (
|
|
8011
|
-
const raw =
|
|
8323
|
+
if (existsSync10(input.usersFile)) {
|
|
8324
|
+
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8012
8325
|
if (raw) {
|
|
8013
8326
|
const parsed = JSON.parse(raw);
|
|
8014
8327
|
if (!Array.isArray(parsed)) {
|
|
@@ -8032,11 +8345,11 @@ function writeAdminEntry(input) {
|
|
|
8032
8345
|
return result;
|
|
8033
8346
|
}
|
|
8034
8347
|
try {
|
|
8035
|
-
const accountJsonPath =
|
|
8036
|
-
if (!
|
|
8348
|
+
const accountJsonPath = join13(input.accountDir, "account.json");
|
|
8349
|
+
if (!existsSync10(accountJsonPath)) {
|
|
8037
8350
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
8038
8351
|
}
|
|
8039
|
-
const config = JSON.parse(
|
|
8352
|
+
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
8040
8353
|
const admins = config.admins ?? [];
|
|
8041
8354
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
8042
8355
|
result.accountJsonResult = "noop";
|
|
@@ -8060,9 +8373,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
8060
8373
|
usersWithoutAccount: []
|
|
8061
8374
|
};
|
|
8062
8375
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
8063
|
-
if (
|
|
8376
|
+
if (existsSync10(input.usersFile)) {
|
|
8064
8377
|
try {
|
|
8065
|
-
const raw =
|
|
8378
|
+
const raw = readFileSync14(input.usersFile, "utf-8").trim();
|
|
8066
8379
|
if (raw) {
|
|
8067
8380
|
const users = JSON.parse(raw);
|
|
8068
8381
|
for (const u of users) {
|
|
@@ -8075,10 +8388,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
8075
8388
|
}
|
|
8076
8389
|
}
|
|
8077
8390
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
8078
|
-
if (
|
|
8391
|
+
if (existsSync10(input.accountsDir)) {
|
|
8079
8392
|
let entries;
|
|
8080
8393
|
try {
|
|
8081
|
-
entries =
|
|
8394
|
+
entries = readdirSync8(input.accountsDir);
|
|
8082
8395
|
} catch (err) {
|
|
8083
8396
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8084
8397
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -8087,17 +8400,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
8087
8400
|
}
|
|
8088
8401
|
for (const entry of entries) {
|
|
8089
8402
|
if (entry.startsWith(".")) continue;
|
|
8090
|
-
const accountDir =
|
|
8403
|
+
const accountDir = join13(input.accountsDir, entry);
|
|
8091
8404
|
try {
|
|
8092
8405
|
if (!statSync5(accountDir).isDirectory()) continue;
|
|
8093
8406
|
} catch {
|
|
8094
8407
|
continue;
|
|
8095
8408
|
}
|
|
8096
|
-
const accountJsonPath =
|
|
8097
|
-
if (!
|
|
8409
|
+
const accountJsonPath = join13(accountDir, "account.json");
|
|
8410
|
+
if (!existsSync10(accountJsonPath)) continue;
|
|
8098
8411
|
let admins = [];
|
|
8099
8412
|
try {
|
|
8100
|
-
const config = JSON.parse(
|
|
8413
|
+
const config = JSON.parse(readFileSync14(accountJsonPath, "utf-8"));
|
|
8101
8414
|
admins = config.admins ?? [];
|
|
8102
8415
|
} catch (err) {
|
|
8103
8416
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -8137,8 +8450,8 @@ function hashPin2(pin) {
|
|
|
8137
8450
|
return createHash3("sha256").update(pin).digest("hex");
|
|
8138
8451
|
}
|
|
8139
8452
|
function readUsersFile2() {
|
|
8140
|
-
if (!
|
|
8141
|
-
const raw =
|
|
8453
|
+
if (!existsSync11(USERS_FILE)) return null;
|
|
8454
|
+
const raw = readFileSync15(USERS_FILE, "utf-8").trim();
|
|
8142
8455
|
if (!raw) return [];
|
|
8143
8456
|
return JSON.parse(raw);
|
|
8144
8457
|
}
|
|
@@ -8191,7 +8504,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
8191
8504
|
} catch (err) {
|
|
8192
8505
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
8193
8506
|
}
|
|
8194
|
-
const credentialsPresent =
|
|
8507
|
+
const credentialsPresent = existsSync11(CLAUDE_CREDENTIALS_FILE);
|
|
8195
8508
|
const ranMs = Date.now() - start;
|
|
8196
8509
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
8197
8510
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -8209,7 +8522,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
8209
8522
|
return c.json({ launched: cdpReady });
|
|
8210
8523
|
}
|
|
8211
8524
|
ensureLogDir();
|
|
8212
|
-
|
|
8525
|
+
writeFileSync7(logPath("claude-auth"), "");
|
|
8213
8526
|
const claudeAuthLogFd = openSync2(logPath("claude-auth"), "a");
|
|
8214
8527
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
8215
8528
|
if (process.platform === "darwin") {
|
|
@@ -8298,9 +8611,9 @@ app8.post("/set-pin", async (c) => {
|
|
|
8298
8611
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
8299
8612
|
if (process.platform === "linux") {
|
|
8300
8613
|
let installOwner = null;
|
|
8301
|
-
if (
|
|
8614
|
+
if (existsSync11(INSTALL_OWNER_FILE)) {
|
|
8302
8615
|
try {
|
|
8303
|
-
const raw =
|
|
8616
|
+
const raw = readFileSync15(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
8304
8617
|
if (raw.length > 0) installOwner = raw;
|
|
8305
8618
|
} catch (err) {
|
|
8306
8619
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -8373,7 +8686,7 @@ app8.delete("/set-pin", async (c) => {
|
|
|
8373
8686
|
unlinkSync(USERS_FILE);
|
|
8374
8687
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${matchedUser.userId.slice(0, 8)}\u2026`);
|
|
8375
8688
|
} else {
|
|
8376
|
-
|
|
8689
|
+
writeFileSync7(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
8377
8690
|
console.log(`[set-pin] removed entry from users.json: userId=${matchedUser.userId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
8378
8691
|
}
|
|
8379
8692
|
return c.json({ ok: true });
|
|
@@ -8381,9 +8694,9 @@ app8.delete("/set-pin", async (c) => {
|
|
|
8381
8694
|
var onboarding_default = app8;
|
|
8382
8695
|
|
|
8383
8696
|
// server/routes/client-error.ts
|
|
8384
|
-
import { appendFileSync, existsSync as
|
|
8385
|
-
import { join as
|
|
8386
|
-
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");
|
|
8387
8700
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
8388
8701
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
8389
8702
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -8426,10 +8739,10 @@ function stackHead(stack) {
|
|
|
8426
8739
|
}
|
|
8427
8740
|
function rotateIfNeeded() {
|
|
8428
8741
|
try {
|
|
8429
|
-
if (!
|
|
8742
|
+
if (!existsSync12(CLIENT_ERRORS_LOG)) return;
|
|
8430
8743
|
const stats = statSync6(CLIENT_ERRORS_LOG);
|
|
8431
8744
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
8432
|
-
|
|
8745
|
+
renameSync3(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
8433
8746
|
} catch (err) {
|
|
8434
8747
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8435
8748
|
}
|
|
@@ -8708,18 +9021,18 @@ app10.post("/", async (c) => {
|
|
|
8708
9021
|
var session_default = app10;
|
|
8709
9022
|
|
|
8710
9023
|
// server/routes/admin/logs.ts
|
|
8711
|
-
import { existsSync as
|
|
8712
|
-
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";
|
|
8713
9026
|
|
|
8714
9027
|
// app/lib/logs-read-resolve.ts
|
|
8715
|
-
import { existsSync as
|
|
8716
|
-
import { join as
|
|
9028
|
+
import { existsSync as existsSync13 } from "fs";
|
|
9029
|
+
import { join as join15 } from "path";
|
|
8717
9030
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
8718
9031
|
const tried = [filename];
|
|
8719
9032
|
const hits = [];
|
|
8720
9033
|
for (const dir of logDirs) {
|
|
8721
|
-
const fullPath =
|
|
8722
|
-
if (
|
|
9034
|
+
const fullPath = join15(dir, filename);
|
|
9035
|
+
if (existsSync13(fullPath)) {
|
|
8723
9036
|
hits.push({ path: fullPath, dir });
|
|
8724
9037
|
}
|
|
8725
9038
|
}
|
|
@@ -8736,7 +9049,7 @@ app11.get("/", async (c) => {
|
|
|
8736
9049
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
8737
9050
|
const download = c.req.query("download") === "1";
|
|
8738
9051
|
const account = resolveAccount();
|
|
8739
|
-
const accountLogDir = account ?
|
|
9052
|
+
const accountLogDir = account ? resolve12(account.accountDir, "logs") : null;
|
|
8740
9053
|
const logDirs = [];
|
|
8741
9054
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
8742
9055
|
logDirs.push(LOG_DIR);
|
|
@@ -8744,10 +9057,10 @@ app11.get("/", async (c) => {
|
|
|
8744
9057
|
const safe = basename4(fileParam);
|
|
8745
9058
|
const searched = [];
|
|
8746
9059
|
for (const dir of logDirs) {
|
|
8747
|
-
const filePath =
|
|
9060
|
+
const filePath = resolve12(dir, safe);
|
|
8748
9061
|
searched.push(filePath);
|
|
8749
9062
|
try {
|
|
8750
|
-
const buffer =
|
|
9063
|
+
const buffer = readFileSync16(filePath);
|
|
8751
9064
|
const onDiskBytes = statSync7(filePath).size;
|
|
8752
9065
|
const headers = {
|
|
8753
9066
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -8812,7 +9125,7 @@ app11.get("/", async (c) => {
|
|
|
8812
9125
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
8813
9126
|
try {
|
|
8814
9127
|
const filename = basename4(hit.path);
|
|
8815
|
-
const buffer =
|
|
9128
|
+
const buffer = readFileSync16(hit.path);
|
|
8816
9129
|
const onDiskBytes = statSync7(hit.path).size;
|
|
8817
9130
|
const headers = {
|
|
8818
9131
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -8847,19 +9160,19 @@ app11.get("/", async (c) => {
|
|
|
8847
9160
|
const seen = /* @__PURE__ */ new Set();
|
|
8848
9161
|
const logs = {};
|
|
8849
9162
|
for (const dir of logDirs) {
|
|
8850
|
-
if (!
|
|
9163
|
+
if (!existsSync14(dir)) continue;
|
|
8851
9164
|
let files;
|
|
8852
9165
|
try {
|
|
8853
|
-
files =
|
|
9166
|
+
files = readdirSync9(dir).filter((f) => f.endsWith(".log"));
|
|
8854
9167
|
} catch (err) {
|
|
8855
9168
|
const reason = err instanceof Error ? err.message : String(err);
|
|
8856
9169
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
8857
9170
|
continue;
|
|
8858
9171
|
}
|
|
8859
|
-
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 }) => {
|
|
8860
9173
|
seen.add(name);
|
|
8861
9174
|
try {
|
|
8862
|
-
const content =
|
|
9175
|
+
const content = readFileSync16(resolve12(dir, name));
|
|
8863
9176
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
8864
9177
|
logs[name] = tail.trim() || "(empty)";
|
|
8865
9178
|
} catch (err) {
|
|
@@ -8898,8 +9211,8 @@ var claude_info_default = app12;
|
|
|
8898
9211
|
|
|
8899
9212
|
// server/routes/admin/attachment.ts
|
|
8900
9213
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
8901
|
-
import { existsSync as
|
|
8902
|
-
import { resolve as
|
|
9214
|
+
import { existsSync as existsSync15 } from "fs";
|
|
9215
|
+
import { resolve as resolve13 } from "path";
|
|
8903
9216
|
var app13 = new Hono();
|
|
8904
9217
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
8905
9218
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -8911,12 +9224,12 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8911
9224
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
8912
9225
|
return new Response("Not found", { status: 404 });
|
|
8913
9226
|
}
|
|
8914
|
-
const dir =
|
|
8915
|
-
if (!
|
|
9227
|
+
const dir = resolve13(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
9228
|
+
if (!existsSync15(dir)) {
|
|
8916
9229
|
return new Response("Not found", { status: 404 });
|
|
8917
9230
|
}
|
|
8918
|
-
const metaPath =
|
|
8919
|
-
if (!
|
|
9231
|
+
const metaPath = resolve13(dir, `${attachmentId}.meta.json`);
|
|
9232
|
+
if (!existsSync15(metaPath)) {
|
|
8920
9233
|
return new Response("Not found", { status: 404 });
|
|
8921
9234
|
}
|
|
8922
9235
|
let meta;
|
|
@@ -8930,7 +9243,7 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8930
9243
|
if (!dataFile) {
|
|
8931
9244
|
return new Response("Not found", { status: 404 });
|
|
8932
9245
|
}
|
|
8933
|
-
const filePath =
|
|
9246
|
+
const filePath = resolve13(dir, dataFile);
|
|
8934
9247
|
const buffer = await readFile2(filePath);
|
|
8935
9248
|
return new Response(new Uint8Array(buffer), {
|
|
8936
9249
|
headers: {
|
|
@@ -8943,24 +9256,24 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8943
9256
|
var attachment_default = app13;
|
|
8944
9257
|
|
|
8945
9258
|
// server/routes/admin/agents.ts
|
|
8946
|
-
import { resolve as
|
|
8947
|
-
import { readdirSync as
|
|
9259
|
+
import { resolve as resolve14 } from "path";
|
|
9260
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync17, existsSync as existsSync16, rmSync } from "fs";
|
|
8948
9261
|
var app14 = new Hono();
|
|
8949
9262
|
app14.get("/", (c) => {
|
|
8950
9263
|
const account = resolveAccount();
|
|
8951
9264
|
if (!account) return c.json({ agents: [] });
|
|
8952
|
-
const agentsDir =
|
|
8953
|
-
if (!
|
|
9265
|
+
const agentsDir = resolve14(account.accountDir, "agents");
|
|
9266
|
+
if (!existsSync16(agentsDir)) return c.json({ agents: [] });
|
|
8954
9267
|
const agents = [];
|
|
8955
9268
|
try {
|
|
8956
|
-
const entries =
|
|
9269
|
+
const entries = readdirSync10(agentsDir, { withFileTypes: true });
|
|
8957
9270
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
8958
9271
|
if (!entry.isDirectory()) continue;
|
|
8959
9272
|
if (entry.name === "admin") continue;
|
|
8960
|
-
const configPath2 =
|
|
8961
|
-
if (!
|
|
9273
|
+
const configPath2 = resolve14(agentsDir, entry.name, "config.json");
|
|
9274
|
+
if (!existsSync16(configPath2)) continue;
|
|
8962
9275
|
try {
|
|
8963
|
-
const config = JSON.parse(
|
|
9276
|
+
const config = JSON.parse(readFileSync17(configPath2, "utf-8"));
|
|
8964
9277
|
agents.push({
|
|
8965
9278
|
slug: entry.name,
|
|
8966
9279
|
displayName: config.displayName ?? entry.name,
|
|
@@ -8986,8 +9299,8 @@ app14.delete("/:slug", async (c) => {
|
|
|
8986
9299
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
8987
9300
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8988
9301
|
}
|
|
8989
|
-
const agentDir =
|
|
8990
|
-
if (!
|
|
9302
|
+
const agentDir = resolve14(account.accountDir, "agents", slug);
|
|
9303
|
+
if (!existsSync16(agentDir)) {
|
|
8991
9304
|
return c.json({ error: "Agent not found" }, 404);
|
|
8992
9305
|
}
|
|
8993
9306
|
try {
|
|
@@ -9016,8 +9329,8 @@ app14.post("/:slug/project", async (c) => {
|
|
|
9016
9329
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9017
9330
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9018
9331
|
}
|
|
9019
|
-
const agentDir =
|
|
9020
|
-
if (!
|
|
9332
|
+
const agentDir = resolve14(account.accountDir, "agents", slug);
|
|
9333
|
+
if (!existsSync16(agentDir)) {
|
|
9021
9334
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9022
9335
|
}
|
|
9023
9336
|
try {
|
|
@@ -9033,7 +9346,7 @@ var agents_default = app14;
|
|
|
9033
9346
|
// server/routes/admin/sessions.ts
|
|
9034
9347
|
import crypto2 from "crypto";
|
|
9035
9348
|
import { resolve as resolvePath } from "path";
|
|
9036
|
-
import { existsSync as
|
|
9349
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync3, createWriteStream } from "fs";
|
|
9037
9350
|
|
|
9038
9351
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
9039
9352
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -9193,7 +9506,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
9193
9506
|
let reason = null;
|
|
9194
9507
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
9195
9508
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
9196
|
-
else if (!
|
|
9509
|
+
else if (!existsSync17(a.storagePath)) reason = "missing-file";
|
|
9197
9510
|
if (reason) {
|
|
9198
9511
|
invalid++;
|
|
9199
9512
|
try {
|
|
@@ -9719,8 +10032,8 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
9719
10032
|
var sessions_default = app15;
|
|
9720
10033
|
|
|
9721
10034
|
// app/lib/claude-agent/spawn-context.ts
|
|
9722
|
-
import { existsSync as
|
|
9723
|
-
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";
|
|
9724
10037
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
9725
10038
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
9726
10039
|
try {
|
|
@@ -9734,10 +10047,10 @@ async function resolveOwnerProfileBlock(accountId, userId) {
|
|
|
9734
10047
|
return { ok: false, reason: "neo4j-unreachable" };
|
|
9735
10048
|
}
|
|
9736
10049
|
}
|
|
9737
|
-
function frontmatterField(manifest,
|
|
10050
|
+
function frontmatterField(manifest, field2) {
|
|
9738
10051
|
const fm = manifest.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
9739
10052
|
if (!fm) return null;
|
|
9740
|
-
const re = new RegExp(`^${
|
|
10053
|
+
const re = new RegExp(`^${field2}:\\s*(.*?)\\r?$`, "m");
|
|
9741
10054
|
const m = fm[1].match(re);
|
|
9742
10055
|
if (!m) return null;
|
|
9743
10056
|
let value = m[1].trim();
|
|
@@ -9749,14 +10062,14 @@ function frontmatterField(manifest, field) {
|
|
|
9749
10062
|
function extractPluginToolDescriptions(pluginDir) {
|
|
9750
10063
|
const out = /* @__PURE__ */ new Map();
|
|
9751
10064
|
const candidates = [
|
|
9752
|
-
|
|
9753
|
-
|
|
10065
|
+
join16(pluginDir, "mcp/dist/index.js"),
|
|
10066
|
+
join16(pluginDir, "mcp/src/index.ts")
|
|
9754
10067
|
];
|
|
9755
10068
|
let raw = null;
|
|
9756
10069
|
for (const path2 of candidates) {
|
|
9757
|
-
if (!
|
|
10070
|
+
if (!existsSync18(path2)) continue;
|
|
9758
10071
|
try {
|
|
9759
|
-
raw =
|
|
10072
|
+
raw = readFileSync18(path2, "utf-8");
|
|
9760
10073
|
break;
|
|
9761
10074
|
} catch {
|
|
9762
10075
|
}
|
|
@@ -9805,24 +10118,24 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
9805
10118
|
}
|
|
9806
10119
|
function listPluginDirs() {
|
|
9807
10120
|
const out = /* @__PURE__ */ new Map();
|
|
9808
|
-
const platformPlugins =
|
|
9809
|
-
if (
|
|
9810
|
-
for (const name of
|
|
9811
|
-
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);
|
|
9812
10125
|
try {
|
|
9813
10126
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
9814
10127
|
} catch {
|
|
9815
10128
|
}
|
|
9816
10129
|
}
|
|
9817
10130
|
}
|
|
9818
|
-
const premiumRoot =
|
|
9819
|
-
if (
|
|
9820
|
-
for (const bundle of
|
|
9821
|
-
const bundlePlugins =
|
|
9822
|
-
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;
|
|
9823
10136
|
try {
|
|
9824
|
-
for (const name of
|
|
9825
|
-
const dir =
|
|
10137
|
+
for (const name of readdirSync11(bundlePlugins)) {
|
|
10138
|
+
const dir = join16(bundlePlugins, name);
|
|
9826
10139
|
try {
|
|
9827
10140
|
if (statSync8(dir).isDirectory()) out.set(name, dir);
|
|
9828
10141
|
} catch {
|
|
@@ -9835,10 +10148,10 @@ function listPluginDirs() {
|
|
|
9835
10148
|
return out;
|
|
9836
10149
|
}
|
|
9837
10150
|
function readEnabledPlugins(accountId) {
|
|
9838
|
-
const accountFile =
|
|
9839
|
-
if (!
|
|
10151
|
+
const accountFile = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10152
|
+
if (!existsSync18(accountFile)) return /* @__PURE__ */ new Set();
|
|
9840
10153
|
try {
|
|
9841
|
-
const parsed = JSON.parse(
|
|
10154
|
+
const parsed = JSON.parse(readFileSync18(accountFile, "utf-8"));
|
|
9842
10155
|
return new Set(
|
|
9843
10156
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
9844
10157
|
);
|
|
@@ -9847,10 +10160,10 @@ function readEnabledPlugins(accountId) {
|
|
|
9847
10160
|
}
|
|
9848
10161
|
}
|
|
9849
10162
|
function readFrontmatter(path2) {
|
|
9850
|
-
if (!
|
|
10163
|
+
if (!existsSync18(path2)) return null;
|
|
9851
10164
|
let raw;
|
|
9852
10165
|
try {
|
|
9853
|
-
raw =
|
|
10166
|
+
raw = readFileSync18(path2, "utf-8");
|
|
9854
10167
|
} catch {
|
|
9855
10168
|
return null;
|
|
9856
10169
|
}
|
|
@@ -9865,7 +10178,7 @@ function computeActivePlugins(accountId) {
|
|
|
9865
10178
|
for (const name of Array.from(enabled).sort()) {
|
|
9866
10179
|
const dir = pluginDirs.get(name);
|
|
9867
10180
|
if (!dir) continue;
|
|
9868
|
-
const fm = readFrontmatter(
|
|
10181
|
+
const fm = readFrontmatter(join16(dir, "PLUGIN.md"));
|
|
9869
10182
|
if (!fm) continue;
|
|
9870
10183
|
const description = frontmatterField(`---
|
|
9871
10184
|
${fm}
|
|
@@ -9882,7 +10195,7 @@ ${fm}
|
|
|
9882
10195
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
9883
10196
|
);
|
|
9884
10197
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
9885
|
-
const hasSource =
|
|
10198
|
+
const hasSource = existsSync18(join16(dir, "mcp/dist/index.js")) || existsSync18(join16(dir, "mcp/src/index.ts"));
|
|
9886
10199
|
if (hasSource) {
|
|
9887
10200
|
console.warn(
|
|
9888
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`
|
|
@@ -9892,7 +10205,7 @@ ${fm}
|
|
|
9892
10205
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
9893
10206
|
const skills = [];
|
|
9894
10207
|
for (const relPath of skillPaths) {
|
|
9895
|
-
const skillPath =
|
|
10208
|
+
const skillPath = join16(dir, relPath);
|
|
9896
10209
|
const skillFm = readFrontmatter(skillPath);
|
|
9897
10210
|
if (!skillFm) continue;
|
|
9898
10211
|
const skillName = frontmatterField(`---
|
|
@@ -9908,11 +10221,11 @@ ${skillFm}
|
|
|
9908
10221
|
return out;
|
|
9909
10222
|
}
|
|
9910
10223
|
function computeSpecialistDomains(accountId) {
|
|
9911
|
-
const specialistsDir =
|
|
9912
|
-
if (!
|
|
10224
|
+
const specialistsDir = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10225
|
+
if (!existsSync18(specialistsDir)) return [];
|
|
9913
10226
|
let entries;
|
|
9914
10227
|
try {
|
|
9915
|
-
entries =
|
|
10228
|
+
entries = readdirSync11(specialistsDir);
|
|
9916
10229
|
} catch {
|
|
9917
10230
|
return [];
|
|
9918
10231
|
}
|
|
@@ -9936,7 +10249,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
9936
10249
|
const out = [];
|
|
9937
10250
|
for (const file of entries.sort()) {
|
|
9938
10251
|
if (!file.endsWith(".md")) continue;
|
|
9939
|
-
const fm = readFrontmatter(
|
|
10252
|
+
const fm = readFrontmatter(join16(specialistsDir, file));
|
|
9940
10253
|
if (!fm) continue;
|
|
9941
10254
|
const wrapped = `---
|
|
9942
10255
|
${fm}
|
|
@@ -9954,11 +10267,11 @@ ${fm}
|
|
|
9954
10267
|
return out;
|
|
9955
10268
|
}
|
|
9956
10269
|
function computeDormantPlugins(accountId) {
|
|
9957
|
-
const accountFile =
|
|
9958
|
-
if (!
|
|
10270
|
+
const accountFile = resolve15(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10271
|
+
if (!existsSync18(accountFile)) return [];
|
|
9959
10272
|
let enabled;
|
|
9960
10273
|
try {
|
|
9961
|
-
const raw =
|
|
10274
|
+
const raw = readFileSync18(accountFile, "utf-8");
|
|
9962
10275
|
const parsed = JSON.parse(raw);
|
|
9963
10276
|
enabled = new Set(
|
|
9964
10277
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -9969,22 +10282,22 @@ function computeDormantPlugins(accountId) {
|
|
|
9969
10282
|
);
|
|
9970
10283
|
return [];
|
|
9971
10284
|
}
|
|
9972
|
-
const pluginsDir =
|
|
9973
|
-
if (!
|
|
10285
|
+
const pluginsDir = resolve15(PLATFORM_ROOT, "plugins");
|
|
10286
|
+
if (!existsSync18(pluginsDir)) return [];
|
|
9974
10287
|
let entries;
|
|
9975
10288
|
try {
|
|
9976
|
-
entries =
|
|
10289
|
+
entries = readdirSync11(pluginsDir);
|
|
9977
10290
|
} catch {
|
|
9978
10291
|
return [];
|
|
9979
10292
|
}
|
|
9980
10293
|
const out = [];
|
|
9981
10294
|
for (const name of entries) {
|
|
9982
10295
|
if (enabled.has(name)) continue;
|
|
9983
|
-
const manifestPath =
|
|
9984
|
-
if (!
|
|
10296
|
+
const manifestPath = resolve15(pluginsDir, name, "PLUGIN.md");
|
|
10297
|
+
if (!existsSync18(manifestPath)) continue;
|
|
9985
10298
|
let manifest;
|
|
9986
10299
|
try {
|
|
9987
|
-
manifest =
|
|
10300
|
+
manifest = readFileSync18(manifestPath, "utf-8");
|
|
9988
10301
|
} catch {
|
|
9989
10302
|
continue;
|
|
9990
10303
|
}
|
|
@@ -9998,13 +10311,13 @@ function computeDormantPlugins(accountId) {
|
|
|
9998
10311
|
}
|
|
9999
10312
|
|
|
10000
10313
|
// server/routes/admin/claude-sessions.ts
|
|
10001
|
-
import { existsSync as
|
|
10002
|
-
import { resolve as
|
|
10314
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "fs";
|
|
10315
|
+
import { resolve as resolve16 } from "path";
|
|
10003
10316
|
function readTunnelState(brandConfigDir) {
|
|
10004
10317
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10005
|
-
if (!
|
|
10318
|
+
if (!existsSync19(statePath)) return null;
|
|
10006
10319
|
try {
|
|
10007
|
-
const parsed = JSON.parse(
|
|
10320
|
+
const parsed = JSON.parse(readFileSync19(statePath, "utf-8"));
|
|
10008
10321
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
10009
10322
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
10010
10323
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -10015,10 +10328,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10015
10328
|
}
|
|
10016
10329
|
}
|
|
10017
10330
|
function resolveTunnelUrl() {
|
|
10018
|
-
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(), "..");
|
|
10019
10332
|
let brand;
|
|
10020
10333
|
try {
|
|
10021
|
-
brand = JSON.parse(
|
|
10334
|
+
brand = JSON.parse(readFileSync19(resolve16(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10022
10335
|
} catch {
|
|
10023
10336
|
return null;
|
|
10024
10337
|
}
|
|
@@ -10263,15 +10576,15 @@ var events_default = app18;
|
|
|
10263
10576
|
import { createReadStream as createReadStream2 } from "fs";
|
|
10264
10577
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
10265
10578
|
import { realpathSync as realpathSync4 } from "fs";
|
|
10266
|
-
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";
|
|
10267
10580
|
import { Readable as Readable2 } from "stream";
|
|
10268
10581
|
|
|
10269
10582
|
// app/lib/data-path.ts
|
|
10270
10583
|
import { realpathSync as realpathSync3 } from "fs";
|
|
10271
|
-
import { resolve as
|
|
10272
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
10273
|
-
var DATA_ROOT =
|
|
10274
|
-
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;
|
|
10275
10588
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
10276
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;
|
|
10277
10590
|
function crossesForeignAccountPartition(relPath, accountId) {
|
|
@@ -10284,7 +10597,7 @@ function crossesForeignAccountPartition(relPath, accountId) {
|
|
|
10284
10597
|
}
|
|
10285
10598
|
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
10286
10599
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
10287
|
-
const absolute =
|
|
10600
|
+
const absolute = resolve17(rootAbs, cleaned);
|
|
10288
10601
|
let rootReal;
|
|
10289
10602
|
try {
|
|
10290
10603
|
rootReal = realpathSync3(rootAbs);
|
|
@@ -10643,7 +10956,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10643
10956
|
|
|
10644
10957
|
// app/lib/file-index.ts
|
|
10645
10958
|
import * as fsp from "fs/promises";
|
|
10646
|
-
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";
|
|
10647
10960
|
import { tmpdir as tmpdir2 } from "os";
|
|
10648
10961
|
import { execFile as execFile2 } from "child_process";
|
|
10649
10962
|
import { promisify as promisify2 } from "util";
|
|
@@ -10714,7 +11027,7 @@ async function extractPdf(absolute) {
|
|
|
10714
11027
|
return stdout.trim();
|
|
10715
11028
|
}
|
|
10716
11029
|
async function ocrPdf(absolute) {
|
|
10717
|
-
const outPdf =
|
|
11030
|
+
const outPdf = join17(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
10718
11031
|
try {
|
|
10719
11032
|
await execFileAsync2(
|
|
10720
11033
|
"ocrmypdf",
|
|
@@ -10776,7 +11089,7 @@ async function readDisplayName(absolute) {
|
|
|
10776
11089
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10777
11090
|
if (base === `${stem}.meta.json`) return null;
|
|
10778
11091
|
try {
|
|
10779
|
-
const raw = await fsp.readFile(
|
|
11092
|
+
const raw = await fsp.readFile(join17(dir, `${stem}.meta.json`), "utf-8");
|
|
10780
11093
|
const meta = JSON.parse(raw);
|
|
10781
11094
|
const dn = meta.displayName ?? meta.filename;
|
|
10782
11095
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -10796,7 +11109,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
10796
11109
|
let clean = true;
|
|
10797
11110
|
for (const entry of entries) {
|
|
10798
11111
|
if (entry.isSymbolicLink()) continue;
|
|
10799
|
-
const abs =
|
|
11112
|
+
const abs = join17(root, entry.name);
|
|
10800
11113
|
if (entry.isDirectory()) {
|
|
10801
11114
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
10802
11115
|
if (!sub.clean) clean = false;
|
|
@@ -10951,8 +11264,8 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
10951
11264
|
return withSession(opts, async (session) => {
|
|
10952
11265
|
const walked = [];
|
|
10953
11266
|
const subtreeRoots = [
|
|
10954
|
-
|
|
10955
|
-
|
|
11267
|
+
resolve18(dataRoot, "uploads", accountId),
|
|
11268
|
+
resolve18(dataRoot, "accounts", accountId)
|
|
10956
11269
|
];
|
|
10957
11270
|
let clean = true;
|
|
10958
11271
|
for (const root of subtreeRoots) {
|
|
@@ -11033,7 +11346,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
11033
11346
|
async function indexFile(accountId, relativePath, opts) {
|
|
11034
11347
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
11035
11348
|
const embed2 = opts?.embed ?? embed;
|
|
11036
|
-
const absolute =
|
|
11349
|
+
const absolute = resolve18(dataRoot, relativePath);
|
|
11037
11350
|
await withSession(opts, async (session) => {
|
|
11038
11351
|
const st = await fsp.stat(absolute);
|
|
11039
11352
|
const wf = {
|
|
@@ -11067,7 +11380,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
11067
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;
|
|
11068
11381
|
async function readMeta(absDir, baseName) {
|
|
11069
11382
|
try {
|
|
11070
|
-
const raw = await readFile4(
|
|
11383
|
+
const raw = await readFile4(join18(absDir, `${baseName}.meta.json`), "utf8");
|
|
11071
11384
|
const parsed = JSON.parse(raw);
|
|
11072
11385
|
if (typeof parsed?.filename === "string") {
|
|
11073
11386
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11078,7 +11391,7 @@ async function readMeta(absDir, baseName) {
|
|
|
11078
11391
|
}
|
|
11079
11392
|
async function readAccountNames() {
|
|
11080
11393
|
const map = /* @__PURE__ */ new Map();
|
|
11081
|
-
const accountsDir =
|
|
11394
|
+
const accountsDir = resolve19(DATA_ROOT, "accounts");
|
|
11082
11395
|
let names;
|
|
11083
11396
|
try {
|
|
11084
11397
|
names = await readdir3(accountsDir);
|
|
@@ -11087,7 +11400,7 @@ async function readAccountNames() {
|
|
|
11087
11400
|
}
|
|
11088
11401
|
for (const name of names) {
|
|
11089
11402
|
if (!UUID_RE3.test(name)) continue;
|
|
11090
|
-
const configPath2 =
|
|
11403
|
+
const configPath2 = resolve19(accountsDir, name, "account.json");
|
|
11091
11404
|
try {
|
|
11092
11405
|
const raw = await readFile4(configPath2, "utf8");
|
|
11093
11406
|
const parsed = JSON.parse(raw);
|
|
@@ -11105,7 +11418,7 @@ async function readAccountNames() {
|
|
|
11105
11418
|
}
|
|
11106
11419
|
async function enrich(absolute, entry, accountNames) {
|
|
11107
11420
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
11108
|
-
const meta = await readMeta(
|
|
11421
|
+
const meta = await readMeta(join18(absolute, entry.name), entry.name);
|
|
11109
11422
|
if (meta?.filename) {
|
|
11110
11423
|
entry.displayName = meta.filename;
|
|
11111
11424
|
entry.mimeType = meta.mimeType;
|
|
@@ -11203,7 +11516,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
11203
11516
|
continue;
|
|
11204
11517
|
}
|
|
11205
11518
|
try {
|
|
11206
|
-
const entryPath =
|
|
11519
|
+
const entryPath = join18(absolute, name);
|
|
11207
11520
|
const s = await stat4(entryPath);
|
|
11208
11521
|
entries.push({
|
|
11209
11522
|
name,
|
|
@@ -11328,8 +11641,8 @@ app19.post("/upload", requireAdminSession, async (c) => {
|
|
|
11328
11641
|
}
|
|
11329
11642
|
const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
|
|
11330
11643
|
const finalName = `${Date.now()}-${safeName}`;
|
|
11331
|
-
const destDir =
|
|
11332
|
-
const destPath =
|
|
11644
|
+
const destDir = resolve19(DATA_ROOT, "uploads", accountId);
|
|
11645
|
+
const destPath = resolve19(destDir, finalName);
|
|
11333
11646
|
try {
|
|
11334
11647
|
await mkdir3(destDir, { recursive: true });
|
|
11335
11648
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
@@ -11394,7 +11707,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
11394
11707
|
}
|
|
11395
11708
|
const dot = base.lastIndexOf(".");
|
|
11396
11709
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11397
|
-
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;
|
|
11398
11711
|
await unlink2(absolute);
|
|
11399
11712
|
if (sidecarPath) {
|
|
11400
11713
|
try {
|
|
@@ -13443,8 +13756,8 @@ var graph_default_view_default = app25;
|
|
|
13443
13756
|
|
|
13444
13757
|
// server/routes/admin/sidebar-artefacts.ts
|
|
13445
13758
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
13446
|
-
import { resolve as
|
|
13447
|
-
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";
|
|
13448
13761
|
var LIMIT = 50;
|
|
13449
13762
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
13450
13763
|
function toDataRootRelPath(absPath) {
|
|
@@ -13463,7 +13776,7 @@ app26.get("/", requireAdminSession, async (c) => {
|
|
|
13463
13776
|
if (accountFiles === null) {
|
|
13464
13777
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
13465
13778
|
}
|
|
13466
|
-
const accountDir =
|
|
13779
|
+
const accountDir = resolve20(ACCOUNTS_DIR, accountId);
|
|
13467
13780
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
13468
13781
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
13469
13782
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -13514,8 +13827,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
13514
13827
|
async function fetchAgentTemplateRows(accountDir) {
|
|
13515
13828
|
const rows = [];
|
|
13516
13829
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
13517
|
-
const overridePath =
|
|
13518
|
-
const bundledPath =
|
|
13830
|
+
const overridePath = resolve20(accountDir, "agents", "admin", filename);
|
|
13831
|
+
const bundledPath = resolve20(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
13519
13832
|
const labelStem = filename.replace(/\.md$/, "");
|
|
13520
13833
|
const row = await readAgentTemplateRow({
|
|
13521
13834
|
id: `agent-template:admin:${filename}`,
|
|
@@ -13528,12 +13841,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13528
13841
|
});
|
|
13529
13842
|
if (row) rows.push(row);
|
|
13530
13843
|
}
|
|
13531
|
-
const overrideDir =
|
|
13532
|
-
const bundledDir =
|
|
13844
|
+
const overrideDir = resolve20(accountDir, "specialists", "agents");
|
|
13845
|
+
const bundledDir = resolve20(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
13533
13846
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
13534
13847
|
for (const filename of specialistNames) {
|
|
13535
|
-
const overridePath =
|
|
13536
|
-
const bundledPath =
|
|
13848
|
+
const overridePath = resolve20(overrideDir, filename);
|
|
13849
|
+
const bundledPath = resolve20(bundledDir, filename);
|
|
13537
13850
|
const row = await readAgentTemplateRow({
|
|
13538
13851
|
id: `agent-template:specialist:${filename}`,
|
|
13539
13852
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -13550,7 +13863,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13550
13863
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
13551
13864
|
const names = /* @__PURE__ */ new Set();
|
|
13552
13865
|
for (const dir of [overrideDir, bundledDir]) {
|
|
13553
|
-
if (!
|
|
13866
|
+
if (!existsSync20(dir)) continue;
|
|
13554
13867
|
try {
|
|
13555
13868
|
const entries = await readdir4(dir);
|
|
13556
13869
|
for (const entry of entries) {
|
|
@@ -13565,7 +13878,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
13565
13878
|
}
|
|
13566
13879
|
async function readAgentTemplateRow(inp) {
|
|
13567
13880
|
let chosenPath = null;
|
|
13568
|
-
if (
|
|
13881
|
+
if (existsSync20(inp.overridePath)) {
|
|
13569
13882
|
try {
|
|
13570
13883
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
13571
13884
|
chosenPath = inp.overridePath;
|
|
@@ -13576,7 +13889,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
13576
13889
|
);
|
|
13577
13890
|
return null;
|
|
13578
13891
|
}
|
|
13579
|
-
} else if (
|
|
13892
|
+
} else if (existsSync20(inp.bundledPath)) {
|
|
13580
13893
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
13581
13894
|
console.error(
|
|
13582
13895
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -13900,24 +14213,24 @@ app31.get("/", async (c) => {
|
|
|
13900
14213
|
var system_stats_default = app31;
|
|
13901
14214
|
|
|
13902
14215
|
// server/routes/admin/health.ts
|
|
13903
|
-
import { existsSync as
|
|
13904
|
-
import { resolve as
|
|
13905
|
-
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(), "..");
|
|
13906
14219
|
var brandHostname = "maxy";
|
|
13907
|
-
var brandJsonPath =
|
|
13908
|
-
if (
|
|
14220
|
+
var brandJsonPath = join19(PLATFORM_ROOT6, "config", "brand.json");
|
|
14221
|
+
if (existsSync21(brandJsonPath)) {
|
|
13909
14222
|
try {
|
|
13910
|
-
const brand = JSON.parse(
|
|
14223
|
+
const brand = JSON.parse(readFileSync20(brandJsonPath, "utf-8"));
|
|
13911
14224
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
13912
14225
|
} catch {
|
|
13913
14226
|
}
|
|
13914
14227
|
}
|
|
13915
|
-
var VERSION_FILE =
|
|
14228
|
+
var VERSION_FILE = resolve21(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
13916
14229
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
13917
14230
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
13918
14231
|
function readVersion() {
|
|
13919
|
-
if (!
|
|
13920
|
-
return
|
|
14232
|
+
if (!existsSync21(VERSION_FILE)) return "unknown";
|
|
14233
|
+
return readFileSync20(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
13921
14234
|
}
|
|
13922
14235
|
async function probeConversationDb() {
|
|
13923
14236
|
let session;
|
|
@@ -14459,16 +14772,16 @@ var admin_default = app39;
|
|
|
14459
14772
|
|
|
14460
14773
|
// app/lib/access-gate.ts
|
|
14461
14774
|
import neo4j4 from "neo4j-driver";
|
|
14462
|
-
import { readFileSync as
|
|
14463
|
-
import { resolve as
|
|
14775
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
14776
|
+
import { resolve as resolve22 } from "path";
|
|
14464
14777
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
14465
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14778
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
|
|
14466
14779
|
var driver = null;
|
|
14467
14780
|
function readPassword() {
|
|
14468
14781
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
14469
|
-
const passwordFile =
|
|
14782
|
+
const passwordFile = resolve22(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
14470
14783
|
try {
|
|
14471
|
-
return
|
|
14784
|
+
return readFileSync21(passwordFile, "utf-8").trim();
|
|
14472
14785
|
} catch {
|
|
14473
14786
|
throw new Error(
|
|
14474
14787
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -14756,9 +15069,9 @@ var verify_token_default = app40;
|
|
|
14756
15069
|
|
|
14757
15070
|
// app/lib/access-email.ts
|
|
14758
15071
|
import { spawn as spawn2 } from "child_process";
|
|
14759
|
-
import { resolve as
|
|
14760
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
14761
|
-
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(
|
|
14762
15075
|
PLATFORM_ROOT8,
|
|
14763
15076
|
"plugins",
|
|
14764
15077
|
"email",
|
|
@@ -14900,8 +15213,8 @@ app42.route("/request-magic-link", request_magic_link_default);
|
|
|
14900
15213
|
var access_default = app42;
|
|
14901
15214
|
|
|
14902
15215
|
// server/routes/sites.ts
|
|
14903
|
-
import { existsSync as
|
|
14904
|
-
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";
|
|
14905
15218
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14906
15219
|
var MIME = {
|
|
14907
15220
|
".html": "text/html; charset=utf-8",
|
|
@@ -14958,15 +15271,15 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
14958
15271
|
}
|
|
14959
15272
|
segments.push(seg);
|
|
14960
15273
|
}
|
|
14961
|
-
const rootDir =
|
|
14962
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
15274
|
+
const rootDir = resolve24(account.accountDir, "sites");
|
|
15275
|
+
let filePath = segments.length === 0 ? rootDir : resolve24(rootDir, ...segments);
|
|
14963
15276
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
14964
15277
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
14965
15278
|
return c.text("Forbidden", 403);
|
|
14966
15279
|
}
|
|
14967
15280
|
let stat7;
|
|
14968
15281
|
try {
|
|
14969
|
-
stat7 =
|
|
15282
|
+
stat7 = existsSync22(filePath) ? statSync9(filePath) : null;
|
|
14970
15283
|
} catch {
|
|
14971
15284
|
stat7 = null;
|
|
14972
15285
|
}
|
|
@@ -14979,13 +15292,13 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
14979
15292
|
return c.redirect(target, 301);
|
|
14980
15293
|
}
|
|
14981
15294
|
if (stat7?.isDirectory()) {
|
|
14982
|
-
filePath =
|
|
15295
|
+
filePath = resolve24(filePath, "index.html");
|
|
14983
15296
|
}
|
|
14984
15297
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
14985
15298
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
14986
15299
|
return c.text("Forbidden", 403);
|
|
14987
15300
|
}
|
|
14988
|
-
if (!
|
|
15301
|
+
if (!existsSync22(filePath)) {
|
|
14989
15302
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
14990
15303
|
return c.text("Not found", 404);
|
|
14991
15304
|
}
|
|
@@ -15004,7 +15317,7 @@ app43.get("/:rel{.*}", (c) => {
|
|
|
15004
15317
|
}
|
|
15005
15318
|
let body;
|
|
15006
15319
|
try {
|
|
15007
|
-
body =
|
|
15320
|
+
body = readFileSync22(realPath);
|
|
15008
15321
|
} catch (err) {
|
|
15009
15322
|
const code = err?.code;
|
|
15010
15323
|
if (code === "EISDIR") {
|
|
@@ -15040,7 +15353,7 @@ var sites_default = app43;
|
|
|
15040
15353
|
|
|
15041
15354
|
// app/lib/visitor-token.ts
|
|
15042
15355
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
15043
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
15356
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync23, writeFileSync as writeFileSync8 } from "fs";
|
|
15044
15357
|
import { dirname as dirname6 } from "path";
|
|
15045
15358
|
var TOKEN_PREFIX = "v1.";
|
|
15046
15359
|
var SECRET_BYTES = 32;
|
|
@@ -15049,7 +15362,7 @@ var cachedSecret = null;
|
|
|
15049
15362
|
function getSecret() {
|
|
15050
15363
|
if (cachedSecret) return cachedSecret;
|
|
15051
15364
|
try {
|
|
15052
|
-
const hex2 =
|
|
15365
|
+
const hex2 = readFileSync23(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
15053
15366
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
15054
15367
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
15055
15368
|
return cachedSecret;
|
|
@@ -15059,11 +15372,11 @@ function getSecret() {
|
|
|
15059
15372
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
15060
15373
|
try {
|
|
15061
15374
|
mkdirSync4(dirname6(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
15062
|
-
|
|
15375
|
+
writeFileSync8(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
15063
15376
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
15064
15377
|
} catch {
|
|
15065
15378
|
}
|
|
15066
|
-
const hex =
|
|
15379
|
+
const hex = readFileSync23(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
15067
15380
|
cachedSecret = Buffer.from(hex, "hex");
|
|
15068
15381
|
return cachedSecret;
|
|
15069
15382
|
}
|
|
@@ -15116,8 +15429,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
15116
15429
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
15117
15430
|
|
|
15118
15431
|
// app/lib/brand-config.ts
|
|
15119
|
-
import { existsSync as
|
|
15120
|
-
import { join as
|
|
15432
|
+
import { existsSync as existsSync23, readFileSync as readFileSync24 } from "fs";
|
|
15433
|
+
import { join as join20 } from "path";
|
|
15121
15434
|
var cached2 = null;
|
|
15122
15435
|
var cachedAttempted = false;
|
|
15123
15436
|
function readBrandConfig() {
|
|
@@ -15125,10 +15438,10 @@ function readBrandConfig() {
|
|
|
15125
15438
|
cachedAttempted = true;
|
|
15126
15439
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
15127
15440
|
if (!platformRoot2) return null;
|
|
15128
|
-
const brandPath =
|
|
15129
|
-
if (!
|
|
15441
|
+
const brandPath = join20(platformRoot2, "config", "brand.json");
|
|
15442
|
+
if (!existsSync23(brandPath)) return null;
|
|
15130
15443
|
try {
|
|
15131
|
-
cached2 = JSON.parse(
|
|
15444
|
+
cached2 = JSON.parse(readFileSync24(brandPath, "utf-8"));
|
|
15132
15445
|
return cached2;
|
|
15133
15446
|
} catch {
|
|
15134
15447
|
return null;
|
|
@@ -15616,14 +15929,14 @@ async function writeEvent(opts) {
|
|
|
15616
15929
|
var visitor_event_default = app46;
|
|
15617
15930
|
|
|
15618
15931
|
// server/routes/session.ts
|
|
15619
|
-
import { resolve as
|
|
15620
|
-
import { existsSync as
|
|
15932
|
+
import { resolve as resolve25 } from "path";
|
|
15933
|
+
import { existsSync as existsSync24, writeFileSync as writeFileSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
15621
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;
|
|
15622
15935
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
15623
15936
|
try {
|
|
15624
|
-
const cacheDir =
|
|
15937
|
+
const cacheDir = resolve25(MAXY_DIR, "branding-cache", accountId);
|
|
15625
15938
|
mkdirSync5(cacheDir, { recursive: true });
|
|
15626
|
-
|
|
15939
|
+
writeFileSync9(resolve25(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
15627
15940
|
} catch (err) {
|
|
15628
15941
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
15629
15942
|
}
|
|
@@ -15711,8 +16024,8 @@ app47.post("/", async (c) => {
|
|
|
15711
16024
|
}
|
|
15712
16025
|
let agentConfig = null;
|
|
15713
16026
|
if (account) {
|
|
15714
|
-
const agentDir =
|
|
15715
|
-
if (!
|
|
16027
|
+
const agentDir = resolve25(account.accountDir, "agents", agentSlug);
|
|
16028
|
+
if (!existsSync24(agentDir) || !existsSync24(resolve25(agentDir, "config.json"))) {
|
|
15716
16029
|
return c.json({ error: "Agent not found" }, 404);
|
|
15717
16030
|
}
|
|
15718
16031
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -15992,7 +16305,7 @@ function startGraphHealthTimer() {
|
|
|
15992
16305
|
|
|
15993
16306
|
// app/lib/file-watcher.ts
|
|
15994
16307
|
import * as fsp2 from "fs/promises";
|
|
15995
|
-
import { resolve as
|
|
16308
|
+
import { resolve as resolve26, sep as sep7 } from "path";
|
|
15996
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;
|
|
15997
16310
|
var DEFAULT_COALESCE_MS = 500;
|
|
15998
16311
|
var ROOTS = ["uploads", "accounts"];
|
|
@@ -16011,7 +16324,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16011
16324
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
16012
16325
|
for (const r of ROOTS) {
|
|
16013
16326
|
try {
|
|
16014
|
-
await fsp2.mkdir(
|
|
16327
|
+
await fsp2.mkdir(resolve26(dataRoot, r), { recursive: true });
|
|
16015
16328
|
} catch (err) {
|
|
16016
16329
|
console.error(
|
|
16017
16330
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -16032,7 +16345,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16032
16345
|
timers.set(relativePath, t);
|
|
16033
16346
|
}
|
|
16034
16347
|
async function runHook(relativePath, accountId) {
|
|
16035
|
-
const absolute =
|
|
16348
|
+
const absolute = resolve26(dataRoot, relativePath);
|
|
16036
16349
|
let exists = false;
|
|
16037
16350
|
try {
|
|
16038
16351
|
const st = await fsp2.stat(absolute);
|
|
@@ -16056,7 +16369,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16056
16369
|
}
|
|
16057
16370
|
}
|
|
16058
16371
|
async function watchRoot(rootName) {
|
|
16059
|
-
const absRoot =
|
|
16372
|
+
const absRoot = resolve26(dataRoot, rootName);
|
|
16060
16373
|
try {
|
|
16061
16374
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
16062
16375
|
for await (const event of iter) {
|
|
@@ -16745,6 +17058,9 @@ function createWebchatChannelRoutes(deps) {
|
|
|
16745
17058
|
var QUEUED_THRESHOLD_MS2 = 3e4;
|
|
16746
17059
|
var ACK_THRESHOLD_MS2 = 3e4;
|
|
16747
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
|
+
}
|
|
16748
17064
|
var WebchatGateway = class {
|
|
16749
17065
|
constructor(deps) {
|
|
16750
17066
|
this.deps = deps;
|
|
@@ -16807,7 +17123,7 @@ var WebchatGateway = class {
|
|
|
16807
17123
|
);
|
|
16808
17124
|
if (willDeliverNow) this.lastDeliveredAt.set(input.key, Date.now());
|
|
16809
17125
|
console.error(
|
|
16810
|
-
`[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"}`
|
|
16811
17127
|
);
|
|
16812
17128
|
if (!hadSubscriber && !this.spawning.has(input.key)) {
|
|
16813
17129
|
this.spawning.add(input.key);
|
|
@@ -16818,7 +17134,10 @@ var WebchatGateway = class {
|
|
|
16818
17134
|
key: input.key,
|
|
16819
17135
|
role: input.role,
|
|
16820
17136
|
gatewayUrl: this.deps.gatewayUrl,
|
|
16821
|
-
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 } : {}
|
|
16822
17141
|
});
|
|
16823
17142
|
} finally {
|
|
16824
17143
|
this.spawning.delete(input.key);
|
|
@@ -16944,8 +17263,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
16944
17263
|
|
|
16945
17264
|
// ../lib/entitlement/src/index.ts
|
|
16946
17265
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
16947
|
-
import { existsSync as
|
|
16948
|
-
import { resolve as
|
|
17266
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
|
|
17267
|
+
import { resolve as resolve27 } from "path";
|
|
16949
17268
|
|
|
16950
17269
|
// ../lib/entitlement/src/canonicalize.ts
|
|
16951
17270
|
function canonicalize(value) {
|
|
@@ -16980,7 +17299,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
16980
17299
|
var GRACE_DAYS = 7;
|
|
16981
17300
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
16982
17301
|
function pubkeyPath(brand) {
|
|
16983
|
-
return
|
|
17302
|
+
return resolve27(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
16984
17303
|
}
|
|
16985
17304
|
var memo = null;
|
|
16986
17305
|
function memoKey(mtimeMs, account) {
|
|
@@ -16992,8 +17311,8 @@ function resolveEntitlement(brand, account) {
|
|
|
16992
17311
|
if (brand.commercialMode !== true) {
|
|
16993
17312
|
return logResolved(implicitTrust(account), null);
|
|
16994
17313
|
}
|
|
16995
|
-
const entitlementPath =
|
|
16996
|
-
if (!
|
|
17314
|
+
const entitlementPath = resolve27(brand.configDir, "entitlement.json");
|
|
17315
|
+
if (!existsSync25(entitlementPath)) {
|
|
16997
17316
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
16998
17317
|
}
|
|
16999
17318
|
const stat7 = statSync10(entitlementPath);
|
|
@@ -17008,7 +17327,7 @@ function resolveEntitlement(brand, account) {
|
|
|
17008
17327
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
17009
17328
|
let pubkeyPem;
|
|
17010
17329
|
try {
|
|
17011
|
-
pubkeyPem =
|
|
17330
|
+
pubkeyPem = readFileSync25(pubkeyPath(brand), "utf-8");
|
|
17012
17331
|
} catch (err) {
|
|
17013
17332
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
17014
17333
|
reason: "pubkey-missing"
|
|
@@ -17022,7 +17341,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
17022
17341
|
}
|
|
17023
17342
|
let envelope;
|
|
17024
17343
|
try {
|
|
17025
|
-
envelope = JSON.parse(
|
|
17344
|
+
envelope = JSON.parse(readFileSync25(entitlementPath, "utf-8"));
|
|
17026
17345
|
} catch {
|
|
17027
17346
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
17028
17347
|
}
|
|
@@ -17183,14 +17502,14 @@ function clientFrom(c) {
|
|
|
17183
17502
|
);
|
|
17184
17503
|
}
|
|
17185
17504
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
17186
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
17505
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join21(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
17187
17506
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
17188
|
-
if (BRAND_JSON_PATH && !
|
|
17507
|
+
if (BRAND_JSON_PATH && !existsSync26(BRAND_JSON_PATH)) {
|
|
17189
17508
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
17190
17509
|
}
|
|
17191
|
-
if (BRAND_JSON_PATH &&
|
|
17510
|
+
if (BRAND_JSON_PATH && existsSync26(BRAND_JSON_PATH)) {
|
|
17192
17511
|
try {
|
|
17193
|
-
const parsed = JSON.parse(
|
|
17512
|
+
const parsed = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
17194
17513
|
BRAND = { ...BRAND, ...parsed };
|
|
17195
17514
|
} catch (err) {
|
|
17196
17515
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -17209,11 +17528,11 @@ var brandLoginOpts = {
|
|
|
17209
17528
|
bodyFont: BRAND.defaultFonts?.body,
|
|
17210
17529
|
logoContainsName: !!BRAND.logoContainsName
|
|
17211
17530
|
};
|
|
17212
|
-
var ALIAS_DOMAINS_PATH =
|
|
17531
|
+
var ALIAS_DOMAINS_PATH = join21(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
17213
17532
|
function loadAliasDomains() {
|
|
17214
17533
|
try {
|
|
17215
|
-
if (!
|
|
17216
|
-
const parsed = JSON.parse(
|
|
17534
|
+
if (!existsSync26(ALIAS_DOMAINS_PATH)) return null;
|
|
17535
|
+
const parsed = JSON.parse(readFileSync26(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
17217
17536
|
if (!Array.isArray(parsed)) {
|
|
17218
17537
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
17219
17538
|
return null;
|
|
@@ -17241,7 +17560,7 @@ var app48 = new Hono();
|
|
|
17241
17560
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
17242
17561
|
var waGateway = new WaGateway({
|
|
17243
17562
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17244
|
-
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"),
|
|
17245
17564
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
17246
17565
|
// account + path validation here and funnel through the shared send core.
|
|
17247
17566
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -17257,7 +17576,7 @@ var waGateway = new WaGateway({
|
|
|
17257
17576
|
caption,
|
|
17258
17577
|
accountId,
|
|
17259
17578
|
maxyAccountId,
|
|
17260
|
-
platformRoot:
|
|
17579
|
+
platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, ".."))
|
|
17261
17580
|
});
|
|
17262
17581
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
17263
17582
|
},
|
|
@@ -17297,14 +17616,14 @@ app48.route("/", waGateway.routes());
|
|
|
17297
17616
|
waGateway.startSweeper();
|
|
17298
17617
|
var webchatGateway = new WebchatGateway({
|
|
17299
17618
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
17300
|
-
serverPath: process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ??
|
|
17301
|
-
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 }) => {
|
|
17302
17621
|
if (role !== "admin") {
|
|
17303
17622
|
console.error(`[webchat:inbound] op=spawn-refused key=${key} role=${role} reason=public-path-not-wired`);
|
|
17304
17623
|
return;
|
|
17305
17624
|
}
|
|
17306
17625
|
const result = await managerRcSpawn({
|
|
17307
|
-
sessionId: adminSessionIdFor(accountId, key),
|
|
17626
|
+
sessionId: sessionId ?? adminSessionIdFor(accountId, key),
|
|
17308
17627
|
role: "admin",
|
|
17309
17628
|
channel: "webchat",
|
|
17310
17629
|
senderId: key,
|
|
@@ -17638,20 +17957,20 @@ app48.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
17638
17957
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
17639
17958
|
return c.text("Not found", 404);
|
|
17640
17959
|
}
|
|
17641
|
-
const filePath =
|
|
17642
|
-
const expectedDir =
|
|
17960
|
+
const filePath = resolve28(account.accountDir, "agents", slug, "assets", filename);
|
|
17961
|
+
const expectedDir = resolve28(account.accountDir, "agents", slug, "assets");
|
|
17643
17962
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
17644
17963
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
17645
17964
|
return c.text("Forbidden", 403);
|
|
17646
17965
|
}
|
|
17647
|
-
if (!
|
|
17966
|
+
if (!existsSync26(filePath)) {
|
|
17648
17967
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
17649
17968
|
return c.text("Not found", 404);
|
|
17650
17969
|
}
|
|
17651
17970
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
17652
17971
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
17653
17972
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
17654
|
-
const body =
|
|
17973
|
+
const body = readFileSync26(filePath);
|
|
17655
17974
|
return c.body(body, 200, {
|
|
17656
17975
|
"Content-Type": contentType,
|
|
17657
17976
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -17668,20 +17987,20 @@ app48.get("/generated/:filename", (c) => {
|
|
|
17668
17987
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
17669
17988
|
return c.text("Not found", 404);
|
|
17670
17989
|
}
|
|
17671
|
-
const filePath =
|
|
17672
|
-
const expectedDir =
|
|
17990
|
+
const filePath = resolve28(account.accountDir, "generated", filename);
|
|
17991
|
+
const expectedDir = resolve28(account.accountDir, "generated");
|
|
17673
17992
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
17674
17993
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
17675
17994
|
return c.text("Forbidden", 403);
|
|
17676
17995
|
}
|
|
17677
|
-
if (!
|
|
17996
|
+
if (!existsSync26(filePath)) {
|
|
17678
17997
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
17679
17998
|
return c.text("Not found", 404);
|
|
17680
17999
|
}
|
|
17681
18000
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
17682
18001
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
17683
18002
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
17684
|
-
const body =
|
|
18003
|
+
const body = readFileSync26(filePath);
|
|
17685
18004
|
return c.body(body, 200, {
|
|
17686
18005
|
"Content-Type": contentType,
|
|
17687
18006
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -17694,9 +18013,9 @@ app48.route("/v", visitor_consent_default);
|
|
|
17694
18013
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
17695
18014
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
17696
18015
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
17697
|
-
if (BRAND_JSON_PATH &&
|
|
18016
|
+
if (BRAND_JSON_PATH && existsSync26(BRAND_JSON_PATH)) {
|
|
17698
18017
|
try {
|
|
17699
|
-
const fullBrand = JSON.parse(
|
|
18018
|
+
const fullBrand = JSON.parse(readFileSync26(BRAND_JSON_PATH, "utf-8"));
|
|
17700
18019
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
17701
18020
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
17702
18021
|
} catch {
|
|
@@ -17713,9 +18032,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
17713
18032
|
function readInstalledVersion() {
|
|
17714
18033
|
try {
|
|
17715
18034
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
17716
|
-
const versionFile =
|
|
17717
|
-
if (!
|
|
17718
|
-
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();
|
|
17719
18038
|
return content || "unknown";
|
|
17720
18039
|
} catch {
|
|
17721
18040
|
return "unknown";
|
|
@@ -17756,7 +18075,7 @@ var clientErrorReporterScript = `<script>
|
|
|
17756
18075
|
function cachedHtml(file) {
|
|
17757
18076
|
let html = htmlCache.get(file);
|
|
17758
18077
|
if (!html) {
|
|
17759
|
-
html =
|
|
18078
|
+
html = readFileSync26(resolve28(process.cwd(), "public", file), "utf-8");
|
|
17760
18079
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
17761
18080
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
17762
18081
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -17772,13 +18091,13 @@ ${clientErrorReporterScript}
|
|
|
17772
18091
|
}
|
|
17773
18092
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
17774
18093
|
function loadBrandingCache(agentSlug) {
|
|
17775
|
-
const configDir2 =
|
|
18094
|
+
const configDir2 = join21(homedir3(), BRAND.configDir);
|
|
17776
18095
|
try {
|
|
17777
18096
|
const accountId = getDefaultAccountId();
|
|
17778
18097
|
if (!accountId) return null;
|
|
17779
|
-
const cachePath =
|
|
17780
|
-
if (!
|
|
17781
|
-
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"));
|
|
17782
18101
|
} catch {
|
|
17783
18102
|
return null;
|
|
17784
18103
|
}
|
|
@@ -17866,7 +18185,7 @@ app48.use("/vnc-popout.html", logViewerFetch);
|
|
|
17866
18185
|
app48.get("/vnc-popout.html", (c) => {
|
|
17867
18186
|
let html = htmlCache.get("vnc-popout.html");
|
|
17868
18187
|
if (!html) {
|
|
17869
|
-
html =
|
|
18188
|
+
html = readFileSync26(resolve28(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
17870
18189
|
const name = escapeHtml(BRAND.productName);
|
|
17871
18190
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
17872
18191
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -18022,11 +18341,11 @@ try {
|
|
|
18022
18341
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
18023
18342
|
async function runAdminUserReconcileTick() {
|
|
18024
18343
|
try {
|
|
18025
|
-
if (!
|
|
18344
|
+
if (!existsSync26(USERS_FILE)) {
|
|
18026
18345
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
18027
18346
|
return;
|
|
18028
18347
|
}
|
|
18029
|
-
const usersRaw =
|
|
18348
|
+
const usersRaw = readFileSync26(USERS_FILE, "utf-8").trim();
|
|
18030
18349
|
if (!usersRaw) {
|
|
18031
18350
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
18032
18351
|
return;
|
|
@@ -18136,7 +18455,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
18136
18455
|
}
|
|
18137
18456
|
init({
|
|
18138
18457
|
configDir: configDirForWhatsApp,
|
|
18139
|
-
platformRoot:
|
|
18458
|
+
platformRoot: resolve28(process.env.MAXY_PLATFORM_ROOT ?? join21(__dirname, "..")),
|
|
18140
18459
|
accountConfig: bootAccountConfig,
|
|
18141
18460
|
onMessage: async (msg) => {
|
|
18142
18461
|
if (msg.isOwnerMirror) {
|