@rubytech/create-maxy-code 0.1.191 → 0.1.192
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__/brew-resolve.test.js +1 -1
- package/dist/__tests__/macos-darwin-branch.test.js +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/payload/platform/lib/mcp-eager/dist/index.d.ts +55 -0
- package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/mcp-eager/dist/index.js +76 -0
- package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -1
- package/payload/platform/lib/mcp-eager/package.json +7 -0
- package/payload/platform/lib/mcp-eager/src/index.ts +101 -0
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-admin-tool-gate.test.sh +102 -0
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +4 -4
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +56 -0
- package/payload/platform/plugins/browser/mcp/dist/index.js +19 -19
- package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/index.js +12 -12
- package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +8 -8
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +35 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
- package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +1 -0
- package/payload/platform/plugins/url-get/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +34 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.d.ts +116 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.d.ts.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.js +125 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-eager/dist/index.js.map +1 -0
- package/payload/premium-plugins/writer-craft/lib/mcp-eager/package.json +7 -0
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +5 -4
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -1
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +5 -4
- package/payload/server/public/assets/AdminShell-CdgotOLV.js +1 -0
- package/payload/server/public/assets/{Checkbox-g2WZRfCt.js → Checkbox-DsHqjzGj.js} +1 -1
- package/payload/server/public/assets/admin-CWOprOdW.js +1 -0
- package/payload/server/public/assets/{arc-DMDAZHAN.js → arc-aUiRP9AS.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL--v-pJPNp.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-BVKxPUIS.js → architectureDiagram-Q4EWVU46-DROzw8rH.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BpD-1G1V.js → blockDiagram-DXYQGD6D-Dw9sieJu.js} +1 -1
- package/payload/server/public/assets/{brand-BGvv6AYI.js → brand-DKUA91KU.js} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CFl9Dr6U.js → c4Diagram-AHTNJAMY-fnwntjFK.js} +1 -1
- package/payload/server/public/assets/channel-DEl-UCEn.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-Di4bO8ir.js → chunk-2KRD3SAO-BK3470lx.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-B2Uc6pEC.js → chunk-336JU56O-DVpyamlA.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-yiGugjCx.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-DyEhFk-Z.js → chunk-4BX2VUAB-BOvVdJLf.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Dvf5uiFR.js → chunk-4TB4RGXK-BAPL_MqI.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-BRJOZLpU.js → chunk-55IACEB6-BwZyF7vR.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-DUQR1rF9.js → chunk-5FUZZQ4R-Ba-5D35r.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-OTvNug7K.js → chunk-5PVQY5BW-BtDS8-t9.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-BG6-9r6c.js → chunk-67CJDMHE-D5bhMrtY.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BvMbitX7.js → chunk-7N4EOEYR-Si7Lgrwc.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-CE8mGBD5.js → chunk-AA7GKIK3-DMuHtDqO.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-DP7LTBll.js → chunk-BSJP7CBP-L79XKVcb.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-VfnIdN-h.js → chunk-CIAEETIT-C0O7Upmg.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-CRAsAWbD.js → chunk-EDXVE4YY-CqcdpDg_.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-BNllMoi_.js → chunk-ENJZ2VHE-CaBy9U1e.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-w-yBZsN2.js → chunk-FMBD7UC4-C_E43NFJ.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-f9cFywhd.js → chunk-FOC6F5B3-D9lWWHAu.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-vTeVS4qd.js → chunk-ICPOFSXX-BdPjOce4.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-B_ZUrFUq.js → chunk-K5T4RW27-DuhsNH4c.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-CcWTvRlI.js → chunk-KGLVRYIC-B4-A1Abi.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-D-5-peQw.js → chunk-LIHQZDEY-BxqgHRgT.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-B4Z5L25I.js → chunk-ORNJ4GCN-DEYQ5WaJ.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-BdSFcvNa.js → chunk-OYMX7WX6-CK6wx_FD.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-Bd-GrQM6.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-BpFXup4D.js → chunk-U2HBQHQK-DyZFy43o.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DF-6QHx4.js → chunk-X2U36JSP-CMTofLbX.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-m1Y_r88I.js → chunk-XPW4576I-CBfZXZDB.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-CKgDoLRT.js → chunk-YZCP3GAM-YfFrkYbQ.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-B0ACvZCZ.js → chunk-ZZ45TVLE-BVfvS5n3.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BZ9e1dmR.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-B1_4kXdN.js +1 -0
- package/payload/server/public/assets/clone-CNXfxCnl.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BhtgY3T7.js → cose-bilkent-S5V4N54A-Br2gjtEO.js} +1 -1
- package/payload/server/public/assets/{dagre-3yl9rfxR.js → dagre-ComHkUs6.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-D-Ux4uwL.js → dagre-KV5264BT-BB-QqzpF.js} +1 -1
- package/payload/server/public/assets/data-DEsRsfI1.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-D-MOMikl.js → diagram-5BDNPKRD-CpQQszhw.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DKdFcnhf.js → diagram-G4DWMVQ6-DLdElVzs.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-ajamR766.js → diagram-MMDJMWI5-JQ3ceLSO.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-D2Pbk2Kk.js → diagram-TYMM5635-D_-AtVPR.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-v3o948pk.js → erDiagram-SMLLAGMA-Dq50MKD-.js} +1 -1
- package/payload/server/public/assets/{flatten-BsWEYbBB.js → flatten-Bo6YRmWl.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-byC1a6GE.js → flowDiagram-DWJPFMVM-CEdKm-zL.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-Dybzs-Sw.js → ganttDiagram-T4ZO3ILL-CpTomdNN.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-CI0s_tqn.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DvzXYLuW.js → gitGraphDiagram-UUTBAWPF-VU-gjbee.js} +1 -1
- package/payload/server/public/assets/graph-BXaY_xoS.js +51 -0
- package/payload/server/public/assets/graph-labels-EqZyoU25.js +1 -0
- package/payload/server/public/assets/{graphlib-DvH_spaA.js → graphlib-nLzyerxi.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-g3gYW7Qm.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-ThwX5Xgr.js +2 -0
- package/payload/server/public/assets/{isEmpty-BWl67LAZ.js → isEmpty-D6Kr-M1M.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CpY5W64P.js → ishikawaDiagram-UXIWVN3A-DaKxxHLW.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-ymMAQVdm.js → journeyDiagram-VCZTEJTY-DtMAHpWz.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-_NX9hNK3.js → kanban-definition-6JOO6SKY-s898dJRu.js} +1 -1
- package/payload/server/public/assets/{line-Dz7zKWX-.js → line-D96q2CLD.js} +1 -1
- package/payload/server/public/assets/{linear-0O14Y6uf.js → linear-DOh_6k2k.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BCWd1en6.js → mermaid-parser.core-CqFLtzz8.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-gSoFkVoN.js → mermaid.core-o9rmBTu-.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-QuIyK2bd.js → mindmap-definition-QFDTVHPH-BM8KKsaM.js} +1 -1
- package/payload/server/public/assets/{ordinal-krseTxxN.js → ordinal-BDi6f4xk.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-CT0TB9HI.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-CXLe7TFF.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DHK0yy7U.js → pieDiagram-DEJITSTG-B66Y-dcU.js} +1 -1
- package/payload/server/public/assets/public-ClAaV52O.js +35 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-wK1jwWo5.js → quadrantDiagram-34T5L4WZ-Bv4mojq8.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-DnPLBl-D.js +1 -0
- package/payload/server/public/assets/{reduce-tk-xY6Fv.js → reduce-CGi9ik8i.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-W_mH85_d.js → requirementDiagram-MS252O5E-BNYdfEKS.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-nGAM-YLQ.js → sankeyDiagram-XADWPNL6-Do8BgX92.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-SMfUCwBH.js → sequenceDiagram-FGHM5R23-VN57FKth.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CYKXFirH.js → stateDiagram-FHFEXIEX-CCtRfCg0.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Cz319KBI.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-DethbNFa.js → timeline-definition-GMOUNBTQ-ja01S9Wd.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-C3cb7Xwe.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-Dc7G3Bgm.js +1 -0
- package/payload/server/public/assets/useSelectionMode-ejMSaa52.js +5 -0
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BUlJTe9Z.js → vennDiagram-DHZGUBPP-wWbiL1f6.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-DtgibWAt.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CL1TvZ7j.js → wardleyDiagram-NUSXRM2D-BZgue-PK.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Cav10l-Z.js → xychartDiagram-5P7HB3ND-B_ynYRnW.js} +1 -1
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +5 -5
- package/payload/server/public/index.html +5 -7
- package/payload/server/public/public.html +4 -4
- package/payload/server/server.js +535 -494
- package/payload/server/public/assets/admin-DFxXLXfg.js +0 -216
- package/payload/server/public/assets/architecture-YZFGNWBL-COhEvUpo.js +0 -1
- package/payload/server/public/assets/channel-BTEFjudQ.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-CcIGcm29.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-CWh_0JsP.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-ClkdniKF.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-kjJetfh2.js +0 -1
- package/payload/server/public/assets/clone-BllVm2iY.js +0 -1
- package/payload/server/public/assets/data-DtYcqL1G.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-DeTNsAO0.js +0 -1
- package/payload/server/public/assets/graph-C-XPyGsO.js +0 -1
- package/payload/server/public/assets/graph-labels-CZin3myX.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DJJ9GlS6.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-C2FeU8nE.js +0 -2
- package/payload/server/public/assets/lib-BEvO-mE0.js +0 -33
- package/payload/server/public/assets/packet-4T2RLAQJ-CGbvGkvF.js +0 -1
- package/payload/server/public/assets/page-CKlvbjKn.js +0 -1
- package/payload/server/public/assets/page-DSj21hpG.js +0 -51
- package/payload/server/public/assets/pie-ZZUOXDRM-BZy8rjFn.js +0 -1
- package/payload/server/public/assets/public-BnS9zREj.js +0 -7
- package/payload/server/public/assets/radar-PYXPWWZC-DcfWIVXr.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B9ZwM8kx.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-3WugwVdj.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cf5mDLlu.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-Bv4md4b3.js +0 -1
- /package/payload/server/public/assets/{_baseFor-BHtDrjIo.js → _baseFor-Cam2PbSt.js} +0 -0
- /package/payload/server/public/assets/{array-DetWRiSa.js → array-DYRGGQae.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-C9yNhe1u.js → cytoscape.esm-nWsJMTNI.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-_WRwicXn.js → defaultLocale-Du1XY3Dp.js} +0 -0
- /package/payload/server/public/assets/{dist-Bd4S37oi.js → dist-BzAsli7o.js} +0 -0
- /package/payload/server/public/assets/{init-sTEcj9YX.js → init-B5BXBRcm.js} +0 -0
- /package/payload/server/public/assets/{katex-s61Rgv6l.js → katex-HOUACuRw.js} +0 -0
- /package/payload/server/public/assets/{path-B0Ik7Tu9.js → path-CNO468J-.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-DKRO8IF-.js → rough.esm-DRO6hWPh.js} +0 -0
- /package/payload/server/public/assets/{src-B6XdH6xq.js → src-CWiyyVfn.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -815,8 +815,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
815
815
|
};
|
|
816
816
|
|
|
817
817
|
// server/index.ts
|
|
818
|
-
import { readFileSync as readFileSync20, existsSync as
|
|
819
|
-
import { resolve as
|
|
818
|
+
import { readFileSync as readFileSync20, existsSync as existsSync22, watchFile } from "fs";
|
|
819
|
+
import { resolve as resolve23, join as join15, basename as basename6 } from "path";
|
|
820
820
|
import { homedir as homedir2 } from "os";
|
|
821
821
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
822
822
|
|
|
@@ -1274,7 +1274,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1274
1274
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1275
1275
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1276
1276
|
const timer2 = new Promise(
|
|
1277
|
-
(
|
|
1277
|
+
(resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
|
|
1278
1278
|
);
|
|
1279
1279
|
const result = await Promise.race([
|
|
1280
1280
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1402,11 +1402,11 @@ async function createWaSocket(opts) {
|
|
|
1402
1402
|
return sock;
|
|
1403
1403
|
}
|
|
1404
1404
|
async function waitForConnection(sock) {
|
|
1405
|
-
return new Promise((
|
|
1405
|
+
return new Promise((resolve24, reject) => {
|
|
1406
1406
|
const handler = (update) => {
|
|
1407
1407
|
if (update.connection === "open") {
|
|
1408
1408
|
sock.ev.off("connection.update", handler);
|
|
1409
|
-
|
|
1409
|
+
resolve24();
|
|
1410
1410
|
}
|
|
1411
1411
|
if (update.connection === "close") {
|
|
1412
1412
|
sock.ev.off("connection.update", handler);
|
|
@@ -1520,14 +1520,14 @@ ${inspected}`;
|
|
|
1520
1520
|
return inspect2(err, INSPECT_OPTS2);
|
|
1521
1521
|
}
|
|
1522
1522
|
function withTimeout(label, promise, timeoutMs) {
|
|
1523
|
-
return new Promise((
|
|
1523
|
+
return new Promise((resolve24, reject) => {
|
|
1524
1524
|
const timer2 = setTimeout(() => {
|
|
1525
1525
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1526
1526
|
}, timeoutMs);
|
|
1527
1527
|
promise.then(
|
|
1528
1528
|
(value) => {
|
|
1529
1529
|
clearTimeout(timer2);
|
|
1530
|
-
|
|
1530
|
+
resolve24(value);
|
|
1531
1531
|
},
|
|
1532
1532
|
(err) => {
|
|
1533
1533
|
clearTimeout(timer2);
|
|
@@ -2062,8 +2062,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2062
2062
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2063
2063
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2064
2064
|
let release;
|
|
2065
|
-
const mine = new Promise((
|
|
2066
|
-
release =
|
|
2065
|
+
const mine = new Promise((resolve24) => {
|
|
2066
|
+
release = resolve24;
|
|
2067
2067
|
});
|
|
2068
2068
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2069
2069
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3099,11 +3099,11 @@ async function connectWithReconnect(conn) {
|
|
|
3099
3099
|
console.error(
|
|
3100
3100
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3101
3101
|
);
|
|
3102
|
-
await new Promise((
|
|
3103
|
-
const timer2 = setTimeout(
|
|
3102
|
+
await new Promise((resolve24) => {
|
|
3103
|
+
const timer2 = setTimeout(resolve24, delay);
|
|
3104
3104
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3105
3105
|
clearTimeout(timer2);
|
|
3106
|
-
|
|
3106
|
+
resolve24();
|
|
3107
3107
|
}, { once: true });
|
|
3108
3108
|
});
|
|
3109
3109
|
}
|
|
@@ -3111,16 +3111,16 @@ async function connectWithReconnect(conn) {
|
|
|
3111
3111
|
}
|
|
3112
3112
|
}
|
|
3113
3113
|
function waitForDisconnectEvent(conn) {
|
|
3114
|
-
return new Promise((
|
|
3114
|
+
return new Promise((resolve24) => {
|
|
3115
3115
|
if (!conn.sock) {
|
|
3116
|
-
|
|
3116
|
+
resolve24();
|
|
3117
3117
|
return;
|
|
3118
3118
|
}
|
|
3119
3119
|
const sock = conn.sock;
|
|
3120
3120
|
const handler = (update) => {
|
|
3121
3121
|
if (update.connection === "close") {
|
|
3122
3122
|
sock.ev.off("connection.update", handler);
|
|
3123
|
-
|
|
3123
|
+
resolve24();
|
|
3124
3124
|
}
|
|
3125
3125
|
};
|
|
3126
3126
|
sock.ev.on("connection.update", handler);
|
|
@@ -3382,8 +3382,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3382
3382
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3383
3383
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3384
3384
|
let resolvePending;
|
|
3385
|
-
const sttPending = new Promise((
|
|
3386
|
-
resolvePending =
|
|
3385
|
+
const sttPending = new Promise((resolve24) => {
|
|
3386
|
+
resolvePending = resolve24;
|
|
3387
3387
|
});
|
|
3388
3388
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3389
3389
|
try {
|
|
@@ -3787,20 +3787,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
3787
3787
|
|
|
3788
3788
|
// server/routes/health.ts
|
|
3789
3789
|
function checkPort(port2, timeoutMs = 500) {
|
|
3790
|
-
return new Promise((
|
|
3790
|
+
return new Promise((resolve24) => {
|
|
3791
3791
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
3792
3792
|
socket.setTimeout(timeoutMs);
|
|
3793
3793
|
socket.once("connect", () => {
|
|
3794
3794
|
socket.destroy();
|
|
3795
|
-
|
|
3795
|
+
resolve24(true);
|
|
3796
3796
|
});
|
|
3797
3797
|
socket.once("error", () => {
|
|
3798
3798
|
socket.destroy();
|
|
3799
|
-
|
|
3799
|
+
resolve24(false);
|
|
3800
3800
|
});
|
|
3801
3801
|
socket.once("timeout", () => {
|
|
3802
3802
|
socket.destroy();
|
|
3803
|
-
|
|
3803
|
+
resolve24(false);
|
|
3804
3804
|
});
|
|
3805
3805
|
});
|
|
3806
3806
|
}
|
|
@@ -4536,12 +4536,12 @@ async function dispatchOnce(input) {
|
|
|
4536
4536
|
});
|
|
4537
4537
|
if (!entry) return { error: "spawn-failed" };
|
|
4538
4538
|
entry.lastInboundAt = Date.now();
|
|
4539
|
-
let
|
|
4539
|
+
let resolve24;
|
|
4540
4540
|
const turnPromise = new Promise((r) => {
|
|
4541
|
-
|
|
4541
|
+
resolve24 = r;
|
|
4542
4542
|
});
|
|
4543
4543
|
const listener = (text) => {
|
|
4544
|
-
|
|
4544
|
+
resolve24(text);
|
|
4545
4545
|
};
|
|
4546
4546
|
entry.subscribers.add(listener);
|
|
4547
4547
|
const writeOk = await writeInput(entry, input.text);
|
|
@@ -4983,8 +4983,8 @@ async function startLogin(opts) {
|
|
|
4983
4983
|
resetActiveLogin(accountId);
|
|
4984
4984
|
let resolveQr = null;
|
|
4985
4985
|
let rejectQr = null;
|
|
4986
|
-
const qrPromise = new Promise((
|
|
4987
|
-
resolveQr =
|
|
4986
|
+
const qrPromise = new Promise((resolve24, reject) => {
|
|
4987
|
+
resolveQr = resolve24;
|
|
4988
4988
|
rejectQr = reject;
|
|
4989
4989
|
});
|
|
4990
4990
|
const qrTimer = setTimeout(
|
|
@@ -8769,11 +8769,23 @@ async function cascadeDeleteDocument(params) {
|
|
|
8769
8769
|
// app/lib/file-index.ts
|
|
8770
8770
|
import * as fsp from "fs/promises";
|
|
8771
8771
|
import { resolve as resolve13, relative as relative2, join as join11, basename as basename3, extname as extname2, sep as sep3 } from "path";
|
|
8772
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
8772
8773
|
import { execFile as execFile2 } from "child_process";
|
|
8773
8774
|
import { promisify as promisify2 } from "util";
|
|
8774
8775
|
var execFileAsync2 = promisify2(execFile2);
|
|
8775
8776
|
var CONTENT_CAP = 1e5;
|
|
8776
|
-
var
|
|
8777
|
+
var OCR_TIMEOUT_MS = 3e4;
|
|
8778
|
+
var OCR_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8779
|
+
".png",
|
|
8780
|
+
".jpg",
|
|
8781
|
+
".jpeg",
|
|
8782
|
+
".gif",
|
|
8783
|
+
".webp",
|
|
8784
|
+
".tiff",
|
|
8785
|
+
".tif",
|
|
8786
|
+
".bmp"
|
|
8787
|
+
]);
|
|
8788
|
+
var RECONCILE_DEBOUNCE_MS = 5 * 60 * 1e3;
|
|
8777
8789
|
var lastReconcileAt = /* @__PURE__ */ new Map();
|
|
8778
8790
|
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
8779
8791
|
".txt",
|
|
@@ -8826,26 +8838,60 @@ async function extractPdf(absolute) {
|
|
|
8826
8838
|
});
|
|
8827
8839
|
return stdout.trim();
|
|
8828
8840
|
}
|
|
8841
|
+
async function ocrPdf(absolute) {
|
|
8842
|
+
const outPdf = join11(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
8843
|
+
try {
|
|
8844
|
+
await execFileAsync2(
|
|
8845
|
+
"ocrmypdf",
|
|
8846
|
+
["--skip-text", "--quiet", "--output-type", "pdf", absolute, outPdf],
|
|
8847
|
+
{ maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
|
|
8848
|
+
);
|
|
8849
|
+
const { stdout } = await execFileAsync2("pdftotext", [outPdf, "-"], {
|
|
8850
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
8851
|
+
timeout: OCR_TIMEOUT_MS
|
|
8852
|
+
});
|
|
8853
|
+
return stdout.trim();
|
|
8854
|
+
} finally {
|
|
8855
|
+
await fsp.rm(outPdf, { force: true });
|
|
8856
|
+
}
|
|
8857
|
+
}
|
|
8858
|
+
async function ocrImage(absolute) {
|
|
8859
|
+
const { stdout } = await execFileAsync2(
|
|
8860
|
+
"tesseract",
|
|
8861
|
+
[absolute, "-", "-l", "eng", "--psm", "3"],
|
|
8862
|
+
{ maxBuffer: 10 * 1024 * 1024, timeout: OCR_TIMEOUT_MS }
|
|
8863
|
+
);
|
|
8864
|
+
return stdout.trim();
|
|
8865
|
+
}
|
|
8829
8866
|
function stripHtml(html) {
|
|
8830
8867
|
return html.replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8831
8868
|
}
|
|
8832
8869
|
async function extractFileContent(absolute) {
|
|
8833
8870
|
const ext = extname2(absolute).toLowerCase();
|
|
8834
8871
|
try {
|
|
8835
|
-
if (ext === ".pdf")
|
|
8872
|
+
if (ext === ".pdf") {
|
|
8873
|
+
const text = (await extractPdf(absolute)).slice(0, CONTENT_CAP);
|
|
8874
|
+
if (text.length > 0) return { content: text, route: "pdftotext" };
|
|
8875
|
+
const ocred = (await ocrPdf(absolute)).slice(0, CONTENT_CAP);
|
|
8876
|
+
return ocred.length > 0 ? { content: ocred, route: "ocr-pdf" } : { content: "", route: "name-only" };
|
|
8877
|
+
}
|
|
8836
8878
|
if (HTML_EXTENSIONS.has(ext)) {
|
|
8837
8879
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8838
|
-
return stripHtml(raw).slice(0, CONTENT_CAP);
|
|
8880
|
+
return { content: stripHtml(raw).slice(0, CONTENT_CAP), route: "html" };
|
|
8839
8881
|
}
|
|
8840
8882
|
if (TEXT_EXTENSIONS.has(ext)) {
|
|
8841
8883
|
const raw = await fsp.readFile(absolute, "utf-8");
|
|
8842
|
-
return raw.slice(0, CONTENT_CAP);
|
|
8884
|
+
return { content: raw.slice(0, CONTENT_CAP), route: "text" };
|
|
8843
8885
|
}
|
|
8844
|
-
|
|
8886
|
+
if (OCR_IMAGE_EXTENSIONS.has(ext)) {
|
|
8887
|
+
const ocred = (await ocrImage(absolute)).slice(0, CONTENT_CAP);
|
|
8888
|
+
return ocred.length > 0 ? { content: ocred, route: "ocr-image" } : { content: "", route: "name-only" };
|
|
8889
|
+
}
|
|
8890
|
+
return { content: "", route: "name-only" };
|
|
8845
8891
|
} catch (err) {
|
|
8846
8892
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8847
8893
|
console.error(`[file-index] extract-failed path="${relative2(DATA_ROOT, absolute)}" err="${msg}"`);
|
|
8848
|
-
return "";
|
|
8894
|
+
return { content: "", route: "name-only" };
|
|
8849
8895
|
}
|
|
8850
8896
|
}
|
|
8851
8897
|
async function readDisplayName(absolute) {
|
|
@@ -8909,9 +8955,86 @@ async function upsertFileArtifact(session, f) {
|
|
|
8909
8955
|
f
|
|
8910
8956
|
);
|
|
8911
8957
|
}
|
|
8958
|
+
async function linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolutePath) {
|
|
8959
|
+
const res = await session.run(
|
|
8960
|
+
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
8961
|
+
OPTIONAL MATCH (d:KnowledgeDocument {accountId: $accountId, sourcePath: $absolutePath})
|
|
8962
|
+
WHERE NOT d:Trashed
|
|
8963
|
+
FOREACH (_ IN CASE WHEN d IS NULL THEN [] ELSE [1] END |
|
|
8964
|
+
MERGE (f)-[:INGESTED_AS]->(d))
|
|
8965
|
+
RETURN elementId(d) AS docId`,
|
|
8966
|
+
{ accountId, relativePath, absolutePath }
|
|
8967
|
+
);
|
|
8968
|
+
const docId = res.records[0]?.get("docId");
|
|
8969
|
+
if (docId) {
|
|
8970
|
+
console.error(
|
|
8971
|
+
`[file-index] linked-kd account=${accountId} relativePath="${relativePath}" docId=${docId.slice(0, 12)}`
|
|
8972
|
+
);
|
|
8973
|
+
}
|
|
8974
|
+
}
|
|
8975
|
+
async function findLinkedKnowledgeDocs(session, accountId, relativePaths) {
|
|
8976
|
+
if (relativePaths.length === 0) return [];
|
|
8977
|
+
const res = await session.run(
|
|
8978
|
+
`MATCH (f:FileArtifact {accountId: $accountId})-[:INGESTED_AS]->(d:KnowledgeDocument)
|
|
8979
|
+
WHERE f.relativePath IN $relativePaths AND NOT d:Trashed
|
|
8980
|
+
OPTIONAL MATCH (d)-[:HAS_SECTION]->(s:Section)
|
|
8981
|
+
OPTIONAL MATCH (s)-[:HAS_CHUNK]->(c:Chunk)
|
|
8982
|
+
WITH d, collect(DISTINCT s) AS ss, collect(DISTINCT c) AS cc
|
|
8983
|
+
RETURN elementId(d) AS docId,
|
|
8984
|
+
[x IN ss WHERE x IS NOT NULL | elementId(x)] AS sectionIds,
|
|
8985
|
+
[x IN cc WHERE x IS NOT NULL | elementId(x)] AS chunkIds`,
|
|
8986
|
+
{ accountId, relativePaths }
|
|
8987
|
+
);
|
|
8988
|
+
return res.records.map((rec) => ({
|
|
8989
|
+
docId: rec.get("docId"),
|
|
8990
|
+
sectionIds: rec.get("sectionIds") ?? [],
|
|
8991
|
+
chunkIds: rec.get("chunkIds") ?? []
|
|
8992
|
+
}));
|
|
8993
|
+
}
|
|
8994
|
+
async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths) {
|
|
8995
|
+
const linked = await findLinkedKnowledgeDocs(session, accountId, relativePaths);
|
|
8996
|
+
let kds = 0, sections = 0, chunks = 0;
|
|
8997
|
+
for (const { docId, sectionIds, chunkIds } of linked) {
|
|
8998
|
+
try {
|
|
8999
|
+
await trashNode({
|
|
9000
|
+
session,
|
|
9001
|
+
accountId,
|
|
9002
|
+
elementId: docId,
|
|
9003
|
+
by: "file-index:cascade",
|
|
9004
|
+
reason: "physical file removed from FileArtifact index"
|
|
9005
|
+
});
|
|
9006
|
+
kds++;
|
|
9007
|
+
for (const sid of sectionIds) {
|
|
9008
|
+
await trashNode({
|
|
9009
|
+
session,
|
|
9010
|
+
accountId,
|
|
9011
|
+
elementId: sid,
|
|
9012
|
+
by: `file-index:cascade:from-${docId}`,
|
|
9013
|
+
reason: `cascade from KnowledgeDocument ${docId}`
|
|
9014
|
+
});
|
|
9015
|
+
sections++;
|
|
9016
|
+
}
|
|
9017
|
+
for (const cid of chunkIds) {
|
|
9018
|
+
await trashNode({
|
|
9019
|
+
session,
|
|
9020
|
+
accountId,
|
|
9021
|
+
elementId: cid,
|
|
9022
|
+
by: `file-index:cascade:from-${docId}`,
|
|
9023
|
+
reason: `cascade from KnowledgeDocument ${docId}`
|
|
9024
|
+
});
|
|
9025
|
+
chunks++;
|
|
9026
|
+
}
|
|
9027
|
+
} catch (err) {
|
|
9028
|
+
console.error(
|
|
9029
|
+
`[file-index] cascade-trash-failed account=${accountId} docId=${docId.slice(0, 12)} err="${err.message}"`
|
|
9030
|
+
);
|
|
9031
|
+
}
|
|
9032
|
+
}
|
|
9033
|
+
return { kds, sections, chunks };
|
|
9034
|
+
}
|
|
8912
9035
|
async function buildArtifact(accountId, wf, embed2) {
|
|
8913
9036
|
const name = basename3(wf.absolute);
|
|
8914
|
-
const content = await extractFileContent(wf.absolute);
|
|
9037
|
+
const { content, route } = await extractFileContent(wf.absolute);
|
|
8915
9038
|
const displayName = await readDisplayName(wf.absolute);
|
|
8916
9039
|
const embedInput = `${name}
|
|
8917
9040
|
${content}`.slice(0, CONTENT_CAP);
|
|
@@ -8923,7 +9046,7 @@ ${content}`.slice(0, CONTENT_CAP);
|
|
|
8923
9046
|
console.error(`[file-index] embed-failed path="${wf.relativePath}" err="${err.message}"`);
|
|
8924
9047
|
}
|
|
8925
9048
|
console.error(
|
|
8926
|
-
`[file-index] index-file account=${accountId} path="${wf.relativePath}" chars=${content.length} embed-ms=${Date.now() - embedStart}`
|
|
9049
|
+
`[file-index] index-file account=${accountId} path="${wf.relativePath}" extractor=${route} chars=${content.length} embed-ms=${Date.now() - embedStart}`
|
|
8927
9050
|
);
|
|
8928
9051
|
return {
|
|
8929
9052
|
accountId,
|
|
@@ -8982,14 +9105,29 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
8982
9105
|
const unchanged = prior && prior.sizeBytes === wf.sizeBytes && prior.modifiedAt === wf.modifiedAt && prior.hasEmbedding;
|
|
8983
9106
|
if (unchanged) {
|
|
8984
9107
|
skipped++;
|
|
8985
|
-
|
|
9108
|
+
} else {
|
|
9109
|
+
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9110
|
+
upserted++;
|
|
8986
9111
|
}
|
|
8987
|
-
await
|
|
8988
|
-
upserted++;
|
|
9112
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, wf.relativePath, wf.absolute);
|
|
8989
9113
|
}
|
|
8990
9114
|
let pruned = 0;
|
|
9115
|
+
let cascadeKds = 0, cascadeSections = 0, cascadeChunks = 0;
|
|
8991
9116
|
if (clean) {
|
|
8992
9117
|
const foundPaths = walked.map((w) => w.relativePath);
|
|
9118
|
+
const goneRes = await session.run(
|
|
9119
|
+
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
9120
|
+
WHERE NOT f.relativePath IN $foundPaths
|
|
9121
|
+
RETURN f.relativePath AS rp`,
|
|
9122
|
+
{ accountId, foundPaths }
|
|
9123
|
+
);
|
|
9124
|
+
const gonePaths = goneRes.records.map((r) => r.get("rp"));
|
|
9125
|
+
if (gonePaths.length > 0) {
|
|
9126
|
+
const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, gonePaths);
|
|
9127
|
+
cascadeKds = cascade.kds;
|
|
9128
|
+
cascadeSections = cascade.sections;
|
|
9129
|
+
cascadeChunks = cascade.chunks;
|
|
9130
|
+
}
|
|
8993
9131
|
const pruneRes = await session.run(
|
|
8994
9132
|
`MATCH (f:FileArtifact {accountId: $accountId})
|
|
8995
9133
|
WHERE NOT f.relativePath IN $foundPaths
|
|
@@ -9001,7 +9139,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
9001
9139
|
pruned = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9002
9140
|
}
|
|
9003
9141
|
console.error(
|
|
9004
|
-
`[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} clean=${clean} ms=${Date.now() - t0}`
|
|
9142
|
+
`[file-index] reconcile account=${accountId} walked=${walked.length} upserted=${upserted} skipped=${skipped} pruned=${pruned} cascade-kds=${cascadeKds} cascade-sections=${cascadeSections} cascade-chunks=${cascadeChunks} clean=${clean} ms=${Date.now() - t0}`
|
|
9005
9143
|
);
|
|
9006
9144
|
return { walked: walked.length, upserted, skipped, pruned };
|
|
9007
9145
|
});
|
|
@@ -9030,10 +9168,12 @@ async function indexFile(accountId, relativePath, opts) {
|
|
|
9030
9168
|
modifiedAt: st.mtime.toISOString()
|
|
9031
9169
|
};
|
|
9032
9170
|
await upsertFileArtifact(session, await buildArtifact(accountId, wf, embed2));
|
|
9171
|
+
await linkFileArtifactToKnowledgeDocument(session, accountId, relativePath, absolute);
|
|
9033
9172
|
});
|
|
9034
9173
|
}
|
|
9035
9174
|
async function dropFileIndex(accountId, relativePath, opts) {
|
|
9036
9175
|
await withSession(opts, async (session) => {
|
|
9176
|
+
const cascade = await cascadeTrashLinkedKnowledgeDocs(session, accountId, [relativePath]);
|
|
9037
9177
|
const res = await session.run(
|
|
9038
9178
|
`MATCH (f:FileArtifact {accountId: $accountId, relativePath: $relativePath})
|
|
9039
9179
|
DETACH DELETE f
|
|
@@ -9042,7 +9182,9 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
9042
9182
|
);
|
|
9043
9183
|
const c = res.records[0]?.get("dropped");
|
|
9044
9184
|
const dropped = typeof c?.toNumber === "function" ? c.toNumber() : Number(c ?? 0);
|
|
9045
|
-
console.error(
|
|
9185
|
+
console.error(
|
|
9186
|
+
`[file-index] drop account=${accountId} path="${relativePath}" dropped=${dropped} cascade-kds=${cascade.kds} cascade-sections=${cascade.sections} cascade-chunks=${cascade.chunks}`
|
|
9187
|
+
);
|
|
9046
9188
|
});
|
|
9047
9189
|
}
|
|
9048
9190
|
|
|
@@ -9139,7 +9281,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
9139
9281
|
var app15 = new Hono();
|
|
9140
9282
|
app15.get("/", requireAdminSession, async (c) => {
|
|
9141
9283
|
const cacheKey = c.var.cacheKey;
|
|
9142
|
-
|
|
9284
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
9285
|
+
if (!accountId) {
|
|
9143
9286
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
9144
9287
|
return c.json({ error: "Account not found for session" }, 401);
|
|
9145
9288
|
}
|
|
@@ -9152,17 +9295,26 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9152
9295
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9153
9296
|
}
|
|
9154
9297
|
const { absolute, relative: relPath2 } = resolution;
|
|
9298
|
+
if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9299
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9300
|
+
return c.json({ error: "Not found" }, 404);
|
|
9301
|
+
}
|
|
9155
9302
|
try {
|
|
9156
9303
|
const info = await stat4(absolute);
|
|
9157
9304
|
if (!info.isDirectory()) {
|
|
9158
9305
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
9159
9306
|
}
|
|
9160
9307
|
const names = await readdir3(absolute);
|
|
9308
|
+
const segs = relPath2.split("/").filter(Boolean);
|
|
9309
|
+
const isAccountParent = segs.length === 1 && (segs[0] === "accounts" || segs[0] === "uploads");
|
|
9161
9310
|
const entries = [];
|
|
9162
9311
|
for (const name of names) {
|
|
9163
9312
|
if (UUID_RE3.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
|
|
9164
9313
|
continue;
|
|
9165
9314
|
}
|
|
9315
|
+
if (isAccountParent && UUID_RE3.test(name) && name !== accountId) {
|
|
9316
|
+
continue;
|
|
9317
|
+
}
|
|
9166
9318
|
try {
|
|
9167
9319
|
const entryPath = join12(absolute, name);
|
|
9168
9320
|
const s = await stat4(entryPath);
|
|
@@ -9340,6 +9492,10 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9340
9492
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9341
9493
|
}
|
|
9342
9494
|
const { absolute, relative: relPath2 } = resolution;
|
|
9495
|
+
if (crossesForeignAccountPartition(relPath2, accountId)) {
|
|
9496
|
+
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath2}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9497
|
+
return c.json({ error: "Not found" }, 404);
|
|
9498
|
+
}
|
|
9343
9499
|
const base = basename4(absolute);
|
|
9344
9500
|
const segments = relPath2.split("/").filter(Boolean);
|
|
9345
9501
|
if (base === "account.json" || segments.includes(".git")) {
|
|
@@ -11397,126 +11553,14 @@ var WRITE_CYPHER = `
|
|
|
11397
11553
|
var graph_default_view_default = app21;
|
|
11398
11554
|
|
|
11399
11555
|
// server/routes/admin/sidebar-artefacts.ts
|
|
11400
|
-
import
|
|
11401
|
-
import {
|
|
11402
|
-
import { resolve as resolve16, relative as relative4, isAbsolute, sep as sep6 } from "path";
|
|
11556
|
+
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
11557
|
+
import { resolve as resolve15, relative as relative3, isAbsolute, sep as sep5, basename as basename5 } from "path";
|
|
11403
11558
|
import { existsSync as existsSync16 } from "fs";
|
|
11404
|
-
|
|
11405
|
-
// app/lib/doc-source-resolve.ts
|
|
11406
|
-
import { readdirSync as readdirSync8, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
11407
|
-
import { relative as relative3, resolve as resolve15, sep as sep5 } from "path";
|
|
11408
|
-
function containedFile(absPath, root) {
|
|
11409
|
-
try {
|
|
11410
|
-
const real = realpathSync5(absPath);
|
|
11411
|
-
const rootReal = realpathSync5(root);
|
|
11412
|
-
if (real !== rootReal && !real.startsWith(rootReal + sep5)) return null;
|
|
11413
|
-
return statSync7(real).isFile() ? real : null;
|
|
11414
|
-
} catch {
|
|
11415
|
-
return null;
|
|
11416
|
-
}
|
|
11417
|
-
}
|
|
11418
|
-
function dataFileInDir(dir) {
|
|
11419
|
-
let entries;
|
|
11420
|
-
try {
|
|
11421
|
-
entries = readdirSync8(dir, { withFileTypes: true }).flatMap((e) => e.isFile() ? [e.name] : []);
|
|
11422
|
-
} catch {
|
|
11423
|
-
return null;
|
|
11424
|
-
}
|
|
11425
|
-
const file = entries.find((e) => !e.endsWith(".meta.json"));
|
|
11426
|
-
return file ? resolve15(dir, file) : null;
|
|
11427
|
-
}
|
|
11428
|
-
function mapToDownloadRoot(absPath, roots) {
|
|
11429
|
-
const underData = containedFile(absPath, roots.dataRoot);
|
|
11430
|
-
if (underData) {
|
|
11431
|
-
return { root: "data", relPath: relative3(realpathSync5(roots.dataRoot), underData), absReal: underData };
|
|
11432
|
-
}
|
|
11433
|
-
if (roots.claudeUploadsRoot) {
|
|
11434
|
-
const underClaude = containedFile(absPath, roots.claudeUploadsRoot);
|
|
11435
|
-
if (underClaude) {
|
|
11436
|
-
return {
|
|
11437
|
-
root: "claude-uploads",
|
|
11438
|
-
relPath: relative3(realpathSync5(roots.claudeUploadsRoot), underClaude),
|
|
11439
|
-
absReal: underClaude
|
|
11440
|
-
};
|
|
11441
|
-
}
|
|
11442
|
-
}
|
|
11443
|
-
return null;
|
|
11444
|
-
}
|
|
11445
|
-
function resolveDocDownload(input, roots) {
|
|
11446
|
-
const { accountId, attachmentId, name, sourcePath, sourceType } = input;
|
|
11447
|
-
if (sourcePath) {
|
|
11448
|
-
const mapped = mapToDownloadRoot(sourcePath, roots);
|
|
11449
|
-
if (mapped) {
|
|
11450
|
-
return { ok: true, absPath: mapped.absReal, root: mapped.root, relPath: mapped.relPath, via: "stored" };
|
|
11451
|
-
}
|
|
11452
|
-
}
|
|
11453
|
-
if (attachmentId) {
|
|
11454
|
-
const uploadsDir = resolve15(roots.attachmentsRoot, accountId, attachmentId);
|
|
11455
|
-
const file = dataFileInDir(uploadsDir);
|
|
11456
|
-
if (file) {
|
|
11457
|
-
const real = containedFile(file, roots.dataRoot);
|
|
11458
|
-
if (real) {
|
|
11459
|
-
return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "uploads" };
|
|
11460
|
-
}
|
|
11461
|
-
}
|
|
11462
|
-
}
|
|
11463
|
-
if (attachmentId && roots.claudeUploadsRoot) {
|
|
11464
|
-
const claudeDir = resolve15(roots.claudeUploadsRoot, attachmentId);
|
|
11465
|
-
const file = dataFileInDir(claudeDir);
|
|
11466
|
-
if (file) {
|
|
11467
|
-
const real = containedFile(file, roots.claudeUploadsRoot);
|
|
11468
|
-
if (real) {
|
|
11469
|
-
return {
|
|
11470
|
-
ok: true,
|
|
11471
|
-
absPath: real,
|
|
11472
|
-
root: "claude-uploads",
|
|
11473
|
-
relPath: relative3(realpathSync5(roots.claudeUploadsRoot), real),
|
|
11474
|
-
via: "claude-uploads"
|
|
11475
|
-
};
|
|
11476
|
-
}
|
|
11477
|
-
}
|
|
11478
|
-
}
|
|
11479
|
-
if (name) {
|
|
11480
|
-
const outputFile = resolve15(roots.accountsDir, accountId, "output", name);
|
|
11481
|
-
const real = containedFile(outputFile, roots.dataRoot);
|
|
11482
|
-
if (real) {
|
|
11483
|
-
return { ok: true, absPath: real, root: "data", relPath: relative3(realpathSync5(roots.dataRoot), real), via: "output" };
|
|
11484
|
-
}
|
|
11485
|
-
}
|
|
11486
|
-
return { ok: false, reason: sourceType === "web" ? "no-persisted-file" : "unresolved" };
|
|
11487
|
-
}
|
|
11488
|
-
|
|
11489
|
-
// server/routes/admin/sidebar-artefacts.ts
|
|
11490
11559
|
var LIMIT = 50;
|
|
11491
|
-
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
11492
11560
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
11493
11561
|
function toDataRootRelPath(absPath) {
|
|
11494
|
-
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT +
|
|
11495
|
-
return
|
|
11496
|
-
}
|
|
11497
|
-
function resolveDocDownloadRow(meta) {
|
|
11498
|
-
const result = resolveDocDownload(
|
|
11499
|
-
{
|
|
11500
|
-
accountId: meta.accountId,
|
|
11501
|
-
attachmentId: meta.attachmentId,
|
|
11502
|
-
name: meta.name,
|
|
11503
|
-
sourcePath: meta.sourcePath,
|
|
11504
|
-
sourceType: meta.sourceType
|
|
11505
|
-
},
|
|
11506
|
-
{
|
|
11507
|
-
dataRoot: DATA_ROOT,
|
|
11508
|
-
attachmentsRoot: ATTACHMENTS_ROOT,
|
|
11509
|
-
accountsDir: ACCOUNTS_DIR,
|
|
11510
|
-
claudeUploadsRoot: CLAUDE_UPLOADS_ROOT
|
|
11511
|
-
}
|
|
11512
|
-
);
|
|
11513
|
-
const aid = meta.attachmentId ? meta.attachmentId.slice(0, 8) : "none";
|
|
11514
|
-
if (result.ok) {
|
|
11515
|
-
console.log(`[admin/sidebar-artefacts] download-resolved id=${aid} via=${result.via} root=${result.root}`);
|
|
11516
|
-
return { downloadPath: result.relPath, downloadRoot: result.root };
|
|
11517
|
-
}
|
|
11518
|
-
console.log(`[admin/sidebar-artefacts] not-downloadable id=${aid} reason=${result.reason}`);
|
|
11519
|
-
return { downloadPath: null, downloadRoot: null };
|
|
11562
|
+
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep5)) return null;
|
|
11563
|
+
return relative3(DATA_ROOT, absPath);
|
|
11520
11564
|
}
|
|
11521
11565
|
var app22 = new Hono();
|
|
11522
11566
|
app22.get("/", requireAdminSession, async (c) => {
|
|
@@ -11526,118 +11570,64 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
11526
11570
|
return c.json({ error: "Account not found for session" }, 401);
|
|
11527
11571
|
}
|
|
11528
11572
|
const start = Date.now();
|
|
11529
|
-
const
|
|
11530
|
-
if (
|
|
11573
|
+
const outputs = await fetchOutputArtefacts(accountId);
|
|
11574
|
+
if (outputs === null) {
|
|
11531
11575
|
return c.json({ error: "Failed to load artefacts" }, 500);
|
|
11532
11576
|
}
|
|
11533
|
-
const accountDir =
|
|
11577
|
+
const accountDir = resolve15(ACCOUNTS_DIR, accountId);
|
|
11534
11578
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
11535
|
-
const artefacts = [...
|
|
11579
|
+
const artefacts = [...outputs, ...agents].sort(
|
|
11536
11580
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
11537
11581
|
).slice(0, LIMIT);
|
|
11538
11582
|
const ms = Date.now() - start;
|
|
11539
11583
|
console.log(
|
|
11540
|
-
`[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length}
|
|
11584
|
+
`[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} outputs=${outputs.length} agents=${agents.length} ms=${ms}`
|
|
11541
11585
|
);
|
|
11542
11586
|
return c.json({ artefacts });
|
|
11543
11587
|
});
|
|
11544
|
-
async function
|
|
11588
|
+
async function fetchOutputArtefacts(accountId) {
|
|
11545
11589
|
const session = getSession();
|
|
11546
|
-
let metas = [];
|
|
11547
11590
|
try {
|
|
11548
11591
|
const result = await session.run(
|
|
11549
|
-
`MATCH (
|
|
11550
|
-
WHERE
|
|
11551
|
-
RETURN
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11592
|
+
`MATCH (f:FileArtifact { accountId: $accountId })
|
|
11593
|
+
WHERE f.relativePath CONTAINS '/output/'
|
|
11594
|
+
RETURN f.relativePath AS relativePath,
|
|
11595
|
+
f.displayName AS displayName,
|
|
11596
|
+
f.mimeType AS mimeType,
|
|
11597
|
+
f.modifiedAt AS modifiedAt
|
|
11598
|
+
ORDER BY f.modifiedAt DESC
|
|
11599
|
+
LIMIT 50`,
|
|
11600
|
+
{ accountId }
|
|
11601
|
+
);
|
|
11602
|
+
return result.records.map((r) => {
|
|
11603
|
+
const relativePath = r.get("relativePath");
|
|
11604
|
+
const displayName = r.get("displayName") ?? null;
|
|
11605
|
+
const mimeType = r.get("mimeType") ?? "";
|
|
11606
|
+
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
11607
|
+
return {
|
|
11608
|
+
id: `output-file:${relativePath}`,
|
|
11609
|
+
name: displayName ?? basename5(relativePath),
|
|
11610
|
+
kind: "output-file",
|
|
11611
|
+
updatedAt: modifiedAt,
|
|
11612
|
+
editable: false,
|
|
11613
|
+
mimeType,
|
|
11614
|
+
downloadPath: relativePath,
|
|
11615
|
+
downloadRoot: "data"
|
|
11616
|
+
};
|
|
11617
|
+
});
|
|
11567
11618
|
} catch (err) {
|
|
11568
11619
|
const message = err instanceof Error ? err.message : String(err);
|
|
11569
11620
|
console.error(`[admin/sidebar-artefacts] account=${accountId} error="${message}"`);
|
|
11570
|
-
await session.close();
|
|
11571
11621
|
return null;
|
|
11572
11622
|
} finally {
|
|
11573
11623
|
await session.close();
|
|
11574
11624
|
}
|
|
11575
|
-
return Promise.all(metas.map(async (m) => {
|
|
11576
|
-
const { content, skipReason } = await readArtefactContent(accountId, m.attachmentId, m.mimeType, m.name);
|
|
11577
|
-
const { downloadPath, downloadRoot } = resolveDocDownloadRow({
|
|
11578
|
-
accountId,
|
|
11579
|
-
attachmentId: m.attachmentId,
|
|
11580
|
-
name: m.name,
|
|
11581
|
-
sourcePath: m.sourcePath,
|
|
11582
|
-
sourceType: m.sourceType
|
|
11583
|
-
});
|
|
11584
|
-
return {
|
|
11585
|
-
id: m.id,
|
|
11586
|
-
name: m.name,
|
|
11587
|
-
kind: "knowledge-doc",
|
|
11588
|
-
updatedAt: m.updatedAt,
|
|
11589
|
-
content,
|
|
11590
|
-
editable: skipReason === null,
|
|
11591
|
-
mimeType: m.mimeType,
|
|
11592
|
-
skipReason,
|
|
11593
|
-
downloadPath,
|
|
11594
|
-
downloadRoot
|
|
11595
|
-
};
|
|
11596
|
-
}));
|
|
11597
|
-
}
|
|
11598
|
-
async function readArtefactContent(accountId, attachmentId, mimeType, displayName) {
|
|
11599
|
-
if (!attachmentId) {
|
|
11600
|
-
logSkip(displayName, "null-attachmentId", mimeType);
|
|
11601
|
-
return { content: "", skipReason: "null-attachmentId" };
|
|
11602
|
-
}
|
|
11603
|
-
const isText = TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p));
|
|
11604
|
-
if (!isText) {
|
|
11605
|
-
logSkip(displayName, "non-text-mime", mimeType);
|
|
11606
|
-
return { content: "", skipReason: "non-text-mime" };
|
|
11607
|
-
}
|
|
11608
|
-
const accountDir = resolve16(ATTACHMENTS_ROOT, accountId);
|
|
11609
|
-
const dir = resolve16(accountDir, attachmentId);
|
|
11610
|
-
try {
|
|
11611
|
-
validateFilePathInAccount(dir, accountDir);
|
|
11612
|
-
} catch {
|
|
11613
|
-
logSkip(displayName, "containment-rejected", mimeType);
|
|
11614
|
-
return { content: "", skipReason: "containment-rejected" };
|
|
11615
|
-
}
|
|
11616
|
-
try {
|
|
11617
|
-
const entries = await readdir4(dir);
|
|
11618
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11619
|
-
if (!dataFile) {
|
|
11620
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11621
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11622
|
-
}
|
|
11623
|
-
return { content: await readFile5(resolve16(dir, dataFile), "utf-8"), skipReason: null };
|
|
11624
|
-
} catch (err) {
|
|
11625
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
11626
|
-
console.error(`[admin/sidebar-artefacts] read-failed attachmentId=${attachmentId.slice(0, 8)} error="${message}"`);
|
|
11627
|
-
logSkip(displayName, "missing-on-disk", mimeType);
|
|
11628
|
-
return { content: "", skipReason: "missing-on-disk" };
|
|
11629
|
-
}
|
|
11630
|
-
}
|
|
11631
|
-
function logSkip(name, reason, mimeType) {
|
|
11632
|
-
console.log(
|
|
11633
|
-
`[admin/sidebar-artefacts] content-skipped name="${name}" reason=${reason} mimeType=${mimeType || "none"}`
|
|
11634
|
-
);
|
|
11635
11625
|
}
|
|
11636
11626
|
async function fetchAgentTemplateRows(accountDir) {
|
|
11637
11627
|
const rows = [];
|
|
11638
11628
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
11639
|
-
const overridePath =
|
|
11640
|
-
const bundledPath =
|
|
11629
|
+
const overridePath = resolve15(accountDir, "agents", "admin", filename);
|
|
11630
|
+
const bundledPath = resolve15(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
11641
11631
|
const labelStem = filename.replace(/\.md$/, "");
|
|
11642
11632
|
const row = await readAgentTemplateRow({
|
|
11643
11633
|
id: `agent-template:admin:${filename}`,
|
|
@@ -11651,12 +11641,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11651
11641
|
});
|
|
11652
11642
|
if (row) rows.push(row);
|
|
11653
11643
|
}
|
|
11654
|
-
const overrideDir =
|
|
11655
|
-
const bundledDir =
|
|
11644
|
+
const overrideDir = resolve15(accountDir, "specialists", "agents");
|
|
11645
|
+
const bundledDir = resolve15(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
11656
11646
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
11657
11647
|
for (const filename of specialistNames) {
|
|
11658
|
-
const overridePath =
|
|
11659
|
-
const bundledPath =
|
|
11648
|
+
const overridePath = resolve15(overrideDir, filename);
|
|
11649
|
+
const bundledPath = resolve15(bundledDir, filename);
|
|
11660
11650
|
const row = await readAgentTemplateRow({
|
|
11661
11651
|
id: `agent-template:specialist:${filename}`,
|
|
11662
11652
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -11711,20 +11701,15 @@ async function readAgentTemplateRow(inp) {
|
|
|
11711
11701
|
}
|
|
11712
11702
|
if (!chosenPath) return null;
|
|
11713
11703
|
try {
|
|
11714
|
-
const
|
|
11715
|
-
readFile5(chosenPath, "utf-8"),
|
|
11716
|
-
stat5(chosenPath)
|
|
11717
|
-
]);
|
|
11704
|
+
const st = await stat5(chosenPath);
|
|
11718
11705
|
const dlPath = toDataRootRelPath(chosenPath);
|
|
11719
11706
|
return {
|
|
11720
11707
|
id: inp.id,
|
|
11721
11708
|
name: inp.displayName,
|
|
11722
11709
|
kind: "agent-template",
|
|
11723
11710
|
updatedAt: st.mtime.toISOString(),
|
|
11724
|
-
content,
|
|
11725
11711
|
editable: inp.editable,
|
|
11726
11712
|
mimeType: "text/markdown",
|
|
11727
|
-
skipReason: null,
|
|
11728
11713
|
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
11729
11714
|
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
11730
11715
|
// (outside DATA_ROOT) → null, so the client shows "not downloadable".
|
|
@@ -11742,14 +11727,14 @@ async function readAgentTemplateRow(inp) {
|
|
|
11742
11727
|
}
|
|
11743
11728
|
}
|
|
11744
11729
|
function isWithin(target, root) {
|
|
11745
|
-
const rel =
|
|
11730
|
+
const rel = relative3(root, target);
|
|
11746
11731
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
11747
11732
|
}
|
|
11748
11733
|
var sidebar_artefacts_default = app22;
|
|
11749
11734
|
|
|
11750
11735
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
11751
11736
|
import { mkdir as mkdir4, readdir as readdir5, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11752
|
-
import { resolve as
|
|
11737
|
+
import { resolve as resolve16 } from "path";
|
|
11753
11738
|
import { existsSync as existsSync17 } from "fs";
|
|
11754
11739
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11755
11740
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
@@ -11762,7 +11747,7 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
11762
11747
|
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
11763
11748
|
return c.json({ error: "id and content required" }, 400);
|
|
11764
11749
|
}
|
|
11765
|
-
const accountDir =
|
|
11750
|
+
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
11766
11751
|
const resolved = await resolveSavePath(body.id, accountId, accountDir);
|
|
11767
11752
|
if (resolved.kind === "heal-race") {
|
|
11768
11753
|
c.header("Retry-After", "2");
|
|
@@ -11807,17 +11792,17 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
11807
11792
|
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11808
11793
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11809
11794
|
}
|
|
11810
|
-
const parent =
|
|
11795
|
+
const parent = resolve16(accountDir, "agents", "admin");
|
|
11811
11796
|
await mkdir4(parent, { recursive: true });
|
|
11812
11797
|
try {
|
|
11813
11798
|
validateFilePathInAccount(parent, accountDir);
|
|
11814
11799
|
} catch {
|
|
11815
11800
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11816
11801
|
}
|
|
11817
|
-
return { kind: "admin-template", path:
|
|
11802
|
+
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
11818
11803
|
}
|
|
11819
11804
|
if (UUID_RE4.test(id)) {
|
|
11820
|
-
const dir =
|
|
11805
|
+
const dir = resolve16(ATTACHMENTS_ROOT, accountId, id);
|
|
11821
11806
|
if (!existsSync17(dir)) {
|
|
11822
11807
|
const attShort = id.slice(0, 8);
|
|
11823
11808
|
if (isHealPending(accountId, id)) {
|
|
@@ -11850,7 +11835,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
11850
11835
|
}
|
|
11851
11836
|
}
|
|
11852
11837
|
try {
|
|
11853
|
-
validateFilePathInAccount(dir,
|
|
11838
|
+
validateFilePathInAccount(dir, resolve16(ATTACHMENTS_ROOT, accountId));
|
|
11854
11839
|
} catch {
|
|
11855
11840
|
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11856
11841
|
}
|
|
@@ -11859,7 +11844,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
11859
11844
|
if (!dataFile) {
|
|
11860
11845
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
11861
11846
|
}
|
|
11862
|
-
return { kind: "knowledge-doc", path:
|
|
11847
|
+
return { kind: "knowledge-doc", path: resolve16(dir, dataFile) };
|
|
11863
11848
|
}
|
|
11864
11849
|
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11865
11850
|
}
|
|
@@ -11868,57 +11853,8 @@ function relPath(absPath, root) {
|
|
|
11868
11853
|
}
|
|
11869
11854
|
var sidebar_artefact_save_default = app23;
|
|
11870
11855
|
|
|
11871
|
-
// server/routes/admin/sidebar-artefact-content.ts
|
|
11872
|
-
import { readFile as readFile6, readdir as readdir6 } from "fs/promises";
|
|
11873
|
-
import { existsSync as existsSync18 } from "fs";
|
|
11874
|
-
import { resolve as resolve18 } from "path";
|
|
11875
|
-
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
11876
|
-
var app24 = new Hono();
|
|
11877
|
-
app24.get("/", requireAdminSession, async (c) => {
|
|
11878
|
-
const cacheKey = c.var.cacheKey;
|
|
11879
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
11880
|
-
if (!accountId) return new Response("Unauthorized", { status: 401 });
|
|
11881
|
-
const id = c.req.query("id") ?? "";
|
|
11882
|
-
if (!UUID_RE5.test(id)) {
|
|
11883
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11884
|
-
return new Response("Not found", { status: 404 });
|
|
11885
|
-
}
|
|
11886
|
-
const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
|
|
11887
|
-
if (!existsSync18(dir)) {
|
|
11888
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11889
|
-
return new Response("Not found", { status: 404 });
|
|
11890
|
-
}
|
|
11891
|
-
let meta;
|
|
11892
|
-
try {
|
|
11893
|
-
meta = JSON.parse(await readFile6(resolve18(dir, `${id}.meta.json`), "utf-8"));
|
|
11894
|
-
} catch {
|
|
11895
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11896
|
-
return new Response("Not found", { status: 404 });
|
|
11897
|
-
}
|
|
11898
|
-
const entries = await readdir6(dir);
|
|
11899
|
-
const dataFile = entries.find((f) => !f.endsWith(".meta.json"));
|
|
11900
|
-
if (!dataFile) {
|
|
11901
|
-
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
11902
|
-
return new Response("Not found", { status: 404 });
|
|
11903
|
-
}
|
|
11904
|
-
const start = Date.now();
|
|
11905
|
-
const buffer = await readFile6(resolve18(dir, dataFile));
|
|
11906
|
-
const ms = Date.now() - start;
|
|
11907
|
-
console.log(
|
|
11908
|
-
`[admin/sidebar-artefact-content] account=${accountId} id=${id.slice(0, 8)} mime=${meta.mimeType} bytes=${buffer.length} ms=${ms}`
|
|
11909
|
-
);
|
|
11910
|
-
return new Response(new Uint8Array(buffer), {
|
|
11911
|
-
headers: {
|
|
11912
|
-
"Content-Type": meta.mimeType,
|
|
11913
|
-
"Content-Disposition": `inline; filename="${meta.filename}"`,
|
|
11914
|
-
"Cache-Control": "private, max-age=3600"
|
|
11915
|
-
}
|
|
11916
|
-
});
|
|
11917
|
-
});
|
|
11918
|
-
var sidebar_artefact_content_default = app24;
|
|
11919
|
-
|
|
11920
11856
|
// server/routes/admin/system-stats.ts
|
|
11921
|
-
import { readFile as
|
|
11857
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
11922
11858
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
11923
11859
|
function parseCpuStat(blob) {
|
|
11924
11860
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
@@ -11962,11 +11898,11 @@ function parseMeminfo(blob) {
|
|
|
11962
11898
|
}
|
|
11963
11899
|
var SAMPLE_DELAY_MS = 100;
|
|
11964
11900
|
async function sampleLinux() {
|
|
11965
|
-
const a = parseCpuStat(await
|
|
11901
|
+
const a = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
|
|
11966
11902
|
await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
|
|
11967
|
-
const b = parseCpuStat(await
|
|
11968
|
-
const meminfo = parseMeminfo(await
|
|
11969
|
-
const loadavgRaw = (await
|
|
11903
|
+
const b = parseCpuStat(await readFile5("/proc/stat", "utf-8"));
|
|
11904
|
+
const meminfo = parseMeminfo(await readFile5("/proc/meminfo", "utf-8"));
|
|
11905
|
+
const loadavgRaw = (await readFile5("/proc/loadavg", "utf-8")).trim();
|
|
11970
11906
|
const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
|
|
11971
11907
|
if (![l1, l5, l15].every(Number.isFinite)) {
|
|
11972
11908
|
throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
|
|
@@ -12012,8 +11948,8 @@ async function sample() {
|
|
|
12012
11948
|
if (process.platform === "linux") return sampleLinux();
|
|
12013
11949
|
return sampleOsFallback();
|
|
12014
11950
|
}
|
|
12015
|
-
var
|
|
12016
|
-
|
|
11951
|
+
var app24 = new Hono();
|
|
11952
|
+
app24.get("/", async (c) => {
|
|
12017
11953
|
const started = Date.now();
|
|
12018
11954
|
if (!inflight) {
|
|
12019
11955
|
inflight = sample().finally(() => {
|
|
@@ -12036,26 +11972,26 @@ app25.get("/", async (c) => {
|
|
|
12036
11972
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
12037
11973
|
}
|
|
12038
11974
|
});
|
|
12039
|
-
var system_stats_default =
|
|
11975
|
+
var system_stats_default = app24;
|
|
12040
11976
|
|
|
12041
11977
|
// server/routes/admin/health.ts
|
|
12042
|
-
import { existsSync as
|
|
12043
|
-
import { resolve as
|
|
12044
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
11978
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
11979
|
+
import { resolve as resolve17, join as join13 } from "path";
|
|
11980
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
12045
11981
|
var brandHostname = "maxy";
|
|
12046
11982
|
var brandJsonPath = join13(PLATFORM_ROOT6, "config", "brand.json");
|
|
12047
|
-
if (
|
|
11983
|
+
if (existsSync18(brandJsonPath)) {
|
|
12048
11984
|
try {
|
|
12049
11985
|
const brand = JSON.parse(readFileSync14(brandJsonPath, "utf-8"));
|
|
12050
11986
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
12051
11987
|
} catch {
|
|
12052
11988
|
}
|
|
12053
11989
|
}
|
|
12054
|
-
var VERSION_FILE =
|
|
11990
|
+
var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
12055
11991
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12056
11992
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12057
11993
|
function readVersion() {
|
|
12058
|
-
if (!
|
|
11994
|
+
if (!existsSync18(VERSION_FILE)) return "unknown";
|
|
12059
11995
|
return readFileSync14(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12060
11996
|
}
|
|
12061
11997
|
async function probeConversationDb() {
|
|
@@ -12081,8 +12017,8 @@ async function probeConversationDb() {
|
|
|
12081
12017
|
});
|
|
12082
12018
|
}
|
|
12083
12019
|
}
|
|
12084
|
-
var
|
|
12085
|
-
|
|
12020
|
+
var app25 = new Hono();
|
|
12021
|
+
app25.get("/", async (c) => {
|
|
12086
12022
|
const version = readVersion();
|
|
12087
12023
|
const probe = await probeConversationDb();
|
|
12088
12024
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12104,7 +12040,7 @@ app26.get("/", async (c) => {
|
|
|
12104
12040
|
uptimeMs
|
|
12105
12041
|
});
|
|
12106
12042
|
});
|
|
12107
|
-
var health_default2 =
|
|
12043
|
+
var health_default2 = app25;
|
|
12108
12044
|
|
|
12109
12045
|
// server/routes/admin/linkedin-ingest.ts
|
|
12110
12046
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12200,8 +12136,8 @@ function buildInitialMessage(env) {
|
|
|
12200
12136
|
}
|
|
12201
12137
|
return header;
|
|
12202
12138
|
}
|
|
12203
|
-
var
|
|
12204
|
-
|
|
12139
|
+
var app26 = new Hono();
|
|
12140
|
+
app26.post("/", requireAdminSession, async (c) => {
|
|
12205
12141
|
let body;
|
|
12206
12142
|
try {
|
|
12207
12143
|
body = await c.req.json();
|
|
@@ -12255,10 +12191,10 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
12255
12191
|
);
|
|
12256
12192
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
12257
12193
|
});
|
|
12258
|
-
var linkedin_ingest_default =
|
|
12194
|
+
var linkedin_ingest_default = app26;
|
|
12259
12195
|
|
|
12260
12196
|
// server/routes/admin/post-turn-context.ts
|
|
12261
|
-
import
|
|
12197
|
+
import neo4j2 from "neo4j-driver";
|
|
12262
12198
|
var TAG21 = "[post-turn-context]";
|
|
12263
12199
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
12264
12200
|
"embedding",
|
|
@@ -12271,10 +12207,10 @@ function isLoopbackAddr2(addr) {
|
|
|
12271
12207
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12272
12208
|
}
|
|
12273
12209
|
function convertValue(value) {
|
|
12274
|
-
if (
|
|
12210
|
+
if (neo4j2.isDateTime(value) || neo4j2.isDate(value) || neo4j2.isLocalDateTime(value) || neo4j2.isLocalTime(value) || neo4j2.isTime(value) || neo4j2.isDuration(value)) {
|
|
12275
12211
|
return value.toString();
|
|
12276
12212
|
}
|
|
12277
|
-
if (
|
|
12213
|
+
if (neo4j2.isInt(value)) {
|
|
12278
12214
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12279
12215
|
}
|
|
12280
12216
|
if (Array.isArray(value)) {
|
|
@@ -12297,8 +12233,8 @@ function pruneProperties(raw) {
|
|
|
12297
12233
|
}
|
|
12298
12234
|
return out;
|
|
12299
12235
|
}
|
|
12300
|
-
var
|
|
12301
|
-
|
|
12236
|
+
var app27 = new Hono();
|
|
12237
|
+
app27.get("/", async (c) => {
|
|
12302
12238
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12303
12239
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
12304
12240
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12358,10 +12294,10 @@ app28.get("/", async (c) => {
|
|
|
12358
12294
|
await session.close();
|
|
12359
12295
|
}
|
|
12360
12296
|
});
|
|
12361
|
-
var post_turn_context_default =
|
|
12297
|
+
var post_turn_context_default = app27;
|
|
12362
12298
|
|
|
12363
12299
|
// server/routes/admin/public-session-context.ts
|
|
12364
|
-
import
|
|
12300
|
+
import neo4j3 from "neo4j-driver";
|
|
12365
12301
|
var TAG22 = "[public-session-context]";
|
|
12366
12302
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
12367
12303
|
"embedding",
|
|
@@ -12374,10 +12310,10 @@ function isLoopbackAddr3(addr) {
|
|
|
12374
12310
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12375
12311
|
}
|
|
12376
12312
|
function convertValue2(value) {
|
|
12377
|
-
if (
|
|
12313
|
+
if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
|
|
12378
12314
|
return value.toString();
|
|
12379
12315
|
}
|
|
12380
|
-
if (
|
|
12316
|
+
if (neo4j3.isInt(value)) {
|
|
12381
12317
|
return value.inSafeRange() ? value.toNumber() : value.toString();
|
|
12382
12318
|
}
|
|
12383
12319
|
if (Array.isArray(value)) {
|
|
@@ -12400,8 +12336,8 @@ function pruneProperties2(raw) {
|
|
|
12400
12336
|
}
|
|
12401
12337
|
return out;
|
|
12402
12338
|
}
|
|
12403
|
-
var
|
|
12404
|
-
|
|
12339
|
+
var app28 = new Hono();
|
|
12340
|
+
app28.get("/", async (c) => {
|
|
12405
12341
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12406
12342
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
12407
12343
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12460,15 +12396,15 @@ app29.get("/", async (c) => {
|
|
|
12460
12396
|
await session.close();
|
|
12461
12397
|
}
|
|
12462
12398
|
});
|
|
12463
|
-
var public_session_context_default =
|
|
12399
|
+
var public_session_context_default = app28;
|
|
12464
12400
|
|
|
12465
12401
|
// server/routes/admin/public-session-exit.ts
|
|
12466
12402
|
var TAG23 = "[public-session-exit-route]";
|
|
12467
12403
|
function isLoopbackAddr4(addr) {
|
|
12468
12404
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12469
12405
|
}
|
|
12470
|
-
var
|
|
12471
|
-
|
|
12406
|
+
var app29 = new Hono();
|
|
12407
|
+
app29.post("/", async (c) => {
|
|
12472
12408
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12473
12409
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12474
12410
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12495,15 +12431,15 @@ app30.post("/", async (c) => {
|
|
|
12495
12431
|
handlePublicSessionExit(sessionId);
|
|
12496
12432
|
return c.json({ ok: true });
|
|
12497
12433
|
});
|
|
12498
|
-
var public_session_exit_default =
|
|
12434
|
+
var public_session_exit_default = app29;
|
|
12499
12435
|
|
|
12500
12436
|
// server/routes/admin/access-session-evict.ts
|
|
12501
12437
|
var TAG24 = "[access-session-evict]";
|
|
12502
12438
|
function isLoopbackAddr5(addr) {
|
|
12503
12439
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12504
12440
|
}
|
|
12505
|
-
var
|
|
12506
|
-
|
|
12441
|
+
var app30 = new Hono();
|
|
12442
|
+
app30.post("/", async (c) => {
|
|
12507
12443
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12508
12444
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12509
12445
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12531,48 +12467,47 @@ app31.post("/", async (c) => {
|
|
|
12531
12467
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12532
12468
|
return c.json({ ok: true, dropped });
|
|
12533
12469
|
});
|
|
12534
|
-
var access_session_evict_default =
|
|
12470
|
+
var access_session_evict_default = app30;
|
|
12535
12471
|
|
|
12536
12472
|
// server/routes/admin/index.ts
|
|
12537
|
-
var
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
|
|
12555
|
-
|
|
12556
|
-
|
|
12557
|
-
|
|
12558
|
-
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
var admin_default = app32;
|
|
12473
|
+
var app31 = new Hono();
|
|
12474
|
+
app31.route("/session", session_default);
|
|
12475
|
+
app31.route("/logs", logs_default);
|
|
12476
|
+
app31.route("/claude-info", claude_info_default);
|
|
12477
|
+
app31.route("/attachment", attachment_default);
|
|
12478
|
+
app31.route("/agents", agents_default);
|
|
12479
|
+
app31.route("/sessions", sessions_default);
|
|
12480
|
+
app31.route("/claude-sessions", claude_sessions_default);
|
|
12481
|
+
app31.route("/log-ingest", log_ingest_default);
|
|
12482
|
+
app31.route("/events", events_default);
|
|
12483
|
+
app31.route("/files", files_default);
|
|
12484
|
+
app31.route("/graph-search", graph_search_default);
|
|
12485
|
+
app31.route("/graph-subgraph", graph_subgraph_default);
|
|
12486
|
+
app31.route("/graph-delete", graph_delete_default);
|
|
12487
|
+
app31.route("/graph-restore", graph_restore_default);
|
|
12488
|
+
app31.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12489
|
+
app31.route("/graph-default-view", graph_default_view_default);
|
|
12490
|
+
app31.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12491
|
+
app31.route("/sidebar-artefact-save", sidebar_artefact_save_default);
|
|
12492
|
+
app31.route("/system-stats", system_stats_default);
|
|
12493
|
+
app31.route("/health-brand", health_default2);
|
|
12494
|
+
app31.route("/linkedin-ingest", linkedin_ingest_default);
|
|
12495
|
+
app31.route("/post-turn-context", post_turn_context_default);
|
|
12496
|
+
app31.route("/public-session-context", public_session_context_default);
|
|
12497
|
+
app31.route("/public-session-exit", public_session_exit_default);
|
|
12498
|
+
app31.route("/access-session-evict", access_session_evict_default);
|
|
12499
|
+
var admin_default = app31;
|
|
12565
12500
|
|
|
12566
12501
|
// app/lib/access-gate.ts
|
|
12567
|
-
import
|
|
12502
|
+
import neo4j4 from "neo4j-driver";
|
|
12568
12503
|
import { readFileSync as readFileSync15 } from "fs";
|
|
12569
|
-
import { resolve as
|
|
12504
|
+
import { resolve as resolve18 } from "path";
|
|
12570
12505
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12571
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12506
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
12572
12507
|
var driver = null;
|
|
12573
12508
|
function readPassword() {
|
|
12574
12509
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12575
|
-
const passwordFile =
|
|
12510
|
+
const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12576
12511
|
try {
|
|
12577
12512
|
return readFileSync15(passwordFile, "utf-8").trim();
|
|
12578
12513
|
} catch {
|
|
@@ -12592,7 +12527,7 @@ function getDriver() {
|
|
|
12592
12527
|
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
12593
12528
|
const password = readPassword();
|
|
12594
12529
|
console.error(`[ui/access-gate] resolved neo4j_uri=${uri}`);
|
|
12595
|
-
driver =
|
|
12530
|
+
driver = neo4j4.driver(uri, neo4j4.auth.basic(user, password), {
|
|
12596
12531
|
maxConnectionPoolSize: 5
|
|
12597
12532
|
});
|
|
12598
12533
|
}
|
|
@@ -12775,8 +12710,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12775
12710
|
var TAG25 = "[access-verify]";
|
|
12776
12711
|
var MINT_TAG = "[access-session-mint]";
|
|
12777
12712
|
var COOKIE_NAME = "__access_session";
|
|
12778
|
-
var
|
|
12779
|
-
|
|
12713
|
+
var app32 = new Hono();
|
|
12714
|
+
app32.post("/", async (c) => {
|
|
12780
12715
|
const ip = c.var.clientIp || "unknown";
|
|
12781
12716
|
let body;
|
|
12782
12717
|
try {
|
|
@@ -12858,13 +12793,13 @@ app33.post("/", async (c) => {
|
|
|
12858
12793
|
displayName: grant.displayName
|
|
12859
12794
|
});
|
|
12860
12795
|
});
|
|
12861
|
-
var verify_token_default =
|
|
12796
|
+
var verify_token_default = app32;
|
|
12862
12797
|
|
|
12863
12798
|
// app/lib/access-email.ts
|
|
12864
12799
|
import { spawn as spawn2 } from "child_process";
|
|
12865
|
-
import { resolve as
|
|
12866
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12867
|
-
var SEND_SCRIPT =
|
|
12800
|
+
import { resolve as resolve19 } from "path";
|
|
12801
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
12802
|
+
var SEND_SCRIPT = resolve19(
|
|
12868
12803
|
PLATFORM_ROOT8,
|
|
12869
12804
|
"plugins",
|
|
12870
12805
|
"email",
|
|
@@ -12921,9 +12856,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12921
12856
|
|
|
12922
12857
|
// server/routes/access/request-magic-link.ts
|
|
12923
12858
|
var TAG26 = "[access-request-link]";
|
|
12924
|
-
var
|
|
12859
|
+
var app33 = new Hono();
|
|
12925
12860
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12926
|
-
|
|
12861
|
+
app33.post("/", async (c) => {
|
|
12927
12862
|
let body;
|
|
12928
12863
|
try {
|
|
12929
12864
|
body = await c.req.json();
|
|
@@ -12997,17 +12932,17 @@ app34.post("/", async (c) => {
|
|
|
12997
12932
|
);
|
|
12998
12933
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
12999
12934
|
});
|
|
13000
|
-
var request_magic_link_default =
|
|
12935
|
+
var request_magic_link_default = app33;
|
|
13001
12936
|
|
|
13002
12937
|
// server/routes/access/index.ts
|
|
13003
|
-
var
|
|
13004
|
-
|
|
13005
|
-
|
|
13006
|
-
var access_default =
|
|
12938
|
+
var app34 = new Hono();
|
|
12939
|
+
app34.route("/verify-token", verify_token_default);
|
|
12940
|
+
app34.route("/request-magic-link", request_magic_link_default);
|
|
12941
|
+
var access_default = app34;
|
|
13007
12942
|
|
|
13008
12943
|
// server/routes/sites.ts
|
|
13009
|
-
import { existsSync as
|
|
13010
|
-
import { resolve as
|
|
12944
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
|
|
12945
|
+
import { resolve as resolve20 } from "path";
|
|
13011
12946
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13012
12947
|
var MIME = {
|
|
13013
12948
|
".html": "text/html; charset=utf-8",
|
|
@@ -13038,8 +12973,8 @@ function getExt(p) {
|
|
|
13038
12973
|
if (idx < p.lastIndexOf("/")) return "";
|
|
13039
12974
|
return p.slice(idx).toLowerCase();
|
|
13040
12975
|
}
|
|
13041
|
-
var
|
|
13042
|
-
|
|
12976
|
+
var app35 = new Hono();
|
|
12977
|
+
app35.get("/:rel{.*}", (c) => {
|
|
13043
12978
|
const reqPath = c.req.path;
|
|
13044
12979
|
const rawRel = c.req.param("rel") ?? "";
|
|
13045
12980
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -13064,19 +12999,19 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13064
12999
|
}
|
|
13065
13000
|
segments.push(seg);
|
|
13066
13001
|
}
|
|
13067
|
-
const rootDir =
|
|
13068
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
13002
|
+
const rootDir = resolve20(account.accountDir, "sites");
|
|
13003
|
+
let filePath = segments.length === 0 ? rootDir : resolve20(rootDir, ...segments);
|
|
13069
13004
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
13070
13005
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13071
13006
|
return c.text("Forbidden", 403);
|
|
13072
13007
|
}
|
|
13073
|
-
let
|
|
13008
|
+
let stat8;
|
|
13074
13009
|
try {
|
|
13075
|
-
|
|
13010
|
+
stat8 = existsSync19(filePath) ? statSync7(filePath) : null;
|
|
13076
13011
|
} catch {
|
|
13077
|
-
|
|
13012
|
+
stat8 = null;
|
|
13078
13013
|
}
|
|
13079
|
-
if (
|
|
13014
|
+
if (stat8?.isDirectory() && !reqPath.endsWith("/")) {
|
|
13080
13015
|
const search = new URL(c.req.url).search;
|
|
13081
13016
|
const target = `${reqPath}/${search}`;
|
|
13082
13017
|
console.log(
|
|
@@ -13084,22 +13019,22 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13084
13019
|
);
|
|
13085
13020
|
return c.redirect(target, 301);
|
|
13086
13021
|
}
|
|
13087
|
-
if (
|
|
13088
|
-
filePath =
|
|
13022
|
+
if (stat8?.isDirectory()) {
|
|
13023
|
+
filePath = resolve20(filePath, "index.html");
|
|
13089
13024
|
}
|
|
13090
13025
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
13091
13026
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13092
13027
|
return c.text("Forbidden", 403);
|
|
13093
13028
|
}
|
|
13094
|
-
if (!
|
|
13029
|
+
if (!existsSync19(filePath)) {
|
|
13095
13030
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13096
13031
|
return c.text("Not found", 404);
|
|
13097
13032
|
}
|
|
13098
13033
|
let realPath;
|
|
13099
13034
|
let realRoot;
|
|
13100
13035
|
try {
|
|
13101
|
-
realPath =
|
|
13102
|
-
realRoot =
|
|
13036
|
+
realPath = realpathSync5(filePath);
|
|
13037
|
+
realRoot = realpathSync5(rootDir);
|
|
13103
13038
|
} catch {
|
|
13104
13039
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13105
13040
|
return c.text("Not found", 404);
|
|
@@ -13142,7 +13077,7 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13142
13077
|
"X-Content-Type-Options": "nosniff"
|
|
13143
13078
|
});
|
|
13144
13079
|
});
|
|
13145
|
-
var sites_default =
|
|
13080
|
+
var sites_default = app35;
|
|
13146
13081
|
|
|
13147
13082
|
// app/lib/visitor-token.ts
|
|
13148
13083
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -13222,7 +13157,7 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13222
13157
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13223
13158
|
|
|
13224
13159
|
// app/lib/brand-config.ts
|
|
13225
|
-
import { existsSync as
|
|
13160
|
+
import { existsSync as existsSync20, readFileSync as readFileSync18 } from "fs";
|
|
13226
13161
|
import { join as join14 } from "path";
|
|
13227
13162
|
var cached2 = null;
|
|
13228
13163
|
var cachedAttempted = false;
|
|
@@ -13232,7 +13167,7 @@ function readBrandConfig() {
|
|
|
13232
13167
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13233
13168
|
if (!platformRoot) return null;
|
|
13234
13169
|
const brandPath = join14(platformRoot, "config", "brand.json");
|
|
13235
|
-
if (!
|
|
13170
|
+
if (!existsSync20(brandPath)) return null;
|
|
13236
13171
|
try {
|
|
13237
13172
|
cached2 = JSON.parse(readFileSync18(brandPath, "utf-8"));
|
|
13238
13173
|
return cached2;
|
|
@@ -13242,7 +13177,7 @@ function readBrandConfig() {
|
|
|
13242
13177
|
}
|
|
13243
13178
|
|
|
13244
13179
|
// server/routes/visitor-consent.ts
|
|
13245
|
-
var
|
|
13180
|
+
var app36 = new Hono();
|
|
13246
13181
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
13247
13182
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
13248
13183
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -13287,17 +13222,17 @@ function siteSlugFromReferer(referer) {
|
|
|
13287
13222
|
return "";
|
|
13288
13223
|
}
|
|
13289
13224
|
}
|
|
13290
|
-
|
|
13225
|
+
app36.options("/consent", (c) => {
|
|
13291
13226
|
const origin = getOrigin(c);
|
|
13292
13227
|
setCorsHeaders(c, origin);
|
|
13293
13228
|
return c.body(null, 204);
|
|
13294
13229
|
});
|
|
13295
|
-
|
|
13230
|
+
app36.options("/brand-config", (c) => {
|
|
13296
13231
|
const origin = getOrigin(c);
|
|
13297
13232
|
setCorsHeaders(c, origin);
|
|
13298
13233
|
return c.body(null, 204);
|
|
13299
13234
|
});
|
|
13300
|
-
|
|
13235
|
+
app36.post("/consent", async (c) => {
|
|
13301
13236
|
const origin = getOrigin(c);
|
|
13302
13237
|
setCorsHeaders(c, origin);
|
|
13303
13238
|
let raw;
|
|
@@ -13337,7 +13272,7 @@ app37.post("/consent", async (c) => {
|
|
|
13337
13272
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
13338
13273
|
return c.body(null, 204);
|
|
13339
13274
|
});
|
|
13340
|
-
|
|
13275
|
+
app36.get("/brand-config", (c) => {
|
|
13341
13276
|
const origin = getOrigin(c);
|
|
13342
13277
|
setCorsHeaders(c, origin);
|
|
13343
13278
|
const brand = readBrandConfig();
|
|
@@ -13347,7 +13282,7 @@ app37.get("/brand-config", (c) => {
|
|
|
13347
13282
|
c.header("Cache-Control", "public, max-age=300");
|
|
13348
13283
|
return c.json({ consent: { copy, palette } });
|
|
13349
13284
|
});
|
|
13350
|
-
var visitor_consent_default =
|
|
13285
|
+
var visitor_consent_default = app36;
|
|
13351
13286
|
|
|
13352
13287
|
// server/routes/listings.ts
|
|
13353
13288
|
function getCookie(headerValue, name) {
|
|
@@ -13374,8 +13309,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
13374
13309
|
}
|
|
13375
13310
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
13376
13311
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
13377
|
-
var
|
|
13378
|
-
|
|
13312
|
+
var app37 = new Hono();
|
|
13313
|
+
app37.get("/:slug/click", async (c) => {
|
|
13379
13314
|
const slug = c.req.param("slug") ?? "";
|
|
13380
13315
|
const rawSession = c.req.query("session") ?? "";
|
|
13381
13316
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13439,10 +13374,10 @@ app38.get("/:slug/click", async (c) => {
|
|
|
13439
13374
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13440
13375
|
return c.redirect(redirectUrl, 302);
|
|
13441
13376
|
});
|
|
13442
|
-
var listings_default =
|
|
13377
|
+
var listings_default = app37;
|
|
13443
13378
|
|
|
13444
13379
|
// server/routes/visitor-event.ts
|
|
13445
|
-
var
|
|
13380
|
+
var app38 = new Hono();
|
|
13446
13381
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13447
13382
|
var buckets = /* @__PURE__ */ new Map();
|
|
13448
13383
|
var RATE_LIMIT = 60;
|
|
@@ -13509,12 +13444,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13509
13444
|
return false;
|
|
13510
13445
|
}
|
|
13511
13446
|
}
|
|
13512
|
-
|
|
13447
|
+
app38.options("/event", (c) => {
|
|
13513
13448
|
const origin = getOrigin2(c);
|
|
13514
13449
|
setCorsHeaders2(c, origin);
|
|
13515
13450
|
return c.body(null, 204);
|
|
13516
13451
|
});
|
|
13517
|
-
|
|
13452
|
+
app38.post("/event", async (c) => {
|
|
13518
13453
|
const origin = getOrigin2(c);
|
|
13519
13454
|
setCorsHeaders2(c, origin);
|
|
13520
13455
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13719,7 +13654,7 @@ async function writeEvent(opts) {
|
|
|
13719
13654
|
);
|
|
13720
13655
|
}
|
|
13721
13656
|
}
|
|
13722
|
-
var visitor_event_default =
|
|
13657
|
+
var visitor_event_default = app38;
|
|
13723
13658
|
|
|
13724
13659
|
// app/lib/graph-health.ts
|
|
13725
13660
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13802,6 +13737,109 @@ function startGraphHealthTimer() {
|
|
|
13802
13737
|
if (typeof timer.unref === "function") timer.unref();
|
|
13803
13738
|
}
|
|
13804
13739
|
|
|
13740
|
+
// app/lib/file-watcher.ts
|
|
13741
|
+
import * as fsp2 from "fs/promises";
|
|
13742
|
+
import { resolve as resolve21, sep as sep6 } from "path";
|
|
13743
|
+
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;
|
|
13744
|
+
var DEFAULT_COALESCE_MS = 500;
|
|
13745
|
+
var ROOTS = ["uploads", "accounts"];
|
|
13746
|
+
function _routeEvent(rootName, filename) {
|
|
13747
|
+
if (!filename) return null;
|
|
13748
|
+
const segs = filename.split(sep6).filter(Boolean);
|
|
13749
|
+
if (segs.length < 2) return null;
|
|
13750
|
+
const accountId = segs[0];
|
|
13751
|
+
if (!ACCOUNT_UUID_RE2.test(accountId)) return null;
|
|
13752
|
+
return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
|
|
13753
|
+
}
|
|
13754
|
+
async function startFileWatcher(opts = {}) {
|
|
13755
|
+
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
13756
|
+
const coalesceMs = opts.coalesceMs ?? DEFAULT_COALESCE_MS;
|
|
13757
|
+
const indexFn = opts.index ?? indexFile;
|
|
13758
|
+
const dropFn = opts.drop ?? dropFileIndex;
|
|
13759
|
+
for (const r of ROOTS) {
|
|
13760
|
+
try {
|
|
13761
|
+
await fsp2.mkdir(resolve21(dataRoot, r), { recursive: true });
|
|
13762
|
+
} catch (err) {
|
|
13763
|
+
console.error(
|
|
13764
|
+
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
13765
|
+
);
|
|
13766
|
+
return { stop: async () => {
|
|
13767
|
+
} };
|
|
13768
|
+
}
|
|
13769
|
+
}
|
|
13770
|
+
const controller = new AbortController();
|
|
13771
|
+
const timers = /* @__PURE__ */ new Map();
|
|
13772
|
+
function schedule(relativePath, accountId) {
|
|
13773
|
+
const existing = timers.get(relativePath);
|
|
13774
|
+
if (existing) clearTimeout(existing);
|
|
13775
|
+
const t = setTimeout(() => {
|
|
13776
|
+
timers.delete(relativePath);
|
|
13777
|
+
void runHook(relativePath, accountId);
|
|
13778
|
+
}, coalesceMs);
|
|
13779
|
+
timers.set(relativePath, t);
|
|
13780
|
+
}
|
|
13781
|
+
async function runHook(relativePath, accountId) {
|
|
13782
|
+
const absolute = resolve21(dataRoot, relativePath);
|
|
13783
|
+
let exists = false;
|
|
13784
|
+
try {
|
|
13785
|
+
const st = await fsp2.stat(absolute);
|
|
13786
|
+
exists = st.isFile();
|
|
13787
|
+
} catch (err) {
|
|
13788
|
+
const code = err.code;
|
|
13789
|
+
if (code !== "ENOENT") {
|
|
13790
|
+
console.error(`[file-watcher] stat-error path="${relativePath}" err="${err.message}"`);
|
|
13791
|
+
}
|
|
13792
|
+
}
|
|
13793
|
+
try {
|
|
13794
|
+
if (exists) {
|
|
13795
|
+
await indexFn(accountId, relativePath);
|
|
13796
|
+
} else {
|
|
13797
|
+
await dropFn(accountId, relativePath);
|
|
13798
|
+
}
|
|
13799
|
+
} catch (err) {
|
|
13800
|
+
console.error(`[file-watcher] hook-failed path="${relativePath}" err="${err.message}"`);
|
|
13801
|
+
} finally {
|
|
13802
|
+
opts.onSettled?.(relativePath);
|
|
13803
|
+
}
|
|
13804
|
+
}
|
|
13805
|
+
async function watchRoot(rootName) {
|
|
13806
|
+
const absRoot = resolve21(dataRoot, rootName);
|
|
13807
|
+
try {
|
|
13808
|
+
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
13809
|
+
for await (const event of iter) {
|
|
13810
|
+
const routed = _routeEvent(rootName, event.filename);
|
|
13811
|
+
if (!routed) continue;
|
|
13812
|
+
schedule(routed.relativePath, routed.accountId);
|
|
13813
|
+
}
|
|
13814
|
+
} catch (err) {
|
|
13815
|
+
const code = err.code;
|
|
13816
|
+
const name = err.name;
|
|
13817
|
+
if (code === "ABORT_ERR" || name === "AbortError") return;
|
|
13818
|
+
console.error(`[file-watcher] loop-error root="${rootName}" err="${err.message}"`);
|
|
13819
|
+
}
|
|
13820
|
+
}
|
|
13821
|
+
for (const r of ROOTS) void watchRoot(r);
|
|
13822
|
+
const sigHandler = () => {
|
|
13823
|
+
void stop();
|
|
13824
|
+
};
|
|
13825
|
+
process.once("SIGTERM", sigHandler);
|
|
13826
|
+
process.once("SIGINT", sigHandler);
|
|
13827
|
+
let stopped = false;
|
|
13828
|
+
async function stop() {
|
|
13829
|
+
if (stopped) return;
|
|
13830
|
+
stopped = true;
|
|
13831
|
+
process.off("SIGTERM", sigHandler);
|
|
13832
|
+
process.off("SIGINT", sigHandler);
|
|
13833
|
+
controller.abort();
|
|
13834
|
+
for (const t of timers.values()) clearTimeout(t);
|
|
13835
|
+
timers.clear();
|
|
13836
|
+
}
|
|
13837
|
+
console.error(
|
|
13838
|
+
`[file-watcher] started roots=${ROOTS.join(",")} dataRoot="${dataRoot}" coalesce-ms=${coalesceMs}`
|
|
13839
|
+
);
|
|
13840
|
+
return { stop };
|
|
13841
|
+
}
|
|
13842
|
+
|
|
13805
13843
|
// app/lib/whatsapp/inbound/claude-bridge.ts
|
|
13806
13844
|
var TAG27 = "[whatsapp-adaptor]";
|
|
13807
13845
|
function whatsappTurnTimeoutMs() {
|
|
@@ -13863,8 +13901,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
13863
13901
|
|
|
13864
13902
|
// ../lib/entitlement/src/index.ts
|
|
13865
13903
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13866
|
-
import { existsSync as
|
|
13867
|
-
import { resolve as
|
|
13904
|
+
import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
|
|
13905
|
+
import { resolve as resolve22 } from "path";
|
|
13868
13906
|
|
|
13869
13907
|
// ../lib/entitlement/src/canonicalize.ts
|
|
13870
13908
|
function canonicalize(value) {
|
|
@@ -13899,7 +13937,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
13899
13937
|
var GRACE_DAYS = 7;
|
|
13900
13938
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
13901
13939
|
function pubkeyPath(brand) {
|
|
13902
|
-
return
|
|
13940
|
+
return resolve22(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
13903
13941
|
}
|
|
13904
13942
|
var memo = null;
|
|
13905
13943
|
function memoKey(mtimeMs, account) {
|
|
@@ -13911,12 +13949,12 @@ function resolveEntitlement(brand, account) {
|
|
|
13911
13949
|
if (brand.commercialMode !== true) {
|
|
13912
13950
|
return logResolved(implicitTrust(account), null);
|
|
13913
13951
|
}
|
|
13914
|
-
const entitlementPath =
|
|
13915
|
-
if (!
|
|
13952
|
+
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
13953
|
+
if (!existsSync21(entitlementPath)) {
|
|
13916
13954
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13917
13955
|
}
|
|
13918
|
-
const
|
|
13919
|
-
const key = memoKey(
|
|
13956
|
+
const stat8 = statSync8(entitlementPath);
|
|
13957
|
+
const key = memoKey(stat8.mtimeMs, account);
|
|
13920
13958
|
if (memo && memo.key === key) {
|
|
13921
13959
|
return memo.result;
|
|
13922
13960
|
}
|
|
@@ -14104,10 +14142,10 @@ function clientFrom(c) {
|
|
|
14104
14142
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
14105
14143
|
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join15(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
14106
14144
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
14107
|
-
if (BRAND_JSON_PATH && !
|
|
14145
|
+
if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
|
|
14108
14146
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
14109
14147
|
}
|
|
14110
|
-
if (BRAND_JSON_PATH &&
|
|
14148
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14111
14149
|
try {
|
|
14112
14150
|
const parsed = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
14113
14151
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -14131,7 +14169,7 @@ var brandLoginOpts = {
|
|
|
14131
14169
|
var ALIAS_DOMAINS_PATH = join15(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
14132
14170
|
function loadAliasDomains() {
|
|
14133
14171
|
try {
|
|
14134
|
-
if (!
|
|
14172
|
+
if (!existsSync22(ALIAS_DOMAINS_PATH)) return null;
|
|
14135
14173
|
const parsed = JSON.parse(readFileSync20(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
14136
14174
|
if (!Array.isArray(parsed)) {
|
|
14137
14175
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -14156,9 +14194,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
14156
14194
|
function isPublicHost(host) {
|
|
14157
14195
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
14158
14196
|
}
|
|
14159
|
-
var
|
|
14160
|
-
|
|
14161
|
-
|
|
14197
|
+
var app39 = new Hono();
|
|
14198
|
+
app39.use("*", clientIpMiddleware);
|
|
14199
|
+
app39.use("*", async (c, next) => {
|
|
14162
14200
|
await next();
|
|
14163
14201
|
c.header("X-Content-Type-Options", "nosniff");
|
|
14164
14202
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -14168,7 +14206,7 @@ app40.use("*", async (c, next) => {
|
|
|
14168
14206
|
);
|
|
14169
14207
|
});
|
|
14170
14208
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
14171
|
-
|
|
14209
|
+
app39.use("*", async (c, next) => {
|
|
14172
14210
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
14173
14211
|
await next();
|
|
14174
14212
|
return;
|
|
@@ -14201,7 +14239,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
14201
14239
|
"/sites/"
|
|
14202
14240
|
];
|
|
14203
14241
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
14204
|
-
|
|
14242
|
+
app39.use("*", async (c, next) => {
|
|
14205
14243
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14206
14244
|
if (!isPublicHost(host)) {
|
|
14207
14245
|
await next();
|
|
@@ -14241,7 +14279,7 @@ function resolveRemoteAuthOpts() {
|
|
|
14241
14279
|
return brandLoginOpts;
|
|
14242
14280
|
}
|
|
14243
14281
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
14244
|
-
|
|
14282
|
+
app39.post("/__remote-auth/login", async (c) => {
|
|
14245
14283
|
const client = clientFrom(c);
|
|
14246
14284
|
const clientIp = client.ip || "unknown";
|
|
14247
14285
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -14286,7 +14324,7 @@ app40.post("/__remote-auth/login", async (c) => {
|
|
|
14286
14324
|
}
|
|
14287
14325
|
});
|
|
14288
14326
|
});
|
|
14289
|
-
|
|
14327
|
+
app39.get("/__remote-auth/logout", (c) => {
|
|
14290
14328
|
const client = clientFrom(c);
|
|
14291
14329
|
const clientIp = client.ip || "unknown";
|
|
14292
14330
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -14299,7 +14337,7 @@ app40.get("/__remote-auth/logout", (c) => {
|
|
|
14299
14337
|
}
|
|
14300
14338
|
});
|
|
14301
14339
|
});
|
|
14302
|
-
|
|
14340
|
+
app39.post("/__remote-auth/change-password", async (c) => {
|
|
14303
14341
|
const client = clientFrom(c);
|
|
14304
14342
|
const clientIp = client.ip || "unknown";
|
|
14305
14343
|
const rateLimited = checkRateLimit(client);
|
|
@@ -14350,13 +14388,13 @@ app40.post("/__remote-auth/change-password", async (c) => {
|
|
|
14350
14388
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
14351
14389
|
}
|
|
14352
14390
|
});
|
|
14353
|
-
|
|
14391
|
+
app39.get("/__remote-auth/setup", (c) => {
|
|
14354
14392
|
if (isRemoteAuthConfigured()) {
|
|
14355
14393
|
return c.redirect("/");
|
|
14356
14394
|
}
|
|
14357
14395
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
14358
14396
|
});
|
|
14359
|
-
|
|
14397
|
+
app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
14360
14398
|
if (isRemoteAuthConfigured()) {
|
|
14361
14399
|
return c.redirect("/");
|
|
14362
14400
|
}
|
|
@@ -14394,10 +14432,10 @@ app40.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
14394
14432
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
14395
14433
|
}
|
|
14396
14434
|
});
|
|
14397
|
-
|
|
14435
|
+
app39.get("/api/remote-auth/status", (c) => {
|
|
14398
14436
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
14399
14437
|
});
|
|
14400
|
-
|
|
14438
|
+
app39.post("/api/remote-auth/set-password", async (c) => {
|
|
14401
14439
|
let body;
|
|
14402
14440
|
try {
|
|
14403
14441
|
body = await c.req.json();
|
|
@@ -14428,9 +14466,9 @@ app40.post("/api/remote-auth/set-password", async (c) => {
|
|
|
14428
14466
|
return c.json({ error: "Failed to save password" }, 500);
|
|
14429
14467
|
}
|
|
14430
14468
|
});
|
|
14431
|
-
|
|
14469
|
+
app39.route("/api/_client-error", client_error_default);
|
|
14432
14470
|
console.log("[client-error-route] mounted");
|
|
14433
|
-
|
|
14471
|
+
app39.use("*", async (c, next) => {
|
|
14434
14472
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14435
14473
|
const path2 = c.req.path;
|
|
14436
14474
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14463,12 +14501,12 @@ app40.use("*", async (c, next) => {
|
|
|
14463
14501
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14464
14502
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14465
14503
|
});
|
|
14466
|
-
|
|
14467
|
-
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
|
|
14471
|
-
|
|
14504
|
+
app39.route("/api/health", health_default);
|
|
14505
|
+
app39.route("/api/chat", chat_default);
|
|
14506
|
+
app39.route("/api/whatsapp", whatsapp_default);
|
|
14507
|
+
app39.route("/api/onboarding", onboarding_default);
|
|
14508
|
+
app39.route("/api/admin", admin_default);
|
|
14509
|
+
app39.route("/api/access", access_default);
|
|
14472
14510
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14473
14511
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14474
14512
|
var IMAGE_MIME = {
|
|
@@ -14480,7 +14518,7 @@ var IMAGE_MIME = {
|
|
|
14480
14518
|
".svg": "image/svg+xml",
|
|
14481
14519
|
".ico": "image/x-icon"
|
|
14482
14520
|
};
|
|
14483
|
-
|
|
14521
|
+
app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
14484
14522
|
const slug = c.req.param("slug");
|
|
14485
14523
|
const filename = c.req.param("filename");
|
|
14486
14524
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14496,13 +14534,13 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14496
14534
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
14497
14535
|
return c.text("Not found", 404);
|
|
14498
14536
|
}
|
|
14499
|
-
const filePath =
|
|
14500
|
-
const expectedDir =
|
|
14537
|
+
const filePath = resolve23(account.accountDir, "agents", slug, "assets", filename);
|
|
14538
|
+
const expectedDir = resolve23(account.accountDir, "agents", slug, "assets");
|
|
14501
14539
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14502
14540
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14503
14541
|
return c.text("Forbidden", 403);
|
|
14504
14542
|
}
|
|
14505
|
-
if (!
|
|
14543
|
+
if (!existsSync22(filePath)) {
|
|
14506
14544
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14507
14545
|
return c.text("Not found", 404);
|
|
14508
14546
|
}
|
|
@@ -14515,7 +14553,7 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14515
14553
|
"Cache-Control": "public, max-age=3600"
|
|
14516
14554
|
});
|
|
14517
14555
|
});
|
|
14518
|
-
|
|
14556
|
+
app39.get("/generated/:filename", (c) => {
|
|
14519
14557
|
const filename = c.req.param("filename");
|
|
14520
14558
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14521
14559
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14526,13 +14564,13 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14526
14564
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14527
14565
|
return c.text("Not found", 404);
|
|
14528
14566
|
}
|
|
14529
|
-
const filePath =
|
|
14530
|
-
const expectedDir =
|
|
14567
|
+
const filePath = resolve23(account.accountDir, "generated", filename);
|
|
14568
|
+
const expectedDir = resolve23(account.accountDir, "generated");
|
|
14531
14569
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14532
14570
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14533
14571
|
return c.text("Forbidden", 403);
|
|
14534
14572
|
}
|
|
14535
|
-
if (!
|
|
14573
|
+
if (!existsSync22(filePath)) {
|
|
14536
14574
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14537
14575
|
return c.text("Not found", 404);
|
|
14538
14576
|
}
|
|
@@ -14545,14 +14583,14 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14545
14583
|
"Cache-Control": "public, max-age=86400"
|
|
14546
14584
|
});
|
|
14547
14585
|
});
|
|
14548
|
-
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14586
|
+
app39.route("/sites", sites_default);
|
|
14587
|
+
app39.route("/listings", listings_default);
|
|
14588
|
+
app39.route("/v", visitor_event_default);
|
|
14589
|
+
app39.route("/v", visitor_consent_default);
|
|
14552
14590
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14553
14591
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14554
14592
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14555
|
-
if (BRAND_JSON_PATH &&
|
|
14593
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14556
14594
|
try {
|
|
14557
14595
|
const fullBrand = JSON.parse(readFileSync20(BRAND_JSON_PATH, "utf-8"));
|
|
14558
14596
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -14572,7 +14610,7 @@ function readInstalledVersion() {
|
|
|
14572
14610
|
try {
|
|
14573
14611
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14574
14612
|
const versionFile = join15(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14575
|
-
if (!
|
|
14613
|
+
if (!existsSync22(versionFile)) return "unknown";
|
|
14576
14614
|
const content = readFileSync20(versionFile, "utf-8").trim();
|
|
14577
14615
|
return content || "unknown";
|
|
14578
14616
|
} catch {
|
|
@@ -14614,7 +14652,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14614
14652
|
function cachedHtml(file) {
|
|
14615
14653
|
let html = htmlCache.get(file);
|
|
14616
14654
|
if (!html) {
|
|
14617
|
-
html = readFileSync20(
|
|
14655
|
+
html = readFileSync20(resolve23(process.cwd(), "public", file), "utf-8");
|
|
14618
14656
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14619
14657
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14620
14658
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14633,12 +14671,12 @@ function loadBrandingCache(agentSlug) {
|
|
|
14633
14671
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14634
14672
|
try {
|
|
14635
14673
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14636
|
-
if (!
|
|
14674
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14637
14675
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14638
14676
|
const accountId = account.accountId;
|
|
14639
14677
|
if (!accountId) return null;
|
|
14640
14678
|
const cachePath = join15(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14641
|
-
if (!
|
|
14679
|
+
if (!existsSync22(cachePath)) return null;
|
|
14642
14680
|
return JSON.parse(readFileSync20(cachePath, "utf-8"));
|
|
14643
14681
|
} catch {
|
|
14644
14682
|
return null;
|
|
@@ -14648,7 +14686,7 @@ function resolveDefaultSlug() {
|
|
|
14648
14686
|
try {
|
|
14649
14687
|
const configDir2 = join15(homedir2(), BRAND.configDir);
|
|
14650
14688
|
const accountJsonPath = join15(configDir2, "account.json");
|
|
14651
|
-
if (!
|
|
14689
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14652
14690
|
const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
|
|
14653
14691
|
return account.defaultAgent || null;
|
|
14654
14692
|
} catch {
|
|
@@ -14685,7 +14723,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14685
14723
|
function escapeHtml(s) {
|
|
14686
14724
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14687
14725
|
}
|
|
14688
|
-
|
|
14726
|
+
app39.get("/", (c) => {
|
|
14689
14727
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14690
14728
|
if (isPublicHost(host)) {
|
|
14691
14729
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14693,12 +14731,12 @@ app40.get("/", (c) => {
|
|
|
14693
14731
|
}
|
|
14694
14732
|
return c.html(cachedHtml("index.html"));
|
|
14695
14733
|
});
|
|
14696
|
-
|
|
14734
|
+
app39.get("/public", (c) => {
|
|
14697
14735
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14698
14736
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14699
14737
|
return c.html(cachedHtml("public.html"));
|
|
14700
14738
|
});
|
|
14701
|
-
|
|
14739
|
+
app39.get("/chat", (c) => {
|
|
14702
14740
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14703
14741
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14704
14742
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14717,12 +14755,12 @@ async function logViewerFetch(c, next) {
|
|
|
14717
14755
|
duration_ms: Date.now() - start
|
|
14718
14756
|
});
|
|
14719
14757
|
}
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
|
|
14758
|
+
app39.use("/vnc-viewer.html", logViewerFetch);
|
|
14759
|
+
app39.use("/vnc-popout.html", logViewerFetch);
|
|
14760
|
+
app39.get("/vnc-popout.html", (c) => {
|
|
14723
14761
|
let html = htmlCache.get("vnc-popout.html");
|
|
14724
14762
|
if (!html) {
|
|
14725
|
-
html = readFileSync20(
|
|
14763
|
+
html = readFileSync20(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14726
14764
|
const name = escapeHtml(BRAND.productName);
|
|
14727
14765
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14728
14766
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14732,7 +14770,7 @@ app40.get("/vnc-popout.html", (c) => {
|
|
|
14732
14770
|
}
|
|
14733
14771
|
return c.html(html);
|
|
14734
14772
|
});
|
|
14735
|
-
|
|
14773
|
+
app39.post("/api/vnc/client-event", async (c) => {
|
|
14736
14774
|
let body;
|
|
14737
14775
|
try {
|
|
14738
14776
|
body = await c.req.json();
|
|
@@ -14753,25 +14791,25 @@ app40.post("/api/vnc/client-event", async (c) => {
|
|
|
14753
14791
|
});
|
|
14754
14792
|
return c.json({ ok: true });
|
|
14755
14793
|
});
|
|
14756
|
-
|
|
14794
|
+
app39.get("/g/:slug", (c) => {
|
|
14757
14795
|
return c.html(brandedPublicHtml());
|
|
14758
14796
|
});
|
|
14759
|
-
|
|
14797
|
+
app39.get("/graph", (c) => {
|
|
14760
14798
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14761
14799
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14762
14800
|
return c.html(cachedHtml("graph.html"));
|
|
14763
14801
|
});
|
|
14764
|
-
|
|
14802
|
+
app39.get("/sessions", (c) => {
|
|
14765
14803
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14766
14804
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14767
14805
|
return c.html(cachedHtml("sessions.html"));
|
|
14768
14806
|
});
|
|
14769
|
-
|
|
14807
|
+
app39.get("/data", (c) => {
|
|
14770
14808
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14771
14809
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14772
14810
|
return c.html(cachedHtml("data.html"));
|
|
14773
14811
|
});
|
|
14774
|
-
|
|
14812
|
+
app39.get("/:slug", async (c, next) => {
|
|
14775
14813
|
const slug = c.req.param("slug");
|
|
14776
14814
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14777
14815
|
const branding = loadBrandingCache(slug);
|
|
@@ -14781,15 +14819,15 @@ app40.get("/:slug", async (c, next) => {
|
|
|
14781
14819
|
await next();
|
|
14782
14820
|
});
|
|
14783
14821
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14784
|
-
|
|
14822
|
+
app39.get("/favicon.ico", (c) => {
|
|
14785
14823
|
c.header("Cache-Control", "public, max-age=300");
|
|
14786
14824
|
return c.redirect(brandFaviconPath, 302);
|
|
14787
14825
|
});
|
|
14788
14826
|
}
|
|
14789
|
-
|
|
14827
|
+
app39.use("/*", serveStatic({ root: "./public" }));
|
|
14790
14828
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14791
14829
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14792
|
-
var httpServer = serve({ fetch:
|
|
14830
|
+
var httpServer = serve({ fetch: app39.fetch, port, hostname });
|
|
14793
14831
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14794
14832
|
{
|
|
14795
14833
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14825,7 +14863,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14825
14863
|
}
|
|
14826
14864
|
try {
|
|
14827
14865
|
const registered = [];
|
|
14828
|
-
for (const r of
|
|
14866
|
+
for (const r of app39.routes ?? []) {
|
|
14829
14867
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14830
14868
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14831
14869
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14847,7 +14885,7 @@ try {
|
|
|
14847
14885
|
}
|
|
14848
14886
|
(async () => {
|
|
14849
14887
|
try {
|
|
14850
|
-
if (!
|
|
14888
|
+
if (!existsSync22(USERS_FILE)) return;
|
|
14851
14889
|
const usersRaw = readFileSync20(USERS_FILE, "utf-8").trim();
|
|
14852
14890
|
if (!usersRaw) return;
|
|
14853
14891
|
const users = JSON.parse(usersRaw);
|
|
@@ -14864,6 +14902,9 @@ try {
|
|
|
14864
14902
|
}
|
|
14865
14903
|
})();
|
|
14866
14904
|
startGraphHealthTimer();
|
|
14905
|
+
void startFileWatcher().catch((err) => {
|
|
14906
|
+
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
14907
|
+
});
|
|
14867
14908
|
try {
|
|
14868
14909
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
14869
14910
|
console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
|
|
@@ -14882,7 +14923,7 @@ try {
|
|
|
14882
14923
|
} catch (err) {
|
|
14883
14924
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
14884
14925
|
}
|
|
14885
|
-
var configDirForWhatsApp =
|
|
14926
|
+
var configDirForWhatsApp = basename6(MAXY_DIR) || ".maxy";
|
|
14886
14927
|
var bootAccount = resolveAccount();
|
|
14887
14928
|
var bootAccountConfig = bootAccount?.config;
|
|
14888
14929
|
var bootPublicAgent = bootAccount ? resolvePublicAgent(bootAccount.accountDir, { accountId: bootAccount.accountId })?.slug ?? null : null;
|
|
@@ -14940,7 +14981,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14940
14981
|
}
|
|
14941
14982
|
init({
|
|
14942
14983
|
configDir: configDirForWhatsApp,
|
|
14943
|
-
platformRoot:
|
|
14984
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join15(__dirname, "..")),
|
|
14944
14985
|
accountConfig: bootAccountConfig,
|
|
14945
14986
|
onMessage: async (msg) => {
|
|
14946
14987
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|