@rubytech/create-maxy-code 0.1.308 → 0.1.309
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/claude-ptys-slice.test.js +1 -1
- package/dist/__tests__/cloudflared-slice.test.js +1 -1
- package/dist/__tests__/macos-darwin-branch.test.js +4 -6
- package/package.json +1 -1
- package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +28 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts +9 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admin-access-password/dist/index.js +26 -0
- package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -1
- package/payload/platform/lib/admin-access-password/src/index.ts +24 -0
- package/payload/platform/lib/models/dist/index.d.ts +7 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +10 -0
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +10 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +4 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +20 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -0
- 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 +11 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/server/{chunk-FBGIHWWM.js → chunk-J6WDAWFJ.js} +20 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AccessGate-CU4Qw6M6.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-DUpRIM1h.js +1 -0
- package/payload/server/public/assets/AdminShell-DkoQSsqo.js +1 -0
- package/payload/server/public/assets/{Checkbox-8elc7oXU.js → Checkbox-DMA1hVhn.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-BIHiyyxU.js +1 -0
- package/payload/server/public/assets/admin-BHvOMcCh.js +1 -0
- package/payload/server/public/assets/{arc-DxSm8tli.js → arc-Dl9QFDgW.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Crq5RSDG.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-7JSAh0vL.js → architectureDiagram-Q4EWVU46-CNLQUVi9.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-DzbKNqbH.js → audio-attachment-mime-DOBET-W1.js} +3 -3
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DLoVmHKD.js → blockDiagram-DXYQGD6D-B-QxfVjk.js} +1 -1
- package/payload/server/public/assets/brand-4F9ZXBF8.css +1 -0
- package/payload/server/public/assets/{brand-Dh5UlVO2.js → brand-C7kj0USi.js} +1 -1
- package/payload/server/public/assets/browser-eLSiC7_b.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Nv1G0o9P.js → c4Diagram-AHTNJAMY-NuYFvPDU.js} +1 -1
- package/payload/server/public/assets/channel-KT66MFN2.js +1 -0
- package/payload/server/public/assets/chat-DedpVKUl.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BpqPMhoA.js → chunk-2KRD3SAO-l5VL1KQm.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DgXHlVU_.js → chunk-336JU56O-C5gVznC2.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CWMiOm8Y.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-nwyZSZH8.js → chunk-4BX2VUAB-BtMVz_Sq.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Tfxz9LHX.js → chunk-4TB4RGXK-C8-dmCuT.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-6FMJQGXG.js → chunk-55IACEB6-C5gWvEJW.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-g2FgZF3D.js → chunk-5FUZZQ4R-BZ7VZoAC.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DtLwXsPH.js → chunk-5PVQY5BW-C_ajQOGC.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-K91CP5ZU.js → chunk-67CJDMHE-BJOR2dwK.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BGpCQhqK.js → chunk-7N4EOEYR-DvZLpquX.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-jkDbInck.js → chunk-AA7GKIK3-h5tVsPlW.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-mDosdzGs.js → chunk-BSJP7CBP-DLOF2-m3.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DhBxewpQ.js → chunk-CIAEETIT-CQRQMPCf.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B7c-9Emg.js → chunk-EDXVE4YY-K9-EfuM2.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Cqhhncox.js → chunk-ENJZ2VHE-DVoy6NvU.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-BpDq6wj1.js → chunk-FMBD7UC4-CQn_2o2b.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-Ds02-ktu.js → chunk-FOC6F5B3-CuN73goS.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BTX5POFr.js → chunk-ICPOFSXX-CKhl9J-H.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-Du1PXXBU.js → chunk-K5T4RW27-CBskuQmq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-siasOAf8.js → chunk-KGLVRYIC-Chtjt8xK.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-xf1rbZtf.js → chunk-LIHQZDEY-EOBiBNSH.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DeTLQ_LD.js → chunk-ORNJ4GCN-uPPq-5MN.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DQ7_oVJn.js → chunk-OYMX7WX6-BRzbxJOT.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DCzpF46A.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CXmFUKgn.js → chunk-U2HBQHQK-Bndyn5nF.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Bj8-8Wkz.js → chunk-X2U36JSP-BspGBHXW.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Con3TXqt.js → chunk-XPW4576I-HgXQ2k9h.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Dx8BHGWf.js → chunk-YZCP3GAM-C7oTyCnw.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dp4Q5Y-f.js → chunk-ZZ45TVLE-CufWa7QL.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-QOU4HzJJ.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DcOUai3Z.js +1 -0
- package/payload/server/public/assets/clone-CHh05KN-.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-pZiCv69E.js → cose-bilkent-S5V4N54A-BM3yEbF-.js} +1 -1
- package/payload/server/public/assets/{dagre-CLqhEgbL.js → dagre-C7WHNZO8.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BCxE8iyk.js → dagre-KV5264BT-bcZx3l06.js} +1 -1
- package/payload/server/public/assets/data-BcoBY39U.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-slUEdZzz.js → diagram-5BDNPKRD-B7VotaMF.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DPcraMfu.js → diagram-G4DWMVQ6-CWWvEsFx.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DR6luhGK.js → diagram-MMDJMWI5-DYHVkTYJ.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Jap1B4wA.js → diagram-TYMM5635-CHeB6Ama.js} +1 -1
- package/payload/server/public/assets/{dist-Dbh7HrZX.js → dist-CjjtmoWL.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DJKUs2hO.js → erDiagram-SMLLAGMA-C9gog8QP.js} +1 -1
- package/payload/server/public/assets/{flatten-Cl1Bc3dR.js → flatten-QcJDm7yK.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C8W-ZZ9W.js → flowDiagram-DWJPFMVM-B2O9lKTh.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DYCX4Xu2.js → ganttDiagram-T4ZO3ILL-DEa4AwbR.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BC-u4jgy.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CZu_fpgS.js → gitGraphDiagram-UUTBAWPF-BjXPQpBL.js} +1 -1
- package/payload/server/public/assets/{graph-DKSjcpmR.js → graph-C7Hye_vp.js} +2 -2
- package/payload/server/public/assets/{graph-labels-CVWPQgBV.js → graph-labels-YYgGsEVd.js} +1 -1
- package/payload/server/public/assets/{graphlib-Bdp7TA4y.js → graphlib-CBevn2DP.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DPUetTz-.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-q2dl09-M.js +2 -0
- package/payload/server/public/assets/{isEmpty-D1pGOD1J.js → isEmpty-BO6BAEn7.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B7KfIX6z.js → ishikawaDiagram-UXIWVN3A-CPLfpvqv.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CSDwBfhF.js → journeyDiagram-VCZTEJTY-CTHe8MiD.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CWzcEKTr.js → kanban-definition-6JOO6SKY-Bm9h1O3Y.js} +1 -1
- package/payload/server/public/assets/{line-BNQSlbYn.js → line-C31b0rtY.js} +1 -1
- package/payload/server/public/assets/{linear-BN6kGN93.js → linear-Cfm_8_pU.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CcFhkElq.js → mermaid-parser.core-B3tGwOcE.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-BsIeJ7Cc.js → mermaid.core-BM3s85ZW.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CQVzj6D_.js → mindmap-definition-QFDTVHPH-CaGv_mIB.js} +1 -1
- package/payload/server/public/assets/operator-WsXhcbBF.js +1 -0
- package/payload/server/public/assets/{ordinal-CBZeH4Yp.js → ordinal-jLCwuvYg.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BcfR-ZwA.js +1 -0
- package/payload/server/public/assets/page-BhHTnqv4.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BiKgZdNB.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DnrQ9fyn.js → pieDiagram-DEJITSTG-BhAXps4u.js} +1 -1
- package/payload/server/public/assets/public-ViXjC_dA.js +6 -0
- package/payload/server/public/assets/public-next-BKECyMz2.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BQWlCyWi.js → quadrantDiagram-34T5L4WZ-BWtTdNs8.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-nvCjiW_J.js +1 -0
- package/payload/server/public/assets/{reduce-PuPlFPRX.js → reduce-Dmi_NdVH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-Du_vZhU1.js → requirementDiagram-MS252O5E-CWU0qCcP.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js → sankeyDiagram-XADWPNL6-DYvutQld.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CS8GVol8.js → sequenceDiagram-FGHM5R23-Cir0hBWS.js} +1 -1
- package/payload/server/public/assets/{src-BoaldmnP.js → src-CwB968DO.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Bv1NW2F1.js → stateDiagram-FHFEXIEX-Be-h8YSS.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CAnmjSj7.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ClGYAsr0.js → timeline-definition-GMOUNBTQ-C3C4Wuyk.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BinXCVyM.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-CSmh20Ze.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-FIodJKzS.js → useSelectionMode-CG_Iel5F.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C2wTcxQT.js → vennDiagram-DHZGUBPP-mDclw0Sa.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BiCmRKWx.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D86-ivEx.js → wardleyDiagram-NUSXRM2D-mvk-YA9g.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Ba5WAN8P.js → xychartDiagram-5P7HB3ND-9M7k1hmD.js} +1 -1
- package/payload/server/public/browser.html +8 -8
- package/payload/server/public/chat.html +11 -11
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +10 -10
- package/payload/server/public/operator.html +13 -13
- package/payload/server/public/public-next.html +24 -0
- package/payload/server/public/public.html +9 -8
- package/payload/server/server.js +819 -614
- package/dist/__tests__/onboarding-state-readback.test.js +0 -61
- package/dist/__tests__/rss-sampler-installer.test.js +0 -27
- package/dist/onboarding-readback.js +0 -27
- package/payload/server/public/assets/AdminLoginScreens-BZIA9Z6o.js +0 -1
- package/payload/server/public/assets/AdminShell-iazLHsk7.js +0 -1
- package/payload/server/public/assets/admin-BEx6o3fa.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +0 -1
- package/payload/server/public/assets/brand-CmMZe4RK.css +0 -1
- package/payload/server/public/assets/browser-D16sPVkI.js +0 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +0 -1
- package/payload/server/public/assets/chat-x4PnXhkd.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +0 -1
- package/payload/server/public/assets/clone-DnNHGhNe.js +0 -1
- package/payload/server/public/assets/data-DqG45sq0.js +0 -1
- package/payload/server/public/assets/file-download-BvGS7Qmi.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +0 -2
- package/payload/server/public/assets/operator-Cnzbhdh2.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +0 -1
- package/payload/server/public/assets/page-CH8JQkQN.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +0 -1
- package/payload/server/public/assets/public-CA90VhI9.js +0 -6
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +0 -1
- /package/payload/server/public/assets/{file-download-qc_xy7Az.css → OperatorConversations-qc_xy7Az.css} +0 -0
- /package/payload/server/public/assets/{_baseFor-brRjpUOX.js → _baseFor-D8P3gUw3.js} +0 -0
- /package/payload/server/public/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
- /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-TvRJ2tGX.js → cytoscape.esm-mZ4wTuB7.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
- /package/payload/server/public/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
- /package/payload/server/public/assets/{katex-RxgSu_dy.js → katex-DaHGEgm7.js} +0 -0
- /package/payload/server/public/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CQ36nxok.js → preload-helper-TKOBYGYD.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-6CnTHTkH.js → rough.esm-JX0wREDd.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
VISITOR_TOKEN_SECRET_FILE,
|
|
26
26
|
VNC_DISPLAY,
|
|
27
27
|
WEBSOCKIFY_PORT,
|
|
28
|
+
accessPasswordCollides,
|
|
28
29
|
autoDeliverPremiumPlugins,
|
|
29
30
|
bindVisitorToGroup,
|
|
30
31
|
canAccessAdmin,
|
|
@@ -109,7 +110,7 @@ import {
|
|
|
109
110
|
vncLog,
|
|
110
111
|
walkPremiumBundles,
|
|
111
112
|
writeAdminUserAndPerson
|
|
112
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-J6WDAWFJ.js";
|
|
113
114
|
import {
|
|
114
115
|
__commonJS,
|
|
115
116
|
__toESM
|
|
@@ -1227,7 +1228,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1227
1228
|
|
|
1228
1229
|
// server/index.ts
|
|
1229
1230
|
import { readFileSync as readFileSync27, existsSync as existsSync28, watchFile } from "fs";
|
|
1230
|
-
import { resolve as
|
|
1231
|
+
import { resolve as resolve31, join as join25, basename as basename9 } from "path";
|
|
1231
1232
|
import { homedir as homedir3 } from "os";
|
|
1232
1233
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1233
1234
|
|
|
@@ -1875,7 +1876,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1875
1876
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1876
1877
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1877
1878
|
const timer2 = new Promise(
|
|
1878
|
-
(
|
|
1879
|
+
(resolve32) => setTimeout(() => resolve32("timeout"), timeoutMs)
|
|
1879
1880
|
);
|
|
1880
1881
|
const result = await Promise.race([
|
|
1881
1882
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2003,11 +2004,11 @@ async function createWaSocket(opts) {
|
|
|
2003
2004
|
return sock;
|
|
2004
2005
|
}
|
|
2005
2006
|
async function waitForConnection(sock) {
|
|
2006
|
-
return new Promise((
|
|
2007
|
+
return new Promise((resolve32, reject) => {
|
|
2007
2008
|
const handler = (update) => {
|
|
2008
2009
|
if (update.connection === "open") {
|
|
2009
2010
|
sock.ev.off("connection.update", handler);
|
|
2010
|
-
|
|
2011
|
+
resolve32();
|
|
2011
2012
|
}
|
|
2012
2013
|
if (update.connection === "close") {
|
|
2013
2014
|
sock.ev.off("connection.update", handler);
|
|
@@ -2121,14 +2122,14 @@ ${inspected}`;
|
|
|
2121
2122
|
return inspect2(err, INSPECT_OPTS2);
|
|
2122
2123
|
}
|
|
2123
2124
|
function withTimeout(label, promise, timeoutMs) {
|
|
2124
|
-
return new Promise((
|
|
2125
|
+
return new Promise((resolve32, reject) => {
|
|
2125
2126
|
const timer2 = setTimeout(() => {
|
|
2126
2127
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2127
2128
|
}, timeoutMs);
|
|
2128
2129
|
promise.then(
|
|
2129
2130
|
(value) => {
|
|
2130
2131
|
clearTimeout(timer2);
|
|
2131
|
-
|
|
2132
|
+
resolve32(value);
|
|
2132
2133
|
},
|
|
2133
2134
|
(err) => {
|
|
2134
2135
|
clearTimeout(timer2);
|
|
@@ -3012,8 +3013,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
3012
3013
|
const { givenName, familyName } = splitName(input.pushName);
|
|
3013
3014
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
3014
3015
|
let release;
|
|
3015
|
-
const mine = new Promise((
|
|
3016
|
-
release =
|
|
3016
|
+
const mine = new Promise((resolve32) => {
|
|
3017
|
+
release = resolve32;
|
|
3017
3018
|
});
|
|
3018
3019
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
3019
3020
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -4093,11 +4094,11 @@ async function connectWithReconnect(conn) {
|
|
|
4093
4094
|
console.error(
|
|
4094
4095
|
`${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
4095
4096
|
);
|
|
4096
|
-
await new Promise((
|
|
4097
|
-
const timer2 = setTimeout(
|
|
4097
|
+
await new Promise((resolve32) => {
|
|
4098
|
+
const timer2 = setTimeout(resolve32, delay);
|
|
4098
4099
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
4099
4100
|
clearTimeout(timer2);
|
|
4100
|
-
|
|
4101
|
+
resolve32();
|
|
4101
4102
|
}, { once: true });
|
|
4102
4103
|
});
|
|
4103
4104
|
}
|
|
@@ -4105,16 +4106,16 @@ async function connectWithReconnect(conn) {
|
|
|
4105
4106
|
}
|
|
4106
4107
|
}
|
|
4107
4108
|
function waitForDisconnectEvent(conn) {
|
|
4108
|
-
return new Promise((
|
|
4109
|
+
return new Promise((resolve32) => {
|
|
4109
4110
|
if (!conn.sock) {
|
|
4110
|
-
|
|
4111
|
+
resolve32();
|
|
4111
4112
|
return;
|
|
4112
4113
|
}
|
|
4113
4114
|
const sock = conn.sock;
|
|
4114
4115
|
const handler = (update) => {
|
|
4115
4116
|
if (update.connection === "close") {
|
|
4116
4117
|
sock.ev.off("connection.update", handler);
|
|
4117
|
-
|
|
4118
|
+
resolve32();
|
|
4118
4119
|
}
|
|
4119
4120
|
};
|
|
4120
4121
|
sock.ev.on("connection.update", handler);
|
|
@@ -4374,8 +4375,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4374
4375
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4375
4376
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4376
4377
|
let resolvePending;
|
|
4377
|
-
const sttPending = new Promise((
|
|
4378
|
-
resolvePending =
|
|
4378
|
+
const sttPending = new Promise((resolve32) => {
|
|
4379
|
+
resolvePending = resolve32;
|
|
4379
4380
|
});
|
|
4380
4381
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4381
4382
|
try {
|
|
@@ -4769,20 +4770,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
4769
4770
|
|
|
4770
4771
|
// server/routes/health.ts
|
|
4771
4772
|
function checkPort(port2, timeoutMs = 500) {
|
|
4772
|
-
return new Promise((
|
|
4773
|
+
return new Promise((resolve32) => {
|
|
4773
4774
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
4774
4775
|
socket.setTimeout(timeoutMs);
|
|
4775
4776
|
socket.once("connect", () => {
|
|
4776
4777
|
socket.destroy();
|
|
4777
|
-
|
|
4778
|
+
resolve32(true);
|
|
4778
4779
|
});
|
|
4779
4780
|
socket.once("error", () => {
|
|
4780
4781
|
socket.destroy();
|
|
4781
|
-
|
|
4782
|
+
resolve32(false);
|
|
4782
4783
|
});
|
|
4783
4784
|
socket.once("timeout", () => {
|
|
4784
4785
|
socket.destroy();
|
|
4785
|
-
|
|
4786
|
+
resolve32(false);
|
|
4786
4787
|
});
|
|
4787
4788
|
});
|
|
4788
4789
|
}
|
|
@@ -5175,8 +5176,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5175
5176
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5176
5177
|
}
|
|
5177
5178
|
function createChatRoutes(deps) {
|
|
5178
|
-
const
|
|
5179
|
-
|
|
5179
|
+
const app51 = new Hono();
|
|
5180
|
+
app51.post("/", async (c) => {
|
|
5180
5181
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5181
5182
|
const contentType = c.req.header("content-type") ?? "";
|
|
5182
5183
|
const account = resolveAccount();
|
|
@@ -5399,7 +5400,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5399
5400
|
}
|
|
5400
5401
|
});
|
|
5401
5402
|
});
|
|
5402
|
-
return
|
|
5403
|
+
return app51;
|
|
5403
5404
|
}
|
|
5404
5405
|
|
|
5405
5406
|
// server/routes/whatsapp.ts
|
|
@@ -5821,8 +5822,8 @@ async function startLogin(opts) {
|
|
|
5821
5822
|
await clearAuth(authDir);
|
|
5822
5823
|
let resolveCode = null;
|
|
5823
5824
|
let rejectCode = null;
|
|
5824
|
-
const codePromise = new Promise((
|
|
5825
|
-
resolveCode =
|
|
5825
|
+
const codePromise = new Promise((resolve32, reject) => {
|
|
5826
|
+
resolveCode = resolve32;
|
|
5826
5827
|
rejectCode = reject;
|
|
5827
5828
|
});
|
|
5828
5829
|
const codeTimer = setTimeout(
|
|
@@ -7442,18 +7443,199 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
7442
7443
|
});
|
|
7443
7444
|
var whatsapp_reader_default = app4;
|
|
7444
7445
|
|
|
7446
|
+
// server/routes/public-reader.ts
|
|
7447
|
+
import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2 } from "fs";
|
|
7448
|
+
import { basename as basename3, dirname as dirname2, join as join11, resolve as resolve12, sep as sep4 } from "path";
|
|
7449
|
+
|
|
7450
|
+
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
7451
|
+
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
7452
|
+
"operator-inbound",
|
|
7453
|
+
"agent-reply",
|
|
7454
|
+
"agent-reply-document",
|
|
7455
|
+
"agent-error"
|
|
7456
|
+
]);
|
|
7457
|
+
function isDeliveredKind(kind, set) {
|
|
7458
|
+
return set.has(kind);
|
|
7459
|
+
}
|
|
7460
|
+
|
|
7461
|
+
// app/lib/public-reader/filter-delivered.ts
|
|
7462
|
+
function filterDeliveredFrames(lines) {
|
|
7463
|
+
const turns = [];
|
|
7464
|
+
let dropped = 0;
|
|
7465
|
+
for (const turn of parseTranscript(lines)) {
|
|
7466
|
+
if (isDeliveredKind(turn.kind, PUBLIC_DELIVERED_KINDS)) turns.push(turn);
|
|
7467
|
+
else dropped++;
|
|
7468
|
+
}
|
|
7469
|
+
return { turns, dropped };
|
|
7470
|
+
}
|
|
7471
|
+
|
|
7472
|
+
// app/lib/public-reader/resolve-visitor-session.ts
|
|
7473
|
+
function resolveVisitorSession(rows, visitorPersonId) {
|
|
7474
|
+
const matches = rows.filter(
|
|
7475
|
+
(r) => r.role === "public" && r.channel === "webchat" && r.personId === visitorPersonId
|
|
7476
|
+
);
|
|
7477
|
+
if (matches.length === 0) return null;
|
|
7478
|
+
return matches.reduce(
|
|
7479
|
+
(best, r) => (r.startedAt ?? "") > (best.startedAt ?? "") ? r : best
|
|
7480
|
+
);
|
|
7481
|
+
}
|
|
7482
|
+
|
|
7483
|
+
// server/routes/public-reader.ts
|
|
7484
|
+
var app5 = new Hono();
|
|
7485
|
+
var TAG20 = "[public-webchat]";
|
|
7486
|
+
function parseAccessSessionId(cookieHeader) {
|
|
7487
|
+
if (!cookieHeader) return null;
|
|
7488
|
+
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
7489
|
+
return part ? part.slice("__access_session=".length) : null;
|
|
7490
|
+
}
|
|
7491
|
+
function resolveVisitor(c) {
|
|
7492
|
+
const id = parseAccessSessionId(c.req.header("cookie"));
|
|
7493
|
+
const session = id ? getAccessSession(id) : null;
|
|
7494
|
+
return session && session.personId ? { personId: session.personId } : null;
|
|
7495
|
+
}
|
|
7496
|
+
function enumeratePublicRows() {
|
|
7497
|
+
const cfg = claudeConfigDir();
|
|
7498
|
+
if (!cfg) return [];
|
|
7499
|
+
const rows = [];
|
|
7500
|
+
for (const { path: path2 } of enumerateJsonls(join11(cfg, "projects"))) {
|
|
7501
|
+
const sessionId = basename3(path2).replace(/\.jsonl$/, "");
|
|
7502
|
+
const projectDir = dirname2(path2);
|
|
7503
|
+
const meta = readSidecarMeta(join11(projectDir, `${sessionId}.meta.json`));
|
|
7504
|
+
rows.push({
|
|
7505
|
+
sessionId,
|
|
7506
|
+
projectDir,
|
|
7507
|
+
role: meta.role,
|
|
7508
|
+
channel: meta.channel,
|
|
7509
|
+
personId: meta.personId,
|
|
7510
|
+
senderId: meta.senderId,
|
|
7511
|
+
startedAt: meta.startedAt
|
|
7512
|
+
});
|
|
7513
|
+
}
|
|
7514
|
+
return rows;
|
|
7515
|
+
}
|
|
7516
|
+
app5.get("/session", (c) => {
|
|
7517
|
+
const visitor = resolveVisitor(c);
|
|
7518
|
+
if (!visitor) {
|
|
7519
|
+
console.error(`${TAG20} op=reader-refused reason=no-grant path=/session`);
|
|
7520
|
+
return c.json({ error: "gate-required" }, 401);
|
|
7521
|
+
}
|
|
7522
|
+
const found = resolveVisitorSession(enumeratePublicRows(), visitor.personId);
|
|
7523
|
+
if (found) {
|
|
7524
|
+
console.log(`${TAG20} op=session-resume key=${(found.senderId ?? "").slice(0, 8)} sessionId=${found.sessionId.slice(0, 8)}`);
|
|
7525
|
+
return c.json({ sessionId: found.sessionId, projectDir: found.projectDir, sessionKey: found.senderId });
|
|
7526
|
+
}
|
|
7527
|
+
const sessionKey = crypto.randomUUID();
|
|
7528
|
+
console.log(`${TAG20} op=session-new key=${sessionKey.slice(0, 8)}`);
|
|
7529
|
+
return c.json({ sessionId: null, projectDir: null, sessionKey });
|
|
7530
|
+
});
|
|
7531
|
+
function readFrom2(path2, from) {
|
|
7532
|
+
const end = statSync5(path2).size;
|
|
7533
|
+
if (end <= from) return { buf: Buffer.alloc(0), end: from };
|
|
7534
|
+
const fd = openSync2(path2, "r");
|
|
7535
|
+
try {
|
|
7536
|
+
const buf = Buffer.alloc(end - from);
|
|
7537
|
+
readSync2(fd, buf, 0, buf.length, from);
|
|
7538
|
+
return { buf, end };
|
|
7539
|
+
} finally {
|
|
7540
|
+
closeSync2(fd);
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
app5.get("/stream", (c) => {
|
|
7544
|
+
const visitor = resolveVisitor(c);
|
|
7545
|
+
if (!visitor) {
|
|
7546
|
+
console.error(`${TAG20} op=reader-refused reason=no-grant path=/stream`);
|
|
7547
|
+
return c.json({ error: "gate-required" }, 401);
|
|
7548
|
+
}
|
|
7549
|
+
const sessionId = c.req.query("sessionId") ?? "";
|
|
7550
|
+
const projectDir = c.req.query("projectDir") ?? "";
|
|
7551
|
+
const cfg = claudeConfigDir();
|
|
7552
|
+
const projectsRoot = cfg ? resolve12(join11(cfg, "projects")) : null;
|
|
7553
|
+
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7554
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7555
|
+
}
|
|
7556
|
+
const jsonlPath = resolve12(join11(projectDir, `${sessionId}.jsonl`));
|
|
7557
|
+
if (!jsonlPath.startsWith(projectsRoot + sep4)) {
|
|
7558
|
+
return c.json({ error: "bad session reference" }, 400);
|
|
7559
|
+
}
|
|
7560
|
+
const meta = readSidecarMeta(join11(projectDir, `${sessionId}.meta.json`));
|
|
7561
|
+
if (!(meta.role === "public" && meta.channel === "webchat" && meta.personId === visitor.personId)) {
|
|
7562
|
+
console.error(`${TAG20} op=reader-refused reason=not-owner sessionId=${sessionId.slice(0, 8)}`);
|
|
7563
|
+
return c.json({ error: "forbidden" }, 403);
|
|
7564
|
+
}
|
|
7565
|
+
const senderShort = (meta.senderId ?? "").slice(0, 8);
|
|
7566
|
+
const encoder = new TextEncoder();
|
|
7567
|
+
console.log(`${TAG20} op=reader-open key=${senderShort} mode=delivered-only sessionId=${sessionId.slice(0, 8)}`);
|
|
7568
|
+
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7569
|
+
data: ${JSON.stringify(turn)}
|
|
7570
|
+
|
|
7571
|
+
`));
|
|
7572
|
+
const readable = new ReadableStream({
|
|
7573
|
+
start(controller) {
|
|
7574
|
+
let offset = 0;
|
|
7575
|
+
const emit = (lines) => {
|
|
7576
|
+
const { turns, dropped } = filterDeliveredFrames(lines);
|
|
7577
|
+
for (const turn of turns) send(controller, turn, offset);
|
|
7578
|
+
if (dropped > 0) console.log(`${TAG20} op=reader-filtered key=${senderShort} dropped=${dropped}`);
|
|
7579
|
+
};
|
|
7580
|
+
try {
|
|
7581
|
+
const { buf, end } = readFrom2(jsonlPath, 0);
|
|
7582
|
+
offset = end;
|
|
7583
|
+
emit(buf.toString("utf8").split("\n"));
|
|
7584
|
+
} catch {
|
|
7585
|
+
controller.enqueue(encoder.encode('event: error\ndata: "read-failed"\n\n'));
|
|
7586
|
+
}
|
|
7587
|
+
const drain = () => {
|
|
7588
|
+
try {
|
|
7589
|
+
const { buf, end } = readFrom2(jsonlPath, offset);
|
|
7590
|
+
if (end <= offset) return;
|
|
7591
|
+
const { lines, nextOffset } = splitNewLines(buf, offset);
|
|
7592
|
+
offset = nextOffset;
|
|
7593
|
+
emit(lines);
|
|
7594
|
+
} catch {
|
|
7595
|
+
}
|
|
7596
|
+
};
|
|
7597
|
+
let watcher = null;
|
|
7598
|
+
try {
|
|
7599
|
+
watcher = watch2(jsonlPath, drain);
|
|
7600
|
+
} catch {
|
|
7601
|
+
}
|
|
7602
|
+
const poll = setInterval(drain, 1e3);
|
|
7603
|
+
const heartbeat = setInterval(() => {
|
|
7604
|
+
try {
|
|
7605
|
+
controller.enqueue(encoder.encode(": ping\n\n"));
|
|
7606
|
+
} catch {
|
|
7607
|
+
}
|
|
7608
|
+
}, 2e4);
|
|
7609
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
7610
|
+
watcher?.close();
|
|
7611
|
+
clearInterval(poll);
|
|
7612
|
+
clearInterval(heartbeat);
|
|
7613
|
+
console.log(`${TAG20} op=reader-close key=${senderShort}`);
|
|
7614
|
+
try {
|
|
7615
|
+
controller.close();
|
|
7616
|
+
} catch {
|
|
7617
|
+
}
|
|
7618
|
+
});
|
|
7619
|
+
}
|
|
7620
|
+
});
|
|
7621
|
+
return new Response(readable, {
|
|
7622
|
+
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
|
|
7623
|
+
});
|
|
7624
|
+
});
|
|
7625
|
+
var public_reader_default = app5;
|
|
7626
|
+
|
|
7445
7627
|
// server/routes/webchat.ts
|
|
7446
|
-
import { basename as
|
|
7447
|
-
import { join as
|
|
7628
|
+
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7629
|
+
import { join as join13 } from "path";
|
|
7448
7630
|
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
7449
7631
|
|
|
7450
7632
|
// server/canonical-webchat-override.ts
|
|
7451
7633
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
7452
|
-
import { join as
|
|
7634
|
+
import { join as join12 } from "path";
|
|
7453
7635
|
var FILE = "canonical-webchat-session.json";
|
|
7454
7636
|
var UUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
7455
7637
|
function canonicalOverridePath(accountDir) {
|
|
7456
|
-
return
|
|
7638
|
+
return join12(accountDir, FILE);
|
|
7457
7639
|
}
|
|
7458
7640
|
function readCanonicalOverrideId(accountDir) {
|
|
7459
7641
|
try {
|
|
@@ -7488,10 +7670,10 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
7488
7670
|
function locateSession(sessionId) {
|
|
7489
7671
|
const cfg = claudeConfigDir();
|
|
7490
7672
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7491
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7492
|
-
if (
|
|
7493
|
-
const dir =
|
|
7494
|
-
const meta = readSidecarMeta(
|
|
7673
|
+
for (const { path: path2 } of enumerateJsonls(join13(cfg, "projects"))) {
|
|
7674
|
+
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7675
|
+
const dir = dirname3(path2);
|
|
7676
|
+
const meta = readSidecarMeta(join13(dir, `${sessionId}.meta.json`));
|
|
7495
7677
|
return { projectDir: dir, channel: meta.channel };
|
|
7496
7678
|
}
|
|
7497
7679
|
}
|
|
@@ -7500,7 +7682,7 @@ function locateSession(sessionId) {
|
|
|
7500
7682
|
function locateSidecar(sessionId) {
|
|
7501
7683
|
const cfg = claudeConfigDir();
|
|
7502
7684
|
if (!cfg) return null;
|
|
7503
|
-
const projectsRoot =
|
|
7685
|
+
const projectsRoot = join13(cfg, "projects");
|
|
7504
7686
|
let slugs;
|
|
7505
7687
|
try {
|
|
7506
7688
|
slugs = readdirSync7(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -7508,7 +7690,7 @@ function locateSidecar(sessionId) {
|
|
|
7508
7690
|
return null;
|
|
7509
7691
|
}
|
|
7510
7692
|
for (const slug of slugs) {
|
|
7511
|
-
const metaPath =
|
|
7693
|
+
const metaPath = join13(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
7512
7694
|
if (existsSync8(metaPath)) {
|
|
7513
7695
|
return { channel: readSidecarMeta(metaPath).channel };
|
|
7514
7696
|
}
|
|
@@ -7606,8 +7788,8 @@ async function reapplyLeversViaManager() {
|
|
|
7606
7788
|
}
|
|
7607
7789
|
}
|
|
7608
7790
|
function createWebchatRoutes(deps) {
|
|
7609
|
-
const
|
|
7610
|
-
|
|
7791
|
+
const app51 = new Hono();
|
|
7792
|
+
app51.post("/send", requireAdminSession, async (c) => {
|
|
7611
7793
|
let accountId;
|
|
7612
7794
|
try {
|
|
7613
7795
|
accountId = resolvePlatformAccountId();
|
|
@@ -7738,7 +7920,7 @@ ${note}` : note;
|
|
|
7738
7920
|
}
|
|
7739
7921
|
return c.json({ ok: true });
|
|
7740
7922
|
});
|
|
7741
|
-
|
|
7923
|
+
app51.post("/settings", requireAdminSession, async (c) => {
|
|
7742
7924
|
const body = await c.req.json().catch(() => null);
|
|
7743
7925
|
const op = body?.op;
|
|
7744
7926
|
const value = body?.value;
|
|
@@ -7760,7 +7942,7 @@ ${note}` : note;
|
|
|
7760
7942
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
7761
7943
|
return c.json({ error: "account unresolved" }, 503);
|
|
7762
7944
|
}
|
|
7763
|
-
const accountJsonPath =
|
|
7945
|
+
const accountJsonPath = join13(account.accountDir, "account.json");
|
|
7764
7946
|
try {
|
|
7765
7947
|
const parsed = JSON.parse(readFileSync13(accountJsonPath, "utf8"));
|
|
7766
7948
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -7778,7 +7960,7 @@ ${note}` : note;
|
|
|
7778
7960
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
7779
7961
|
return c.json({ ok: true, settingsApplied });
|
|
7780
7962
|
});
|
|
7781
|
-
|
|
7963
|
+
app51.get("/session", requireAdminSession, async (c) => {
|
|
7782
7964
|
let accountId;
|
|
7783
7965
|
try {
|
|
7784
7966
|
accountId = resolvePlatformAccountId();
|
|
@@ -7807,9 +7989,9 @@ ${note}` : note;
|
|
|
7807
7989
|
const cfg = claudeConfigDir();
|
|
7808
7990
|
let projectDir = null;
|
|
7809
7991
|
if (cfg) {
|
|
7810
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7811
|
-
if (
|
|
7812
|
-
projectDir =
|
|
7992
|
+
for (const { path: path2 } of enumerateJsonls(join13(cfg, "projects"))) {
|
|
7993
|
+
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7994
|
+
projectDir = dirname3(path2);
|
|
7813
7995
|
break;
|
|
7814
7996
|
}
|
|
7815
7997
|
}
|
|
@@ -7817,15 +7999,15 @@ ${note}` : note;
|
|
|
7817
7999
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
7818
8000
|
return c.json({ sessionId, projectDir, ...indicators, ...readLevers(account) });
|
|
7819
8001
|
});
|
|
7820
|
-
return
|
|
8002
|
+
return app51;
|
|
7821
8003
|
}
|
|
7822
8004
|
|
|
7823
8005
|
// server/routes/webchat-greeting.ts
|
|
7824
|
-
import { resolve as
|
|
8006
|
+
import { resolve as resolve13 } from "path";
|
|
7825
8007
|
|
|
7826
8008
|
// app/lib/claude-agent/specialist-roster.ts
|
|
7827
8009
|
import { existsSync as existsSync9, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "fs";
|
|
7828
|
-
import { join as
|
|
8010
|
+
import { join as join14 } from "path";
|
|
7829
8011
|
function field(fm, name) {
|
|
7830
8012
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
7831
8013
|
if (!m) return null;
|
|
@@ -7844,7 +8026,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
7844
8026
|
if (!file.endsWith(".md")) continue;
|
|
7845
8027
|
let raw;
|
|
7846
8028
|
try {
|
|
7847
|
-
raw = readFileSync14(
|
|
8029
|
+
raw = readFileSync14(join14(specialistsDir, file), "utf-8");
|
|
7848
8030
|
} catch (err) {
|
|
7849
8031
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
7850
8032
|
continue;
|
|
@@ -7885,8 +8067,8 @@ var TASKS_CYPHER = `
|
|
|
7885
8067
|
WITH t ORDER BY coalesce(t.createdAt, '') ASC
|
|
7886
8068
|
WITH collect({ taskId: t.taskId, name: t.name, status: t.status }) AS all
|
|
7887
8069
|
RETURN all[0..${TASK_ITEMS_CAP}] AS items, size(all) AS total`;
|
|
7888
|
-
var
|
|
7889
|
-
|
|
8070
|
+
var app6 = new Hono();
|
|
8071
|
+
app6.get("/", requireAdminSession, async (c) => {
|
|
7890
8072
|
const cacheKey = c.var.cacheKey;
|
|
7891
8073
|
const accountId = getAccountIdForSession(cacheKey);
|
|
7892
8074
|
if (!accountId) {
|
|
@@ -7926,7 +8108,7 @@ app5.get("/", requireAdminSession, async (c) => {
|
|
|
7926
8108
|
let specialists = [];
|
|
7927
8109
|
try {
|
|
7928
8110
|
const roster = readSpecialistRoster(
|
|
7929
|
-
|
|
8111
|
+
resolve13(ACCOUNTS_DIR, accountId, "specialists", "agents")
|
|
7930
8112
|
);
|
|
7931
8113
|
specialists = roster.specialists;
|
|
7932
8114
|
for (const s of roster.skipped) {
|
|
@@ -7957,15 +8139,15 @@ function r2n(value) {
|
|
|
7957
8139
|
}
|
|
7958
8140
|
return Number(value ?? 0);
|
|
7959
8141
|
}
|
|
7960
|
-
var webchat_greeting_default =
|
|
8142
|
+
var webchat_greeting_default = app6;
|
|
7961
8143
|
|
|
7962
8144
|
// server/routes/telegram.ts
|
|
7963
8145
|
import { homedir } from "os";
|
|
7964
|
-
import { resolve as
|
|
8146
|
+
import { resolve as resolve15, join as join15 } from "path";
|
|
7965
8147
|
import { existsSync as existsSync10, readFileSync as readFileSync15 } from "fs";
|
|
7966
8148
|
|
|
7967
8149
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
7968
|
-
import { resolve as
|
|
8150
|
+
import { resolve as resolve14 } from "path";
|
|
7969
8151
|
|
|
7970
8152
|
// app/lib/channel-pty-bridge/manager-client.ts
|
|
7971
8153
|
function managerBase2() {
|
|
@@ -8086,7 +8268,7 @@ function classifyTimeout(ndjson, writeAtMs) {
|
|
|
8086
8268
|
|
|
8087
8269
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
8088
8270
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
8089
|
-
var
|
|
8271
|
+
var TAG21 = "[public-session-review]";
|
|
8090
8272
|
var CONSUMED_CAP = 500;
|
|
8091
8273
|
var consumed = /* @__PURE__ */ new Set();
|
|
8092
8274
|
function consumeOnce(sessionId) {
|
|
@@ -8113,7 +8295,7 @@ async function fetchJsonl(sessionId) {
|
|
|
8113
8295
|
return await res.text();
|
|
8114
8296
|
} catch (err) {
|
|
8115
8297
|
console.error(
|
|
8116
|
-
`${
|
|
8298
|
+
`${TAG21} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
8117
8299
|
);
|
|
8118
8300
|
return null;
|
|
8119
8301
|
}
|
|
@@ -8137,7 +8319,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
8137
8319
|
const res = await fetch(url);
|
|
8138
8320
|
if (!res.ok) {
|
|
8139
8321
|
console.error(
|
|
8140
|
-
`${
|
|
8322
|
+
`${TAG21} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
8141
8323
|
);
|
|
8142
8324
|
return [];
|
|
8143
8325
|
}
|
|
@@ -8145,7 +8327,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
8145
8327
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
8146
8328
|
} catch (err) {
|
|
8147
8329
|
console.error(
|
|
8148
|
-
`${
|
|
8330
|
+
`${TAG21} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
8149
8331
|
);
|
|
8150
8332
|
return [];
|
|
8151
8333
|
}
|
|
@@ -8174,7 +8356,7 @@ function composeInitialMessage(input) {
|
|
|
8174
8356
|
}
|
|
8175
8357
|
async function dispatchReviewer(input, initialMessage) {
|
|
8176
8358
|
const sessionId = randomUUID7();
|
|
8177
|
-
console.log(`${
|
|
8359
|
+
console.log(`${TAG21} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
8178
8360
|
const spawned = await managerRcSpawn({
|
|
8179
8361
|
sessionId,
|
|
8180
8362
|
initialMessage,
|
|
@@ -8194,21 +8376,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
8194
8376
|
const dispatchedAt = Date.now();
|
|
8195
8377
|
if (consumed.has(input.sessionId)) {
|
|
8196
8378
|
console.log(
|
|
8197
|
-
`${
|
|
8379
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
8198
8380
|
);
|
|
8199
8381
|
return;
|
|
8200
8382
|
}
|
|
8201
8383
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
8202
8384
|
if (!jsonl) {
|
|
8203
8385
|
console.log(
|
|
8204
|
-
`${
|
|
8386
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
8205
8387
|
);
|
|
8206
8388
|
return;
|
|
8207
8389
|
}
|
|
8208
8390
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
8209
8391
|
if (operatorTurns === 0) {
|
|
8210
8392
|
console.log(
|
|
8211
|
-
`${
|
|
8393
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
8212
8394
|
);
|
|
8213
8395
|
return;
|
|
8214
8396
|
}
|
|
@@ -8222,19 +8404,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
8222
8404
|
});
|
|
8223
8405
|
if (!consumeOnce(input.sessionId)) {
|
|
8224
8406
|
console.log(
|
|
8225
|
-
`${
|
|
8407
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
8226
8408
|
);
|
|
8227
8409
|
return;
|
|
8228
8410
|
}
|
|
8229
8411
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
8230
8412
|
if (!dispatched.ok) {
|
|
8231
8413
|
console.error(
|
|
8232
|
-
`${
|
|
8414
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
8233
8415
|
);
|
|
8234
8416
|
return;
|
|
8235
8417
|
}
|
|
8236
8418
|
console.log(
|
|
8237
|
-
`${
|
|
8419
|
+
`${TAG21} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
8238
8420
|
);
|
|
8239
8421
|
}
|
|
8240
8422
|
|
|
@@ -8405,7 +8587,7 @@ async function fanOut(subscribers, text, onError, tag) {
|
|
|
8405
8587
|
}
|
|
8406
8588
|
|
|
8407
8589
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
8408
|
-
var
|
|
8590
|
+
var TAG22 = "[whatsapp-adaptor]";
|
|
8409
8591
|
var SEND_USER_FILE = "SendUserFile";
|
|
8410
8592
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
8411
8593
|
function platformRoot() {
|
|
@@ -8440,7 +8622,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8440
8622
|
maxyAccountId = resolvePlatformAccountId();
|
|
8441
8623
|
} catch (err) {
|
|
8442
8624
|
console.error(
|
|
8443
|
-
`${
|
|
8625
|
+
`${TAG22} file-delivery reject reason=account-unresolved sender=${entry.senderId} message=${err instanceof Error ? err.message : String(err)}`
|
|
8444
8626
|
);
|
|
8445
8627
|
return;
|
|
8446
8628
|
}
|
|
@@ -8457,7 +8639,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8457
8639
|
if (!result.ok) {
|
|
8458
8640
|
failedFiles.push(files[i]);
|
|
8459
8641
|
console.error(
|
|
8460
|
-
`${
|
|
8642
|
+
`${TAG22} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
8461
8643
|
);
|
|
8462
8644
|
}
|
|
8463
8645
|
}
|
|
@@ -8474,7 +8656,7 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8474
8656
|
const sid = entry.sessionId.slice(0, 8);
|
|
8475
8657
|
for (const file of failed) {
|
|
8476
8658
|
console.error(
|
|
8477
|
-
`${
|
|
8659
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE} file=${file}`
|
|
8478
8660
|
);
|
|
8479
8661
|
}
|
|
8480
8662
|
const okAt = documentOutboundAt(entry.senderId);
|
|
@@ -8485,13 +8667,13 @@ function makeWhatsAppFileDelivery(entry) {
|
|
|
8485
8667
|
if (!delivered) {
|
|
8486
8668
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
8487
8669
|
console.error(
|
|
8488
|
-
`${
|
|
8670
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
8489
8671
|
);
|
|
8490
8672
|
}
|
|
8491
8673
|
}
|
|
8492
8674
|
if (firedTools.includes(SEND_USER_FILE) && attempts === 0 && !documentWentOut) {
|
|
8493
8675
|
console.error(
|
|
8494
|
-
`${
|
|
8676
|
+
`${TAG22} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${SEND_USER_FILE}`
|
|
8495
8677
|
);
|
|
8496
8678
|
}
|
|
8497
8679
|
}
|
|
@@ -8562,7 +8744,7 @@ async function ensureEntry(input) {
|
|
|
8562
8744
|
});
|
|
8563
8745
|
} else {
|
|
8564
8746
|
console.error(`${tag} route role=${input.role} target=public-spawn senderId=${input.senderId}`);
|
|
8565
|
-
const attachmentDir =
|
|
8747
|
+
const attachmentDir = resolve14(DATA_ROOT, "accounts", input.accountId, "uploads", "public", input.senderId);
|
|
8566
8748
|
spawned = await managerSpawn({
|
|
8567
8749
|
senderId: input.senderId,
|
|
8568
8750
|
role: input.role,
|
|
@@ -8694,12 +8876,12 @@ async function dispatchOnce(input) {
|
|
|
8694
8876
|
});
|
|
8695
8877
|
if (!entry) return { error: "spawn-failed" };
|
|
8696
8878
|
entry.lastInboundAt = Date.now();
|
|
8697
|
-
let
|
|
8879
|
+
let resolve32;
|
|
8698
8880
|
const turnPromise = new Promise((r) => {
|
|
8699
|
-
|
|
8881
|
+
resolve32 = r;
|
|
8700
8882
|
});
|
|
8701
8883
|
const listener = (text) => {
|
|
8702
|
-
|
|
8884
|
+
resolve32(text);
|
|
8703
8885
|
};
|
|
8704
8886
|
entry.subscribers.add(listener);
|
|
8705
8887
|
const writeAtMs = Date.now();
|
|
@@ -8846,11 +9028,11 @@ function routeTelegramUpdate(input) {
|
|
|
8846
9028
|
}
|
|
8847
9029
|
|
|
8848
9030
|
// server/routes/telegram.ts
|
|
8849
|
-
var
|
|
9031
|
+
var TAG23 = "[telegram-inbound]";
|
|
8850
9032
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
8851
9033
|
function configDirName() {
|
|
8852
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
8853
|
-
const brandPath =
|
|
9034
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
9035
|
+
const brandPath = join15(platformRoot2, "config", "brand.json");
|
|
8854
9036
|
if (existsSync10(brandPath)) {
|
|
8855
9037
|
try {
|
|
8856
9038
|
return JSON.parse(readFileSync15(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -8861,7 +9043,7 @@ function configDirName() {
|
|
|
8861
9043
|
}
|
|
8862
9044
|
function secretPath(botType) {
|
|
8863
9045
|
const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
|
|
8864
|
-
return
|
|
9046
|
+
return resolve15(homedir(), configDirName(), filename);
|
|
8865
9047
|
}
|
|
8866
9048
|
async function sendTelegram(botToken, chatId, text) {
|
|
8867
9049
|
try {
|
|
@@ -8876,23 +9058,23 @@ async function sendTelegram(botToken, chatId, text) {
|
|
|
8876
9058
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
8877
9059
|
}
|
|
8878
9060
|
}
|
|
8879
|
-
var
|
|
8880
|
-
|
|
9061
|
+
var app7 = new Hono();
|
|
9062
|
+
app7.post("/", async (c) => {
|
|
8881
9063
|
const botParam = c.req.query("bot");
|
|
8882
9064
|
const botType = botParam === "admin" ? "admin" : botParam === "public" ? "public" : null;
|
|
8883
9065
|
if (!botType) {
|
|
8884
|
-
console.error(`${
|
|
9066
|
+
console.error(`${TAG23} op=reject reason=missing-bot-param`);
|
|
8885
9067
|
return c.json({ ok: false }, 400);
|
|
8886
9068
|
}
|
|
8887
9069
|
const sp = secretPath(botType);
|
|
8888
9070
|
if (!existsSync10(sp)) {
|
|
8889
|
-
console.error(`${
|
|
9071
|
+
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
8890
9072
|
return c.json({ ok: false }, 401);
|
|
8891
9073
|
}
|
|
8892
9074
|
const expected = readFileSync15(sp, "utf-8").trim();
|
|
8893
9075
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
8894
9076
|
if (got !== expected) {
|
|
8895
|
-
console.error(`${
|
|
9077
|
+
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
8896
9078
|
return c.json({ ok: false }, 401);
|
|
8897
9079
|
}
|
|
8898
9080
|
let update;
|
|
@@ -8903,25 +9085,25 @@ app6.post("/", async (c) => {
|
|
|
8903
9085
|
}
|
|
8904
9086
|
const account = resolveAccount();
|
|
8905
9087
|
if (!account) {
|
|
8906
|
-
console.error(`${
|
|
9088
|
+
console.error(`${TAG23} op=reject reason=no-account`);
|
|
8907
9089
|
return c.json({ ok: true }, 200);
|
|
8908
9090
|
}
|
|
8909
9091
|
const decision = routeTelegramUpdate({ update, botType, config: account.config.telegram ?? {} });
|
|
8910
9092
|
if (decision.kind === "ignore") {
|
|
8911
|
-
console.error(`${
|
|
9093
|
+
console.error(`${TAG23} op=ignore reason=${decision.reason}`);
|
|
8912
9094
|
return c.json({ ok: true }, 200);
|
|
8913
9095
|
}
|
|
8914
9096
|
if (decision.kind === "denied") {
|
|
8915
|
-
console.error(`${
|
|
9097
|
+
console.error(`${TAG23} op=denied reason=${decision.reason} agentType=${decision.agentType}`);
|
|
8916
9098
|
return c.json({ ok: true }, 200);
|
|
8917
9099
|
}
|
|
8918
9100
|
const role = decision.agentType === "admin" ? "admin" : "public";
|
|
8919
9101
|
const agentSlug = role === "admin" ? "admin" : resolveDefaultAgentSlug(account.accountDir);
|
|
8920
9102
|
if (!agentSlug) {
|
|
8921
|
-
console.error(`${
|
|
9103
|
+
console.error(`${TAG23} op=reject reason=no-default-agent`);
|
|
8922
9104
|
return c.json({ ok: true }, 200);
|
|
8923
9105
|
}
|
|
8924
|
-
console.error(`${
|
|
9106
|
+
console.error(`${TAG23} op=update accountId=${account.accountId} from=${decision.senderId}`);
|
|
8925
9107
|
const botToken = botType === "admin" ? account.config.telegram?.adminBotToken : account.config.telegram?.publicBotToken;
|
|
8926
9108
|
const { senderId, chatId, text } = decision;
|
|
8927
9109
|
void (async () => {
|
|
@@ -8935,29 +9117,29 @@ app6.post("/", async (c) => {
|
|
|
8935
9117
|
timeoutMs: DISPATCH_TIMEOUT_MS
|
|
8936
9118
|
});
|
|
8937
9119
|
if ("error" in result) {
|
|
8938
|
-
console.error(`${
|
|
9120
|
+
console.error(`${TAG23} op=dispatch-failed from=${senderId} error=${result.error}`);
|
|
8939
9121
|
return;
|
|
8940
9122
|
}
|
|
8941
9123
|
if (!botToken) {
|
|
8942
9124
|
const reason = account.config.telegram ? "no-bot-token" : "no-telegram-config";
|
|
8943
|
-
console.error(`${
|
|
9125
|
+
console.error(`${TAG23} op=reply-dropped reason=${reason} botType=${botType}`);
|
|
8944
9126
|
return;
|
|
8945
9127
|
}
|
|
8946
9128
|
const sent = await sendTelegram(botToken, chatId, result.turnText);
|
|
8947
|
-
console.error(`${
|
|
9129
|
+
console.error(`${TAG23} op=reply-sent from=${senderId} ok=${sent.ok}${sent.ok ? "" : ` error=${sent.error}`}`);
|
|
8948
9130
|
})();
|
|
8949
9131
|
return c.json({ ok: true }, 200);
|
|
8950
9132
|
});
|
|
8951
|
-
var telegram_default =
|
|
9133
|
+
var telegram_default = app7;
|
|
8952
9134
|
|
|
8953
9135
|
// server/routes/onboarding.ts
|
|
8954
9136
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
8955
|
-
import { openSync as
|
|
9137
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync8, writeSync, existsSync as existsSync12, readFileSync as readFileSync17, unlinkSync } from "fs";
|
|
8956
9138
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
8957
9139
|
|
|
8958
9140
|
// ../lib/admins-write/src/index.ts
|
|
8959
|
-
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as
|
|
8960
|
-
import { dirname as
|
|
9141
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
|
|
9142
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
8961
9143
|
function logLine(input, result) {
|
|
8962
9144
|
const userIdShort = input.userId.slice(0, 8);
|
|
8963
9145
|
console.error(
|
|
@@ -8965,7 +9147,7 @@ function logLine(input, result) {
|
|
|
8965
9147
|
);
|
|
8966
9148
|
}
|
|
8967
9149
|
function writeFileAtomic(filePath, contents, mode) {
|
|
8968
|
-
mkdirSync2(
|
|
9150
|
+
mkdirSync2(dirname4(filePath), { recursive: true });
|
|
8969
9151
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
8970
9152
|
writeFileSync7(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
8971
9153
|
renameSync3(tempPath, filePath);
|
|
@@ -8999,7 +9181,7 @@ function writeAdminEntry(input) {
|
|
|
8999
9181
|
return result;
|
|
9000
9182
|
}
|
|
9001
9183
|
try {
|
|
9002
|
-
const accountJsonPath =
|
|
9184
|
+
const accountJsonPath = join16(input.accountDir, "account.json");
|
|
9003
9185
|
if (!existsSync11(accountJsonPath)) {
|
|
9004
9186
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9005
9187
|
}
|
|
@@ -9054,13 +9236,13 @@ function checkAdminAuthInvariant(input) {
|
|
|
9054
9236
|
}
|
|
9055
9237
|
for (const entry of entries) {
|
|
9056
9238
|
if (entry.startsWith(".")) continue;
|
|
9057
|
-
const accountDir =
|
|
9239
|
+
const accountDir = join16(input.accountsDir, entry);
|
|
9058
9240
|
try {
|
|
9059
|
-
if (!
|
|
9241
|
+
if (!statSync6(accountDir).isDirectory()) continue;
|
|
9060
9242
|
} catch {
|
|
9061
9243
|
continue;
|
|
9062
9244
|
}
|
|
9063
|
-
const accountJsonPath =
|
|
9245
|
+
const accountJsonPath = join16(accountDir, "account.json");
|
|
9064
9246
|
if (!existsSync11(accountJsonPath)) continue;
|
|
9065
9247
|
let admins = [];
|
|
9066
9248
|
try {
|
|
@@ -9135,11 +9317,11 @@ async function waitForAuthPage(timeoutMs = 2e4) {
|
|
|
9135
9317
|
}
|
|
9136
9318
|
return false;
|
|
9137
9319
|
}
|
|
9138
|
-
var
|
|
9139
|
-
|
|
9320
|
+
var app8 = new Hono();
|
|
9321
|
+
app8.get("/claude-auth", async (c) => {
|
|
9140
9322
|
return c.json({ authenticated: await checkAuthStatus() });
|
|
9141
9323
|
});
|
|
9142
|
-
|
|
9324
|
+
app8.post("/claude-auth", async (c) => {
|
|
9143
9325
|
let body = {};
|
|
9144
9326
|
try {
|
|
9145
9327
|
body = await c.req.json();
|
|
@@ -9177,7 +9359,7 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9177
9359
|
}
|
|
9178
9360
|
ensureLogDir();
|
|
9179
9361
|
writeFileSync8(logPath("claude-auth"), "");
|
|
9180
|
-
const claudeAuthLogFd =
|
|
9362
|
+
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
9181
9363
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
9182
9364
|
if (process.platform === "darwin") {
|
|
9183
9365
|
vncLog("claude-auth", { action: "start", transport: "native", platform: "darwin" });
|
|
@@ -9187,7 +9369,7 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9187
9369
|
claudeProc2.unref();
|
|
9188
9370
|
claudeProc2.stdout?.on("data", onClaudeOutput);
|
|
9189
9371
|
claudeProc2.stderr?.on("data", onClaudeOutput);
|
|
9190
|
-
claudeProc2.once("close", () =>
|
|
9372
|
+
claudeProc2.once("close", () => closeSync3(claudeAuthLogFd));
|
|
9191
9373
|
return c.json({ started: true, transport: "native" });
|
|
9192
9374
|
}
|
|
9193
9375
|
if (transport === "vnc") {
|
|
@@ -9205,11 +9387,11 @@ app7.post("/claude-auth", async (c) => {
|
|
|
9205
9387
|
claudeProc.unref();
|
|
9206
9388
|
claudeProc.stdout?.on("data", onClaudeOutput);
|
|
9207
9389
|
claudeProc.stderr?.on("data", onClaudeOutput);
|
|
9208
|
-
claudeProc.once("close", () =>
|
|
9390
|
+
claudeProc.once("close", () => closeSync3(claudeAuthLogFd));
|
|
9209
9391
|
await waitForAuthPage(2e4);
|
|
9210
9392
|
return c.json({ started: true, transport });
|
|
9211
9393
|
});
|
|
9212
|
-
|
|
9394
|
+
app8.post("/set-pin", async (c) => {
|
|
9213
9395
|
let existingUsers = null;
|
|
9214
9396
|
try {
|
|
9215
9397
|
existingUsers = readUsersFile2();
|
|
@@ -9311,7 +9493,7 @@ ${body.pin}
|
|
|
9311
9493
|
}
|
|
9312
9494
|
return c.json({ ok: true });
|
|
9313
9495
|
});
|
|
9314
|
-
|
|
9496
|
+
app8.delete("/set-pin", async (c) => {
|
|
9315
9497
|
let users = null;
|
|
9316
9498
|
try {
|
|
9317
9499
|
users = readUsersFile2();
|
|
@@ -9345,12 +9527,12 @@ app7.delete("/set-pin", async (c) => {
|
|
|
9345
9527
|
}
|
|
9346
9528
|
return c.json({ ok: true });
|
|
9347
9529
|
});
|
|
9348
|
-
var onboarding_default =
|
|
9530
|
+
var onboarding_default = app8;
|
|
9349
9531
|
|
|
9350
9532
|
// server/routes/client-error.ts
|
|
9351
|
-
import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as
|
|
9352
|
-
import { join as
|
|
9353
|
-
var CLIENT_ERRORS_LOG =
|
|
9533
|
+
import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync7 } from "fs";
|
|
9534
|
+
import { join as join17 } from "path";
|
|
9535
|
+
var CLIENT_ERRORS_LOG = join17(LOG_DIR, "client-errors.log");
|
|
9354
9536
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
9355
9537
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
9356
9538
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -9394,15 +9576,15 @@ function stackHead(stack) {
|
|
|
9394
9576
|
function rotateIfNeeded() {
|
|
9395
9577
|
try {
|
|
9396
9578
|
if (!existsSync13(CLIENT_ERRORS_LOG)) return;
|
|
9397
|
-
const stats =
|
|
9579
|
+
const stats = statSync7(CLIENT_ERRORS_LOG);
|
|
9398
9580
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
9399
9581
|
renameSync4(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
9400
9582
|
} catch (err) {
|
|
9401
9583
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9402
9584
|
}
|
|
9403
9585
|
}
|
|
9404
|
-
var
|
|
9405
|
-
|
|
9586
|
+
var app9 = new Hono();
|
|
9587
|
+
app9.post("/", async (c) => {
|
|
9406
9588
|
const client = resolveClientIp(
|
|
9407
9589
|
c.env?.incoming?.socket?.remoteAddress,
|
|
9408
9590
|
c.req.header("x-forwarded-for")
|
|
@@ -9504,7 +9686,7 @@ app8.post("/", async (c) => {
|
|
|
9504
9686
|
}
|
|
9505
9687
|
return c.json({ ok: true });
|
|
9506
9688
|
});
|
|
9507
|
-
var client_error_default =
|
|
9689
|
+
var client_error_default = app9;
|
|
9508
9690
|
|
|
9509
9691
|
// server/routes/admin/session.ts
|
|
9510
9692
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -9562,8 +9744,8 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
9562
9744
|
sessionId: initialSessionId
|
|
9563
9745
|
};
|
|
9564
9746
|
}
|
|
9565
|
-
var
|
|
9566
|
-
|
|
9747
|
+
var app10 = new Hono();
|
|
9748
|
+
app10.get("/", async (c) => {
|
|
9567
9749
|
const signedSessionToken = c.req.query("session_key");
|
|
9568
9750
|
if (!signedSessionToken) {
|
|
9569
9751
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
@@ -9609,7 +9791,7 @@ app9.get("/", async (c) => {
|
|
|
9609
9791
|
sessionId: getSessionIdForSession(cacheKey) ?? null
|
|
9610
9792
|
});
|
|
9611
9793
|
});
|
|
9612
|
-
|
|
9794
|
+
app10.post("/", async (c) => {
|
|
9613
9795
|
let body;
|
|
9614
9796
|
try {
|
|
9615
9797
|
body = await c.req.json();
|
|
@@ -9672,20 +9854,20 @@ app9.post("/", async (c) => {
|
|
|
9672
9854
|
const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
|
|
9673
9855
|
return c.json(payload);
|
|
9674
9856
|
});
|
|
9675
|
-
var session_default =
|
|
9857
|
+
var session_default = app10;
|
|
9676
9858
|
|
|
9677
9859
|
// server/routes/admin/logs.ts
|
|
9678
|
-
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as
|
|
9679
|
-
import { resolve as
|
|
9860
|
+
import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
|
|
9861
|
+
import { resolve as resolve16, basename as basename5 } from "path";
|
|
9680
9862
|
|
|
9681
9863
|
// app/lib/logs-read-resolve.ts
|
|
9682
9864
|
import { existsSync as existsSync14 } from "fs";
|
|
9683
|
-
import { join as
|
|
9865
|
+
import { join as join18 } from "path";
|
|
9684
9866
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9685
9867
|
const tried = [filename];
|
|
9686
9868
|
const hits = [];
|
|
9687
9869
|
for (const dir of logDirs) {
|
|
9688
|
-
const fullPath =
|
|
9870
|
+
const fullPath = join18(dir, filename);
|
|
9689
9871
|
if (existsSync14(fullPath)) {
|
|
9690
9872
|
hits.push({ path: fullPath, dir });
|
|
9691
9873
|
}
|
|
@@ -9695,27 +9877,27 @@ function resolveSessionLogPaths(filename, logDirs) {
|
|
|
9695
9877
|
|
|
9696
9878
|
// server/routes/admin/logs.ts
|
|
9697
9879
|
var TAIL_BYTES = 8192;
|
|
9698
|
-
var
|
|
9699
|
-
|
|
9880
|
+
var app11 = new Hono();
|
|
9881
|
+
app11.get("/", async (c) => {
|
|
9700
9882
|
const fileParam = c.req.query("file");
|
|
9701
9883
|
const typeParam = c.req.query("type");
|
|
9702
9884
|
const sessionIdParam = c.req.query("sessionId");
|
|
9703
9885
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
9704
9886
|
const download = c.req.query("download") === "1";
|
|
9705
9887
|
const account = resolveAccount();
|
|
9706
|
-
const accountLogDir = account ?
|
|
9888
|
+
const accountLogDir = account ? resolve16(account.accountDir, "logs") : null;
|
|
9707
9889
|
const logDirs = [];
|
|
9708
9890
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
9709
9891
|
logDirs.push(LOG_DIR);
|
|
9710
9892
|
if (fileParam) {
|
|
9711
|
-
const safe =
|
|
9893
|
+
const safe = basename5(fileParam);
|
|
9712
9894
|
const searched = [];
|
|
9713
9895
|
for (const dir of logDirs) {
|
|
9714
|
-
const filePath =
|
|
9896
|
+
const filePath = resolve16(dir, safe);
|
|
9715
9897
|
searched.push(filePath);
|
|
9716
9898
|
try {
|
|
9717
9899
|
const buffer = readFileSync18(filePath);
|
|
9718
|
-
const onDiskBytes =
|
|
9900
|
+
const onDiskBytes = statSync8(filePath).size;
|
|
9719
9901
|
const headers = {
|
|
9720
9902
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9721
9903
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -9778,9 +9960,9 @@ app10.get("/", async (c) => {
|
|
|
9778
9960
|
if (hit) {
|
|
9779
9961
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
9780
9962
|
try {
|
|
9781
|
-
const filename =
|
|
9963
|
+
const filename = basename5(hit.path);
|
|
9782
9964
|
const buffer = readFileSync18(hit.path);
|
|
9783
|
-
const onDiskBytes =
|
|
9965
|
+
const onDiskBytes = statSync8(hit.path).size;
|
|
9784
9966
|
const headers = {
|
|
9785
9967
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9786
9968
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -9823,10 +10005,10 @@ app10.get("/", async (c) => {
|
|
|
9823
10005
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
9824
10006
|
continue;
|
|
9825
10007
|
}
|
|
9826
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime:
|
|
10008
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync8(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
9827
10009
|
seen.add(name);
|
|
9828
10010
|
try {
|
|
9829
|
-
const content = readFileSync18(
|
|
10011
|
+
const content = readFileSync18(resolve16(dir, name));
|
|
9830
10012
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
9831
10013
|
logs[name] = tail.trim() || "(empty)";
|
|
9832
10014
|
} catch (err) {
|
|
@@ -9838,12 +10020,12 @@ app10.get("/", async (c) => {
|
|
|
9838
10020
|
}
|
|
9839
10021
|
return c.json({ logs });
|
|
9840
10022
|
});
|
|
9841
|
-
var logs_default =
|
|
10023
|
+
var logs_default = app11;
|
|
9842
10024
|
|
|
9843
10025
|
// server/routes/admin/claude-info.ts
|
|
9844
10026
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
9845
|
-
var
|
|
9846
|
-
|
|
10027
|
+
var app12 = new Hono();
|
|
10028
|
+
app12.get("/", (c) => {
|
|
9847
10029
|
let version = "unknown";
|
|
9848
10030
|
try {
|
|
9849
10031
|
const raw = execFileSync3("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
@@ -9861,14 +10043,14 @@ app11.get("/", (c) => {
|
|
|
9861
10043
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
9862
10044
|
return c.json({ version, account, model, thinkingView });
|
|
9863
10045
|
});
|
|
9864
|
-
var claude_info_default =
|
|
10046
|
+
var claude_info_default = app12;
|
|
9865
10047
|
|
|
9866
10048
|
// server/routes/admin/attachment.ts
|
|
9867
10049
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
9868
10050
|
import { existsSync as existsSync16 } from "fs";
|
|
9869
|
-
import { resolve as
|
|
9870
|
-
var
|
|
9871
|
-
|
|
10051
|
+
import { resolve as resolve17 } from "path";
|
|
10052
|
+
var app13 = new Hono();
|
|
10053
|
+
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
9872
10054
|
const attachmentId = c.req.param("attachmentId");
|
|
9873
10055
|
const cacheKey = c.var.cacheKey;
|
|
9874
10056
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -9878,11 +10060,11 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9878
10060
|
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(attachmentId)) {
|
|
9879
10061
|
return new Response("Not found", { status: 404 });
|
|
9880
10062
|
}
|
|
9881
|
-
const dir =
|
|
10063
|
+
const dir = resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
9882
10064
|
if (!existsSync16(dir)) {
|
|
9883
10065
|
return new Response("Not found", { status: 404 });
|
|
9884
10066
|
}
|
|
9885
|
-
const metaPath =
|
|
10067
|
+
const metaPath = resolve17(dir, `${attachmentId}.meta.json`);
|
|
9886
10068
|
if (!existsSync16(metaPath)) {
|
|
9887
10069
|
return new Response("Not found", { status: 404 });
|
|
9888
10070
|
}
|
|
@@ -9897,7 +10079,7 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9897
10079
|
if (!dataFile) {
|
|
9898
10080
|
return new Response("Not found", { status: 404 });
|
|
9899
10081
|
}
|
|
9900
|
-
const filePath =
|
|
10082
|
+
const filePath = resolve17(dir, dataFile);
|
|
9901
10083
|
const buffer = await readFile2(filePath);
|
|
9902
10084
|
return new Response(new Uint8Array(buffer), {
|
|
9903
10085
|
headers: {
|
|
@@ -9907,16 +10089,16 @@ app12.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
9907
10089
|
}
|
|
9908
10090
|
});
|
|
9909
10091
|
});
|
|
9910
|
-
var attachment_default =
|
|
10092
|
+
var attachment_default = app13;
|
|
9911
10093
|
|
|
9912
10094
|
// server/routes/admin/agents.ts
|
|
9913
|
-
import { resolve as
|
|
10095
|
+
import { resolve as resolve18 } from "path";
|
|
9914
10096
|
import { readdirSync as readdirSync11, readFileSync as readFileSync19, existsSync as existsSync17, rmSync } from "fs";
|
|
9915
|
-
var
|
|
9916
|
-
|
|
10097
|
+
var app14 = new Hono();
|
|
10098
|
+
app14.get("/", (c) => {
|
|
9917
10099
|
const account = resolveAccount();
|
|
9918
10100
|
if (!account) return c.json({ agents: [] });
|
|
9919
|
-
const agentsDir =
|
|
10101
|
+
const agentsDir = resolve18(account.accountDir, "agents");
|
|
9920
10102
|
if (!existsSync17(agentsDir)) return c.json({ agents: [] });
|
|
9921
10103
|
const agents = [];
|
|
9922
10104
|
try {
|
|
@@ -9924,7 +10106,7 @@ app13.get("/", (c) => {
|
|
|
9924
10106
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
9925
10107
|
if (!entry.isDirectory()) continue;
|
|
9926
10108
|
if (entry.name === "admin") continue;
|
|
9927
|
-
const configPath2 =
|
|
10109
|
+
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
9928
10110
|
if (!existsSync17(configPath2)) continue;
|
|
9929
10111
|
try {
|
|
9930
10112
|
const config = JSON.parse(readFileSync19(configPath2, "utf-8"));
|
|
@@ -9943,7 +10125,7 @@ app13.get("/", (c) => {
|
|
|
9943
10125
|
}
|
|
9944
10126
|
return c.json({ agents });
|
|
9945
10127
|
});
|
|
9946
|
-
|
|
10128
|
+
app14.delete("/:slug", async (c) => {
|
|
9947
10129
|
const slug = c.req.param("slug");
|
|
9948
10130
|
const account = resolveAccount();
|
|
9949
10131
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -9953,7 +10135,7 @@ app13.delete("/:slug", async (c) => {
|
|
|
9953
10135
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9954
10136
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9955
10137
|
}
|
|
9956
|
-
const agentDir =
|
|
10138
|
+
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
9957
10139
|
if (!existsSync17(agentDir)) {
|
|
9958
10140
|
return c.json({ error: "Agent not found" }, 404);
|
|
9959
10141
|
}
|
|
@@ -9973,7 +10155,7 @@ app13.delete("/:slug", async (c) => {
|
|
|
9973
10155
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
9974
10156
|
}
|
|
9975
10157
|
});
|
|
9976
|
-
|
|
10158
|
+
app14.post("/:slug/project", async (c) => {
|
|
9977
10159
|
const slug = c.req.param("slug");
|
|
9978
10160
|
const account = resolveAccount();
|
|
9979
10161
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -9983,7 +10165,7 @@ app13.post("/:slug/project", async (c) => {
|
|
|
9983
10165
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
9984
10166
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
9985
10167
|
}
|
|
9986
|
-
const agentDir =
|
|
10168
|
+
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
9987
10169
|
if (!existsSync17(agentDir)) {
|
|
9988
10170
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
9989
10171
|
}
|
|
@@ -9995,7 +10177,7 @@ app13.post("/:slug/project", async (c) => {
|
|
|
9995
10177
|
return c.json({ error: `Projection failed: ${msg}` }, 500);
|
|
9996
10178
|
}
|
|
9997
10179
|
});
|
|
9998
|
-
var agents_default =
|
|
10180
|
+
var agents_default = app14;
|
|
9999
10181
|
|
|
10000
10182
|
// server/routes/admin/sessions.ts
|
|
10001
10183
|
import crypto2 from "crypto";
|
|
@@ -10267,8 +10449,8 @@ function formatAge(updatedAtStr) {
|
|
|
10267
10449
|
return "unknown";
|
|
10268
10450
|
}
|
|
10269
10451
|
}
|
|
10270
|
-
var
|
|
10271
|
-
|
|
10452
|
+
var app15 = new Hono();
|
|
10453
|
+
app15.get("/", requireAdminSession, async (c) => {
|
|
10272
10454
|
const cacheKey = c.var.cacheKey;
|
|
10273
10455
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10274
10456
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10298,7 +10480,7 @@ app14.get("/", requireAdminSession, async (c) => {
|
|
|
10298
10480
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
10299
10481
|
}
|
|
10300
10482
|
});
|
|
10301
|
-
|
|
10483
|
+
app15.post("/new", requireAdminSession, async (c) => {
|
|
10302
10484
|
const oldCacheKey = c.var.cacheKey;
|
|
10303
10485
|
console.log(`[admin-chat] new-conversation outcome=ingress cacheKey=${oldCacheKey.slice(0, 8)}`);
|
|
10304
10486
|
const accountId = getAccountIdForSession(oldCacheKey);
|
|
@@ -10315,7 +10497,7 @@ app14.post("/new", requireAdminSession, async (c) => {
|
|
|
10315
10497
|
console.log(`[admin-chat] new-conversation outcome=ok oldKey=${oldCacheKey.slice(0, 8)} newKey=${newCacheKey.slice(0, 8)}`);
|
|
10316
10498
|
return c.json({ session_key: newSignedSessionToken, sessionId: null });
|
|
10317
10499
|
});
|
|
10318
|
-
|
|
10500
|
+
app15.post("/switch", requireAdminSession, async (c) => {
|
|
10319
10501
|
const cacheKey = c.var.cacheKey;
|
|
10320
10502
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10321
10503
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -10343,7 +10525,7 @@ app14.post("/switch", requireAdminSession, async (c) => {
|
|
|
10343
10525
|
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetSessionId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
10344
10526
|
return c.json({ session_key: targetSignedSessionToken, sessionId: targetSessionId });
|
|
10345
10527
|
});
|
|
10346
|
-
|
|
10528
|
+
app15.delete("/:id", requireAdminSession, async (c) => {
|
|
10347
10529
|
const sessionId = c.req.param("id");
|
|
10348
10530
|
const cacheKey = c.var.cacheKey;
|
|
10349
10531
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -10388,7 +10570,7 @@ app14.delete("/:id", requireAdminSession, async (c) => {
|
|
|
10388
10570
|
500
|
|
10389
10571
|
);
|
|
10390
10572
|
});
|
|
10391
|
-
|
|
10573
|
+
app15.post("/:id/resume", async (c) => {
|
|
10392
10574
|
const sessionId = c.req.param("id");
|
|
10393
10575
|
const t0 = Date.now();
|
|
10394
10576
|
const signedSessionToken = c.req.query("session_key") ?? "";
|
|
@@ -10657,7 +10839,7 @@ app14.post("/:id/resume", async (c) => {
|
|
|
10657
10839
|
}
|
|
10658
10840
|
});
|
|
10659
10841
|
});
|
|
10660
|
-
|
|
10842
|
+
app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
10661
10843
|
const sessionId = c.req.param("id");
|
|
10662
10844
|
const cacheKey = c.var.cacheKey;
|
|
10663
10845
|
let body;
|
|
@@ -10683,11 +10865,11 @@ app14.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10683
10865
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
10684
10866
|
}
|
|
10685
10867
|
});
|
|
10686
|
-
var sessions_default =
|
|
10868
|
+
var sessions_default = app15;
|
|
10687
10869
|
|
|
10688
10870
|
// app/lib/claude-agent/spawn-context.ts
|
|
10689
|
-
import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as
|
|
10690
|
-
import { dirname as
|
|
10871
|
+
import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync9 } from "fs";
|
|
10872
|
+
import { dirname as dirname5, resolve as resolve19, join as join19 } from "path";
|
|
10691
10873
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10692
10874
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10693
10875
|
try {
|
|
@@ -10716,8 +10898,8 @@ function frontmatterField(manifest, field2) {
|
|
|
10716
10898
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10717
10899
|
const out = /* @__PURE__ */ new Map();
|
|
10718
10900
|
const candidates = [
|
|
10719
|
-
|
|
10720
|
-
|
|
10901
|
+
join19(pluginDir, "mcp/dist/index.js"),
|
|
10902
|
+
join19(pluginDir, "mcp/src/index.ts")
|
|
10721
10903
|
];
|
|
10722
10904
|
let raw = null;
|
|
10723
10905
|
for (const path2 of candidates) {
|
|
@@ -10772,26 +10954,26 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
10772
10954
|
}
|
|
10773
10955
|
function listPluginDirs() {
|
|
10774
10956
|
const out = /* @__PURE__ */ new Map();
|
|
10775
|
-
const platformPlugins =
|
|
10957
|
+
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
10776
10958
|
if (existsSync19(platformPlugins)) {
|
|
10777
10959
|
for (const name of readdirSync12(platformPlugins)) {
|
|
10778
|
-
const dir =
|
|
10960
|
+
const dir = join19(platformPlugins, name);
|
|
10779
10961
|
try {
|
|
10780
|
-
if (
|
|
10962
|
+
if (statSync9(dir).isDirectory()) out.set(name, dir);
|
|
10781
10963
|
} catch {
|
|
10782
10964
|
}
|
|
10783
10965
|
}
|
|
10784
10966
|
}
|
|
10785
|
-
const premiumRoot =
|
|
10967
|
+
const premiumRoot = resolve19(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
10786
10968
|
if (existsSync19(premiumRoot)) {
|
|
10787
10969
|
for (const bundle of readdirSync12(premiumRoot)) {
|
|
10788
|
-
const bundlePlugins =
|
|
10970
|
+
const bundlePlugins = join19(premiumRoot, bundle, "plugins");
|
|
10789
10971
|
if (!existsSync19(bundlePlugins)) continue;
|
|
10790
10972
|
try {
|
|
10791
10973
|
for (const name of readdirSync12(bundlePlugins)) {
|
|
10792
|
-
const dir =
|
|
10974
|
+
const dir = join19(bundlePlugins, name);
|
|
10793
10975
|
try {
|
|
10794
|
-
if (
|
|
10976
|
+
if (statSync9(dir).isDirectory()) out.set(name, dir);
|
|
10795
10977
|
} catch {
|
|
10796
10978
|
}
|
|
10797
10979
|
}
|
|
@@ -10802,7 +10984,7 @@ function listPluginDirs() {
|
|
|
10802
10984
|
return out;
|
|
10803
10985
|
}
|
|
10804
10986
|
function readEnabledPlugins(accountId) {
|
|
10805
|
-
const accountFile =
|
|
10987
|
+
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10806
10988
|
if (!existsSync19(accountFile)) return /* @__PURE__ */ new Set();
|
|
10807
10989
|
try {
|
|
10808
10990
|
const parsed = JSON.parse(readFileSync20(accountFile, "utf-8"));
|
|
@@ -10832,7 +11014,7 @@ function computeActivePlugins(accountId) {
|
|
|
10832
11014
|
for (const name of Array.from(enabled).sort()) {
|
|
10833
11015
|
const dir = pluginDirs.get(name);
|
|
10834
11016
|
if (!dir) continue;
|
|
10835
|
-
const fm = readFrontmatter(
|
|
11017
|
+
const fm = readFrontmatter(join19(dir, "PLUGIN.md"));
|
|
10836
11018
|
if (!fm) continue;
|
|
10837
11019
|
const description = frontmatterField(`---
|
|
10838
11020
|
${fm}
|
|
@@ -10849,7 +11031,7 @@ ${fm}
|
|
|
10849
11031
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
10850
11032
|
);
|
|
10851
11033
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
10852
|
-
const hasSource = existsSync19(
|
|
11034
|
+
const hasSource = existsSync19(join19(dir, "mcp/dist/index.js")) || existsSync19(join19(dir, "mcp/src/index.ts"));
|
|
10853
11035
|
if (hasSource) {
|
|
10854
11036
|
console.warn(
|
|
10855
11037
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -10859,7 +11041,7 @@ ${fm}
|
|
|
10859
11041
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
10860
11042
|
const skills = [];
|
|
10861
11043
|
for (const relPath of skillPaths) {
|
|
10862
|
-
const skillPath =
|
|
11044
|
+
const skillPath = join19(dir, relPath);
|
|
10863
11045
|
const skillFm = readFrontmatter(skillPath);
|
|
10864
11046
|
if (!skillFm) continue;
|
|
10865
11047
|
const skillName = frontmatterField(`---
|
|
@@ -10875,7 +11057,7 @@ ${skillFm}
|
|
|
10875
11057
|
return out;
|
|
10876
11058
|
}
|
|
10877
11059
|
function computeSpecialistDomains(accountId) {
|
|
10878
|
-
const specialistsDir =
|
|
11060
|
+
const specialistsDir = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
10879
11061
|
if (!existsSync19(specialistsDir)) return [];
|
|
10880
11062
|
let entries;
|
|
10881
11063
|
try {
|
|
@@ -10888,10 +11070,10 @@ function computeSpecialistDomains(accountId) {
|
|
|
10888
11070
|
const resolveDesc = (qualified) => {
|
|
10889
11071
|
if (!qualified.startsWith("mcp__")) return void 0;
|
|
10890
11072
|
const rest = qualified.slice(5);
|
|
10891
|
-
const
|
|
10892
|
-
if (
|
|
10893
|
-
const plugin = rest.slice(0,
|
|
10894
|
-
const tool = rest.slice(
|
|
11073
|
+
const sep9 = rest.indexOf("__");
|
|
11074
|
+
if (sep9 < 0) return void 0;
|
|
11075
|
+
const plugin = rest.slice(0, sep9);
|
|
11076
|
+
const tool = rest.slice(sep9 + 2);
|
|
10895
11077
|
let map = descByPlugin.get(plugin);
|
|
10896
11078
|
if (!map) {
|
|
10897
11079
|
const dir = pluginDirs.get(plugin);
|
|
@@ -10903,7 +11085,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
10903
11085
|
const out = [];
|
|
10904
11086
|
for (const file of entries.sort()) {
|
|
10905
11087
|
if (!file.endsWith(".md")) continue;
|
|
10906
|
-
const fm = readFrontmatter(
|
|
11088
|
+
const fm = readFrontmatter(join19(specialistsDir, file));
|
|
10907
11089
|
if (!fm) continue;
|
|
10908
11090
|
const wrapped = `---
|
|
10909
11091
|
${fm}
|
|
@@ -10921,7 +11103,7 @@ ${fm}
|
|
|
10921
11103
|
return out;
|
|
10922
11104
|
}
|
|
10923
11105
|
function computeDormantPlugins(accountId) {
|
|
10924
|
-
const accountFile =
|
|
11106
|
+
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
10925
11107
|
if (!existsSync19(accountFile)) return [];
|
|
10926
11108
|
let enabled;
|
|
10927
11109
|
try {
|
|
@@ -10936,7 +11118,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10936
11118
|
);
|
|
10937
11119
|
return [];
|
|
10938
11120
|
}
|
|
10939
|
-
const pluginsDir =
|
|
11121
|
+
const pluginsDir = resolve19(PLATFORM_ROOT, "plugins");
|
|
10940
11122
|
if (!existsSync19(pluginsDir)) return [];
|
|
10941
11123
|
let entries;
|
|
10942
11124
|
try {
|
|
@@ -10947,7 +11129,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10947
11129
|
const out = [];
|
|
10948
11130
|
for (const name of entries) {
|
|
10949
11131
|
if (enabled.has(name)) continue;
|
|
10950
|
-
const manifestPath =
|
|
11132
|
+
const manifestPath = resolve19(pluginsDir, name, "PLUGIN.md");
|
|
10951
11133
|
if (!existsSync19(manifestPath)) continue;
|
|
10952
11134
|
let manifest;
|
|
10953
11135
|
try {
|
|
@@ -10966,7 +11148,7 @@ function computeDormantPlugins(accountId) {
|
|
|
10966
11148
|
|
|
10967
11149
|
// server/routes/admin/claude-sessions.ts
|
|
10968
11150
|
import { existsSync as existsSync20, readFileSync as readFileSync21 } from "fs";
|
|
10969
|
-
import { resolve as
|
|
11151
|
+
import { resolve as resolve20 } from "path";
|
|
10970
11152
|
function readTunnelState(brandConfigDir) {
|
|
10971
11153
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
10972
11154
|
if (!existsSync20(statePath)) return null;
|
|
@@ -10982,10 +11164,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
10982
11164
|
}
|
|
10983
11165
|
}
|
|
10984
11166
|
function resolveTunnelUrl() {
|
|
10985
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
11167
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
10986
11168
|
let brand;
|
|
10987
11169
|
try {
|
|
10988
|
-
brand = JSON.parse(readFileSync21(
|
|
11170
|
+
brand = JSON.parse(readFileSync21(resolve20(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
10989
11171
|
} catch {
|
|
10990
11172
|
return null;
|
|
10991
11173
|
}
|
|
@@ -10996,7 +11178,7 @@ function resolveTunnelUrl() {
|
|
|
10996
11178
|
if (!state) return null;
|
|
10997
11179
|
return `https://${hostname2}.${state.domain}`;
|
|
10998
11180
|
}
|
|
10999
|
-
var
|
|
11181
|
+
var TAG24 = "[claude-session-manager:wrapper]";
|
|
11000
11182
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
11001
11183
|
const auth = await ensureAuth();
|
|
11002
11184
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -11008,18 +11190,18 @@ async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
|
11008
11190
|
503
|
|
11009
11191
|
);
|
|
11010
11192
|
}
|
|
11011
|
-
var
|
|
11193
|
+
var app16 = new Hono();
|
|
11012
11194
|
async function performSpawnWithInitialMessage(args) {
|
|
11013
11195
|
const ownerStart = Date.now();
|
|
11014
11196
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
11015
11197
|
const ownerMs = Date.now() - ownerStart;
|
|
11016
11198
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
11017
|
-
console.log(`${
|
|
11199
|
+
console.log(`${TAG24} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
11018
11200
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
11019
11201
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
11020
11202
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
11021
11203
|
const tunnelUrl = resolveTunnelUrl();
|
|
11022
|
-
console.log(`${
|
|
11204
|
+
console.log(`${TAG24} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
11023
11205
|
const upstreamPayload = JSON.stringify({
|
|
11024
11206
|
senderId: args.senderId,
|
|
11025
11207
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -11046,24 +11228,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
11046
11228
|
// unshapely values.
|
|
11047
11229
|
conversationNodeId: args.conversationNodeId
|
|
11048
11230
|
});
|
|
11049
|
-
console.log(`${
|
|
11231
|
+
console.log(`${TAG24} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
11050
11232
|
const forwardStart = Date.now();
|
|
11051
11233
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
11052
11234
|
method: "POST",
|
|
11053
11235
|
headers: { "content-type": "application/json" },
|
|
11054
11236
|
body: upstreamPayload
|
|
11055
11237
|
}).catch((err) => {
|
|
11056
|
-
console.error(`${
|
|
11238
|
+
console.error(`${TAG24} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
11057
11239
|
return null;
|
|
11058
11240
|
});
|
|
11059
11241
|
if (!upstream) return {
|
|
11060
11242
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
11061
11243
|
claudeSessionId: null
|
|
11062
11244
|
};
|
|
11063
|
-
console.log(`${
|
|
11245
|
+
console.log(`${TAG24} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
11064
11246
|
if (args.initialMessage) {
|
|
11065
11247
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
11066
|
-
console.log(`${
|
|
11248
|
+
console.log(`${TAG24} initial-message-inlined bytes=${inputBytes}`);
|
|
11067
11249
|
}
|
|
11068
11250
|
const bodyText = await upstream.text().catch(() => "");
|
|
11069
11251
|
let claudeSessionId = null;
|
|
@@ -11085,8 +11267,8 @@ function mintTranscriptEdge(sessionId, claudeSessionId, accountId) {
|
|
|
11085
11267
|
if (!sessionId || !claudeSessionId) return;
|
|
11086
11268
|
void linkConversationTranscript(sessionId, claudeSessionId, accountId);
|
|
11087
11269
|
}
|
|
11088
|
-
|
|
11089
|
-
|
|
11270
|
+
app16.use("*", requireAdminSession);
|
|
11271
|
+
app16.post("/", async (c) => {
|
|
11090
11272
|
const routeStart = Date.now();
|
|
11091
11273
|
const cacheKey = c.get("cacheKey") ?? "";
|
|
11092
11274
|
let body = {};
|
|
@@ -11098,7 +11280,7 @@ app15.post("/", async (c) => {
|
|
|
11098
11280
|
if (refusal) return refusal;
|
|
11099
11281
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
11100
11282
|
if (!senderId) {
|
|
11101
|
-
console.error(`${
|
|
11283
|
+
console.error(`${TAG24} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
11102
11284
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
11103
11285
|
}
|
|
11104
11286
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -11107,7 +11289,7 @@ app15.post("/", async (c) => {
|
|
|
11107
11289
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
11108
11290
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
11109
11291
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
11110
|
-
console.log(`${
|
|
11292
|
+
console.log(`${TAG24} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
11111
11293
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
11112
11294
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
11113
11295
|
senderId,
|
|
@@ -11126,24 +11308,24 @@ app15.post("/", async (c) => {
|
|
|
11126
11308
|
claudeSessionId,
|
|
11127
11309
|
senderId
|
|
11128
11310
|
);
|
|
11129
|
-
console.log(`${
|
|
11311
|
+
console.log(`${TAG24} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
11130
11312
|
return response;
|
|
11131
11313
|
});
|
|
11132
|
-
var claude_sessions_default =
|
|
11314
|
+
var claude_sessions_default = app16;
|
|
11133
11315
|
|
|
11134
11316
|
// server/routes/admin/log-ingest.ts
|
|
11135
|
-
var
|
|
11317
|
+
var TAG25 = "[log-ingest]";
|
|
11136
11318
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
11137
11319
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
11138
11320
|
var MAX_LINE_BYTES = 4096;
|
|
11139
|
-
var
|
|
11321
|
+
var app17 = new Hono();
|
|
11140
11322
|
function isLoopbackAddr(addr) {
|
|
11141
11323
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
11142
11324
|
}
|
|
11143
|
-
|
|
11325
|
+
app17.post("/", async (c) => {
|
|
11144
11326
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
11145
11327
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
11146
|
-
console.error(`${
|
|
11328
|
+
console.error(`${TAG25} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
11147
11329
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11148
11330
|
}
|
|
11149
11331
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -11152,7 +11334,7 @@ app16.post("/", async (c) => {
|
|
|
11152
11334
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
11153
11335
|
const offender = tokens.find((t) => !isLoopbackAddr(t));
|
|
11154
11336
|
if (offender !== void 0) {
|
|
11155
|
-
console.error(`${
|
|
11337
|
+
console.error(`${TAG25} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
11156
11338
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11157
11339
|
}
|
|
11158
11340
|
}
|
|
@@ -11183,7 +11365,7 @@ app16.post("/", async (c) => {
|
|
|
11183
11365
|
else console.log(formatted);
|
|
11184
11366
|
return c.json({ ok: true }, 200);
|
|
11185
11367
|
});
|
|
11186
|
-
var log_ingest_default =
|
|
11368
|
+
var log_ingest_default = app17;
|
|
11187
11369
|
|
|
11188
11370
|
// server/routes/admin/events.ts
|
|
11189
11371
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -11192,20 +11374,20 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
11192
11374
|
"device-url:vnc-surface-shown",
|
|
11193
11375
|
"device-url:malformed"
|
|
11194
11376
|
]);
|
|
11195
|
-
var
|
|
11196
|
-
|
|
11197
|
-
const
|
|
11377
|
+
var app18 = new Hono();
|
|
11378
|
+
app18.post("/", async (c) => {
|
|
11379
|
+
const TAG34 = "[admin:events]";
|
|
11198
11380
|
let body;
|
|
11199
11381
|
try {
|
|
11200
11382
|
body = await c.req.json();
|
|
11201
11383
|
} catch (err) {
|
|
11202
11384
|
const detail = err instanceof Error ? err.message : String(err);
|
|
11203
|
-
console.error(`${
|
|
11385
|
+
console.error(`${TAG34} reject reason=body-not-json detail=${detail}`);
|
|
11204
11386
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
11205
11387
|
}
|
|
11206
11388
|
const event = typeof body.event === "string" ? body.event : "";
|
|
11207
11389
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
11208
|
-
console.error(`${
|
|
11390
|
+
console.error(`${TAG34} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
11209
11391
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
11210
11392
|
}
|
|
11211
11393
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -11224,13 +11406,13 @@ app17.post("/", async (c) => {
|
|
|
11224
11406
|
console.error(`[${event}] ${formatted}`);
|
|
11225
11407
|
return c.json({ ok: true });
|
|
11226
11408
|
});
|
|
11227
|
-
var events_default =
|
|
11409
|
+
var events_default = app18;
|
|
11228
11410
|
|
|
11229
11411
|
// server/routes/admin/files.ts
|
|
11230
11412
|
import { createReadStream as createReadStream2 } from "fs";
|
|
11231
11413
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
11232
11414
|
import { realpathSync as realpathSync4 } from "fs";
|
|
11233
|
-
import { basename as
|
|
11415
|
+
import { basename as basename7, dirname as dirname6, join as join21, resolve as resolve22, sep as sep6 } from "path";
|
|
11234
11416
|
import { Readable as Readable2 } from "stream";
|
|
11235
11417
|
|
|
11236
11418
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -11548,7 +11730,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11548
11730
|
|
|
11549
11731
|
// app/lib/file-index.ts
|
|
11550
11732
|
import * as fsp from "fs/promises";
|
|
11551
|
-
import { resolve as
|
|
11733
|
+
import { resolve as resolve21, relative as relative2, join as join20, basename as basename6, extname as extname2, sep as sep5 } from "path";
|
|
11552
11734
|
import { tmpdir as tmpdir2 } from "os";
|
|
11553
11735
|
import { execFile as execFile2 } from "child_process";
|
|
11554
11736
|
import { promisify as promisify2 } from "util";
|
|
@@ -11630,7 +11812,7 @@ async function extractPdf(absolute) {
|
|
|
11630
11812
|
return stdout.trim();
|
|
11631
11813
|
}
|
|
11632
11814
|
async function ocrPdf(absolute) {
|
|
11633
|
-
const outPdf =
|
|
11815
|
+
const outPdf = join20(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11634
11816
|
try {
|
|
11635
11817
|
await execFileAsync2(
|
|
11636
11818
|
"ocrmypdf",
|
|
@@ -11686,13 +11868,13 @@ async function extractFileContent(absolute) {
|
|
|
11686
11868
|
}
|
|
11687
11869
|
}
|
|
11688
11870
|
async function readDisplayName(absolute) {
|
|
11689
|
-
const dir = absolute.slice(0, absolute.length -
|
|
11690
|
-
const base =
|
|
11871
|
+
const dir = absolute.slice(0, absolute.length - basename6(absolute).length);
|
|
11872
|
+
const base = basename6(absolute);
|
|
11691
11873
|
const dot = base.lastIndexOf(".");
|
|
11692
11874
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11693
11875
|
if (base === `${stem}.meta.json`) return null;
|
|
11694
11876
|
try {
|
|
11695
|
-
const raw = await fsp.readFile(
|
|
11877
|
+
const raw = await fsp.readFile(join20(dir, `${stem}.meta.json`), "utf-8");
|
|
11696
11878
|
const meta = JSON.parse(raw);
|
|
11697
11879
|
const dn = meta.displayName ?? meta.filename;
|
|
11698
11880
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11712,7 +11894,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11712
11894
|
let clean = true;
|
|
11713
11895
|
for (const entry of entries) {
|
|
11714
11896
|
if (entry.isSymbolicLink()) continue;
|
|
11715
|
-
const abs =
|
|
11897
|
+
const abs = join20(root, entry.name);
|
|
11716
11898
|
if (entry.isDirectory()) {
|
|
11717
11899
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11718
11900
|
if (!sub.clean) clean = false;
|
|
@@ -11721,7 +11903,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11721
11903
|
const st = await fsp.stat(abs);
|
|
11722
11904
|
out.push({
|
|
11723
11905
|
absolute: abs,
|
|
11724
|
-
relativePath: relative2(dataRoot, abs).split(
|
|
11906
|
+
relativePath: relative2(dataRoot, abs).split(sep5).join("/"),
|
|
11725
11907
|
sizeBytes: st.size,
|
|
11726
11908
|
modifiedAt: st.mtime.toISOString()
|
|
11727
11909
|
});
|
|
@@ -11824,7 +12006,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
11824
12006
|
return { kds, sections, chunks };
|
|
11825
12007
|
}
|
|
11826
12008
|
async function buildArtifact(accountId, wf, embed2) {
|
|
11827
|
-
const name =
|
|
12009
|
+
const name = basename6(wf.absolute);
|
|
11828
12010
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
11829
12011
|
const displayName = await readDisplayName(wf.absolute);
|
|
11830
12012
|
const embedInput = `${name}
|
|
@@ -11867,7 +12049,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
11867
12049
|
return withSession(opts, async (session) => {
|
|
11868
12050
|
const walked = [];
|
|
11869
12051
|
const subtreeRoots = [
|
|
11870
|
-
|
|
12052
|
+
resolve21(dataRoot, "accounts", accountId)
|
|
11871
12053
|
];
|
|
11872
12054
|
let clean = true;
|
|
11873
12055
|
for (const root of subtreeRoots) {
|
|
@@ -11950,7 +12132,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
11950
12132
|
async function indexFile(accountId, relativePath, opts) {
|
|
11951
12133
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
11952
12134
|
const embed2 = opts?.embed ?? embed;
|
|
11953
|
-
const absolute =
|
|
12135
|
+
const absolute = resolve21(dataRoot, relativePath);
|
|
11954
12136
|
await withSession(opts, async (session) => {
|
|
11955
12137
|
const st = await fsp.stat(absolute);
|
|
11956
12138
|
const wf = {
|
|
@@ -11984,7 +12166,7 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
11984
12166
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11985
12167
|
async function readMeta(absDir, baseName) {
|
|
11986
12168
|
try {
|
|
11987
|
-
const raw = await readFile4(
|
|
12169
|
+
const raw = await readFile4(join21(absDir, `${baseName}.meta.json`), "utf8");
|
|
11988
12170
|
const parsed = JSON.parse(raw);
|
|
11989
12171
|
if (typeof parsed?.filename === "string") {
|
|
11990
12172
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11995,7 +12177,7 @@ async function readMeta(absDir, baseName) {
|
|
|
11995
12177
|
}
|
|
11996
12178
|
async function readAccountNames() {
|
|
11997
12179
|
const map = /* @__PURE__ */ new Map();
|
|
11998
|
-
const accountsDir =
|
|
12180
|
+
const accountsDir = resolve22(DATA_ROOT, "accounts");
|
|
11999
12181
|
let names;
|
|
12000
12182
|
try {
|
|
12001
12183
|
names = await readdir3(accountsDir);
|
|
@@ -12004,7 +12186,7 @@ async function readAccountNames() {
|
|
|
12004
12186
|
}
|
|
12005
12187
|
for (const name of names) {
|
|
12006
12188
|
if (!UUID_RE3.test(name)) continue;
|
|
12007
|
-
const configPath2 =
|
|
12189
|
+
const configPath2 = resolve22(accountsDir, name, "account.json");
|
|
12008
12190
|
try {
|
|
12009
12191
|
const raw = await readFile4(configPath2, "utf8");
|
|
12010
12192
|
const parsed = JSON.parse(raw);
|
|
@@ -12022,7 +12204,7 @@ async function readAccountNames() {
|
|
|
12022
12204
|
}
|
|
12023
12205
|
async function enrich(absolute, entry, accountNames) {
|
|
12024
12206
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12025
|
-
const meta = await readMeta(
|
|
12207
|
+
const meta = await readMeta(join21(absolute, entry.name), entry.name);
|
|
12026
12208
|
if (meta?.filename) {
|
|
12027
12209
|
entry.displayName = meta.filename;
|
|
12028
12210
|
entry.mimeType = meta.mimeType;
|
|
@@ -12108,8 +12290,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
12108
12290
|
await session.close();
|
|
12109
12291
|
}
|
|
12110
12292
|
}
|
|
12111
|
-
var
|
|
12112
|
-
|
|
12293
|
+
var app19 = new Hono();
|
|
12294
|
+
app19.get("/", requireAdminSession, async (c) => {
|
|
12113
12295
|
const cacheKey = c.var.cacheKey;
|
|
12114
12296
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12115
12297
|
if (!accountId) {
|
|
@@ -12148,7 +12330,7 @@ app18.get("/", requireAdminSession, async (c) => {
|
|
|
12148
12330
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12149
12331
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
12150
12332
|
try {
|
|
12151
|
-
const entryPath =
|
|
12333
|
+
const entryPath = join21(absolute, name);
|
|
12152
12334
|
const s = await stat4(entryPath);
|
|
12153
12335
|
entries.push({
|
|
12154
12336
|
name,
|
|
@@ -12178,7 +12360,7 @@ app18.get("/", requireAdminSession, async (c) => {
|
|
|
12178
12360
|
return c.json({ error: message }, 500);
|
|
12179
12361
|
}
|
|
12180
12362
|
});
|
|
12181
|
-
|
|
12363
|
+
app19.get("/download", requireAdminSession, async (c) => {
|
|
12182
12364
|
const cacheKey = c.var.cacheKey;
|
|
12183
12365
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12184
12366
|
if (!accountId) {
|
|
@@ -12215,7 +12397,7 @@ app18.get("/download", requireAdminSession, async (c) => {
|
|
|
12215
12397
|
if (!info.isFile()) {
|
|
12216
12398
|
return c.json({ error: "Path is not a file" }, 400);
|
|
12217
12399
|
}
|
|
12218
|
-
const filename =
|
|
12400
|
+
const filename = basename7(absolute);
|
|
12219
12401
|
const mimeType = detectMimeType(absolute);
|
|
12220
12402
|
const nodeStream = createReadStream2(absolute);
|
|
12221
12403
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -12242,7 +12424,7 @@ app18.get("/download", requireAdminSession, async (c) => {
|
|
|
12242
12424
|
return c.json({ error: message }, 500);
|
|
12243
12425
|
}
|
|
12244
12426
|
});
|
|
12245
|
-
|
|
12427
|
+
app19.post("/upload", requireAdminSession, async (c) => {
|
|
12246
12428
|
const cacheKey = c.var.cacheKey;
|
|
12247
12429
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12248
12430
|
if (!accountId) {
|
|
@@ -12272,15 +12454,15 @@ app18.post("/upload", requireAdminSession, async (c) => {
|
|
|
12272
12454
|
error: `Unsupported file type: "${file.type}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
12273
12455
|
}, 422);
|
|
12274
12456
|
}
|
|
12275
|
-
const safeName =
|
|
12457
|
+
const safeName = basename7(file.name).replace(/[\0/\\]/g, "_");
|
|
12276
12458
|
const finalName = `${Date.now()}-${safeName}`;
|
|
12277
|
-
const destDir =
|
|
12278
|
-
const destPath =
|
|
12459
|
+
const destDir = resolve22(DATA_ROOT, "accounts", accountId, "uploads");
|
|
12460
|
+
const destPath = resolve22(destDir, finalName);
|
|
12279
12461
|
try {
|
|
12280
12462
|
await mkdir3(destDir, { recursive: true });
|
|
12281
12463
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
12282
12464
|
const destDirReal = realpathSync4(destDir);
|
|
12283
|
-
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal +
|
|
12465
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
12284
12466
|
console.error(`[data] path-traversal-blocked requested="accounts/${accountId}/uploads" resolved="${destDirReal}"`);
|
|
12285
12467
|
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
12286
12468
|
}
|
|
@@ -12303,7 +12485,7 @@ app18.post("/upload", requireAdminSession, async (c) => {
|
|
|
12303
12485
|
mimeType: file.type
|
|
12304
12486
|
});
|
|
12305
12487
|
});
|
|
12306
|
-
|
|
12488
|
+
app19.delete("/", requireAdminSession, async (c) => {
|
|
12307
12489
|
const cacheKey = c.var.cacheKey;
|
|
12308
12490
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12309
12491
|
if (!accountId) {
|
|
@@ -12324,7 +12506,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12324
12506
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12325
12507
|
return c.json({ error: "Not found" }, 404);
|
|
12326
12508
|
}
|
|
12327
|
-
const base =
|
|
12509
|
+
const base = basename7(absolute);
|
|
12328
12510
|
const protection = isProtectedFromDeletion(relPath);
|
|
12329
12511
|
if (protection.protected) {
|
|
12330
12512
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected" rule="${protection.rule}"`);
|
|
@@ -12340,7 +12522,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12340
12522
|
}
|
|
12341
12523
|
const dot = base.lastIndexOf(".");
|
|
12342
12524
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12343
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
12525
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join21(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
12344
12526
|
await unlink2(absolute);
|
|
12345
12527
|
if (sidecarPath) {
|
|
12346
12528
|
try {
|
|
@@ -12379,7 +12561,7 @@ app18.delete("/", requireAdminSession, async (c) => {
|
|
|
12379
12561
|
return c.json({ error: message }, 500);
|
|
12380
12562
|
}
|
|
12381
12563
|
});
|
|
12382
|
-
var files_default =
|
|
12564
|
+
var files_default = app19;
|
|
12383
12565
|
|
|
12384
12566
|
// ../lib/graph-search/src/index.ts
|
|
12385
12567
|
var import_dist = __toESM(require_dist());
|
|
@@ -13144,8 +13326,8 @@ var DEFAULT_LIMIT = 20;
|
|
|
13144
13326
|
var MAX_LIMIT = 2e3;
|
|
13145
13327
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
13146
13328
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
13147
|
-
var
|
|
13148
|
-
|
|
13329
|
+
var app20 = new Hono();
|
|
13330
|
+
app20.get("/", requireAdminSession, async (c) => {
|
|
13149
13331
|
const cacheKey = c.var.cacheKey;
|
|
13150
13332
|
const q = (c.req.query("q") ?? "").trim();
|
|
13151
13333
|
const rawLimit = c.req.query("limit");
|
|
@@ -13281,7 +13463,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
13281
13463
|
await session.close();
|
|
13282
13464
|
}
|
|
13283
13465
|
});
|
|
13284
|
-
var graph_search_default =
|
|
13466
|
+
var graph_search_default = app20;
|
|
13285
13467
|
|
|
13286
13468
|
// server/routes/admin/graph-subgraph.ts
|
|
13287
13469
|
import neo4j2 from "neo4j-driver";
|
|
@@ -13365,8 +13547,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
13365
13547
|
"otpCode",
|
|
13366
13548
|
"cacheKey"
|
|
13367
13549
|
]);
|
|
13368
|
-
var
|
|
13369
|
-
|
|
13550
|
+
var app21 = new Hono();
|
|
13551
|
+
app21.get("/", requireAdminSession, async (c) => {
|
|
13370
13552
|
const cacheKey = c.var.cacheKey;
|
|
13371
13553
|
const accountId = getAccountIdForSession(cacheKey);
|
|
13372
13554
|
if (!accountId) {
|
|
@@ -13949,12 +14131,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
13949
14131
|
}
|
|
13950
14132
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
13951
14133
|
}
|
|
13952
|
-
var graph_subgraph_default =
|
|
14134
|
+
var graph_subgraph_default = app21;
|
|
13953
14135
|
|
|
13954
14136
|
// server/routes/admin/graph-delete.ts
|
|
13955
14137
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
|
|
13956
|
-
var
|
|
13957
|
-
|
|
14138
|
+
var app22 = new Hono();
|
|
14139
|
+
app22.post("/", requireAdminSession, async (c) => {
|
|
13958
14140
|
const cacheKey = c.var.cacheKey;
|
|
13959
14141
|
const accountId = getAccountIdForSession(cacheKey);
|
|
13960
14142
|
if (!accountId) {
|
|
@@ -14116,11 +14298,11 @@ app21.post("/", requireAdminSession, async (c) => {
|
|
|
14116
14298
|
}
|
|
14117
14299
|
}
|
|
14118
14300
|
});
|
|
14119
|
-
var graph_delete_default =
|
|
14301
|
+
var graph_delete_default = app22;
|
|
14120
14302
|
|
|
14121
14303
|
// server/routes/admin/graph-restore.ts
|
|
14122
|
-
var
|
|
14123
|
-
|
|
14304
|
+
var app23 = new Hono();
|
|
14305
|
+
app23.post("/", requireAdminSession, async (c) => {
|
|
14124
14306
|
const cacheKey = c.var.cacheKey;
|
|
14125
14307
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14126
14308
|
if (!accountId) {
|
|
@@ -14184,11 +14366,11 @@ app22.post("/", requireAdminSession, async (c) => {
|
|
|
14184
14366
|
}
|
|
14185
14367
|
}
|
|
14186
14368
|
});
|
|
14187
|
-
var graph_restore_default =
|
|
14369
|
+
var graph_restore_default = app23;
|
|
14188
14370
|
|
|
14189
14371
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
14190
|
-
var
|
|
14191
|
-
|
|
14372
|
+
var app24 = new Hono();
|
|
14373
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
14192
14374
|
const cacheKey = c.var.cacheKey;
|
|
14193
14375
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14194
14376
|
if (!accountId) {
|
|
@@ -14254,11 +14436,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
14254
14436
|
sum(halfEdges) AS relDegree
|
|
14255
14437
|
RETURN label, nodeCount, relDegree
|
|
14256
14438
|
`;
|
|
14257
|
-
var graph_labels_in_graph_default =
|
|
14439
|
+
var graph_labels_in_graph_default = app24;
|
|
14258
14440
|
|
|
14259
14441
|
// server/routes/admin/graph-default-view.ts
|
|
14260
|
-
var
|
|
14261
|
-
|
|
14442
|
+
var app25 = new Hono();
|
|
14443
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
14262
14444
|
const cacheKey = c.var.cacheKey;
|
|
14263
14445
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14264
14446
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14296,7 +14478,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
14296
14478
|
}
|
|
14297
14479
|
}
|
|
14298
14480
|
});
|
|
14299
|
-
|
|
14481
|
+
app25.put("/", requireAdminSession, async (c) => {
|
|
14300
14482
|
const cacheKey = c.var.cacheKey;
|
|
14301
14483
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14302
14484
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14385,20 +14567,20 @@ var WRITE_CYPHER = `
|
|
|
14385
14567
|
p.updatedAt = $updatedAt
|
|
14386
14568
|
RETURN p.labels AS labels
|
|
14387
14569
|
`;
|
|
14388
|
-
var graph_default_view_default =
|
|
14570
|
+
var graph_default_view_default = app25;
|
|
14389
14571
|
|
|
14390
14572
|
// server/routes/admin/sidebar-artefacts.ts
|
|
14391
14573
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
14392
|
-
import { resolve as
|
|
14574
|
+
import { resolve as resolve23, relative as relative3, isAbsolute, sep as sep7, basename as basename8 } from "path";
|
|
14393
14575
|
import { existsSync as existsSync21 } from "fs";
|
|
14394
14576
|
var LIMIT = 50;
|
|
14395
14577
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
14396
14578
|
function toDataRootRelPath(absPath) {
|
|
14397
|
-
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT +
|
|
14579
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep7)) return null;
|
|
14398
14580
|
return relative3(DATA_ROOT, absPath);
|
|
14399
14581
|
}
|
|
14400
|
-
var
|
|
14401
|
-
|
|
14582
|
+
var app26 = new Hono();
|
|
14583
|
+
app26.get("/", requireAdminSession, async (c) => {
|
|
14402
14584
|
const cacheKey = c.var.cacheKey;
|
|
14403
14585
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14404
14586
|
if (!accountId) {
|
|
@@ -14409,7 +14591,7 @@ app25.get("/", requireAdminSession, async (c) => {
|
|
|
14409
14591
|
if (accountFiles === null) {
|
|
14410
14592
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
14411
14593
|
}
|
|
14412
|
-
const accountDir =
|
|
14594
|
+
const accountDir = resolve23(ACCOUNTS_DIR, accountId);
|
|
14413
14595
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
14414
14596
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
14415
14597
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -14442,7 +14624,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
14442
14624
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
14443
14625
|
return {
|
|
14444
14626
|
id: `account-file:${relativePath}`,
|
|
14445
|
-
name: displayName ??
|
|
14627
|
+
name: displayName ?? basename8(relativePath),
|
|
14446
14628
|
kind: "account-file",
|
|
14447
14629
|
updatedAt: modifiedAt,
|
|
14448
14630
|
mimeType,
|
|
@@ -14461,8 +14643,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
14461
14643
|
async function fetchAgentTemplateRows(accountDir) {
|
|
14462
14644
|
const rows = [];
|
|
14463
14645
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
14464
|
-
const overridePath =
|
|
14465
|
-
const bundledPath =
|
|
14646
|
+
const overridePath = resolve23(accountDir, "agents", "admin", filename);
|
|
14647
|
+
const bundledPath = resolve23(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
14466
14648
|
const labelStem = filename.replace(/\.md$/, "");
|
|
14467
14649
|
const row = await readAgentTemplateRow({
|
|
14468
14650
|
id: `agent-template:admin:${filename}`,
|
|
@@ -14475,12 +14657,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
14475
14657
|
});
|
|
14476
14658
|
if (row) rows.push(row);
|
|
14477
14659
|
}
|
|
14478
|
-
const overrideDir =
|
|
14479
|
-
const bundledDir =
|
|
14660
|
+
const overrideDir = resolve23(accountDir, "specialists", "agents");
|
|
14661
|
+
const bundledDir = resolve23(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
14480
14662
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
14481
14663
|
for (const filename of specialistNames) {
|
|
14482
|
-
const overridePath =
|
|
14483
|
-
const bundledPath =
|
|
14664
|
+
const overridePath = resolve23(overrideDir, filename);
|
|
14665
|
+
const bundledPath = resolve23(bundledDir, filename);
|
|
14484
14666
|
const row = await readAgentTemplateRow({
|
|
14485
14667
|
id: `agent-template:specialist:${filename}`,
|
|
14486
14668
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -14562,11 +14744,11 @@ function isWithin(target, root) {
|
|
|
14562
14744
|
const rel = relative3(root, target);
|
|
14563
14745
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
14564
14746
|
}
|
|
14565
|
-
var sidebar_artefacts_default =
|
|
14747
|
+
var sidebar_artefacts_default = app26;
|
|
14566
14748
|
|
|
14567
14749
|
// server/routes/admin/session-delete.ts
|
|
14568
|
-
var
|
|
14569
|
-
|
|
14750
|
+
var app27 = new Hono();
|
|
14751
|
+
app27.post("/", requireAdminSession, async (c) => {
|
|
14570
14752
|
let body;
|
|
14571
14753
|
try {
|
|
14572
14754
|
body = await c.req.json();
|
|
@@ -14604,11 +14786,11 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
14604
14786
|
console.error(`[session-delete] sessionId=${sessionId} delete-status=${del.status}`);
|
|
14605
14787
|
return c.json({ error: `manager-status-${del.status}` }, 502);
|
|
14606
14788
|
});
|
|
14607
|
-
var session_delete_default =
|
|
14789
|
+
var session_delete_default = app27;
|
|
14608
14790
|
|
|
14609
14791
|
// server/routes/admin/session-stop.ts
|
|
14610
|
-
var
|
|
14611
|
-
|
|
14792
|
+
var app28 = new Hono();
|
|
14793
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
14612
14794
|
let body;
|
|
14613
14795
|
try {
|
|
14614
14796
|
body = await c.req.json();
|
|
@@ -14633,11 +14815,11 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
14633
14815
|
console.error(`[session-stop] sessionId=${sessionId} manager-status=${res.status}`);
|
|
14634
14816
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
14635
14817
|
});
|
|
14636
|
-
var session_stop_default =
|
|
14818
|
+
var session_stop_default = app28;
|
|
14637
14819
|
|
|
14638
14820
|
// server/routes/admin/session-archive.ts
|
|
14639
|
-
var
|
|
14640
|
-
|
|
14821
|
+
var app29 = new Hono();
|
|
14822
|
+
app29.post("/", requireAdminSession, async (c) => {
|
|
14641
14823
|
let body;
|
|
14642
14824
|
try {
|
|
14643
14825
|
body = await c.req.json();
|
|
@@ -14685,7 +14867,7 @@ app28.post("/", requireAdminSession, async (c) => {
|
|
|
14685
14867
|
console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
14686
14868
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
14687
14869
|
});
|
|
14688
|
-
var session_archive_default =
|
|
14870
|
+
var session_archive_default = app29;
|
|
14689
14871
|
|
|
14690
14872
|
// server/routes/admin/session-rc-spawn.ts
|
|
14691
14873
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
@@ -14719,8 +14901,8 @@ function shapeWebchatResponse(sessionId, manager) {
|
|
|
14719
14901
|
const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
|
|
14720
14902
|
return { sessionId, outcome, target: `/chat?session=${sessionId}` };
|
|
14721
14903
|
}
|
|
14722
|
-
var
|
|
14723
|
-
|
|
14904
|
+
var app30 = new Hono();
|
|
14905
|
+
app30.post("/", requireAdminSession, async (c) => {
|
|
14724
14906
|
let body;
|
|
14725
14907
|
try {
|
|
14726
14908
|
body = await c.req.json();
|
|
@@ -14773,7 +14955,7 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
14773
14955
|
}
|
|
14774
14956
|
return c.json(parsed ?? {});
|
|
14775
14957
|
});
|
|
14776
|
-
var session_rc_spawn_default =
|
|
14958
|
+
var session_rc_spawn_default = app30;
|
|
14777
14959
|
|
|
14778
14960
|
// server/routes/admin/session-reseat.ts
|
|
14779
14961
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
@@ -14814,8 +14996,9 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId) {
|
|
|
14814
14996
|
if (adminUserId) payload.adminUserId = adminUserId;
|
|
14815
14997
|
return { sessionId, payload };
|
|
14816
14998
|
}
|
|
14817
|
-
var
|
|
14818
|
-
|
|
14999
|
+
var app31 = new Hono();
|
|
15000
|
+
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
15001
|
+
app31.post("/", requireAdminSession, async (c) => {
|
|
14819
15002
|
let body;
|
|
14820
15003
|
try {
|
|
14821
15004
|
body = await c.req.json();
|
|
@@ -14826,57 +15009,65 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14826
15009
|
const model = typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
|
|
14827
15010
|
if (fromSessionId === null) return c.json({ error: "fromSessionId must be a valid session id" }, 400);
|
|
14828
15011
|
if (model === null) return c.json({ error: "model must be a selectable model" }, 400);
|
|
14829
|
-
|
|
14830
|
-
|
|
14831
|
-
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID11, adminUserId);
|
|
14832
|
-
const reseatReqId = randomUUID11();
|
|
14833
|
-
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
14834
|
-
let res;
|
|
14835
|
-
try {
|
|
14836
|
-
res = await fetch(`${managerBase("session-reseat:wrapper")}/rc-spawn`, {
|
|
14837
|
-
method: "POST",
|
|
14838
|
-
headers: { "content-type": "application/json" },
|
|
14839
|
-
body: JSON.stringify(plan.payload)
|
|
14840
|
-
});
|
|
14841
|
-
} catch (err) {
|
|
14842
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
14843
|
-
console.error(`[session-reseat] manager-unreachable err=${msg}`);
|
|
14844
|
-
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
14845
|
-
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
14846
|
-
}
|
|
14847
|
-
const text = await res.text();
|
|
14848
|
-
let parsed = null;
|
|
14849
|
-
try {
|
|
14850
|
-
parsed = JSON.parse(text);
|
|
14851
|
-
} catch {
|
|
14852
|
-
}
|
|
14853
|
-
if (!res.ok) {
|
|
14854
|
-
console.error(`[session-reseat] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
14855
|
-
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
14856
|
-
return c.json(parsed ?? { error: text }, res.status);
|
|
15012
|
+
if (reseatsInFlight.has(fromSessionId)) {
|
|
15013
|
+
return c.json({ error: "re-seat already in progress for this session" }, 409);
|
|
14857
15014
|
}
|
|
15015
|
+
reseatsInFlight.add(fromSessionId);
|
|
14858
15016
|
try {
|
|
14859
|
-
const
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
15017
|
+
const cacheKey = c.get("cacheKey");
|
|
15018
|
+
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15019
|
+
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID11, adminUserId);
|
|
15020
|
+
const reseatReqId = randomUUID11();
|
|
15021
|
+
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
15022
|
+
let res;
|
|
15023
|
+
try {
|
|
15024
|
+
res = await fetch(`${managerBase("session-reseat:wrapper")}/rc-spawn`, {
|
|
15025
|
+
method: "POST",
|
|
15026
|
+
headers: { "content-type": "application/json" },
|
|
15027
|
+
body: JSON.stringify(plan.payload)
|
|
15028
|
+
});
|
|
15029
|
+
} catch (err) {
|
|
15030
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
15031
|
+
console.error(`[session-reseat] manager-unreachable err=${msg}`);
|
|
15032
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
15033
|
+
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
15034
|
+
}
|
|
15035
|
+
const text = await res.text();
|
|
15036
|
+
let parsed = null;
|
|
15037
|
+
try {
|
|
15038
|
+
parsed = JSON.parse(text);
|
|
15039
|
+
} catch {
|
|
15040
|
+
}
|
|
15041
|
+
if (!res.ok) {
|
|
15042
|
+
console.error(`[session-reseat] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
15043
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=reseat-failed`);
|
|
15044
|
+
return c.json(parsed ?? { error: text }, res.status);
|
|
15045
|
+
}
|
|
15046
|
+
try {
|
|
15047
|
+
const account = resolveAccount();
|
|
15048
|
+
if (account) {
|
|
15049
|
+
const accountId = resolvePlatformAccountId();
|
|
15050
|
+
const canonicalId = adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
15051
|
+
const currentOverride = readCanonicalOverrideId(account.accountDir);
|
|
15052
|
+
if (fromSessionId === canonicalId || fromSessionId === currentOverride) {
|
|
15053
|
+
writeCanonicalOverrideId(account.accountDir, plan.sessionId);
|
|
15054
|
+
console.log(`[chat-reseat] op=canonical-forward reseatReqId=${reseatReqId} from=${fromSessionId} to=${plan.sessionId}`);
|
|
15055
|
+
}
|
|
14867
15056
|
}
|
|
15057
|
+
} catch (err) {
|
|
15058
|
+
console.error(`[session-reseat] canonical-forward-failed err=${err instanceof Error ? err.message : String(err)}`);
|
|
14868
15059
|
}
|
|
14869
|
-
|
|
14870
|
-
console.
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
15060
|
+
const target = `/chat?session=${plan.sessionId}`;
|
|
15061
|
+
console.log(`[chat-reseat] op=acquired reseatReqId=${reseatReqId} pid=${parsed?.spawnedPid ?? "none"} new=${plan.sessionId}`);
|
|
15062
|
+
console.log(`[chat-reseat] op=navigate reseatReqId=${reseatReqId} target=${target}`);
|
|
15063
|
+
console.log(`[chat-reseat] op=exit reseatReqId=${reseatReqId} outcome=bound`);
|
|
15064
|
+
const outcome = typeof parsed?.outcome === "string" ? parsed.outcome : "bound";
|
|
15065
|
+
return c.json({ sessionId: plan.sessionId, outcome, target });
|
|
15066
|
+
} finally {
|
|
15067
|
+
reseatsInFlight.delete(fromSessionId);
|
|
15068
|
+
}
|
|
14878
15069
|
});
|
|
14879
|
-
var session_reseat_default =
|
|
15070
|
+
var session_reseat_default = app31;
|
|
14880
15071
|
|
|
14881
15072
|
// server/routes/admin/system-stats.ts
|
|
14882
15073
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -14973,8 +15164,8 @@ async function sample() {
|
|
|
14973
15164
|
if (process.platform === "linux") return sampleLinux();
|
|
14974
15165
|
return sampleOsFallback();
|
|
14975
15166
|
}
|
|
14976
|
-
var
|
|
14977
|
-
|
|
15167
|
+
var app32 = new Hono();
|
|
15168
|
+
app32.get("/", async (c) => {
|
|
14978
15169
|
const started = Date.now();
|
|
14979
15170
|
if (!inflight) {
|
|
14980
15171
|
inflight = sample().finally(() => {
|
|
@@ -14997,14 +15188,14 @@ app31.get("/", async (c) => {
|
|
|
14997
15188
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
14998
15189
|
}
|
|
14999
15190
|
});
|
|
15000
|
-
var system_stats_default =
|
|
15191
|
+
var system_stats_default = app32;
|
|
15001
15192
|
|
|
15002
15193
|
// server/routes/admin/health.ts
|
|
15003
15194
|
import { existsSync as existsSync22, readFileSync as readFileSync22 } from "fs";
|
|
15004
|
-
import { resolve as
|
|
15005
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
15195
|
+
import { resolve as resolve24, join as join22 } from "path";
|
|
15196
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15006
15197
|
var brandHostname = "maxy";
|
|
15007
|
-
var brandJsonPath =
|
|
15198
|
+
var brandJsonPath = join22(PLATFORM_ROOT6, "config", "brand.json");
|
|
15008
15199
|
if (existsSync22(brandJsonPath)) {
|
|
15009
15200
|
try {
|
|
15010
15201
|
const brand = JSON.parse(readFileSync22(brandJsonPath, "utf-8"));
|
|
@@ -15012,7 +15203,7 @@ if (existsSync22(brandJsonPath)) {
|
|
|
15012
15203
|
} catch {
|
|
15013
15204
|
}
|
|
15014
15205
|
}
|
|
15015
|
-
var VERSION_FILE =
|
|
15206
|
+
var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
15016
15207
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
15017
15208
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
15018
15209
|
function readVersion() {
|
|
@@ -15042,8 +15233,8 @@ async function probeConversationDb() {
|
|
|
15042
15233
|
});
|
|
15043
15234
|
}
|
|
15044
15235
|
}
|
|
15045
|
-
var
|
|
15046
|
-
|
|
15236
|
+
var app33 = new Hono();
|
|
15237
|
+
app33.get("/", async (c) => {
|
|
15047
15238
|
const version = readVersion();
|
|
15048
15239
|
const probe = await probeConversationDb();
|
|
15049
15240
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -15065,11 +15256,11 @@ app32.get("/", async (c) => {
|
|
|
15065
15256
|
uptimeMs
|
|
15066
15257
|
});
|
|
15067
15258
|
});
|
|
15068
|
-
var health_default2 =
|
|
15259
|
+
var health_default2 = app33;
|
|
15069
15260
|
|
|
15070
15261
|
// server/routes/admin/linkedin-ingest.ts
|
|
15071
15262
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
15072
|
-
var
|
|
15263
|
+
var TAG26 = "[linkedin-ingest-route]";
|
|
15073
15264
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
15074
15265
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
15075
15266
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -15167,35 +15358,35 @@ function buildInitialMessage(env) {
|
|
|
15167
15358
|
}
|
|
15168
15359
|
return header;
|
|
15169
15360
|
}
|
|
15170
|
-
var
|
|
15171
|
-
|
|
15361
|
+
var app34 = new Hono();
|
|
15362
|
+
app34.post("/", requireAdminSession, async (c) => {
|
|
15172
15363
|
let body;
|
|
15173
15364
|
try {
|
|
15174
15365
|
body = await c.req.json();
|
|
15175
15366
|
} catch {
|
|
15176
|
-
console.error(
|
|
15367
|
+
console.error(TAG26 + " rejected status=400 reason=schema:body-not-json");
|
|
15177
15368
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
15178
15369
|
}
|
|
15179
15370
|
const v = validate(body);
|
|
15180
15371
|
if (!v.ok) {
|
|
15181
|
-
console.error(
|
|
15372
|
+
console.error(TAG26 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
15182
15373
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
15183
15374
|
}
|
|
15184
15375
|
const envelope = v.envelope;
|
|
15185
15376
|
const cacheKey = c.var.cacheKey ?? "";
|
|
15186
15377
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15187
15378
|
if (!senderId) {
|
|
15188
|
-
console.error(
|
|
15379
|
+
console.error(TAG26 + " rejected status=500 reason=admin-account-not-resolved");
|
|
15189
15380
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
15190
15381
|
}
|
|
15191
15382
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
15192
15383
|
console.log(
|
|
15193
|
-
|
|
15384
|
+
TAG26 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
15194
15385
|
);
|
|
15195
15386
|
const initialMessage = buildInitialMessage(envelope);
|
|
15196
15387
|
const spawnStart = Date.now();
|
|
15197
15388
|
const sessionId = randomUUID12();
|
|
15198
|
-
console.log(
|
|
15389
|
+
console.log(TAG26 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
15199
15390
|
const spawned = await managerRcSpawn({
|
|
15200
15391
|
sessionId,
|
|
15201
15392
|
initialMessage,
|
|
@@ -15204,20 +15395,20 @@ app33.post("/", requireAdminSession, async (c) => {
|
|
|
15204
15395
|
});
|
|
15205
15396
|
if ("error" in spawned) {
|
|
15206
15397
|
console.error(
|
|
15207
|
-
|
|
15398
|
+
TAG26 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
15208
15399
|
);
|
|
15209
15400
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
15210
15401
|
}
|
|
15211
15402
|
console.log(
|
|
15212
|
-
|
|
15403
|
+
TAG26 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
15213
15404
|
);
|
|
15214
15405
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
15215
15406
|
});
|
|
15216
|
-
var linkedin_ingest_default =
|
|
15407
|
+
var linkedin_ingest_default = app34;
|
|
15217
15408
|
|
|
15218
15409
|
// server/routes/admin/post-turn-context.ts
|
|
15219
15410
|
import neo4j3 from "neo4j-driver";
|
|
15220
|
-
var
|
|
15411
|
+
var TAG27 = "[post-turn-context]";
|
|
15221
15412
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
15222
15413
|
"embedding",
|
|
15223
15414
|
"passwordHash",
|
|
@@ -15255,11 +15446,11 @@ function pruneProperties(raw) {
|
|
|
15255
15446
|
}
|
|
15256
15447
|
return out;
|
|
15257
15448
|
}
|
|
15258
|
-
var
|
|
15259
|
-
|
|
15449
|
+
var app35 = new Hono();
|
|
15450
|
+
app35.get("/", async (c) => {
|
|
15260
15451
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15261
15452
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15262
|
-
console.error(`${
|
|
15453
|
+
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15263
15454
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15264
15455
|
}
|
|
15265
15456
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15268,7 +15459,7 @@ app34.get("/", async (c) => {
|
|
|
15268
15459
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15269
15460
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15270
15461
|
if (offender !== void 0) {
|
|
15271
|
-
console.error(`${
|
|
15462
|
+
console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15272
15463
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15273
15464
|
}
|
|
15274
15465
|
}
|
|
@@ -15300,7 +15491,7 @@ app34.get("/", async (c) => {
|
|
|
15300
15491
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15301
15492
|
const total = Date.now() - started;
|
|
15302
15493
|
console.log(
|
|
15303
|
-
`${
|
|
15494
|
+
`${TAG27} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
15304
15495
|
);
|
|
15305
15496
|
return c.json({
|
|
15306
15497
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15309,18 +15500,18 @@ app34.get("/", async (c) => {
|
|
|
15309
15500
|
const elapsed = Date.now() - started;
|
|
15310
15501
|
const message = err instanceof Error ? err.message : String(err);
|
|
15311
15502
|
console.error(
|
|
15312
|
-
`${
|
|
15503
|
+
`${TAG27} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
15313
15504
|
);
|
|
15314
15505
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
15315
15506
|
} finally {
|
|
15316
15507
|
await session.close();
|
|
15317
15508
|
}
|
|
15318
15509
|
});
|
|
15319
|
-
var post_turn_context_default =
|
|
15510
|
+
var post_turn_context_default = app35;
|
|
15320
15511
|
|
|
15321
15512
|
// server/routes/admin/public-session-context.ts
|
|
15322
15513
|
import neo4j4 from "neo4j-driver";
|
|
15323
|
-
var
|
|
15514
|
+
var TAG28 = "[public-session-context]";
|
|
15324
15515
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
15325
15516
|
"embedding",
|
|
15326
15517
|
"passwordHash",
|
|
@@ -15358,11 +15549,11 @@ function pruneProperties2(raw) {
|
|
|
15358
15549
|
}
|
|
15359
15550
|
return out;
|
|
15360
15551
|
}
|
|
15361
|
-
var
|
|
15362
|
-
|
|
15552
|
+
var app36 = new Hono();
|
|
15553
|
+
app36.get("/", async (c) => {
|
|
15363
15554
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15364
15555
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
15365
|
-
console.error(`${
|
|
15556
|
+
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15366
15557
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15367
15558
|
}
|
|
15368
15559
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15371,7 +15562,7 @@ app35.get("/", async (c) => {
|
|
|
15371
15562
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15372
15563
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
15373
15564
|
if (offender !== void 0) {
|
|
15374
|
-
console.error(`${
|
|
15565
|
+
console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15375
15566
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15376
15567
|
}
|
|
15377
15568
|
}
|
|
@@ -15402,7 +15593,7 @@ app35.get("/", async (c) => {
|
|
|
15402
15593
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15403
15594
|
const total = Date.now() - started;
|
|
15404
15595
|
console.log(
|
|
15405
|
-
`${
|
|
15596
|
+
`${TAG28} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
15406
15597
|
);
|
|
15407
15598
|
return c.json({
|
|
15408
15599
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15411,25 +15602,25 @@ app35.get("/", async (c) => {
|
|
|
15411
15602
|
const elapsed = Date.now() - started;
|
|
15412
15603
|
const message = err instanceof Error ? err.message : String(err);
|
|
15413
15604
|
console.error(
|
|
15414
|
-
`${
|
|
15605
|
+
`${TAG28} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
15415
15606
|
);
|
|
15416
15607
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
15417
15608
|
} finally {
|
|
15418
15609
|
await session.close();
|
|
15419
15610
|
}
|
|
15420
15611
|
});
|
|
15421
|
-
var public_session_context_default =
|
|
15612
|
+
var public_session_context_default = app36;
|
|
15422
15613
|
|
|
15423
15614
|
// server/routes/admin/public-session-exit.ts
|
|
15424
|
-
var
|
|
15615
|
+
var TAG29 = "[public-session-exit-route]";
|
|
15425
15616
|
function isLoopbackAddr4(addr) {
|
|
15426
15617
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15427
15618
|
}
|
|
15428
|
-
var
|
|
15429
|
-
|
|
15619
|
+
var app37 = new Hono();
|
|
15620
|
+
app37.post("/", async (c) => {
|
|
15430
15621
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15431
15622
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
15432
|
-
console.error(`${
|
|
15623
|
+
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15433
15624
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15434
15625
|
}
|
|
15435
15626
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15438,7 +15629,7 @@ app36.post("/", async (c) => {
|
|
|
15438
15629
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15439
15630
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
15440
15631
|
if (offender !== void 0) {
|
|
15441
|
-
console.error(`${
|
|
15632
|
+
console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15442
15633
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15443
15634
|
}
|
|
15444
15635
|
}
|
|
@@ -15453,18 +15644,18 @@ app36.post("/", async (c) => {
|
|
|
15453
15644
|
handlePublicSessionExit(sessionId);
|
|
15454
15645
|
return c.json({ ok: true });
|
|
15455
15646
|
});
|
|
15456
|
-
var public_session_exit_default =
|
|
15647
|
+
var public_session_exit_default = app37;
|
|
15457
15648
|
|
|
15458
15649
|
// server/routes/admin/access-session-evict.ts
|
|
15459
|
-
var
|
|
15650
|
+
var TAG30 = "[access-session-evict]";
|
|
15460
15651
|
function isLoopbackAddr5(addr) {
|
|
15461
15652
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15462
15653
|
}
|
|
15463
|
-
var
|
|
15464
|
-
|
|
15654
|
+
var app38 = new Hono();
|
|
15655
|
+
app38.post("/", async (c) => {
|
|
15465
15656
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15466
15657
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
15467
|
-
console.error(`${
|
|
15658
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15468
15659
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15469
15660
|
}
|
|
15470
15661
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15473,7 +15664,7 @@ app37.post("/", async (c) => {
|
|
|
15473
15664
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15474
15665
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
15475
15666
|
if (offender !== void 0) {
|
|
15476
|
-
console.error(`${
|
|
15667
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15477
15668
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15478
15669
|
}
|
|
15479
15670
|
}
|
|
@@ -15486,22 +15677,22 @@ app37.post("/", async (c) => {
|
|
|
15486
15677
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
15487
15678
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
15488
15679
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
15489
|
-
console.log(`${
|
|
15680
|
+
console.log(`${TAG30} grantId=${grantId} dropped=${dropped}`);
|
|
15490
15681
|
return c.json({ ok: true, dropped });
|
|
15491
15682
|
});
|
|
15492
|
-
var access_session_evict_default =
|
|
15683
|
+
var access_session_evict_default = app38;
|
|
15493
15684
|
|
|
15494
15685
|
// server/routes/admin/enrol-person.ts
|
|
15495
|
-
var
|
|
15686
|
+
var TAG31 = "[enrol]";
|
|
15496
15687
|
function isLoopbackAddr6(addr) {
|
|
15497
15688
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15498
15689
|
}
|
|
15499
15690
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15500
|
-
var
|
|
15501
|
-
|
|
15691
|
+
var app39 = new Hono();
|
|
15692
|
+
app39.post("/", async (c) => {
|
|
15502
15693
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15503
15694
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
15504
|
-
console.error(`${
|
|
15695
|
+
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15505
15696
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15506
15697
|
}
|
|
15507
15698
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15510,7 +15701,7 @@ app38.post("/", async (c) => {
|
|
|
15510
15701
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15511
15702
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
15512
15703
|
if (offender !== void 0) {
|
|
15513
|
-
console.error(`${
|
|
15704
|
+
console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15514
15705
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15515
15706
|
}
|
|
15516
15707
|
}
|
|
@@ -15535,7 +15726,7 @@ app38.post("/", async (c) => {
|
|
|
15535
15726
|
}
|
|
15536
15727
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
15537
15728
|
if (!accountId) {
|
|
15538
|
-
console.error(`${
|
|
15729
|
+
console.error(`${TAG31} op=person result=no-account-id`);
|
|
15539
15730
|
return c.json({ error: "no-account-id" }, 500);
|
|
15540
15731
|
}
|
|
15541
15732
|
let personId;
|
|
@@ -15543,7 +15734,7 @@ app38.post("/", async (c) => {
|
|
|
15543
15734
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
15544
15735
|
} catch (err) {
|
|
15545
15736
|
console.error(
|
|
15546
|
-
`${
|
|
15737
|
+
`${TAG31} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15547
15738
|
);
|
|
15548
15739
|
return c.json({ error: "enrol-failed" }, 500);
|
|
15549
15740
|
}
|
|
@@ -15553,19 +15744,19 @@ app38.post("/", async (c) => {
|
|
|
15553
15744
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
15554
15745
|
} catch (err) {
|
|
15555
15746
|
console.error(
|
|
15556
|
-
`${
|
|
15747
|
+
`${TAG31} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15557
15748
|
);
|
|
15558
15749
|
}
|
|
15559
15750
|
console.log(
|
|
15560
|
-
`${
|
|
15751
|
+
`${TAG31} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
15561
15752
|
);
|
|
15562
15753
|
return c.json({ personId, grant }, 200);
|
|
15563
15754
|
});
|
|
15564
|
-
var enrol_person_default =
|
|
15755
|
+
var enrol_person_default = app39;
|
|
15565
15756
|
|
|
15566
15757
|
// server/routes/admin/browser.ts
|
|
15567
|
-
var
|
|
15568
|
-
|
|
15758
|
+
var app40 = new Hono();
|
|
15759
|
+
app40.post("/launch", requireAdminSession, async (c) => {
|
|
15569
15760
|
try {
|
|
15570
15761
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
15571
15762
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -15593,50 +15784,50 @@ app39.post("/launch", requireAdminSession, async (c) => {
|
|
|
15593
15784
|
);
|
|
15594
15785
|
}
|
|
15595
15786
|
});
|
|
15596
|
-
var browser_default =
|
|
15787
|
+
var browser_default = app40;
|
|
15597
15788
|
|
|
15598
15789
|
// server/routes/admin/index.ts
|
|
15599
|
-
var
|
|
15600
|
-
|
|
15601
|
-
|
|
15602
|
-
|
|
15603
|
-
|
|
15604
|
-
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
15615
|
-
|
|
15616
|
-
|
|
15617
|
-
|
|
15618
|
-
|
|
15619
|
-
|
|
15620
|
-
|
|
15621
|
-
|
|
15622
|
-
|
|
15623
|
-
|
|
15624
|
-
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
15628
|
-
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
|
|
15632
|
-
var admin_default =
|
|
15790
|
+
var app41 = new Hono();
|
|
15791
|
+
app41.route("/session", session_default);
|
|
15792
|
+
app41.route("/logs", logs_default);
|
|
15793
|
+
app41.route("/claude-info", claude_info_default);
|
|
15794
|
+
app41.route("/attachment", attachment_default);
|
|
15795
|
+
app41.route("/agents", agents_default);
|
|
15796
|
+
app41.route("/sessions", sessions_default);
|
|
15797
|
+
app41.route("/claude-sessions", claude_sessions_default);
|
|
15798
|
+
app41.route("/log-ingest", log_ingest_default);
|
|
15799
|
+
app41.route("/events", events_default);
|
|
15800
|
+
app41.route("/files", files_default);
|
|
15801
|
+
app41.route("/graph-search", graph_search_default);
|
|
15802
|
+
app41.route("/graph-subgraph", graph_subgraph_default);
|
|
15803
|
+
app41.route("/graph-delete", graph_delete_default);
|
|
15804
|
+
app41.route("/graph-restore", graph_restore_default);
|
|
15805
|
+
app41.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
15806
|
+
app41.route("/graph-default-view", graph_default_view_default);
|
|
15807
|
+
app41.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
15808
|
+
app41.route("/sidebar-sessions", sidebar_sessions_default);
|
|
15809
|
+
app41.route("/session-delete", session_delete_default);
|
|
15810
|
+
app41.route("/session-stop", session_stop_default);
|
|
15811
|
+
app41.route("/session-archive", session_archive_default);
|
|
15812
|
+
app41.route("/browser", browser_default);
|
|
15813
|
+
app41.route("/session-rc-spawn", session_rc_spawn_default);
|
|
15814
|
+
app41.route("/session-reseat", session_reseat_default);
|
|
15815
|
+
app41.route("/system-stats", system_stats_default);
|
|
15816
|
+
app41.route("/health-brand", health_default2);
|
|
15817
|
+
app41.route("/linkedin-ingest", linkedin_ingest_default);
|
|
15818
|
+
app41.route("/post-turn-context", post_turn_context_default);
|
|
15819
|
+
app41.route("/public-session-context", public_session_context_default);
|
|
15820
|
+
app41.route("/public-session-exit", public_session_exit_default);
|
|
15821
|
+
app41.route("/access-session-evict", access_session_evict_default);
|
|
15822
|
+
app41.route("/enrol-person", enrol_person_default);
|
|
15823
|
+
var admin_default = app41;
|
|
15633
15824
|
|
|
15634
15825
|
// server/routes/access/verify-token.ts
|
|
15635
|
-
var
|
|
15826
|
+
var TAG32 = "[access-verify]";
|
|
15636
15827
|
var MINT_TAG = "[access-session-mint]";
|
|
15637
15828
|
var COOKIE_NAME = "__access_session";
|
|
15638
|
-
var
|
|
15639
|
-
|
|
15829
|
+
var app42 = new Hono();
|
|
15830
|
+
app42.post("/", async (c) => {
|
|
15640
15831
|
const ip = c.var.clientIp || "unknown";
|
|
15641
15832
|
let body;
|
|
15642
15833
|
try {
|
|
@@ -15651,39 +15842,39 @@ app41.post("/", async (c) => {
|
|
|
15651
15842
|
}
|
|
15652
15843
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
15653
15844
|
if (rateMsg) {
|
|
15654
|
-
console.error(`${
|
|
15845
|
+
console.error(`${TAG32} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
15655
15846
|
return c.json({ error: rateMsg }, 429);
|
|
15656
15847
|
}
|
|
15657
15848
|
const grant = await findGrantByMagicToken(token);
|
|
15658
15849
|
if (!grant) {
|
|
15659
15850
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15660
|
-
console.error(`${
|
|
15851
|
+
console.error(`${TAG32} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
15661
15852
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
15662
15853
|
}
|
|
15663
15854
|
if (grant.agentSlug !== agentSlug) {
|
|
15664
15855
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15665
15856
|
console.error(
|
|
15666
|
-
`${
|
|
15857
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
15667
15858
|
);
|
|
15668
15859
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
15669
15860
|
}
|
|
15670
15861
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
15671
15862
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15672
15863
|
console.error(
|
|
15673
|
-
`${
|
|
15864
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
15674
15865
|
);
|
|
15675
15866
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
15676
15867
|
}
|
|
15677
15868
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
15678
15869
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
15679
15870
|
console.error(
|
|
15680
|
-
`${
|
|
15871
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
15681
15872
|
);
|
|
15682
15873
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
15683
15874
|
}
|
|
15684
15875
|
if (!grant.sliceToken) {
|
|
15685
15876
|
console.error(
|
|
15686
|
-
`${
|
|
15877
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
15687
15878
|
);
|
|
15688
15879
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
15689
15880
|
}
|
|
@@ -15699,12 +15890,12 @@ app41.post("/", async (c) => {
|
|
|
15699
15890
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
15700
15891
|
} catch (err) {
|
|
15701
15892
|
console.error(
|
|
15702
|
-
`${
|
|
15893
|
+
`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
15703
15894
|
);
|
|
15704
15895
|
return c.json({ error: "verification-failed" }, 500);
|
|
15705
15896
|
}
|
|
15706
15897
|
clearAccessRateLimit(ip, agentSlug);
|
|
15707
|
-
console.log(`${
|
|
15898
|
+
console.log(`${TAG32} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
15708
15899
|
console.log(
|
|
15709
15900
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
15710
15901
|
);
|
|
@@ -15718,13 +15909,13 @@ app41.post("/", async (c) => {
|
|
|
15718
15909
|
displayName: grant.displayName
|
|
15719
15910
|
});
|
|
15720
15911
|
});
|
|
15721
|
-
var verify_token_default =
|
|
15912
|
+
var verify_token_default = app42;
|
|
15722
15913
|
|
|
15723
15914
|
// app/lib/access-email.ts
|
|
15724
15915
|
import { spawn as spawn2 } from "child_process";
|
|
15725
|
-
import { resolve as
|
|
15726
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
15727
|
-
var SEND_SCRIPT =
|
|
15916
|
+
import { resolve as resolve25 } from "path";
|
|
15917
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
|
|
15918
|
+
var SEND_SCRIPT = resolve25(
|
|
15728
15919
|
PLATFORM_ROOT7,
|
|
15729
15920
|
"plugins",
|
|
15730
15921
|
"email",
|
|
@@ -15780,10 +15971,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
15780
15971
|
}
|
|
15781
15972
|
|
|
15782
15973
|
// server/routes/access/request-magic-link.ts
|
|
15783
|
-
var
|
|
15784
|
-
var
|
|
15974
|
+
var TAG33 = "[access-request-link]";
|
|
15975
|
+
var app43 = new Hono();
|
|
15785
15976
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
15786
|
-
|
|
15977
|
+
app43.post("/", async (c) => {
|
|
15787
15978
|
let body;
|
|
15788
15979
|
try {
|
|
15789
15980
|
body = await c.req.json();
|
|
@@ -15797,18 +15988,18 @@ app42.post("/", async (c) => {
|
|
|
15797
15988
|
}
|
|
15798
15989
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
15799
15990
|
if (rateMsg) {
|
|
15800
|
-
console.error(`${
|
|
15991
|
+
console.error(`${TAG33} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
15801
15992
|
return c.json({ error: rateMsg }, 429);
|
|
15802
15993
|
}
|
|
15803
15994
|
recordRequestLinkAttempt(contactValue);
|
|
15804
15995
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
15805
15996
|
if (!accountId) {
|
|
15806
|
-
console.error(`${
|
|
15997
|
+
console.error(`${TAG33} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
15807
15998
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15808
15999
|
}
|
|
15809
16000
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
15810
16001
|
if (!grant) {
|
|
15811
|
-
console.log(`${
|
|
16002
|
+
console.log(`${TAG33} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
15812
16003
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15813
16004
|
}
|
|
15814
16005
|
let token;
|
|
@@ -15816,7 +16007,7 @@ app42.post("/", async (c) => {
|
|
|
15816
16007
|
token = await generateNewMagicToken(grant.grantId);
|
|
15817
16008
|
} catch (err) {
|
|
15818
16009
|
console.error(
|
|
15819
|
-
`${
|
|
16010
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
15820
16011
|
);
|
|
15821
16012
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15822
16013
|
}
|
|
@@ -15848,26 +16039,26 @@ app42.post("/", async (c) => {
|
|
|
15848
16039
|
});
|
|
15849
16040
|
if (!sendResult.ok) {
|
|
15850
16041
|
console.error(
|
|
15851
|
-
`${
|
|
16042
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
15852
16043
|
);
|
|
15853
16044
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15854
16045
|
}
|
|
15855
16046
|
console.log(
|
|
15856
|
-
`${
|
|
16047
|
+
`${TAG33} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
15857
16048
|
);
|
|
15858
16049
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
15859
16050
|
});
|
|
15860
|
-
var request_magic_link_default =
|
|
16051
|
+
var request_magic_link_default = app43;
|
|
15861
16052
|
|
|
15862
16053
|
// server/routes/access/index.ts
|
|
15863
|
-
var
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
var access_default =
|
|
16054
|
+
var app44 = new Hono();
|
|
16055
|
+
app44.route("/verify-token", verify_token_default);
|
|
16056
|
+
app44.route("/request-magic-link", request_magic_link_default);
|
|
16057
|
+
var access_default = app44;
|
|
15867
16058
|
|
|
15868
16059
|
// server/routes/sites.ts
|
|
15869
|
-
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as
|
|
15870
|
-
import { resolve as
|
|
16060
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync10 } from "fs";
|
|
16061
|
+
import { resolve as resolve26 } from "path";
|
|
15871
16062
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
15872
16063
|
var MIME = {
|
|
15873
16064
|
".html": "text/html; charset=utf-8",
|
|
@@ -15898,8 +16089,8 @@ function getExt(p) {
|
|
|
15898
16089
|
if (idx < p.lastIndexOf("/")) return "";
|
|
15899
16090
|
return p.slice(idx).toLowerCase();
|
|
15900
16091
|
}
|
|
15901
|
-
var
|
|
15902
|
-
|
|
16092
|
+
var app45 = new Hono();
|
|
16093
|
+
app45.get("/:rel{.*}", (c) => {
|
|
15903
16094
|
const reqPath = c.req.path;
|
|
15904
16095
|
const rawRel = c.req.param("rel") ?? "";
|
|
15905
16096
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -15924,15 +16115,15 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
15924
16115
|
}
|
|
15925
16116
|
segments.push(seg);
|
|
15926
16117
|
}
|
|
15927
|
-
const rootDir =
|
|
15928
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
16118
|
+
const rootDir = resolve26(account.accountDir, "sites");
|
|
16119
|
+
let filePath = segments.length === 0 ? rootDir : resolve26(rootDir, ...segments);
|
|
15929
16120
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
15930
16121
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
15931
16122
|
return c.text("Forbidden", 403);
|
|
15932
16123
|
}
|
|
15933
16124
|
let stat7;
|
|
15934
16125
|
try {
|
|
15935
|
-
stat7 = existsSync23(filePath) ?
|
|
16126
|
+
stat7 = existsSync23(filePath) ? statSync10(filePath) : null;
|
|
15936
16127
|
} catch {
|
|
15937
16128
|
stat7 = null;
|
|
15938
16129
|
}
|
|
@@ -15945,7 +16136,7 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
15945
16136
|
return c.redirect(target, 301);
|
|
15946
16137
|
}
|
|
15947
16138
|
if (stat7?.isDirectory()) {
|
|
15948
|
-
filePath =
|
|
16139
|
+
filePath = resolve26(filePath, "index.html");
|
|
15949
16140
|
}
|
|
15950
16141
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
15951
16142
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
@@ -16002,12 +16193,12 @@ app44.get("/:rel{.*}", (c) => {
|
|
|
16002
16193
|
"X-Content-Type-Options": "nosniff"
|
|
16003
16194
|
});
|
|
16004
16195
|
});
|
|
16005
|
-
var sites_default =
|
|
16196
|
+
var sites_default = app45;
|
|
16006
16197
|
|
|
16007
16198
|
// app/lib/visitor-token.ts
|
|
16008
16199
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
16009
16200
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync24, writeFileSync as writeFileSync9 } from "fs";
|
|
16010
|
-
import { dirname as
|
|
16201
|
+
import { dirname as dirname7 } from "path";
|
|
16011
16202
|
var TOKEN_PREFIX = "v1.";
|
|
16012
16203
|
var SECRET_BYTES = 32;
|
|
16013
16204
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -16024,7 +16215,7 @@ function getSecret() {
|
|
|
16024
16215
|
}
|
|
16025
16216
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
16026
16217
|
try {
|
|
16027
|
-
mkdirSync4(
|
|
16218
|
+
mkdirSync4(dirname7(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
16028
16219
|
writeFileSync9(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
16029
16220
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
16030
16221
|
} catch {
|
|
@@ -16083,7 +16274,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
16083
16274
|
|
|
16084
16275
|
// app/lib/brand-config.ts
|
|
16085
16276
|
import { existsSync as existsSync24, readFileSync as readFileSync25 } from "fs";
|
|
16086
|
-
import { join as
|
|
16277
|
+
import { join as join23 } from "path";
|
|
16087
16278
|
var cached2 = null;
|
|
16088
16279
|
var cachedAttempted = false;
|
|
16089
16280
|
function readBrandConfig() {
|
|
@@ -16091,7 +16282,7 @@ function readBrandConfig() {
|
|
|
16091
16282
|
cachedAttempted = true;
|
|
16092
16283
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
16093
16284
|
if (!platformRoot2) return null;
|
|
16094
|
-
const brandPath =
|
|
16285
|
+
const brandPath = join23(platformRoot2, "config", "brand.json");
|
|
16095
16286
|
if (!existsSync24(brandPath)) return null;
|
|
16096
16287
|
try {
|
|
16097
16288
|
cached2 = JSON.parse(readFileSync25(brandPath, "utf-8"));
|
|
@@ -16102,7 +16293,7 @@ function readBrandConfig() {
|
|
|
16102
16293
|
}
|
|
16103
16294
|
|
|
16104
16295
|
// server/routes/visitor-consent.ts
|
|
16105
|
-
var
|
|
16296
|
+
var app46 = new Hono();
|
|
16106
16297
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
16107
16298
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
16108
16299
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -16147,17 +16338,17 @@ function siteSlugFromReferer(referer) {
|
|
|
16147
16338
|
return "";
|
|
16148
16339
|
}
|
|
16149
16340
|
}
|
|
16150
|
-
|
|
16341
|
+
app46.options("/consent", (c) => {
|
|
16151
16342
|
const origin = getOrigin(c);
|
|
16152
16343
|
setCorsHeaders(c, origin);
|
|
16153
16344
|
return c.body(null, 204);
|
|
16154
16345
|
});
|
|
16155
|
-
|
|
16346
|
+
app46.options("/brand-config", (c) => {
|
|
16156
16347
|
const origin = getOrigin(c);
|
|
16157
16348
|
setCorsHeaders(c, origin);
|
|
16158
16349
|
return c.body(null, 204);
|
|
16159
16350
|
});
|
|
16160
|
-
|
|
16351
|
+
app46.post("/consent", async (c) => {
|
|
16161
16352
|
const origin = getOrigin(c);
|
|
16162
16353
|
setCorsHeaders(c, origin);
|
|
16163
16354
|
let raw;
|
|
@@ -16197,7 +16388,7 @@ app45.post("/consent", async (c) => {
|
|
|
16197
16388
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
16198
16389
|
return c.body(null, 204);
|
|
16199
16390
|
});
|
|
16200
|
-
|
|
16391
|
+
app46.get("/brand-config", (c) => {
|
|
16201
16392
|
const origin = getOrigin(c);
|
|
16202
16393
|
setCorsHeaders(c, origin);
|
|
16203
16394
|
const brand = readBrandConfig();
|
|
@@ -16207,7 +16398,7 @@ app45.get("/brand-config", (c) => {
|
|
|
16207
16398
|
c.header("Cache-Control", "public, max-age=300");
|
|
16208
16399
|
return c.json({ consent: { copy, palette } });
|
|
16209
16400
|
});
|
|
16210
|
-
var visitor_consent_default =
|
|
16401
|
+
var visitor_consent_default = app46;
|
|
16211
16402
|
|
|
16212
16403
|
// server/routes/listings.ts
|
|
16213
16404
|
function getCookie(headerValue, name) {
|
|
@@ -16228,14 +16419,14 @@ function appendConsentParams(pageUrl, token) {
|
|
|
16228
16419
|
const hashIdx = pageUrl.indexOf("#");
|
|
16229
16420
|
const hash = hashIdx >= 0 ? pageUrl.slice(hashIdx) : "";
|
|
16230
16421
|
const base = hashIdx >= 0 ? pageUrl.slice(0, hashIdx) : pageUrl;
|
|
16231
|
-
const
|
|
16232
|
-
return base +
|
|
16422
|
+
const sep9 = base.indexOf("?") >= 0 ? "&" : "?";
|
|
16423
|
+
return base + sep9 + `consent=needed&v=${encodeURIComponent(token)}` + hash;
|
|
16233
16424
|
}
|
|
16234
16425
|
}
|
|
16235
16426
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
16236
16427
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16237
|
-
var
|
|
16238
|
-
|
|
16428
|
+
var app47 = new Hono();
|
|
16429
|
+
app47.get("/:slug/click", async (c) => {
|
|
16239
16430
|
const slug = c.req.param("slug") ?? "";
|
|
16240
16431
|
const rawSession = c.req.query("session") ?? "";
|
|
16241
16432
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -16299,10 +16490,10 @@ app46.get("/:slug/click", async (c) => {
|
|
|
16299
16490
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
16300
16491
|
return c.redirect(redirectUrl, 302);
|
|
16301
16492
|
});
|
|
16302
|
-
var listings_default =
|
|
16493
|
+
var listings_default = app47;
|
|
16303
16494
|
|
|
16304
16495
|
// server/routes/visitor-event.ts
|
|
16305
|
-
var
|
|
16496
|
+
var app48 = new Hono();
|
|
16306
16497
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
16307
16498
|
var buckets = /* @__PURE__ */ new Map();
|
|
16308
16499
|
var RATE_LIMIT = 60;
|
|
@@ -16369,12 +16560,12 @@ function originAllowed(origin, allowlist) {
|
|
|
16369
16560
|
return false;
|
|
16370
16561
|
}
|
|
16371
16562
|
}
|
|
16372
|
-
|
|
16563
|
+
app48.options("/event", (c) => {
|
|
16373
16564
|
const origin = getOrigin2(c);
|
|
16374
16565
|
setCorsHeaders2(c, origin);
|
|
16375
16566
|
return c.body(null, 204);
|
|
16376
16567
|
});
|
|
16377
|
-
|
|
16568
|
+
app48.post("/event", async (c) => {
|
|
16378
16569
|
const origin = getOrigin2(c);
|
|
16379
16570
|
setCorsHeaders2(c, origin);
|
|
16380
16571
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -16579,17 +16770,17 @@ async function writeEvent(opts) {
|
|
|
16579
16770
|
);
|
|
16580
16771
|
}
|
|
16581
16772
|
}
|
|
16582
|
-
var visitor_event_default =
|
|
16773
|
+
var visitor_event_default = app48;
|
|
16583
16774
|
|
|
16584
16775
|
// server/routes/session.ts
|
|
16585
|
-
import { resolve as
|
|
16776
|
+
import { resolve as resolve27 } from "path";
|
|
16586
16777
|
import { existsSync as existsSync25, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5 } from "fs";
|
|
16587
16778
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16588
16779
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
16589
16780
|
try {
|
|
16590
|
-
const cacheDir =
|
|
16781
|
+
const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
|
|
16591
16782
|
mkdirSync5(cacheDir, { recursive: true });
|
|
16592
|
-
writeFileSync10(
|
|
16783
|
+
writeFileSync10(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
16593
16784
|
} catch (err) {
|
|
16594
16785
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
16595
16786
|
}
|
|
@@ -16601,7 +16792,7 @@ function parseVisitorCookie(cookieHeader) {
|
|
|
16601
16792
|
const value = decodeURIComponent(match[1]).trim();
|
|
16602
16793
|
return UUID_RE4.test(value) ? value : null;
|
|
16603
16794
|
}
|
|
16604
|
-
function
|
|
16795
|
+
function parseAccessSessionId2(cookieHeader) {
|
|
16605
16796
|
if (!cookieHeader) return null;
|
|
16606
16797
|
const part = cookieHeader.split(";").map((p) => p.trim()).find((p) => p.startsWith("__access_session="));
|
|
16607
16798
|
return part ? part.slice("__access_session=".length) : null;
|
|
@@ -16625,8 +16816,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
16625
16816
|
headers
|
|
16626
16817
|
});
|
|
16627
16818
|
}
|
|
16628
|
-
var
|
|
16629
|
-
|
|
16819
|
+
var app49 = new Hono();
|
|
16820
|
+
app49.post("/", async (c) => {
|
|
16630
16821
|
let body;
|
|
16631
16822
|
try {
|
|
16632
16823
|
body = await c.req.json();
|
|
@@ -16677,8 +16868,8 @@ app48.post("/", async (c) => {
|
|
|
16677
16868
|
}
|
|
16678
16869
|
let agentConfig = null;
|
|
16679
16870
|
if (account) {
|
|
16680
|
-
const agentDir =
|
|
16681
|
-
if (!existsSync25(agentDir) || !existsSync25(
|
|
16871
|
+
const agentDir = resolve27(account.accountDir, "agents", agentSlug);
|
|
16872
|
+
if (!existsSync25(agentDir) || !existsSync25(resolve27(agentDir, "config.json"))) {
|
|
16682
16873
|
return c.json({ error: "Agent not found" }, 404);
|
|
16683
16874
|
}
|
|
16684
16875
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -16698,7 +16889,7 @@ app48.post("/", async (c) => {
|
|
|
16698
16889
|
if (branding) writeBrandingCache(accountId, agentSlug, branding);
|
|
16699
16890
|
let accessSession = null;
|
|
16700
16891
|
if (agentConfig && agentConfig.accessMode !== "open") {
|
|
16701
|
-
const accessSessionId =
|
|
16892
|
+
const accessSessionId = parseAccessSessionId2(cookieHeader);
|
|
16702
16893
|
accessSession = accessSessionId ? getAccessSession(accessSessionId) : null;
|
|
16703
16894
|
if (!accessSession || accessSession.agentSlug !== agentSlug) {
|
|
16704
16895
|
console.log(`[session] agent=${agentSlug} accessMode=${agentConfig.accessMode} \u2014 auth required`);
|
|
@@ -16837,7 +17028,7 @@ app48.post("/", async (c) => {
|
|
|
16837
17028
|
newVisitorId
|
|
16838
17029
|
);
|
|
16839
17030
|
});
|
|
16840
|
-
var session_default2 =
|
|
17031
|
+
var session_default2 = app49;
|
|
16841
17032
|
|
|
16842
17033
|
// app/lib/graph-health.ts
|
|
16843
17034
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -16958,13 +17149,13 @@ function startGraphHealthTimer() {
|
|
|
16958
17149
|
|
|
16959
17150
|
// app/lib/file-watcher.ts
|
|
16960
17151
|
import * as fsp2 from "fs/promises";
|
|
16961
|
-
import { resolve as
|
|
17152
|
+
import { resolve as resolve28, sep as sep8 } from "path";
|
|
16962
17153
|
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;
|
|
16963
17154
|
var DEFAULT_COALESCE_MS = 500;
|
|
16964
17155
|
var ROOTS = ["accounts"];
|
|
16965
17156
|
function _routeEvent(rootName, filename) {
|
|
16966
17157
|
if (!filename) return null;
|
|
16967
|
-
const segs = filename.split(
|
|
17158
|
+
const segs = filename.split(sep8).filter(Boolean);
|
|
16968
17159
|
if (segs.length < 2) return null;
|
|
16969
17160
|
const accountId = segs[0];
|
|
16970
17161
|
if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
|
|
@@ -16977,7 +17168,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16977
17168
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
16978
17169
|
for (const r of ROOTS) {
|
|
16979
17170
|
try {
|
|
16980
|
-
await fsp2.mkdir(
|
|
17171
|
+
await fsp2.mkdir(resolve28(dataRoot, r), { recursive: true });
|
|
16981
17172
|
} catch (err) {
|
|
16982
17173
|
console.error(
|
|
16983
17174
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -16998,7 +17189,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
16998
17189
|
timers.set(relativePath, t);
|
|
16999
17190
|
}
|
|
17000
17191
|
async function runHook(relativePath, accountId) {
|
|
17001
|
-
const absolute =
|
|
17192
|
+
const absolute = resolve28(dataRoot, relativePath);
|
|
17002
17193
|
let exists = false;
|
|
17003
17194
|
try {
|
|
17004
17195
|
const st = await fsp2.stat(absolute);
|
|
@@ -17022,7 +17213,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
17022
17213
|
}
|
|
17023
17214
|
}
|
|
17024
17215
|
async function watchRoot(rootName) {
|
|
17025
|
-
const absRoot =
|
|
17216
|
+
const absRoot = resolve28(dataRoot, rootName);
|
|
17026
17217
|
try {
|
|
17027
17218
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
17028
17219
|
for await (const event of iter) {
|
|
@@ -17061,7 +17252,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
17061
17252
|
|
|
17062
17253
|
// app/lib/migrate-uploads.ts
|
|
17063
17254
|
import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
|
|
17064
|
-
import { dirname as
|
|
17255
|
+
import { dirname as dirname8, relative as relative4, resolve as resolve29 } from "path";
|
|
17065
17256
|
var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17066
17257
|
async function walkFiles(dir) {
|
|
17067
17258
|
const out = [];
|
|
@@ -17072,7 +17263,7 @@ async function walkFiles(dir) {
|
|
|
17072
17263
|
return out;
|
|
17073
17264
|
}
|
|
17074
17265
|
for (const e of entries) {
|
|
17075
|
-
const abs =
|
|
17266
|
+
const abs = resolve29(dir, e.name);
|
|
17076
17267
|
if (e.isDirectory()) {
|
|
17077
17268
|
out.push(...await walkFiles(abs));
|
|
17078
17269
|
} else if (e.isFile()) {
|
|
@@ -17092,8 +17283,8 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
17092
17283
|
let moved = 0;
|
|
17093
17284
|
for (const oldAbs of files) {
|
|
17094
17285
|
const suffix = relative4(srcDir, oldAbs);
|
|
17095
|
-
const newAbs =
|
|
17096
|
-
await mkdir5(
|
|
17286
|
+
const newAbs = resolve29(destDir, suffix);
|
|
17287
|
+
await mkdir5(dirname8(newAbs), { recursive: true });
|
|
17097
17288
|
await rename(oldAbs, newAbs);
|
|
17098
17289
|
moved++;
|
|
17099
17290
|
const oldRel = relative4(dataRoot, oldAbs);
|
|
@@ -17119,7 +17310,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
17119
17310
|
}
|
|
17120
17311
|
async function migrateUploads(opts = {}) {
|
|
17121
17312
|
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
17122
|
-
const oldRoot =
|
|
17313
|
+
const oldRoot = resolve29(dataRoot, "uploads");
|
|
17123
17314
|
let topEntries;
|
|
17124
17315
|
try {
|
|
17125
17316
|
topEntries = await readdir5(oldRoot, { withFileTypes: true });
|
|
@@ -17140,8 +17331,8 @@ async function migrateUploads(opts = {}) {
|
|
|
17140
17331
|
const name = entry.name;
|
|
17141
17332
|
if (ACCOUNT_UUID_RE3.test(name)) {
|
|
17142
17333
|
moved += await relocateTree(
|
|
17143
|
-
|
|
17144
|
-
|
|
17334
|
+
resolve29(oldRoot, name),
|
|
17335
|
+
resolve29(dataRoot, "accounts", name, "uploads"),
|
|
17145
17336
|
dataRoot,
|
|
17146
17337
|
name,
|
|
17147
17338
|
session
|
|
@@ -17153,8 +17344,8 @@ async function migrateUploads(opts = {}) {
|
|
|
17153
17344
|
continue;
|
|
17154
17345
|
}
|
|
17155
17346
|
moved += await relocateTree(
|
|
17156
|
-
|
|
17157
|
-
|
|
17347
|
+
resolve29(oldRoot, "public"),
|
|
17348
|
+
resolve29(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
17158
17349
|
dataRoot,
|
|
17159
17350
|
null,
|
|
17160
17351
|
// public uploads carry no graph nodes
|
|
@@ -17185,7 +17376,7 @@ async function migrateUploads(opts = {}) {
|
|
|
17185
17376
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
17186
17377
|
import { readdir as readdir6, readFile as readFile6, rename as rename2, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
|
|
17187
17378
|
import { existsSync as existsSync26 } from "fs";
|
|
17188
|
-
import { join as
|
|
17379
|
+
import { join as join24 } from "path";
|
|
17189
17380
|
var ADMIN_ROLE2 = "admin";
|
|
17190
17381
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
17191
17382
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -17230,7 +17421,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17230
17421
|
}
|
|
17231
17422
|
for (const slug of slugs) {
|
|
17232
17423
|
if (!slug.isDirectory()) continue;
|
|
17233
|
-
const slugDir =
|
|
17424
|
+
const slugDir = join24(projectsRoot, slug.name);
|
|
17234
17425
|
let entries;
|
|
17235
17426
|
try {
|
|
17236
17427
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -17239,9 +17430,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17239
17430
|
}
|
|
17240
17431
|
for (const entry of entries) {
|
|
17241
17432
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
17242
|
-
out.push(
|
|
17433
|
+
out.push(join24(slugDir, entry.name));
|
|
17243
17434
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
17244
|
-
const subDir =
|
|
17435
|
+
const subDir = join24(slugDir, entry.name);
|
|
17245
17436
|
let subs;
|
|
17246
17437
|
try {
|
|
17247
17438
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -17249,7 +17440,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17249
17440
|
continue;
|
|
17250
17441
|
}
|
|
17251
17442
|
for (const s of subs) {
|
|
17252
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
17443
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join24(subDir, s.name));
|
|
17253
17444
|
}
|
|
17254
17445
|
}
|
|
17255
17446
|
}
|
|
@@ -17261,7 +17452,7 @@ function shortId(path2) {
|
|
|
17261
17452
|
return base.slice(0, 8);
|
|
17262
17453
|
}
|
|
17263
17454
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
17264
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
17455
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join24(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
17265
17456
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
17266
17457
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
17267
17458
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -17603,8 +17794,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
17603
17794
|
|
|
17604
17795
|
// app/lib/whatsapp/gateway/routes.ts
|
|
17605
17796
|
function createWaChannelRoutes(deps) {
|
|
17606
|
-
const
|
|
17607
|
-
|
|
17797
|
+
const app51 = new Hono();
|
|
17798
|
+
app51.get("/wa-channel/inbound", (c) => {
|
|
17608
17799
|
const senderId = c.req.query("senderId");
|
|
17609
17800
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
17610
17801
|
return streamSSE(c, async (stream2) => {
|
|
@@ -17622,7 +17813,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17622
17813
|
}
|
|
17623
17814
|
});
|
|
17624
17815
|
});
|
|
17625
|
-
|
|
17816
|
+
app51.post("/wa-channel/reply", async (c) => {
|
|
17626
17817
|
const body = await c.req.json().catch(() => null);
|
|
17627
17818
|
const senderId = body?.senderId;
|
|
17628
17819
|
const text = body?.text;
|
|
@@ -17643,7 +17834,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17643
17834
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
17644
17835
|
return c.json({ ok: true });
|
|
17645
17836
|
});
|
|
17646
|
-
|
|
17837
|
+
app51.post("/wa-channel/reply-document", async (c) => {
|
|
17647
17838
|
const body = await c.req.json().catch(() => null);
|
|
17648
17839
|
const senderId = body?.senderId;
|
|
17649
17840
|
const files = body?.files;
|
|
@@ -17682,7 +17873,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17682
17873
|
}
|
|
17683
17874
|
return c.json({ ok: true, results });
|
|
17684
17875
|
});
|
|
17685
|
-
|
|
17876
|
+
app51.post("/wa-channel/ready", async (c) => {
|
|
17686
17877
|
const body = await c.req.json().catch(() => null);
|
|
17687
17878
|
const senderId = body?.senderId;
|
|
17688
17879
|
if (typeof senderId !== "string") {
|
|
@@ -17691,7 +17882,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17691
17882
|
deps.onReady?.(senderId);
|
|
17692
17883
|
return c.json({ ok: true });
|
|
17693
17884
|
});
|
|
17694
|
-
|
|
17885
|
+
app51.post("/wa-channel/received", async (c) => {
|
|
17695
17886
|
const body = await c.req.json().catch(() => null);
|
|
17696
17887
|
const senderId = body?.senderId;
|
|
17697
17888
|
const waMessageId = body?.waMessageId;
|
|
@@ -17701,7 +17892,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17701
17892
|
deps.onReceived?.(senderId, waMessageId);
|
|
17702
17893
|
return c.json({ ok: true });
|
|
17703
17894
|
});
|
|
17704
|
-
|
|
17895
|
+
app51.post("/wa-channel/turn-end", async (c) => {
|
|
17705
17896
|
const body = await c.req.json().catch(() => null);
|
|
17706
17897
|
const senderId = body?.senderId;
|
|
17707
17898
|
const sessionId = body?.sessionId;
|
|
@@ -17732,7 +17923,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17732
17923
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
17733
17924
|
return c.json({ ok: true, delivered: "fallback" });
|
|
17734
17925
|
});
|
|
17735
|
-
return
|
|
17926
|
+
return app51;
|
|
17736
17927
|
}
|
|
17737
17928
|
|
|
17738
17929
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -17985,8 +18176,8 @@ var InboundHub2 = class {
|
|
|
17985
18176
|
|
|
17986
18177
|
// app/lib/webchat/gateway/routes.ts
|
|
17987
18178
|
function createWebchatChannelRoutes(deps) {
|
|
17988
|
-
const
|
|
17989
|
-
|
|
18179
|
+
const app51 = new Hono();
|
|
18180
|
+
app51.get("/webchat-channel/inbound", (c) => {
|
|
17990
18181
|
const key = c.req.query("key");
|
|
17991
18182
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
17992
18183
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18004,7 +18195,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18004
18195
|
}
|
|
18005
18196
|
});
|
|
18006
18197
|
});
|
|
18007
|
-
|
|
18198
|
+
app51.post("/webchat-channel/reply", async (c) => {
|
|
18008
18199
|
const body = await c.req.json().catch(() => null);
|
|
18009
18200
|
const key = body?.key;
|
|
18010
18201
|
const text = body?.text;
|
|
@@ -18014,7 +18205,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18014
18205
|
deps.onReply?.(key, text);
|
|
18015
18206
|
return c.json({ ok: true });
|
|
18016
18207
|
});
|
|
18017
|
-
|
|
18208
|
+
app51.post("/webchat-channel/ready", async (c) => {
|
|
18018
18209
|
const body = await c.req.json().catch(() => null);
|
|
18019
18210
|
const key = body?.key;
|
|
18020
18211
|
if (typeof key !== "string") {
|
|
@@ -18023,7 +18214,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18023
18214
|
deps.onReady?.(key);
|
|
18024
18215
|
return c.json({ ok: true });
|
|
18025
18216
|
});
|
|
18026
|
-
|
|
18217
|
+
app51.post("/webchat-channel/received", async (c) => {
|
|
18027
18218
|
const body = await c.req.json().catch(() => null);
|
|
18028
18219
|
const key = body?.key;
|
|
18029
18220
|
const messageId = body?.messageId;
|
|
@@ -18033,7 +18224,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18033
18224
|
deps.onReceived?.(key, messageId);
|
|
18034
18225
|
return c.json({ ok: true });
|
|
18035
18226
|
});
|
|
18036
|
-
return
|
|
18227
|
+
return app51;
|
|
18037
18228
|
}
|
|
18038
18229
|
|
|
18039
18230
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -18068,16 +18259,16 @@ var WebchatGateway = class {
|
|
|
18068
18259
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
18069
18260
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
18070
18261
|
awaitReply(key, timeoutMs) {
|
|
18071
|
-
return new Promise((
|
|
18262
|
+
return new Promise((resolve32) => {
|
|
18072
18263
|
const timer2 = setTimeout(() => {
|
|
18073
18264
|
this.replyAwaiters.delete(key);
|
|
18074
|
-
|
|
18265
|
+
resolve32({ timeout: true });
|
|
18075
18266
|
}, timeoutMs);
|
|
18076
18267
|
if (timer2.unref) timer2.unref();
|
|
18077
18268
|
this.replyAwaiters.set(key, (r) => {
|
|
18078
18269
|
clearTimeout(timer2);
|
|
18079
18270
|
this.replyAwaiters.delete(key);
|
|
18080
|
-
|
|
18271
|
+
resolve32(r);
|
|
18081
18272
|
});
|
|
18082
18273
|
});
|
|
18083
18274
|
}
|
|
@@ -18346,8 +18537,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
18346
18537
|
|
|
18347
18538
|
// ../lib/entitlement/src/index.ts
|
|
18348
18539
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
18349
|
-
import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as
|
|
18350
|
-
import { resolve as
|
|
18540
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
|
|
18541
|
+
import { resolve as resolve30 } from "path";
|
|
18351
18542
|
|
|
18352
18543
|
// ../lib/entitlement/src/canonicalize.ts
|
|
18353
18544
|
function canonicalize(value) {
|
|
@@ -18382,7 +18573,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
18382
18573
|
var GRACE_DAYS = 7;
|
|
18383
18574
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
18384
18575
|
function pubkeyPath(brand) {
|
|
18385
|
-
return
|
|
18576
|
+
return resolve30(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
18386
18577
|
}
|
|
18387
18578
|
var memo = null;
|
|
18388
18579
|
function memoKey(mtimeMs, account) {
|
|
@@ -18394,11 +18585,11 @@ function resolveEntitlement(brand, account) {
|
|
|
18394
18585
|
if (brand.commercialMode !== true) {
|
|
18395
18586
|
return logResolved(implicitTrust(account), null);
|
|
18396
18587
|
}
|
|
18397
|
-
const entitlementPath =
|
|
18588
|
+
const entitlementPath = resolve30(brand.configDir, "entitlement.json");
|
|
18398
18589
|
if (!existsSync27(entitlementPath)) {
|
|
18399
18590
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
18400
18591
|
}
|
|
18401
|
-
const stat7 =
|
|
18592
|
+
const stat7 = statSync11(entitlementPath);
|
|
18402
18593
|
const key = memoKey(stat7.mtimeMs, account);
|
|
18403
18594
|
if (memo && memo.key === key) {
|
|
18404
18595
|
return memo.result;
|
|
@@ -18585,7 +18776,7 @@ function clientFrom(c) {
|
|
|
18585
18776
|
);
|
|
18586
18777
|
}
|
|
18587
18778
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18588
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
18779
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join25(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
18589
18780
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
18590
18781
|
if (BRAND_JSON_PATH && !existsSync28(BRAND_JSON_PATH)) {
|
|
18591
18782
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -18611,7 +18802,7 @@ var brandLoginOpts = {
|
|
|
18611
18802
|
bodyFont: BRAND.defaultFonts?.body,
|
|
18612
18803
|
logoContainsName: !!BRAND.logoContainsName
|
|
18613
18804
|
};
|
|
18614
|
-
var ALIAS_DOMAINS_PATH =
|
|
18805
|
+
var ALIAS_DOMAINS_PATH = join25(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
18615
18806
|
function loadAliasDomains() {
|
|
18616
18807
|
try {
|
|
18617
18808
|
if (!existsSync28(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -18639,11 +18830,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
18639
18830
|
function isPublicHost(host) {
|
|
18640
18831
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
18641
18832
|
}
|
|
18642
|
-
var
|
|
18833
|
+
var app50 = new Hono();
|
|
18643
18834
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
18644
18835
|
var waGateway = new WaGateway({
|
|
18645
18836
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
18646
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
18837
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
18647
18838
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
18648
18839
|
// account + path validation here and funnel through the shared send core.
|
|
18649
18840
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -18659,7 +18850,7 @@ var waGateway = new WaGateway({
|
|
|
18659
18850
|
caption,
|
|
18660
18851
|
accountId,
|
|
18661
18852
|
maxyAccountId,
|
|
18662
|
-
platformRoot:
|
|
18853
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, ".."))
|
|
18663
18854
|
});
|
|
18664
18855
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
18665
18856
|
},
|
|
@@ -18689,7 +18880,7 @@ var waGateway = new WaGateway({
|
|
|
18689
18880
|
nativeFileFollowers.set(senderId, ac);
|
|
18690
18881
|
}
|
|
18691
18882
|
});
|
|
18692
|
-
|
|
18883
|
+
app50.route("/", waGateway.routes());
|
|
18693
18884
|
waGateway.startSweeper();
|
|
18694
18885
|
var webchatGateway = new WebchatGateway({
|
|
18695
18886
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -18729,15 +18920,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
18729
18920
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
18730
18921
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
18731
18922
|
});
|
|
18732
|
-
|
|
18923
|
+
app50.route("/", webchatGateway.routes());
|
|
18733
18924
|
webchatGateway.startSweeper();
|
|
18734
18925
|
webchatGateway.startPublicReaper();
|
|
18735
18926
|
var chatRoutes = createChatRoutes({
|
|
18736
18927
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
18737
18928
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
18738
18929
|
});
|
|
18739
|
-
|
|
18740
|
-
|
|
18930
|
+
app50.use("*", clientIpMiddleware);
|
|
18931
|
+
app50.use("*", async (c, next) => {
|
|
18741
18932
|
await next();
|
|
18742
18933
|
c.header("X-Content-Type-Options", "nosniff");
|
|
18743
18934
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -18747,7 +18938,7 @@ app49.use("*", async (c, next) => {
|
|
|
18747
18938
|
);
|
|
18748
18939
|
});
|
|
18749
18940
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
18750
|
-
|
|
18941
|
+
app50.use("*", async (c, next) => {
|
|
18751
18942
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
18752
18943
|
await next();
|
|
18753
18944
|
return;
|
|
@@ -18765,7 +18956,7 @@ app49.use("*", async (c, next) => {
|
|
|
18765
18956
|
});
|
|
18766
18957
|
}
|
|
18767
18958
|
});
|
|
18768
|
-
|
|
18959
|
+
app50.use("*", async (c, next) => {
|
|
18769
18960
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
18770
18961
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
18771
18962
|
await next();
|
|
@@ -18796,7 +18987,7 @@ function resolveRemoteAuthOpts() {
|
|
|
18796
18987
|
return brandLoginOpts;
|
|
18797
18988
|
}
|
|
18798
18989
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
18799
|
-
|
|
18990
|
+
app50.post("/__remote-auth/login", async (c) => {
|
|
18800
18991
|
const client = clientFrom(c);
|
|
18801
18992
|
const clientIp = client.ip || "unknown";
|
|
18802
18993
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -18841,7 +19032,7 @@ app49.post("/__remote-auth/login", async (c) => {
|
|
|
18841
19032
|
}
|
|
18842
19033
|
});
|
|
18843
19034
|
});
|
|
18844
|
-
|
|
19035
|
+
app50.get("/__remote-auth/logout", (c) => {
|
|
18845
19036
|
const client = clientFrom(c);
|
|
18846
19037
|
const clientIp = client.ip || "unknown";
|
|
18847
19038
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -18854,7 +19045,7 @@ app49.get("/__remote-auth/logout", (c) => {
|
|
|
18854
19045
|
}
|
|
18855
19046
|
});
|
|
18856
19047
|
});
|
|
18857
|
-
|
|
19048
|
+
app50.post("/__remote-auth/change-password", async (c) => {
|
|
18858
19049
|
const client = clientFrom(c);
|
|
18859
19050
|
const clientIp = client.ip || "unknown";
|
|
18860
19051
|
const rateLimited = checkRateLimit(client);
|
|
@@ -18896,6 +19087,9 @@ app49.post("/__remote-auth/change-password", async (c) => {
|
|
|
18896
19087
|
redirect
|
|
18897
19088
|
}), 200);
|
|
18898
19089
|
}
|
|
19090
|
+
if (targetUserId && await accessPasswordCollides(newPassword, USERS_FILE, targetUserId)) {
|
|
19091
|
+
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "That password is already in use by another admin. Choose a different one.", redirect }), 200);
|
|
19092
|
+
}
|
|
18899
19093
|
try {
|
|
18900
19094
|
if (targetUserId) {
|
|
18901
19095
|
await setAccessPassword(targetUserId, newPassword, USERS_FILE);
|
|
@@ -18910,13 +19104,13 @@ app49.post("/__remote-auth/change-password", async (c) => {
|
|
|
18910
19104
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
18911
19105
|
}
|
|
18912
19106
|
});
|
|
18913
|
-
|
|
19107
|
+
app50.get("/__remote-auth/setup", (c) => {
|
|
18914
19108
|
if (isRemoteAuthConfigured()) {
|
|
18915
19109
|
return c.redirect("/");
|
|
18916
19110
|
}
|
|
18917
19111
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
18918
19112
|
});
|
|
18919
|
-
|
|
19113
|
+
app50.post("/__remote-auth/set-initial-password", async (c) => {
|
|
18920
19114
|
if (isRemoteAuthConfigured()) {
|
|
18921
19115
|
return c.redirect("/");
|
|
18922
19116
|
}
|
|
@@ -18954,10 +19148,10 @@ app49.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
18954
19148
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
18955
19149
|
}
|
|
18956
19150
|
});
|
|
18957
|
-
|
|
19151
|
+
app50.get("/api/remote-auth/status", (c) => {
|
|
18958
19152
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
18959
19153
|
});
|
|
18960
|
-
|
|
19154
|
+
app50.post("/api/remote-auth/set-password", async (c) => {
|
|
18961
19155
|
let body;
|
|
18962
19156
|
try {
|
|
18963
19157
|
body = await c.req.json();
|
|
@@ -18980,6 +19174,9 @@ app49.post("/api/remote-auth/set-password", async (c) => {
|
|
|
18980
19174
|
requirements
|
|
18981
19175
|
}, 400);
|
|
18982
19176
|
}
|
|
19177
|
+
if (sessionUserId && await accessPasswordCollides(body.password, USERS_FILE, sessionUserId)) {
|
|
19178
|
+
return c.json({ error: "That password is already in use by another admin. Choose a different one." }, 400);
|
|
19179
|
+
}
|
|
18983
19180
|
try {
|
|
18984
19181
|
if (sessionUserId) {
|
|
18985
19182
|
await setAccessPassword(sessionUserId, body.password, USERS_FILE);
|
|
@@ -18993,10 +19190,10 @@ app49.post("/api/remote-auth/set-password", async (c) => {
|
|
|
18993
19190
|
return c.json({ error: "Failed to save password" }, 500);
|
|
18994
19191
|
}
|
|
18995
19192
|
});
|
|
18996
|
-
|
|
19193
|
+
app50.route("/api/_client-error", client_error_default);
|
|
18997
19194
|
console.log("[client-error-route] mounted");
|
|
18998
19195
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
18999
|
-
|
|
19196
|
+
app50.use("*", async (c, next) => {
|
|
19000
19197
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19001
19198
|
const path2 = c.req.path;
|
|
19002
19199
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || PWA_PUBLIC_PATHS.has(path2)) {
|
|
@@ -19036,17 +19233,18 @@ app49.use("*", async (c, next) => {
|
|
|
19036
19233
|
}
|
|
19037
19234
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
19038
19235
|
});
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19236
|
+
app50.route("/api/health", health_default);
|
|
19237
|
+
app50.route("/api/chat", chatRoutes);
|
|
19238
|
+
app50.route("/api/whatsapp", whatsapp_default);
|
|
19239
|
+
app50.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
19240
|
+
app50.route("/api/public-reader", public_reader_default);
|
|
19241
|
+
app50.route("/api/webchat", createWebchatRoutes({ handleInbound: (input) => webchatGateway.handleInbound(input) }));
|
|
19242
|
+
app50.route("/api/webchat/greeting", webchat_greeting_default);
|
|
19243
|
+
app50.route("/api/telegram", telegram_default);
|
|
19244
|
+
app50.route("/api/onboarding", onboarding_default);
|
|
19245
|
+
app50.route("/api/admin", admin_default);
|
|
19246
|
+
app50.route("/api/access", access_default);
|
|
19247
|
+
app50.route("/api/session", session_default2);
|
|
19050
19248
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
19051
19249
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
19052
19250
|
var IMAGE_MIME = {
|
|
@@ -19058,7 +19256,7 @@ var IMAGE_MIME = {
|
|
|
19058
19256
|
".svg": "image/svg+xml",
|
|
19059
19257
|
".ico": "image/x-icon"
|
|
19060
19258
|
};
|
|
19061
|
-
|
|
19259
|
+
app50.get("/agent-assets/:slug/:filename", (c) => {
|
|
19062
19260
|
const slug = c.req.param("slug");
|
|
19063
19261
|
const filename = c.req.param("filename");
|
|
19064
19262
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -19074,8 +19272,8 @@ app49.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19074
19272
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
19075
19273
|
return c.text("Not found", 404);
|
|
19076
19274
|
}
|
|
19077
|
-
const filePath =
|
|
19078
|
-
const expectedDir =
|
|
19275
|
+
const filePath = resolve31(account.accountDir, "agents", slug, "assets", filename);
|
|
19276
|
+
const expectedDir = resolve31(account.accountDir, "agents", slug, "assets");
|
|
19079
19277
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
19080
19278
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
19081
19279
|
return c.text("Forbidden", 403);
|
|
@@ -19093,7 +19291,7 @@ app49.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19093
19291
|
"Cache-Control": "public, max-age=3600"
|
|
19094
19292
|
});
|
|
19095
19293
|
});
|
|
19096
|
-
|
|
19294
|
+
app50.get("/generated/:filename", (c) => {
|
|
19097
19295
|
const filename = c.req.param("filename");
|
|
19098
19296
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
19099
19297
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -19104,8 +19302,8 @@ app49.get("/generated/:filename", (c) => {
|
|
|
19104
19302
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
19105
19303
|
return c.text("Not found", 404);
|
|
19106
19304
|
}
|
|
19107
|
-
const filePath =
|
|
19108
|
-
const expectedDir =
|
|
19305
|
+
const filePath = resolve31(account.accountDir, "generated", filename);
|
|
19306
|
+
const expectedDir = resolve31(account.accountDir, "generated");
|
|
19109
19307
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
19110
19308
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
19111
19309
|
return c.text("Forbidden", 403);
|
|
@@ -19123,10 +19321,10 @@ app49.get("/generated/:filename", (c) => {
|
|
|
19123
19321
|
"Cache-Control": "public, max-age=86400"
|
|
19124
19322
|
});
|
|
19125
19323
|
});
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19324
|
+
app50.route("/sites", sites_default);
|
|
19325
|
+
app50.route("/listings", listings_default);
|
|
19326
|
+
app50.route("/v", visitor_event_default);
|
|
19327
|
+
app50.route("/v", visitor_consent_default);
|
|
19130
19328
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
19131
19329
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
19132
19330
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
@@ -19148,11 +19346,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
19148
19346
|
})}</script>`;
|
|
19149
19347
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
19150
19348
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
19151
|
-
var brandIconFsPath =
|
|
19349
|
+
var brandIconFsPath = resolve31(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
19152
19350
|
var brandIconExists = existsSync28(brandIconFsPath);
|
|
19153
19351
|
var SW_SOURCE = (() => {
|
|
19154
19352
|
try {
|
|
19155
|
-
return readFileSync27(
|
|
19353
|
+
return readFileSync27(resolve31(process.cwd(), "public", "sw.js"), "utf-8");
|
|
19156
19354
|
} catch {
|
|
19157
19355
|
return null;
|
|
19158
19356
|
}
|
|
@@ -19160,7 +19358,7 @@ var SW_SOURCE = (() => {
|
|
|
19160
19358
|
function readInstalledVersion() {
|
|
19161
19359
|
try {
|
|
19162
19360
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
19163
|
-
const versionFile =
|
|
19361
|
+
const versionFile = join25(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
19164
19362
|
if (!existsSync28(versionFile)) return "unknown";
|
|
19165
19363
|
const content = readFileSync27(versionFile, "utf-8").trim();
|
|
19166
19364
|
return content || "unknown";
|
|
@@ -19203,7 +19401,7 @@ var clientErrorReporterScript = `<script>
|
|
|
19203
19401
|
function cachedHtml(file) {
|
|
19204
19402
|
let html = htmlCache.get(file);
|
|
19205
19403
|
if (!html) {
|
|
19206
|
-
html = readFileSync27(
|
|
19404
|
+
html = readFileSync27(resolve31(process.cwd(), "public", file), "utf-8");
|
|
19207
19405
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
19208
19406
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
19209
19407
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -19221,11 +19419,11 @@ ${clientErrorReporterScript}
|
|
|
19221
19419
|
}
|
|
19222
19420
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
19223
19421
|
function loadBrandingCache(agentSlug) {
|
|
19224
|
-
const configDir2 =
|
|
19422
|
+
const configDir2 = join25(homedir3(), BRAND.configDir);
|
|
19225
19423
|
try {
|
|
19226
19424
|
const accountId = getDefaultAccountId();
|
|
19227
19425
|
if (!accountId) return null;
|
|
19228
|
-
const cachePath =
|
|
19426
|
+
const cachePath = join25(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
19229
19427
|
if (!existsSync28(cachePath)) return null;
|
|
19230
19428
|
return JSON.parse(readFileSync27(cachePath, "utf-8"));
|
|
19231
19429
|
} catch {
|
|
@@ -19237,6 +19435,9 @@ function resolveDefaultSlug() {
|
|
|
19237
19435
|
if (!account) return null;
|
|
19238
19436
|
return resolveDefaultAgentSlug(account.accountDir);
|
|
19239
19437
|
}
|
|
19438
|
+
function wantsNextSurface(c) {
|
|
19439
|
+
return c.req.query("surface") === "next";
|
|
19440
|
+
}
|
|
19240
19441
|
function brandedPublicHtml(agentSlug) {
|
|
19241
19442
|
const baseHtml = cachedHtml("public.html");
|
|
19242
19443
|
if (!agentSlug) return baseHtml;
|
|
@@ -19270,7 +19471,7 @@ function escapeHtml(s) {
|
|
|
19270
19471
|
function agentUnavailableHtml() {
|
|
19271
19472
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
19272
19473
|
}
|
|
19273
|
-
|
|
19474
|
+
app50.get("/", (c) => {
|
|
19274
19475
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19275
19476
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
19276
19477
|
if (klass === "operator") {
|
|
@@ -19287,19 +19488,22 @@ app49.get("/", (c) => {
|
|
|
19287
19488
|
);
|
|
19288
19489
|
}
|
|
19289
19490
|
console.error(`[public-root] op=serve-default slug=${defaultSlug}`);
|
|
19491
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19290
19492
|
return c.html(brandedPublicHtml(defaultSlug));
|
|
19291
19493
|
}
|
|
19292
19494
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
19293
19495
|
return c.html(cachedHtml("index.html"));
|
|
19294
19496
|
});
|
|
19295
|
-
|
|
19497
|
+
app50.get("/public", (c) => {
|
|
19296
19498
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19297
19499
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19500
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19298
19501
|
return c.html(cachedHtml("public.html"));
|
|
19299
19502
|
});
|
|
19300
|
-
|
|
19503
|
+
app50.get("/public-chat", (c) => {
|
|
19301
19504
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19302
19505
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19506
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19303
19507
|
return c.html(cachedHtml("public.html"));
|
|
19304
19508
|
});
|
|
19305
19509
|
async function logViewerFetch(c, next) {
|
|
@@ -19316,12 +19520,12 @@ async function logViewerFetch(c, next) {
|
|
|
19316
19520
|
duration_ms: Date.now() - start
|
|
19317
19521
|
});
|
|
19318
19522
|
}
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19523
|
+
app50.use("/vnc-viewer.html", logViewerFetch);
|
|
19524
|
+
app50.use("/vnc-popout.html", logViewerFetch);
|
|
19525
|
+
app50.get("/vnc-popout.html", (c) => {
|
|
19322
19526
|
let html = htmlCache.get("vnc-popout.html");
|
|
19323
19527
|
if (!html) {
|
|
19324
|
-
html = readFileSync27(
|
|
19528
|
+
html = readFileSync27(resolve31(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
19325
19529
|
const name = escapeHtml(BRAND.productName);
|
|
19326
19530
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
19327
19531
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -19331,7 +19535,7 @@ app49.get("/vnc-popout.html", (c) => {
|
|
|
19331
19535
|
}
|
|
19332
19536
|
return c.html(html);
|
|
19333
19537
|
});
|
|
19334
|
-
|
|
19538
|
+
app50.post("/api/vnc/client-event", async (c) => {
|
|
19335
19539
|
let body;
|
|
19336
19540
|
try {
|
|
19337
19541
|
body = await c.req.json();
|
|
@@ -19352,11 +19556,11 @@ app49.post("/api/vnc/client-event", async (c) => {
|
|
|
19352
19556
|
});
|
|
19353
19557
|
return c.json({ ok: true });
|
|
19354
19558
|
});
|
|
19355
|
-
|
|
19559
|
+
app50.get("/g/:slug", (c) => {
|
|
19356
19560
|
return c.html(brandedPublicHtml());
|
|
19357
19561
|
});
|
|
19358
19562
|
for (const pwa of PWA_SURFACES) {
|
|
19359
|
-
|
|
19563
|
+
app50.get(pwa.manifestPath, (c) => {
|
|
19360
19564
|
const manifest = buildManifest(pwa, {
|
|
19361
19565
|
productName: BRAND.productName,
|
|
19362
19566
|
iconPath: brandIconPath,
|
|
@@ -19370,7 +19574,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
19370
19574
|
return c.body(JSON.stringify(manifest));
|
|
19371
19575
|
});
|
|
19372
19576
|
}
|
|
19373
|
-
|
|
19577
|
+
app50.get("/sw.js", (c) => {
|
|
19374
19578
|
if (SW_SOURCE == null) {
|
|
19375
19579
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
19376
19580
|
return c.text("Service worker unavailable", 500);
|
|
@@ -19379,27 +19583,27 @@ app49.get("/sw.js", (c) => {
|
|
|
19379
19583
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
19380
19584
|
return c.body(SW_SOURCE);
|
|
19381
19585
|
});
|
|
19382
|
-
|
|
19586
|
+
app50.get("/graph", (c) => {
|
|
19383
19587
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19384
19588
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19385
19589
|
return c.html(cachedHtml("graph.html"));
|
|
19386
19590
|
});
|
|
19387
|
-
|
|
19591
|
+
app50.get("/chat", (c) => {
|
|
19388
19592
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19389
19593
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19390
19594
|
return c.html(cachedHtml("chat.html"));
|
|
19391
19595
|
});
|
|
19392
|
-
|
|
19596
|
+
app50.get("/data", (c) => {
|
|
19393
19597
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19394
19598
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19395
19599
|
return c.html(cachedHtml("data.html"));
|
|
19396
19600
|
});
|
|
19397
|
-
|
|
19601
|
+
app50.get("/browser", (c) => {
|
|
19398
19602
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19399
19603
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19400
19604
|
return c.html(cachedHtml("browser.html"));
|
|
19401
19605
|
});
|
|
19402
|
-
|
|
19606
|
+
app50.get("/:slug", async (c, next) => {
|
|
19403
19607
|
const slug = c.req.param("slug");
|
|
19404
19608
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
19405
19609
|
const account = resolveAccount();
|
|
@@ -19409,18 +19613,19 @@ app49.get("/:slug", async (c, next) => {
|
|
|
19409
19613
|
}
|
|
19410
19614
|
const branding = loadBrandingCache(slug);
|
|
19411
19615
|
console.error(`[public-catchall] served path=/${slug} slug=${slug} branding=${branding ? "hit" : "miss"}`);
|
|
19616
|
+
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19412
19617
|
return c.html(brandedPublicHtml(slug));
|
|
19413
19618
|
}
|
|
19414
19619
|
await next();
|
|
19415
19620
|
});
|
|
19416
19621
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
19417
|
-
|
|
19622
|
+
app50.get("/favicon.ico", (c) => {
|
|
19418
19623
|
c.header("Cache-Control", "public, max-age=300");
|
|
19419
19624
|
return c.redirect(brandFaviconPath, 302);
|
|
19420
19625
|
});
|
|
19421
19626
|
}
|
|
19422
|
-
|
|
19423
|
-
|
|
19627
|
+
app50.use("/*", serveStatic({ root: "./public" }));
|
|
19628
|
+
app50.all("*", (c) => {
|
|
19424
19629
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19425
19630
|
const path2 = c.req.path;
|
|
19426
19631
|
if (isPublicHost(host)) {
|
|
@@ -19434,7 +19639,7 @@ app49.all("*", (c) => {
|
|
|
19434
19639
|
});
|
|
19435
19640
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
19436
19641
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
19437
|
-
var httpServer = serve({ fetch:
|
|
19642
|
+
var httpServer = serve({ fetch: app50.fetch, port, hostname });
|
|
19438
19643
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
19439
19644
|
{
|
|
19440
19645
|
const census = pwaCensus({
|
|
@@ -19488,7 +19693,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
19488
19693
|
}
|
|
19489
19694
|
try {
|
|
19490
19695
|
const registered = [];
|
|
19491
|
-
for (const r of
|
|
19696
|
+
for (const r of app50.routes ?? []) {
|
|
19492
19697
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
19493
19698
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
19494
19699
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -19583,7 +19788,7 @@ try {
|
|
|
19583
19788
|
} catch (err) {
|
|
19584
19789
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
19585
19790
|
}
|
|
19586
|
-
var configDirForWhatsApp =
|
|
19791
|
+
var configDirForWhatsApp = basename9(MAXY_DIR) || ".maxy";
|
|
19587
19792
|
var bootAccount = resolveAccount();
|
|
19588
19793
|
if (bootAccount) {
|
|
19589
19794
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -19645,7 +19850,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
19645
19850
|
}
|
|
19646
19851
|
init({
|
|
19647
19852
|
configDir: configDirForWhatsApp,
|
|
19648
|
-
platformRoot:
|
|
19853
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join25(__dirname, "..")),
|
|
19649
19854
|
accountConfig: bootAccountConfig,
|
|
19650
19855
|
onMessage: async (msg) => {
|
|
19651
19856
|
if (msg.isOwnerMirror) {
|